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

Last change on this file since 618 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
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_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
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
33 %define USE_UNDOC_INTEL ; Not supported by NEC V20/V30
34%endif
35
36%ifdef USE_386
37 CPU 386 ; Allow instructions up to 386
38%elifdef USE_286
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
44%endif
45
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
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.
64%endif
65
66;==========================================================================
67
68;--------------------------------------------------------------------
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
98%ifdef USE_NEC_V
99 %include "NEC_V.inc"
100%endif
101
102
103;--------------------------------------------------------------------
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
118; db 0D6h
119 salc
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;--------------------------------------------------------------------
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
197 push cx
198 xor %1, %1
199 mov cx, 1
200
201ALIGN JUMP_ALIGN
202%%BitLoop:
203 test %2, cx ; Bit set?
204 jnz SHORT %%PopAndReturn; If so, return with ZF cleared
205 shl cx, 1 ; Prepare to test next bit
206 inc %1 ; Increment bit index
207 jmp SHORT %%BitLoop ; Loop until bit found
208%%PopAndReturn:
209 pop cx
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
239 push cx
240 mov cx, 1<<15
241 mov %1, 15
242
243ALIGN JUMP_ALIGN
244%%BitLoop:
245 test %2, cx ; Bit set?
246 jnz SHORT %%PopAndReturn; If so, return with ZF cleared
247 shr cx, 1 ; Prepare to test next bit
248 dec %1 ; Decrement bit index
249 jmp SHORT %%BitLoop ; Loop until bit found
250%%PopAndReturn:
251 pop cx
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;--------------------------------------------------------------------
272%macro eCMOVA 2
273 jbe SHORT %%Return
274 mov %1, %2
275%%Return:
276%endmacro
277
278%macro eCMOVC 2
279 jnc SHORT %%Return
280 mov %1, %2
281%%Return:
282%endmacro
283
284%macro eCMOVNC 2
285 jc SHORT %%Return
286 mov %1, %2
287%%Return:
288%endmacro
289
290%macro eCMOVZ 2
291 jnz SHORT %%Return
292 mov %1, %2
293%%Return:
294%endmacro
295
296%macro eCMOVNZ 2
297 jz SHORT %%Return
298 mov %1, %2
299%%Return:
300%endmacro
301
302%macro eCMOVE 2
303 eCMOVZ %1, %2
304%endmacro
305
306%macro eCMOVNE 2
307 eCMOVNZ %1, %2
308%endmacro
309
310%macro eCMOVB 2
311 eCMOVC %1, %2
312%endmacro
313
314%macro eCMOVS 2
315 jns SHORT %%Return
316 mov %1, %2
317%%Return:
318%endmacro
319
320%macro eCMOVNS 2
321 js SHORT %%Return
322 mov %1, %2
323%%Return:
324%endmacro
325
326
327;--------------------------------------------------------------------
328; Conditional Set.
329;
330; eSETcc
331; Parameters:
332; %1: Destination data
333; Returns:
334; Nothing
335; Corrupts registers:
336; Flags
337;--------------------------------------------------------------------
338%macro eSETZ 1
339 mov %1, 0 ; Clear while preserving flags
340 jnz SHORT %%Return ; Nothing to set
341 inc %1
342%%Return:
343%endmacro
344
345%macro eSETNZ 1
346 mov %1, 0 ; Clear while preserving flags
347 jz SHORT %%Return ; Nothing to set
348 inc %1
349%%Return:
350%endmacro
351
352
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)
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
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
418 push sp
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
445 pop ax ; Skip SP
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:
533; %1: REP/REPE/REPZ or REPNE/REPNZ prefix
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:
540; FLAGS
541;--------------------------------------------------------------------
542%macro eSEG_STR 3
543%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
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
548FSIS cmps, %3
549%ifn strpos
550 FSIS scas, %3
551%endif
552%if strpos ; Must preserve FLAGS
553 jcxz %%End ; Jump to end if no repeats left (preserves FLAGS)
554 jmp SHORT %%Loop ; Loop while repeats left
555 %%End:
556%else ; No need to preserve FLAGS
557 inc cx
558 loop %%Loop
559%endif
560%else ; No bug on V20/V30 and later, don't know about 188/186
561 %2
562 %1 %3
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
581%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
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
590 %if %2 > 3 ; Size optimized value
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
603%endif
604%endmacro
605
606%macro eSHR_IM 2
607 eSHIFT_IM %1, %2, shr
608%endmacro
609
610%macro eSHL_IM 2
611%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
612%ifdef USE_386
613 %if %2 = 1
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
620 %else
621 eSHIFT_IM %1, %2, shl
622 %endif
623%else
624 eSHIFT_IM %1, %2, shl
625%endif
626%endif
627%endmacro
628
629%macro eROR_IM 2
630 eSHIFT_IM %1, %2, ror
631%endmacro
632
633%macro eROL_IM 2
634 eSHIFT_IM %1, %2, rol
635%endmacro
636
637%macro eRCR_IM 2
638 eSHIFT_IM %1, %2, rcr
639%endmacro
640
641%macro eRCL_IM 2
642%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
643%ifdef USE_386
644 %if %2 = 1
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
651 %else
652 eSHIFT_IM %1, %2, rcl
653 %endif
654%else
655 eSHIFT_IM %1, %2, rcl
656%endif
657%endif
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.