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

Last change on this file since 488 was 488, checked in by gregli@…, 10 years ago

Removed unused '4' entry from Strings.asm and recompressed. Added 8x multiplier value for serial drives. Wrapped some preprocessor symbol references so that 'make xt_unused' analysis continues to work.

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