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

Last change on this file was 293, checked in by krille_n_@…, 12 years ago

Commit 1/2 (Library, Configurators and Serial Server):

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