source: xtideuniversalbios/trunk/Assembly_Library/Inc/Emulate.inc@ 197

Last change on this file since 197 was 181, checked in by krille_n_@…, 13 years ago

Changes to all parts of the project:

  • Size optimizations.
  • Added a define (EXCLUDE_FROM_XTIDECFG) to exclude unused library code from XTIDECFG.
  • Tried to minimize time spent with interrupts disabled.
  • Some minor attempts to improve speed (reordering instructions etc).
  • Tried to improve readability, did some cleanup and fixed some errors in comments.
File size: 12.2 KB
Line 
1; Project name : Emulation library
2; Description : Macros for emulating later x86 instruction with older
3; processors.
4; Macros are used so optimized builds could be done
5; easily for different processors.
6;
7; This file must be first to be included to
8; any source file.
9%ifndef EMULATE_INC
10%define EMULATE_INC
11
12; Defines for processor support. Unsupported instructions will be
13; emulated using macros.
14; If using 286, define USE_186 and USE_286
15; If using 386, define USE_186, USE_286 and USE_386
16; If AT class PC is used (instead of XT), define USE_AT
17;%define USE_186 ; Define to use 18x/V20/V30 instructions
18;%define USE_286 ; Define to use 286 instructions
19;%define USE_386 ; Define to use 386 instructions
20;%define USE_AT ; Define for AT class machine
21; Above defines should be set on makefile!
22
23CPU 8086 ; Allow 8088/8086 instructions only
24%ifdef USE_186
25CPU 186 ; Allow instructions up to 188/186/V20/V30
26%elifdef USE_286
27CPU 286 ; Allow instructions up to 286
28%elifdef USE_386
29CPU 386 ; Allow instructions up to 386
30%endif
31BITS 16 ; Set 16 bit code generation
32
33; Alignments for jump targets.
34; Following values are optimal for different processor types:
35; 286 and 386SX WORD (16-bit, 2 bytes)
36; 386DX and 486 DWORD (32-bit, 4 bytes)
37; Pentium and later QWORD (64-bit, 8 bytes)
38%ifdef USE_AT
39 %ifdef USE_386
40 JUMP_ALIGN EQU 4
41 WORD_ALIGN EQU 2
42 %else ; USE_286
43 JUMP_ALIGN EQU 2
44 WORD_ALIGN EQU 2
45 %endif
46%else ; XT
47 JUMP_ALIGN EQU 1
48 WORD_ALIGN EQU 1
49%endif
50
51;==========================================================================
52
53;--------------------------------------------------------------------
54; Emulates BSF (Bit Scan Forward) instruction when necessary.
55; BSF is used to find index of least significant bit.
56;
57; eBSF
58; Parameters:
59; %1: Destination WORD Register for bit index (not CX or same as %2!)
60; %2: Source WORD operand where to search bit (not CX or same as %1!)
61; Returns:
62; %1: Index of highest order bit from %2
63; ZF: Set if %2 is zero
64; Cleared if %2 is non-zero
65; Corrupts registers:
66; Nothing
67;--------------------------------------------------------------------
68%macro eBSF 2
69%ifndef USE_386
70 push cx
71 cmp WORD %2, BYTE 0 ; Source operand is zero?
72 je SHORT %%Return ; If so, return with ZF set
73
74 ; Set destination to zero and load mask for bit 0
75 xor %1, %1
76 mov cx, 1
77
78ALIGN JUMP_ALIGN
79%%BitLoop:
80 test %2, cx ; Bit set?
81 jnz SHORT %%Return ; If so, return with ZF cleared
82 shl cx, 1 ; Prepare to test next bit
83 inc %1 ; Increment bit index
84 jmp SHORT %%BitLoop ; Loop until bit found
85%%Return:
86 pop cx
87;-----------------------------------
88%else
89 bsf %1, %2
90%endif
91%endmacro
92
93
94;--------------------------------------------------------------------
95; Emulates BSR (Bit Scan Reverse) instruction when necessary.
96; BSR is used to find index of most significant bit.
97;
98; eBSR
99; Parameters:
100; %1: Destination WORD Register for bit index (not CX or same as %2!)
101; %2: Source WORD operand where to search bit (not CX or same as %1!)
102; Returns:
103; %1: Index of highest order bit from %2
104; ZF: Set if %2 is zero
105; Cleared if %2 is non-zero
106; Corrupts registers:
107; Nothing
108;--------------------------------------------------------------------
109%macro eBSR 2
110%ifndef USE_386
111 push cx
112 cmp WORD %2, BYTE 0 ; Source operand is zero?
113 je SHORT %%Return ; If so, return with ZF set
114
115 ; Load mask for highest order bit
116 mov cx, 1<<15
117 mov %1, 15
118
119ALIGN JUMP_ALIGN
120%%BitLoop:
121 test %2, cx ; Bit set?
122 jnz SHORT %%Return ; If so, return with ZF cleared
123 shr cx, 1 ; Prepare to test next bit
124 dec %1 ; Decrement bit index
125 jmp SHORT %%BitLoop ; Loop until bit found
126%%Return:
127 pop cx
128;-----------------------------------
129%else
130 bsr %1, %2
131%endif
132%endmacro
133
134
135;--------------------------------------------------------------------
136; Conditional Move.
137;
138; eCMOVcc
139; Parameters:
140; %1: Destination data
141; %2: Source data
142; Returns:
143; Nothing
144; Corrupts registers:
145; Nothing
146;--------------------------------------------------------------------
147%macro eCMOVA 2
148 jbe SHORT %%Return
149 mov %1, %2
150%%Return:
151%endmacro
152
153%macro eCMOVC 2
154 jnc SHORT %%Return
155 mov %1, %2
156%%Return:
157%endmacro
158
159%macro eCMOVZ 2
160 jnz SHORT %%Return
161 mov %1, %2
162%%Return:
163%endmacro
164
165%macro eCMOVNZ 2
166 jz SHORT %%Return
167 mov %1, %2
168%%Return:
169%endmacro
170
171%macro eCMOVE 2
172 eCMOVZ %1, %2
173%endmacro
174
175%macro eCMOVNE 2
176 eCMOVNZ %1, %2
177%endmacro
178
179%macro eCMOVB 2
180 jnb SHORT %%Return
181 mov %1, %2
182%%Return:
183%endmacro
184
185
186;--------------------------------------------------------------------
187; Conditional Set.
188;
189; eCSETcc
190; Parameters:
191; %1: Destination data
192; Returns:
193; Nothing
194; Corrupts registers:
195; Flags
196;--------------------------------------------------------------------
197%macro eCSETZ 1
198 mov %1, 0 ; Clear while preserving flags
199 jnz SHORT %%Return ; Nothing to set
200 inc %1
201%%Return:
202%endmacro
203
204
205;--------------------------------------------------------------------
206; Moves byte with zero-extending to any Register.
207;
208; eMOVZX
209; Parameters:
210; %1: Destination Register (SP not supported)
211; %2: Byte register or byte address
212; Returns:
213; Nothing
214; Corrupts registers:
215; FLAGS
216;--------------------------------------------------------------------
217%macro eMOVZX 2
218%ifndef USE_386
219 %ifidni %1, ax
220 mov al, %2
221 xor ah, ah
222 %elifidni %1, bx
223 mov bl, %2
224 xor bh, bh ; %2 may use BX in effective address
225 %elifidni %1, cx
226 mov cl, %2
227 xor ch, ch
228 %elifidni %1, dx
229 mov dl, %2
230 xor dh, dh
231 %else ; SI, DI, BP (all may be used in effective address)
232 push ax
233 mov al, %2
234 xor ah, ah
235 xchg ax, %1
236 pop ax
237 %endif
238;-----------------------------------
239%else
240 movzx %1, %2
241%endif
242%endmacro
243
244
245;--------------------------------------------------------------------
246; Emulates PUSHA instruction when necessary.
247;
248; ePUSHA
249; Parameters:
250; Nothing
251; Returns:
252; Nothing
253; Corrupts registers:
254; Nothing
255;--------------------------------------------------------------------
256%macro ePUSHA 0
257%ifndef USE_186
258 push ax
259 push cx
260 push dx
261 push bx
262 push sp
263 push bp
264 push si
265 push di
266;-----------------------------------
267%else
268 pusha
269%endif
270%endmacro
271
272
273;--------------------------------------------------------------------
274; Emulates POPA instruction when necessary.
275;
276; ePOPA
277; Parameters:
278; Nothing
279; Returns:
280; Nothing
281; Corrupts registers:
282; Nothing
283;--------------------------------------------------------------------
284%macro ePOPA 0
285%ifndef USE_186
286 pop di
287 pop si
288 pop bp
289 pop ax ; Skip SP
290 pop bx
291 pop dx
292 pop cx
293 pop ax
294;-----------------------------------
295%else
296 popa
297%endif
298%endmacro
299
300
301;--------------------------------------------------------------------
302; Emulates ENTER instruction when necessary.
303;
304; eENTER
305; Parameters:
306; %1: Number of bytes to reserve from stack
307; %2: The lexical nesting level (not emulated, set to 0)
308; Returns:
309; SS:BP: Ptr to old BP
310; ([bp-2] points to highest local stack frame word)
311; Corrupts registers:
312; FLAGS
313;--------------------------------------------------------------------
314%macro eENTER 2
315%ifndef USE_186
316 push bp
317 mov bp, sp
318 sub sp, %1
319;-----------------------------------
320%else
321 enter %1, %2
322%endif
323%endmacro
324
325;--------------------------------------------------------------------
326; Emulates LEAVE instruction when necessary.
327;
328; eLEAVE
329; Parameters:
330; Nothing
331; Returns:
332; BP: What it was before eENTER
333; Corrupts registers:
334; Nothing
335;--------------------------------------------------------------------
336%macro eLEAVE 0
337%ifndef USE_186
338 mov sp, bp
339 pop bp
340;-----------------------------------
341%else
342 leave
343%endif
344%endmacro
345
346
347;--------------------------------------------------------------------
348; Emulates LSS instruction when necessary.
349;
350; eLSS
351; Parameters:
352; %1: Destination register
353; %2: Source memory address without brackets
354; Returns:
355; IF: 0 (interrupts disabled)
356; Corrupts registers:
357; Nothing
358;--------------------------------------------------------------------
359%macro eLSS 2
360%ifndef USE_386
361 cli ; Disable interrupts
362 mov %1, [%2] ; Load offset
363 mov ss, [%2+2] ; Load segment
364;-----------------------------------
365%else
366 lss %1, [%2]
367%endif
368%endmacro
369
370
371;--------------------------------------------------------------------
372; Segment override prefix instruction.
373;
374; eSEG
375; Parameters:
376; %1: Name of the segment (ES, CS, SS, DS, FS or GS)
377; Returns:
378; Nothing
379; Corrupts registers:
380; Nothing
381;--------------------------------------------------------------------
382%macro eSEG 1
383 %ifidni %1, es
384 db 00100110b
385 %elifidni %1, cs
386 db 00101110b
387 %elifidni %1, ss
388 db 00110110b
389 %elifidni %1, ds
390 db 00111110b
391 %elifidni %1, fs
392 db 01100100b
393 %elifidni %1, gs
394 db 01100101b
395 %else
396 %error "Invalid segment override passed to eSEG!"
397 %endif
398%endmacro
399
400
401;--------------------------------------------------------------------
402; Repeats string instruction with segment override.
403; This macro prevents 8088/8086 restart bug.
404;
405; eSEG_STR
406; Parameters:
407; %1: REP/REPNE or REPE prefix
408; %2: Source segment override (destination is always ES)
409; %3: String instruction
410; CX: Repeat count
411; Returns:
412; FLAGS for cmps and scas only
413; Corrupts registers:
414; Nothing
415;--------------------------------------------------------------------
416%macro eSEG_STR 3
417%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
418 %%Loop:
419 %1 ; REP is the prefix that can be lost
420 eSEG %2 ; SEG is the prefix that won't be lost
421 %3 ; String instruction
422 jcxz %%End ; Jump to end if no repeats left (preserves FLAGS)
423 jmp SHORT %%Loop ; Loop while repeats left
424 %%End:
425%else ; No bug on V20/V30 and later, don't know about 188/186
426 eSEG %2
427 %1 %3
428%endif
429%endmacro
430
431
432;--------------------------------------------------------------------
433; Bit shifts and rotates with immediate.
434;
435; eSHIFT_IM
436; Parameters:
437; %1: Shift target
438; %2: Number of bits to shift
439; %3: Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
440; Returns:
441; FLAGS
442; Corrupts registers:
443; Nothing
444;--------------------------------------------------------------------
445%macro eSHIFT_IM 3
446%ifndef USE_186
447 %ifidni %1, cl
448 times %2 %3 %1, 1
449 %elifidni %1, ch
450 times %2 %3 %1, 1
451 %elifidni %1, cx
452 times %2 %3 %1, 1
453 %else
454; %if %2 > 7 ; Original value
455 %if %2 > 3 ; Size optimized value
456 push cx
457 mov cl, %2
458 %3 %1, cl
459 pop cx
460 %else
461 times %2 %3 %1, 1
462 %endif
463 %endif
464;-----------------------------------
465%else
466 %3 %1, %2
467%endif
468%endmacro
469%macro eSHR_IM 2
470 eSHIFT_IM %1, %2, shr
471%endmacro
472%macro eSHL_IM 2
473 eSHIFT_IM %1, %2, shl
474%endmacro
475%macro eROR_IM 2
476 eSHIFT_IM %1, %2, ror
477%endmacro
478%macro eROL_IM 2
479 eSHIFT_IM %1, %2, rol
480%endmacro
481%macro eRCR_IM 2
482 eSHIFT_IM %1, %2, rcr
483%endmacro
484%macro eRCL_IM 2
485 eSHIFT_IM %1, %2, rcl
486%endmacro
487
488
489;--------------------------------------------------------------------
490; Emulates PUSH imm instruction when necessary.
491;
492; ePUSH_I
493; Parameters:
494; %1: Immediate to push
495; Returns:
496; Nothing
497; Corrupts registers:
498; Nothing
499;--------------------------------------------------------------------
500%macro ePUSH_I 1
501%ifndef USE_186
502 push bp ; Immediate goes here
503 push bp
504 mov bp, sp
505 mov WORD [bp+2], %1
506 pop bp
507;-----------------------------------
508%else
509 push %1
510%endif
511%endmacro
512
513
514;--------------------------------------------------------------------
515; Emulates PUSH imm instruction when necessary.
516; ePUSH_T uses temporary register for faster performance
517; and smaller code size than ePUSH_I.
518;
519; ePUSH_T
520; Parameters:
521; %1: Temporary Register
522; %2: Immediate to push
523; Returns:
524; Nothing
525; Corrupts registers:
526; %1
527;--------------------------------------------------------------------
528%macro ePUSH_T 2
529%ifndef USE_186
530 %ifidni %2, 0
531 xor %1, %1
532 %else
533 mov %1, %2
534 %endif
535 push %1
536;-----------------------------------
537%else
538 push %2
539%endif
540%endmacro
541
542
543%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.