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

Last change on this file since 623 was 623, checked in by krille_n_, 22 months ago

Changes:

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