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

Last change on this file since 591 was 589, checked in by Krister Nordvall, 9 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.