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

Last change on this file since 510 was 510, checked in by aitotat@…, 11 years ago

Changes to Assembly Library:

  • USE_UNDOC_INTEL is now automatically defined when defining USE_286 (and USE_386).
File size: 14.1 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    %define USE_UNDOC_INTEL     ; Not supported by NEC V20/V30
27%endif
28
29%ifdef USE_386
30    CPU 386                     ; Allow instructions up to 386
31%elifdef USE_286
32    CPU 286                     ; Allow instructions up to 286
33%elifdef USE_186
34    CPU 186                     ; Allow instructions up to 188/186/V20/V30
35%else
36    CPU 8086                    ; Allow 8088/8086 instructions only
37%endif
38
39BITS 16                         ; Set 16 bit code generation
40
41; Alignments for jump targets.
42; Following values are optimal for different processor types:
43; 286 and 386SX         WORD (16-bit, 2 bytes)
44; 386DX and 486         DWORD (32-bit, 4 bytes)
45; Pentium and later     QWORD (64-bit, 8 bytes)
46%ifdef USE_AT
47    %ifdef USE_386
48        JUMP_ALIGN      EQU     4
49        WORD_ALIGN      EQU     2
50    %else ; USE_286
51        JUMP_ALIGN      EQU     2
52        WORD_ALIGN      EQU     2
53    %endif
54%else ; XT
55    JUMP_ALIGN      EQU     1
56    WORD_ALIGN      EQU     1
57%endif
58
59;==========================================================================
60
61;--------------------------------------------------------------------
62; The undocumented instruction SALC (Set AL According to CF).
63; Available on all Intel processors and truly compatible clones.
64; Does not work on the NEC V20/V30 or Sony CXQ70108 processors.
65;
66; eSALC
67;   Parameters:
68;       Nothing
69;   Returns:
70;       AL:     FFh if CF=1
71;               00h if CF=0
72;   Corrupts registers:
73;       Nothing
74;--------------------------------------------------------------------
75%macro eSALC 0
76    db      0D6h
77%endmacro
78
79
80;--------------------------------------------------------------------
81; The AAD instruction (ASCII Adjust before Division).
82; Available on all Intel processors and truly compatible clones.
83; Does not work on the NEC V20/V30 or Sony CXQ70108 processors
84; unless %1 is 10 (0Ah).
85;
86; eAAD
87;   Parameters:
88;       %1:     Any 8 bit number (0...255)
89;   Returns:
90;       AL:     AH * %1 + AL
91;       AH:     0
92;       Flags:  Set according to result
93;   Corrupts registers:
94;       Nothing
95;--------------------------------------------------------------------
96%macro eAAD 1
97%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
98    %if %1 > 255
99        %error Invalid parameter passed to eAAD (%1 > 255)
100    %else
101        db      0D5h, %1
102    %endif
103%endif
104%endmacro
105
106
107;--------------------------------------------------------------------
108; The AAM instruction (ASCII Adjust after Multiplication).
109; Available on all Intel processors and truly compatible clones.
110; Does not work on the NEC V20/V30 or Sony CXQ70108 processors
111; unless %1 is 10 (0Ah).
112;
113; eAAM
114;   Parameters:
115;       %1:     Any 8 bit number except 0 (1...255)
116;   Returns:
117;       AL:     AL MOD %1
118;       AH:     AL / %1
119;       Flags:  Set according to result
120;   Corrupts registers:
121;       Nothing
122;--------------------------------------------------------------------
123%macro eAAM 1
124%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
125    %if %1 > 255
126        %error Invalid parameter passed to eAAM (%1 > 255)
127    %elif %1 = 0
128        %error Invalid parameter passed to eAAM (%1 = 0). This would cause a divide-by-zero exception!
129    %else
130        db      0D4h, %1
131    %endif
132%endif
133%endmacro
134
135
136;--------------------------------------------------------------------
137; Emulates BSF (Bit Scan Forward) instruction when necessary.
138; BSF is used to find index of least significant bit.
139;
140; eBSF
141;   Parameters:
142;       %1:     Destination WORD Register for bit index (not CX or same as %2!)
143;       %2:     Source WORD operand where to search bit (not CX or same as %1!)
144;   Returns:
145;       %1:     Index of highest order bit from %2
146;       ZF:     Set if %2 is zero
147;               Cleared if %2 is non-zero
148;   Corrupts registers:
149;       Nothing
150;--------------------------------------------------------------------
151%macro eBSF 2
152%ifndef USE_386
153    push    cx
154    cmp     WORD %2, BYTE 0     ; Source operand is zero?
155    je      SHORT %%Return      ;  If so, return with ZF set
156
157    ; Set destination to zero and load mask for bit 0
158    xor     %1, %1
159    mov     cx, 1
160
161ALIGN JUMP_ALIGN
162%%BitLoop:
163    test    %2, cx              ; Bit set?
164    jnz     SHORT %%Return      ;  If so, return with ZF cleared
165    shl     cx, 1               ; Prepare to test next bit
166    inc     %1                  ; Increment bit index
167    jmp     SHORT %%BitLoop     ; Loop until bit found
168%%Return:
169    pop     cx
170;-----------------------------------
171%else
172    bsf     %1, %2
173%endif
174%endmacro
175
176
177;--------------------------------------------------------------------
178; Emulates BSR (Bit Scan Reverse) instruction when necessary.
179; BSR is used to find index of most significant bit.
180;
181; eBSR
182;   Parameters:
183;       %1:     Destination WORD Register for bit index (not CX or same as %2!)
184;       %2:     Source WORD operand where to search bit (not CX or same as %1!)
185;   Returns:
186;       %1:     Index of highest order bit from %2
187;       ZF:     Set if %2 is zero
188;               Cleared if %2 is non-zero
189;   Corrupts registers:
190;       Nothing
191;--------------------------------------------------------------------
192%macro eBSR 2
193%ifndef USE_386
194    push    cx
195    cmp     WORD %2, BYTE 0     ; Source operand is zero?
196    je      SHORT %%Return      ;  If so, return with ZF set
197
198    ; Load mask for highest order bit
199    mov     cx, 1<<15
200    mov     %1, 15
201
202ALIGN JUMP_ALIGN
203%%BitLoop:
204    test    %2, cx              ; Bit set?
205    jnz     SHORT %%Return      ;  If so, return with ZF cleared
206    shr     cx, 1               ; Prepare to test next bit
207    dec     %1                  ; Decrement bit index
208    jmp     SHORT %%BitLoop     ; Loop until bit found
209%%Return:
210    pop     cx
211;-----------------------------------
212%else
213    bsr     %1, %2
214%endif
215%endmacro
216
217
218;--------------------------------------------------------------------
219; Conditional Move.
220;
221; eCMOVcc
222;   Parameters:
223;       %1:     Destination data
224;       %2:     Source data
225;   Returns:
226;       Nothing
227;   Corrupts registers:
228;       Nothing
229;--------------------------------------------------------------------
230%macro eCMOVA 2
231    jbe     SHORT %%Return
232    mov     %1, %2
233%%Return:
234%endmacro
235
236%macro eCMOVC 2
237    jnc     SHORT %%Return
238    mov     %1, %2
239%%Return:
240%endmacro
241
242%macro eCMOVNC 2
243    jc      SHORT %%Return
244    mov     %1, %2
245%%Return:
246%endmacro
247
248%macro eCMOVZ 2
249    jnz     SHORT %%Return
250    mov     %1, %2
251%%Return:
252%endmacro
253
254%macro eCMOVNZ 2
255    jz      SHORT %%Return
256    mov     %1, %2
257%%Return:
258%endmacro
259
260%macro eCMOVE 2
261    eCMOVZ %1, %2
262%endmacro
263
264%macro eCMOVNE 2
265    eCMOVNZ %1, %2
266%endmacro
267
268%macro eCMOVB 2
269    jnb     SHORT %%Return
270    mov     %1, %2
271%%Return:
272%endmacro
273
274%macro eCMOVS 2
275    jns     SHORT %%Return
276    mov     %1, %2
277%%Return:
278%endmacro
279
280%macro eCMOVNS 2
281    js      SHORT %%Return
282    mov     %1, %2
283%%Return:
284%endmacro
285
286
287;--------------------------------------------------------------------
288; Conditional Set.
289;
290; eCSETcc
291;   Parameters:
292;       %1:     Destination data
293;   Returns:
294;       Nothing
295;   Corrupts registers:
296;       Flags
297;--------------------------------------------------------------------
298%macro eCSETZ 1
299    mov     %1, 0           ; Clear while preserving flags
300    jnz     SHORT %%Return  ; Nothing to set
301    inc     %1
302%%Return:
303%endmacro
304
305
306;--------------------------------------------------------------------
307; Moves byte with zero-extending to any Register.
308;
309; eMOVZX
310;   Parameters:
311;       %1:     Destination Register (SP not supported)
312;       %2:     Byte register or byte address
313;   Returns:
314;       Nothing
315;   Corrupts registers:
316;       FLAGS
317;--------------------------------------------------------------------
318%macro eMOVZX 2
319%ifndef USE_386
320    %ifidni %1, ax
321        mov     al, %2
322        xor     ah, ah
323    %elifidni %1, bx
324        mov     bl, %2
325        xor     bh, bh      ; %2 may use BX in effective address
326    %elifidni %1, cx
327        mov     cl, %2
328        xor     ch, ch
329    %elifidni %1, dx
330        mov     dl, %2
331        xor     dh, dh
332    %else   ; SI, DI, BP (all may be used in effective address)
333        push    ax
334        mov     al, %2
335        xor     ah, ah
336        xchg    ax, %1
337        pop     ax
338    %endif
339;-----------------------------------
340%else
341    movzx   %1, %2
342%endif
343%endmacro
344
345
346;--------------------------------------------------------------------
347; Emulates PUSHA instruction when necessary.
348;
349; ePUSHA
350;   Parameters:
351;       Nothing
352;   Returns:
353;       Nothing
354;   Corrupts registers:
355;       Nothing
356;--------------------------------------------------------------------
357%macro ePUSHA 0
358%ifndef USE_186
359    push    ax
360    push    cx
361    push    dx
362    push    bx
363    push    sp
364    push    bp
365    push    si
366    push    di
367;-----------------------------------
368%else
369    pusha
370%endif
371%endmacro
372
373
374;--------------------------------------------------------------------
375; Emulates POPA instruction when necessary.
376;
377; ePOPA
378;   Parameters:
379;       Nothing
380;   Returns:
381;       Nothing
382;   Corrupts registers:
383;       Nothing
384;--------------------------------------------------------------------
385%macro ePOPA 0
386%ifndef USE_186
387    pop     di
388    pop     si
389    pop     bp
390    pop     ax      ; Skip SP
391    pop     bx
392    pop     dx
393    pop     cx
394    pop     ax
395;-----------------------------------
396%else
397    popa
398%endif
399%endmacro
400
401
402;--------------------------------------------------------------------
403; Emulates ENTER instruction when necessary.
404;
405; eENTER
406;   Parameters:
407;       %1:     Number of bytes to reserve from stack
408;       %2:     The lexical nesting level (not emulated, set to 0)
409;   Returns:
410;       SS:BP:  Ptr to old BP
411;               ([bp-2] points to highest local stack frame word)
412;   Corrupts registers:
413;       FLAGS
414;--------------------------------------------------------------------
415%macro eENTER 2
416%ifndef USE_186
417    push    bp
418    mov     bp, sp
419    sub     sp, %1
420;-----------------------------------
421%else
422    enter   %1, %2
423%endif
424%endmacro
425
426;--------------------------------------------------------------------
427; Emulates LEAVE instruction when necessary.
428;
429; eLEAVE
430;   Parameters:
431;       Nothing
432;   Returns:
433;       BP:     What it was before eENTER
434;   Corrupts registers:
435;       Nothing
436;--------------------------------------------------------------------
437%macro eLEAVE 0
438%ifndef USE_186
439    mov     sp, bp
440    pop     bp
441;-----------------------------------
442%else
443    leave
444%endif
445%endmacro
446
447
448;--------------------------------------------------------------------
449; Emulates LSS instruction when necessary.
450;
451; eLSS
452;   Parameters:
453;       %1:     Destination register
454;       %2:     Source memory address without brackets
455;   Returns:
456;       IF:     0 (interrupts disabled)
457;   Corrupts registers:
458;       Nothing
459;--------------------------------------------------------------------
460%macro eLSS 2
461%ifndef USE_386
462    cli                         ; Disable interrupts
463    mov     %1, [%2]            ; Load offset
464    mov     ss, [%2+2]          ; Load segment
465;-----------------------------------
466%else
467    lss     %1, [%2]
468%endif
469%endmacro
470
471
472;--------------------------------------------------------------------
473; Repeats string instruction with segment override.
474; This macro prevents 8088/8086 restart bug.
475;
476; eSEG_STR
477;   Parameters:
478;       %1:     REP/REPNE or REPE prefix
479;       %2:     Source segment override (destination is always ES)
480;       %3:     String instruction
481;       CX:     Repeat count
482;   Returns:
483;       FLAGS for cmps and scas only
484;   Corrupts registers:
485;       Nothing
486;--------------------------------------------------------------------
487%macro eSEG_STR 3
488%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
489    %%Loop:
490        %1                      ; REP is the prefix that can be lost
491        %2                      ; SEG is the prefix that won't be lost
492        %3                      ; String instruction
493        jcxz    %%End           ; Jump to end if no repeats left (preserves FLAGS)
494        jmp     SHORT %%Loop    ; Loop while repeats left
495    %%End:
496%else   ; No bug on V20/V30 and later, don't know about 188/186
497    %2
498    %1 %3
499%endif
500%endmacro
501
502
503;--------------------------------------------------------------------
504; Bit shifts and rotates with immediate.
505;
506; eSHIFT_IM
507;   Parameters:
508;       %1:     Shift target
509;       %2:     Number of bits to shift
510;       %3:     Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
511;   Returns:
512;       FLAGS
513;   Corrupts registers:
514;       Nothing
515;--------------------------------------------------------------------
516%macro eSHIFT_IM 3
517%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
518%ifndef USE_186
519    %ifidni %1, cl
520        times %2    %3      %1, 1
521    %elifidni %1, ch
522        times %2    %3      %1, 1
523    %elifidni %1, cx
524        times %2    %3      %1, 1
525    %else
526        %if %2 > 3  ; Size optimized value
527            push    cx
528            mov     cl, %2
529            %3      %1, cl
530            pop     cx
531        %else
532            times %2    %3      %1, 1
533        %endif
534    %endif
535;-----------------------------------
536%else
537    %3      %1, %2
538%endif
539%endif
540%endmacro
541
542%macro eSHR_IM 2
543    eSHIFT_IM   %1, %2, shr
544%endmacro
545
546%macro eSHL_IM 2
547%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
548%ifdef USE_386
549    %if %2 = 1
550        add     %1, %1  ; Same size but faster on 386 and 486. Fails if %1 is a memory operand.
551    %else
552        eSHIFT_IM   %1, %2, shl
553    %endif
554%else
555    eSHIFT_IM   %1, %2, shl
556%endif
557%endif
558%endmacro
559
560%macro eROR_IM 2
561    eSHIFT_IM   %1, %2, ror
562%endmacro
563
564%macro eROL_IM 2
565    eSHIFT_IM   %1, %2, rol
566%endmacro
567
568%macro eRCR_IM 2
569    eSHIFT_IM   %1, %2, rcr
570%endmacro
571
572%macro eRCL_IM 2
573    eSHIFT_IM   %1, %2, rcl
574%endmacro
575
576
577;--------------------------------------------------------------------
578; Emulates PUSH imm instruction when necessary.
579;
580; ePUSH_I
581;   Parameters:
582;       %1:     Immediate to push
583;   Returns:
584;       Nothing
585;   Corrupts registers:
586;       Nothing
587;--------------------------------------------------------------------
588%macro ePUSH_I 1
589%ifndef USE_186
590    push    bp                  ; Immediate goes here
591    push    bp
592    mov     bp, sp
593    mov     WORD [bp+2], %1
594    pop     bp
595;-----------------------------------
596%else
597    push    %1
598%endif
599%endmacro
600
601
602;--------------------------------------------------------------------
603; Emulates PUSH imm instruction when necessary.
604; ePUSH_T uses temporary register for faster performance
605; and smaller code size than ePUSH_I.
606;
607; ePUSH_T
608;   Parameters:
609;       %1:     Temporary Register
610;       %2:     Immediate to push
611;   Returns:
612;       Nothing
613;   Corrupts registers:
614;       %1
615;--------------------------------------------------------------------
616%macro ePUSH_T 2
617%ifndef USE_186
618    %ifidni %2, 0
619        xor     %1, %1
620    %else
621        mov     %1, %2
622    %endif
623    push    %1
624;-----------------------------------
625%else
626    push    %2
627%endif
628%endmacro
629
630
631%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.