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

Last change on this file since 592 was 592, checked in by krille_n_, 6 years ago

Changes:

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