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

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

Changes:

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