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

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

Changes to Assembly Library:

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