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

Last change on this file since 94 was 94, checked in by aitotat, 13 years ago

Changes to Assembly Library:

  • Added eCMOVNZ and eCMOVNE macros.
File size: 12.5 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 eCMOVC 2
148    jnc     SHORT %%Return
149    mov     %1, %2
150%%Return:
151%endmacro
152
153%macro eCMOVZ 2
154    jnz     SHORT %%Return
155    mov     %1, %2
156%%Return:
157%endmacro
158
159%macro eCMOVNZ 2
160    jz      SHORT %%Return
161    mov     %1, %2
162%%Return:
163%endmacro
164
165%macro eCMOVE 2
166    eCMOVZ %1, %2
167%endmacro
168
169%macro eCMOVNE 2
170    eCMOVNZ %1, %2
171%endmacro
172
173%macro eCMOVB 2
174    jnb     SHORT %%Return
175    mov     %1, %2
176%%Return:
177%endmacro
178
179
180
181;--------------------------------------------------------------------
182; Moves byte with zero-extending to any Register.
183;
184; eMOVZX
185;   Parameters:
186;       %1:     Destination Register (SP not supported)
187;       %2:     Byte register or byte address
188;   Returns:
189;       Nothing
190;   Corrupts registers:
191;       FLAGS
192;--------------------------------------------------------------------
193%macro eMOVZX 2
194%ifndef USE_386
195    %ifidni %1, ax
196        mov     al, %2
197        xor     ah, ah
198    %elifidni %1, bx
199        mov     bl, %2
200        xor     bh, bh      ; %2 may use BX in effective address
201    %elifidni %1, cx
202        mov     cl, %2
203        xor     ch, ch
204    %elifidni %1, dx
205        mov     dl, %2
206        xor     dh, dh
207    %else   ; SI, DI, BP (all may be used in effective address)
208        push    ax
209        mov     al, %2
210        xor     ah, ah
211        xchg    ax, %1
212        pop     ax
213    %endif
214;-----------------------------------
215%else
216    movzx   %1, %2
217%endif
218%endmacro
219
220
221;--------------------------------------------------------------------
222; Emulates PUSHA instruction when necessary.
223;
224; ePUSHA
225;   Parameters:
226;       Nothing
227;   Returns:
228;       Nothing
229;   Corrupts registers:
230;       Nothing
231;--------------------------------------------------------------------
232%macro ePUSHA 0
233%ifndef USE_186
234    push    ax
235    push    cx
236    push    dx
237    push    bx
238    ; SP before first push should be pushed here
239    push    bp
240    push    si
241    push    di
242;-----------------------------------
243%else
244    pusha
245%endif
246%endmacro
247
248
249;--------------------------------------------------------------------
250; Emulates POPA instruction when necessary.
251;
252; ePOPA
253;   Parameters:
254;       Nothing
255;   Returns:
256;       Nothing
257;   Corrupts registers:
258;       Nothing
259;--------------------------------------------------------------------
260%macro ePOPA 0
261%ifndef USE_186
262    pop     di
263    pop     si
264    pop     bp
265    ; Old SP should be skipped here
266    pop     bx
267    pop     dx
268    pop     cx
269    pop     ax
270;-----------------------------------
271%else
272    popa
273%endif
274%endmacro
275
276
277;--------------------------------------------------------------------
278; Emulates ENTER instruction when necessary.
279;
280; eENTER
281;   Parameters:
282;       %1:     Number of bytes to reserve from stack
283;       %2:     The lexical nesting level (not emulated, set to 0)
284;   Returns:
285;       SS:BP:  Ptr to old BP
286;               ([bp-2] points to highest local stack frame word)
287;   Corrupts registers:
288;       FLAGS
289;--------------------------------------------------------------------
290%macro eENTER 2
291%ifndef USE_186
292    push    bp
293    mov     bp, sp
294    sub     sp, %1
295;-----------------------------------
296%else
297    enter   %1, %2
298%endif
299%endmacro
300
301;--------------------------------------------------------------------
302; Emulates LEAVE instruction when necessary.
303;
304; eLEAVE
305;   Parameters:
306;       Nothing
307;   Returns:
308;       BP:     What it was before eENTER
309;   Corrupts registers:
310;       Nothing
311;--------------------------------------------------------------------
312%macro eLEAVE 0
313%ifndef USE_186
314    mov     sp, bp
315    pop     bp
316;-----------------------------------
317%else
318    leave
319%endif
320%endmacro
321
322
323;--------------------------------------------------------------------
324; eENTER_STRUCT
325;   Parameters:
326;       %1:     Number of bytes to reserve from stack
327;   Returns:
328;       SS:BP:  Ptr to beginning of struct reserved from stack
329;   Corrupts registers:
330;       FLAGS
331;--------------------------------------------------------------------
332%macro eENTER_STRUCT 1
333    push    bp
334    sub     sp, %1
335    mov     bp, sp
336%endmacro
337
338;--------------------------------------------------------------------
339; eLEAVE_STRUCT
340;   Parameters:
341;       %1:     Number of bytes reserved with eENTER_STRUCT
342;   Returns:
343;       BP:     What it was before eENTER_STRUCT
344;   Corrupts registers:
345;       FLAGS
346;--------------------------------------------------------------------
347%macro eLEAVE_STRUCT 1
348    add     sp, %1
349    pop     bp
350%endmacro
351
352
353;--------------------------------------------------------------------
354; Emulates LSS instruction when necessary.
355;
356; eLSS
357;   Parameters:
358;       %1:     Destination register
359;       %2:     Source memory address without brackets
360;   Returns:
361;       IF:     0 (interrupts disabled)
362;   Corrupts registers:
363;       Nothing
364;--------------------------------------------------------------------
365%macro eLSS 2
366%ifndef USE_386
367    cli                         ; Disable interrupts
368    mov     %1, [%2]            ; Load offset
369    mov     ss, [%2+2]          ; Load segment
370;-----------------------------------
371%else
372    lss     %1, [%2]
373%endif
374%endmacro
375
376
377;--------------------------------------------------------------------
378; Segment override prefix instruction.
379;
380; eSEG
381;   Parameters:
382;       %1:     Name of the segment (ES, CS, SS, DS, FS or GS)
383;   Returns:
384;       Nothing
385;   Corrupts registers:
386;       Nothing
387;--------------------------------------------------------------------
388%macro eSEG 1
389    %ifidni %1, es
390        db  00100110b
391    %elifidni %1, cs
392        db  00101110b
393    %elifidni %1, ss
394        db  00110110b
395    %elifidni %1, ds
396        db  00111110b
397    %elifidni %1, fs
398        db  01100100b
399    %elifidni %1, gs
400        db  01100101b
401    %else
402        %error "Invalid segment overried passed to eSEG!"
403    %endif
404%endmacro
405
406
407;--------------------------------------------------------------------
408; Repeats string instruction with segment override.
409; This macro prevents 8088/8086 restart bug.
410;
411; eSEG_STR
412;   Parameters:
413;       %1:     REP/REPNE or REPE prefix
414;       %2:     Source segment override (destination is always ES)
415;       %3:     String instruction
416;       CX:     Repeat count
417;   Returns:
418;       FLAGS for cmps and scas only
419;   Corrupts registers:
420;       Nothing
421;--------------------------------------------------------------------
422%macro eSEG_STR 3
423%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
424     %%Loop:
425        %1                      ; REP is the prefix that can be lost
426        eSEG    %2              ; SEG is the prefix that won't be lost
427        %3                      ; String instruction
428        jcxz    %%End           ; Jump to end if no repeats left (preserves FLAGS)
429        jmp     SHORT %%Loop    ; Loop while repeats left
430     %%End:
431%else   ; No bug on V20/V30 and later, don't know about 188/186
432    eSEG    %2
433    %1      %3
434%endif
435%endmacro
436
437
438;--------------------------------------------------------------------
439; Bit shifts and rotates with immediate.
440;
441; eSHIFT_IM
442;   Parameters:
443;       %1:     Shift target
444;       %2:     Number of bits to shift
445;       %3:     Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
446;   Returns:
447;       FLAGS
448;   Corrupts registers:
449;       Nothing
450;--------------------------------------------------------------------
451%macro eSHIFT_IM 3
452%ifndef USE_186
453    %ifidni %1, cl
454        times %2    %3      %1, 1
455    %elifidni %1, ch
456        times %2    %3      %1, 1
457    %elifidni %1, cx
458        times %2    %3      %1, 1
459    %else
460        %if %2 > 7
461            push    cx
462            mov     cl, %2
463            %3      %1, cl
464            pop     cx
465        %else
466            times %2    %3      %1, 1
467        %endif
468    %endif
469;-----------------------------------
470%else
471    %3      %1, %2
472%endif
473%endmacro
474%macro eSHR_IM 2
475    eSHIFT_IM   %1, %2, shr
476%endmacro
477%macro eSHL_IM 2
478    eSHIFT_IM   %1, %2, shl
479%endmacro
480%macro eROR_IM 2
481    eSHIFT_IM   %1, %2, ror
482%endmacro
483%macro eROL_IM 2
484    eSHIFT_IM   %1, %2, rol
485%endmacro
486%macro eRCR_IM 2
487    eSHIFT_IM   %1, %2, rcr
488%endmacro
489%macro eRCL_IM 2
490    eSHIFT_IM   %1, %2, rcl
491%endmacro
492
493
494;--------------------------------------------------------------------
495; Emulates PUSH imm instruction when necessary.
496;
497; ePUSH_I
498;   Parameters:
499;       %1:     Immediate to push
500;   Returns:
501;       Nothing
502;   Corrupts registers:
503;       Nothing
504;--------------------------------------------------------------------
505%macro ePUSH_I 1
506%ifndef USE_186
507    push    bp                  ; Immediate goes here
508    push    bp
509    mov     bp, sp
510    mov     WORD [bp+2], %1
511    pop     bp
512;-----------------------------------
513%else
514    push    %1
515%endif
516%endmacro
517
518
519;--------------------------------------------------------------------
520; Emulates PUSH imm instruction when necessary.
521; ePUSH_T uses temporary register for faster performance
522; and smaller code size than ePUSH_I.
523;
524; ePUSH_T
525;   Parameters:
526;       %1:     Temporary Register
527;       %2:     Immediate to push
528;   Returns:
529;       Nothing
530;   Corrupts registers:
531;       %1
532;--------------------------------------------------------------------
533%macro ePUSH_T 2
534%ifndef USE_186
535    %ifidni %2, 0
536        xor     %1, %1
537    %else
538        mov     %1, %2
539    %endif
540    push    %1
541;-----------------------------------
542%else
543    push    %2
544%endif
545%endmacro
546
547
548%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.