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

Last change on this file since 594 was 592, checked in by Krister Nordvall, 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
RevLine 
[41]1; Project name : Emulation library
[293]2; Description : Macros for emulating later x86 instructions with older
[41]3; processors.
[293]4; Macros are used so optimized builds can be done
[41]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
[293]12; Defines for processor support (should be set in makefile).
13; Unsupported instructions will be emulated using macros.
[41]14; If AT class PC is used (instead of XT), define USE_AT
[293]15
[41]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
[293]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
[510]26 %define USE_UNDOC_INTEL ; Not supported by NEC V20/V30
[293]27%endif
28
29%ifdef USE_386
30 CPU 386 ; Allow instructions up to 386
[41]31%elifdef USE_286
[293]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
[41]37%endif
[293]38
[41]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;--------------------------------------------------------------------
[592]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;--------------------------------------------------------------------
[491]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
[568]106; db 0D6h
107 salc
[491]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;--------------------------------------------------------------------
[41]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
[592]185 push cx
[41]186 xor %1, %1
187 mov cx, 1
188
189ALIGN JUMP_ALIGN
190%%BitLoop:
191 test %2, cx ; Bit set?
[592]192 jnz SHORT %%PopAndReturn; If so, return with ZF cleared
[41]193 shl cx, 1 ; Prepare to test next bit
194 inc %1 ; Increment bit index
195 jmp SHORT %%BitLoop ; Loop until bit found
[592]196%%PopAndReturn:
197 pop cx
[41]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
[592]227 push cx
[41]228 mov cx, 1<<15
229 mov %1, 15
230
231ALIGN JUMP_ALIGN
232%%BitLoop:
233 test %2, cx ; Bit set?
[592]234 jnz SHORT %%PopAndReturn; If so, return with ZF cleared
[41]235 shr cx, 1 ; Prepare to test next bit
236 dec %1 ; Decrement bit index
237 jmp SHORT %%BitLoop ; Loop until bit found
[592]238%%PopAndReturn:
239 pop cx
[41]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;--------------------------------------------------------------------
[146]260%macro eCMOVA 2
261 jbe SHORT %%Return
262 mov %1, %2
263%%Return:
264%endmacro
265
[41]266%macro eCMOVC 2
267 jnc SHORT %%Return
268 mov %1, %2
269%%Return:
270%endmacro
271
[390]272%macro eCMOVNC 2
273 jc SHORT %%Return
274 mov %1, %2
275%%Return:
276%endmacro
277
[64]278%macro eCMOVZ 2
279 jnz SHORT %%Return
280 mov %1, %2
281%%Return:
282%endmacro
283
[94]284%macro eCMOVNZ 2
285 jz SHORT %%Return
[41]286 mov %1, %2
287%%Return:
288%endmacro
289
[94]290%macro eCMOVE 2
[592]291 eCMOVZ %1, %2
[94]292%endmacro
293
294%macro eCMOVNE 2
[592]295 eCMOVNZ %1, %2
[94]296%endmacro
297
[60]298%macro eCMOVB 2
[592]299 eCMOVC %1, %2
[60]300%endmacro
[41]301
[390]302%macro eCMOVS 2
303 jns SHORT %%Return
304 mov %1, %2
305%%Return:
306%endmacro
[41]307
[396]308%macro eCMOVNS 2
309 js SHORT %%Return
310 mov %1, %2
311%%Return:
312%endmacro
[390]313
[396]314
[168]315;--------------------------------------------------------------------
316; Conditional Set.
317;
[592]318; eSETcc
[168]319; Parameters:
320; %1: Destination data
321; Returns:
322; Nothing
323; Corrupts registers:
324; Flags
325;--------------------------------------------------------------------
[592]326%macro eSETZ 1
[168]327 mov %1, 0 ; Clear while preserving flags
328 jnz SHORT %%Return ; Nothing to set
329 inc %1
330%%Return:
331%endmacro
[60]332
[592]333%macro eSETNZ 1
[586]334 mov %1, 0 ; Clear while preserving flags
335 jz SHORT %%Return ; Nothing to set
336 inc %1
337%%Return:
338%endmacro
[168]339
[586]340
[41]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)
[592]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
[41]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
[113]406 push sp
[41]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
[113]433 pop ax ; Skip SP
[41]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:
[592]521; %1: REP/REPE/REPZ or REPNE/REPNZ prefix
[41]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:
[592]528; FLAGS
[41]529;--------------------------------------------------------------------
530%macro eSEG_STR 3
531%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
[223]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
[592]536FSIS cmps, %3
537%ifn strpos
538 FSIS scas, %3
539%endif
540%if strpos ; Must preserve FLAGS
[223]541 jcxz %%End ; Jump to end if no repeats left (preserves FLAGS)
542 jmp SHORT %%Loop ; Loop while repeats left
543 %%End:
[592]544%else ; No need to preserve FLAGS
545 inc cx
546 loop %%Loop
547%endif
[41]548%else ; No bug on V20/V30 and later, don't know about 188/186
[223]549 %2
550 %1 %3
[41]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
[488]569%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
[41]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
[181]578 %if %2 > 3 ; Size optimized value
[41]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
[488]591%endif
[41]592%endmacro
[420]593
[41]594%macro eSHR_IM 2
595 eSHIFT_IM %1, %2, shr
596%endmacro
[445]597
[41]598%macro eSHL_IM 2
[489]599%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
[445]600%ifdef USE_386
601 %if %2 = 1
[592]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
[445]608 %else
609 eSHIFT_IM %1, %2, shl
610 %endif
611%else
[41]612 eSHIFT_IM %1, %2, shl
[445]613%endif
[489]614%endif
[41]615%endmacro
[445]616
[41]617%macro eROR_IM 2
618 eSHIFT_IM %1, %2, ror
619%endmacro
[445]620
[41]621%macro eROL_IM 2
622 eSHIFT_IM %1, %2, rol
623%endmacro
[445]624
[41]625%macro eRCR_IM 2
626 eSHIFT_IM %1, %2, rcr
627%endmacro
[445]628
[41]629%macro eRCL_IM 2
[589]630%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
631%ifdef USE_386
632 %if %2 = 1
[592]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
[589]639 %else
640 eSHIFT_IM %1, %2, rcl
641 %endif
642%else
[41]643 eSHIFT_IM %1, %2, rcl
[589]644%endif
645%endif
[41]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.