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

Last change on this file since 589 was 589, checked in by krille_n_, 8 years ago

Changes:

  • BIOS: Fixed a purely cosmetic bug from r542 where, in builds containing MODULE_EBIOS, the boot menu would display an incorrect drive size (0.4 kB with MODULE_STRINGS_COMPRESSED or 0.5 kB without) for old drives with no support for LBA.
  • Fixed a bug from r392 where Vision_DetectAndReturnIDinAXandPortInDXifControllerPresent would return the ID in AL instead of AH (if DANGEROUS_DETECTION had been defined).
  • Fixed a bug from r587 in AdvAtaInit.asm that would prevent detection of QDI Vision controllers.
  • Also changed how the QDI Vision IDs are defined (removed the need for shifting) to avoid confusion. This fixed a potential bug from r587 in AdvAtaInit.asm where some IDs were not being shifted.
  • Fixed a bug in PDC20x30.asm from r587 where GetPdcIDtoAX would not return with the IDE base port in DX so DisablePdcProgrammingMode would fail.
  • Made some changes to ModuleDependency.inc and other files so that MODULE_ADVANCED_ATA now requires USE_386. Consequently it is no longer included in the regular AT-builds, only in the 386_8k-build.
  • Moved the UNROLL_SECTORS_IN_CX_TO_xWORDS macros from IDE_8bit.inc to IdeIO.inc which means it's now possible to build a BIOS without MODULE_8BIT_IDE.
  • XTIDECFG: Added a minimum DOS version check (since it needs DOS version 2+) to allow the program to quit gracefully in the unlikely scenario where someone tries to run it under DOS version 1.
  • Made some changes to Drive.asm to improve drive enumeration. The old method using GET_DOS_DRIVE_PARAMETER_BLOCK_FOR_SPECIFIC_DRIVE worked well in Windows XP but not in Windows 98 SE (in Windows or in DOS mode). The two problems were; 1) The function call would access the drives which on single floppy drive systems would cause Windows to swap between A: and B: (throwing a blue screen asking the user to insert a disk etc). 2) Only floppy drives and FAT16 drives would be available in the list of drives, no FAT32/optical/network drives.
  • Improved code in IdeControllerMenu.asm so that the default port addresses for all IDE interfaces are now restored when (re-)selecting the (same) type of IDE device.
  • Also made it impossible to select a device type unless the required module is included in the loaded BIOS.
  • The version check done when loading a BIOS now uses the FLASH_SIGNATURE definition from Version.inc. Any changes affecting RomVars now only requires updating that definition. This means that changes to RomVars must be implemented in both the BIOS and XTIDECFG before being committed to the repository.
  • Added a compatibility fix for 3Com 3C503 cards to the ROM checksumming code in Buffers.asm (Buffers_GenerateChecksum).
  • SerDrive: Made some minor changes to file names and paths to improve compatibility with case sensitive environments.
  • BIOSDRVS: Made a minor size optimization which as a side effect also makes it compatible with all DOS versions including DOS version 1.
  • Library: Renamed the WAIT_RETRACE_IF_NECESSARY_THEN macro to CALL_WAIT_FOR_RETRACE_IF_NECESSARY_THEN and made a tail-call-optimized version of it (JMP_WAIT_FOR_RETRACE_IF_NECESSARY_THEN).
  • A speed optimization to the eRCL_IM macro for 386 and higher. This change breaks emulation in the sense that the macro will fail when given a memory operand as the first parameter.
  • Other minor optimizations and fixes.
File size: 14.5 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%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
582%ifdef USE_386
583    %if %2 = 1
584        adc     %1, %1  ; Same size but faster on 386 and 486. Fails if %1 is a memory operand.
585    %else
586        eSHIFT_IM   %1, %2, rcl
587    %endif
588%else
589    eSHIFT_IM   %1, %2, rcl
590%endif
591%endif
592%endmacro
593
594
595;--------------------------------------------------------------------
596; Emulates PUSH imm instruction when necessary.
597;
598; ePUSH_I
599;   Parameters:
600;       %1:     Immediate to push
601;   Returns:
602;       Nothing
603;   Corrupts registers:
604;       Nothing
605;--------------------------------------------------------------------
606%macro ePUSH_I 1
607%ifndef USE_186
608    push    bp                  ; Immediate goes here
609    push    bp
610    mov     bp, sp
611    mov     WORD [bp+2], %1
612    pop     bp
613;-----------------------------------
614%else
615    push    %1
616%endif
617%endmacro
618
619
620;--------------------------------------------------------------------
621; Emulates PUSH imm instruction when necessary.
622; ePUSH_T uses temporary register for faster performance
623; and smaller code size than ePUSH_I.
624;
625; ePUSH_T
626;   Parameters:
627;       %1:     Temporary Register
628;       %2:     Immediate to push
629;   Returns:
630;       Nothing
631;   Corrupts registers:
632;       %1
633;--------------------------------------------------------------------
634%macro ePUSH_T 2
635%ifndef USE_186
636    %ifidni %2, 0
637        xor     %1, %1
638    %else
639        mov     %1, %2
640    %endif
641    push    %1
642;-----------------------------------
643%else
644    push    %2
645%endif
646%endmacro
647
648
649%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.