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

Last change on this file since 586 was 586, checked in by aitotat, 9 years ago

Changes to Assembly Library:

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