source: xtideuniversalbios/trunk/Configurator/Inc/emulate.inc @ 2

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