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

Last change on this file since 596 was 596, checked in by krille_n_, 3 years ago

Changes:

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