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

Last change on this file since 616 was 605, checked in by Krister Nordvall, 4 years ago

Changes:

  • The "Remove other hard drives" option in the Boot settings menu in XTIDECFG is now exposed in all BIOS builds. This is needed because the system BIOS in at least two Zenith computer models (Z-161 and Z-171) does not clear the BDA HD count which causes it to increment on warm boot. Running "Auto Configure" in XTIDECFG now also tries to identify these machines by doing a CRC check on the system BIOS and sets the option to YES if a match is found.
  • WORD_ALIGN is now 2 for XT builds. This should benefit XT class machines with 8086 and NEC V30 CPU:s and the cost is negligible (1 byte for the XT BIOS builds and 12 bytes for XTIDECFG.COM).
  • Other minor optimizations.
File size: 15.9 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
[596]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
[293]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
[510]33 %define USE_UNDOC_INTEL ; Not supported by NEC V20/V30
[293]34%endif
35
36%ifdef USE_386
37 CPU 386 ; Allow instructions up to 386
[41]38%elifdef USE_286
[293]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
[41]44%endif
[293]45
[41]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
[605]62 JUMP_ALIGN EQU 1 ; 2 is optimal for 8086 and NEC V30 CPUs but it's not worth the ROM space for most XT machines with 8088 or NEC V20 CPUs.
63 WORD_ALIGN EQU 2 ; The same applies here but the cost of ROM space is negligible.
[41]64%endif
65
66;==========================================================================
67
68;--------------------------------------------------------------------
[592]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
[596]98%ifdef USE_NEC_V
99 %include "NEC_V.inc"
100%endif
101
102
[592]103;--------------------------------------------------------------------
[491]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
[568]118; db 0D6h
119 salc
[491]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;--------------------------------------------------------------------
[41]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
[592]197 push cx
[41]198 xor %1, %1
199 mov cx, 1
200
201ALIGN JUMP_ALIGN
202%%BitLoop:
203 test %2, cx ; Bit set?
[592]204 jnz SHORT %%PopAndReturn; If so, return with ZF cleared
[41]205 shl cx, 1 ; Prepare to test next bit
206 inc %1 ; Increment bit index
207 jmp SHORT %%BitLoop ; Loop until bit found
[592]208%%PopAndReturn:
209 pop cx
[41]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
[592]239 push cx
[41]240 mov cx, 1<<15
241 mov %1, 15
242
243ALIGN JUMP_ALIGN
244%%BitLoop:
245 test %2, cx ; Bit set?
[592]246 jnz SHORT %%PopAndReturn; If so, return with ZF cleared
[41]247 shr cx, 1 ; Prepare to test next bit
248 dec %1 ; Decrement bit index
249 jmp SHORT %%BitLoop ; Loop until bit found
[592]250%%PopAndReturn:
251 pop cx
[41]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;--------------------------------------------------------------------
[146]272%macro eCMOVA 2
273 jbe SHORT %%Return
274 mov %1, %2
275%%Return:
276%endmacro
277
[41]278%macro eCMOVC 2
279 jnc SHORT %%Return
280 mov %1, %2
281%%Return:
282%endmacro
283
[390]284%macro eCMOVNC 2
285 jc SHORT %%Return
286 mov %1, %2
287%%Return:
288%endmacro
289
[64]290%macro eCMOVZ 2
291 jnz SHORT %%Return
292 mov %1, %2
293%%Return:
294%endmacro
295
[94]296%macro eCMOVNZ 2
297 jz SHORT %%Return
[41]298 mov %1, %2
299%%Return:
300%endmacro
301
[94]302%macro eCMOVE 2
[592]303 eCMOVZ %1, %2
[94]304%endmacro
305
306%macro eCMOVNE 2
[592]307 eCMOVNZ %1, %2
[94]308%endmacro
309
[60]310%macro eCMOVB 2
[592]311 eCMOVC %1, %2
[60]312%endmacro
[41]313
[390]314%macro eCMOVS 2
315 jns SHORT %%Return
316 mov %1, %2
317%%Return:
318%endmacro
[41]319
[396]320%macro eCMOVNS 2
321 js SHORT %%Return
322 mov %1, %2
323%%Return:
324%endmacro
[390]325
[396]326
[168]327;--------------------------------------------------------------------
328; Conditional Set.
329;
[592]330; eSETcc
[168]331; Parameters:
332; %1: Destination data
333; Returns:
334; Nothing
335; Corrupts registers:
336; Flags
337;--------------------------------------------------------------------
[592]338%macro eSETZ 1
[168]339 mov %1, 0 ; Clear while preserving flags
340 jnz SHORT %%Return ; Nothing to set
341 inc %1
342%%Return:
343%endmacro
[60]344
[592]345%macro eSETNZ 1
[586]346 mov %1, 0 ; Clear while preserving flags
347 jz SHORT %%Return ; Nothing to set
348 inc %1
349%%Return:
350%endmacro
[168]351
[586]352
[41]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)
[592]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
[41]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
[113]418 push sp
[41]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
[113]445 pop ax ; Skip SP
[41]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:
[592]533; %1: REP/REPE/REPZ or REPNE/REPNZ prefix
[41]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:
[592]540; FLAGS
[41]541;--------------------------------------------------------------------
542%macro eSEG_STR 3
543%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
[223]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
[592]548FSIS cmps, %3
549%ifn strpos
550 FSIS scas, %3
551%endif
552%if strpos ; Must preserve FLAGS
[223]553 jcxz %%End ; Jump to end if no repeats left (preserves FLAGS)
554 jmp SHORT %%Loop ; Loop while repeats left
555 %%End:
[592]556%else ; No need to preserve FLAGS
557 inc cx
558 loop %%Loop
559%endif
[41]560%else ; No bug on V20/V30 and later, don't know about 188/186
[223]561 %2
562 %1 %3
[41]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
[488]581%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
[41]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
[181]590 %if %2 > 3 ; Size optimized value
[41]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
[488]603%endif
[41]604%endmacro
[420]605
[41]606%macro eSHR_IM 2
607 eSHIFT_IM %1, %2, shr
608%endmacro
[445]609
[41]610%macro eSHL_IM 2
[489]611%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
[445]612%ifdef USE_386
613 %if %2 = 1
[592]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
[445]620 %else
621 eSHIFT_IM %1, %2, shl
622 %endif
623%else
[41]624 eSHIFT_IM %1, %2, shl
[445]625%endif
[489]626%endif
[41]627%endmacro
[445]628
[41]629%macro eROR_IM 2
630 eSHIFT_IM %1, %2, ror
631%endmacro
[445]632
[41]633%macro eROL_IM 2
634 eSHIFT_IM %1, %2, rol
635%endmacro
[445]636
[41]637%macro eRCR_IM 2
638 eSHIFT_IM %1, %2, rcr
639%endmacro
[445]640
[41]641%macro eRCL_IM 2
[589]642%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
643%ifdef USE_386
644 %if %2 = 1
[592]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
[589]651 %else
652 eSHIFT_IM %1, %2, rcl
653 %endif
654%else
[41]655 eSHIFT_IM %1, %2, rcl
[589]656%endif
657%endif
[41]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.