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

Last change on this file since 623 was 623, checked in by Krister Nordvall, 2 years ago

Changes:

  • Reversed the change to IdeDPT.asm in r622 as it didn't work as intended.
  • Reordered some procedures to reduce alignment padding.
  • Added two new defines (EXTRA_LOOP_UNROLLING_SMALL and EXTRA_LOOP_UNROLLING_LARGE) that should improve transfer speeds for some hardware combinations, specifically 808x CPUs with any IDE controller using port I/O and any CPU with XT-IDE controllers.
  • Added a new define (USE_086) for use with 8086 and V30 CPUs only. Unlike the other USE_x86 defines, this define will not change the instruction set used and is therefore compatible with all CPUs. However, it will apply padding to make jump destinations WORD aligned which should improve performance on 8086/V30 CPUs but on 8088/V20 CPUs there is no benefit and, in addition to wasting ROM space, it might in fact be slower on these machines. Since the vast majority of XT class machines are using 8088/V20 CPUs this define is not used in the official XT builds - it's primarily intended for custom BIOS builds.
  • XTIDECFG: The URL to the support forum has been updated.
File size: 16.0 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 %ifndef USE_086 ; 8088/V20 CPUs
63 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.
64 WORD_ALIGN EQU 2 ; The same applies here but the cost of ROM space is negligible.
65 %else ; 8086/V30 CPUs
66 JUMP_ALIGN EQU 2
67 WORD_ALIGN EQU 2
68 %endif
69%endif
70
71;==========================================================================
72
73;--------------------------------------------------------------------
74; Find String In String
75;
76; FSIS
77; Parameters:
78; %1: String to search for (case-insensitive)
79; %2: String to search in
80; Returns:
81; strpos: Position of %1 in %2 if found, 0 if not found
82;--------------------------------------------------------------------
83%macro FSIS 2.nolist
84%defstr s1 %1
85%defstr s2 %2
86%strlen sl1 s1
87%strlen sl2 s2
88%assign strpos 0
89 %if sl1 <= sl2
90 %assign strpos sl2 - sl1 + 1
91 %rep strpos
92 %substr %%ss s2 strpos, sl1
93 %ifidni %%ss, s1
94 %exitrep
95 %else
96 %assign strpos strpos - 1
97 %endif
98 %endrep
99 %endif
100%endmacro
101
102
103%ifdef USE_NEC_V
104 %include "NEC_V.inc"
105%endif
106
107
108;--------------------------------------------------------------------
109; The undocumented instruction SALC (Set AL According to CF).
110; Available on all Intel processors and truly compatible clones.
111; Does not work on the NEC V20/V30 or Sony CXQ70108 processors.
112;
113; eSALC
114; Parameters:
115; Nothing
116; Returns:
117; AL: FFh if CF=1
118; 00h if CF=0
119; Corrupts registers:
120; Nothing
121;--------------------------------------------------------------------
122%macro eSALC 0
123; db 0D6h
124 salc
125%endmacro
126
127
128;--------------------------------------------------------------------
129; The AAD instruction (ASCII Adjust before Division).
130; Available on all Intel processors and truly compatible clones.
131; Does not work on the NEC V20/V30 or Sony CXQ70108 processors
132; unless %1 is 10 (0Ah).
133;
134; eAAD
135; Parameters:
136; %1: Any 8 bit number (0...255)
137; Returns:
138; AL: AH * %1 + AL
139; AH: 0
140; Flags: Set according to result
141; Corrupts registers:
142; Nothing
143;--------------------------------------------------------------------
144%macro eAAD 1
145%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
146 %if %1 > 255
147 %error Invalid parameter passed to eAAD (%1 > 255)
148 %else
149 db 0D5h, %1
150 %endif
151%endif
152%endmacro
153
154
155;--------------------------------------------------------------------
156; The AAM instruction (ASCII Adjust after Multiplication).
157;
158; eAAM
159; Parameters:
160; %1: Any 8 bit number except 0 (1...255)
161; Returns:
162; AL: AL MOD %1
163; AH: AL / %1
164; Flags: Set according to result
165; Corrupts registers:
166; Nothing
167;--------------------------------------------------------------------
168%macro eAAM 1
169%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
170 %if %1 > 255
171 %error Invalid parameter passed to eAAM (%1 > 255)
172 %elif %1 = 0
173 %error Invalid parameter passed to eAAM (%1 = 0). This would cause a divide-by-zero exception!
174 %else
175 db 0D4h, %1
176 %endif
177%endif
178%endmacro
179
180
181;--------------------------------------------------------------------
182; Emulates BSF (Bit Scan Forward) instruction when necessary.
183; BSF is used to find index of least significant bit.
184;
185; eBSF
186; Parameters:
187; %1: Destination WORD Register for bit index (not CX or same as %2!)
188; %2: Source WORD operand where to search bit (not CX or same as %1!)
189; Returns:
190; %1: Index of highest order bit from %2
191; ZF: Set if %2 is zero
192; Cleared if %2 is non-zero
193; Corrupts registers:
194; Nothing
195;--------------------------------------------------------------------
196%macro eBSF 2
197%ifndef USE_386
198 cmp WORD %2, BYTE 0 ; Source operand is zero?
199 je SHORT %%Return ; If so, return with ZF set
200
201 ; Set destination to zero and load mask for bit 0
202 push cx
203 xor %1, %1
204 mov cx, 1
205
206ALIGN JUMP_ALIGN
207%%BitLoop:
208 test %2, cx ; Bit set?
209 jnz SHORT %%PopAndReturn; If so, return with ZF cleared
210 shl cx, 1 ; Prepare to test next bit
211 inc %1 ; Increment bit index
212 jmp SHORT %%BitLoop ; Loop until bit found
213%%PopAndReturn:
214 pop cx
215%%Return:
216;-----------------------------------
217%else
218 bsf %1, %2
219%endif
220%endmacro
221
222
223;--------------------------------------------------------------------
224; Emulates BSR (Bit Scan Reverse) instruction when necessary.
225; BSR is used to find index of most significant bit.
226;
227; eBSR
228; Parameters:
229; %1: Destination WORD Register for bit index (not CX or same as %2!)
230; %2: Source WORD operand where to search bit (not CX or same as %1!)
231; Returns:
232; %1: Index of highest order bit from %2
233; ZF: Set if %2 is zero
234; Cleared if %2 is non-zero
235; Corrupts registers:
236; Nothing
237;--------------------------------------------------------------------
238%macro eBSR 2
239%ifndef USE_386
240 cmp WORD %2, BYTE 0 ; Source operand is zero?
241 je SHORT %%Return ; If so, return with ZF set
242
243 ; Load mask for highest order bit
244 push cx
245 mov cx, 1<<15
246 mov %1, 15
247
248ALIGN JUMP_ALIGN
249%%BitLoop:
250 test %2, cx ; Bit set?
251 jnz SHORT %%PopAndReturn; If so, return with ZF cleared
252 shr cx, 1 ; Prepare to test next bit
253 dec %1 ; Decrement bit index
254 jmp SHORT %%BitLoop ; Loop until bit found
255%%PopAndReturn:
256 pop cx
257%%Return:
258;-----------------------------------
259%else
260 bsr %1, %2
261%endif
262%endmacro
263
264
265;--------------------------------------------------------------------
266; Conditional Move.
267;
268; eCMOVcc
269; Parameters:
270; %1: Destination data
271; %2: Source data
272; Returns:
273; Nothing
274; Corrupts registers:
275; Nothing
276;--------------------------------------------------------------------
277%macro eCMOVA 2
278 jbe SHORT %%Return
279 mov %1, %2
280%%Return:
281%endmacro
282
283%macro eCMOVC 2
284 jnc SHORT %%Return
285 mov %1, %2
286%%Return:
287%endmacro
288
289%macro eCMOVNC 2
290 jc SHORT %%Return
291 mov %1, %2
292%%Return:
293%endmacro
294
295%macro eCMOVZ 2
296 jnz SHORT %%Return
297 mov %1, %2
298%%Return:
299%endmacro
300
301%macro eCMOVNZ 2
302 jz SHORT %%Return
303 mov %1, %2
304%%Return:
305%endmacro
306
307%macro eCMOVE 2
308 eCMOVZ %1, %2
309%endmacro
310
311%macro eCMOVNE 2
312 eCMOVNZ %1, %2
313%endmacro
314
315%macro eCMOVB 2
316 eCMOVC %1, %2
317%endmacro
318
319%macro eCMOVS 2
320 jns SHORT %%Return
321 mov %1, %2
322%%Return:
323%endmacro
324
325%macro eCMOVNS 2
326 js SHORT %%Return
327 mov %1, %2
328%%Return:
329%endmacro
330
331
332;--------------------------------------------------------------------
333; Conditional Set.
334;
335; eSETcc
336; Parameters:
337; %1: Destination data
338; Returns:
339; Nothing
340; Corrupts registers:
341; Flags
342;--------------------------------------------------------------------
343%macro eSETZ 1
344 mov %1, 0 ; Clear while preserving flags
345 jnz SHORT %%Return ; Nothing to set
346 inc %1
347%%Return:
348%endmacro
349
350%macro eSETNZ 1
351 mov %1, 0 ; Clear while preserving flags
352 jz SHORT %%Return ; Nothing to set
353 inc %1
354%%Return:
355%endmacro
356
357
358;--------------------------------------------------------------------
359; Moves byte with zero-extending to any Register.
360;
361; eMOVZX
362; Parameters:
363; %1: Destination Register (SP not supported)
364; %2: Byte register or byte address
365; Returns:
366; Nothing
367; Corrupts registers:
368; FLAGS
369;--------------------------------------------------------------------
370%macro eMOVZX 2
371%ifndef USE_386
372 %ifidni %1, ax
373 mov al, %2
374 xor ah, ah
375 %elifidni %1, bx
376 mov bl, %2
377 xor bh, bh ; %2 may use BX in effective address
378 %elifidni %1, cx
379 mov cl, %2
380 xor ch, ch
381 %elifidni %1, dx
382 mov dl, %2
383 xor dh, dh
384 %else ; SI, DI, BP (all may be used in effective address)
385 FSIS %1, %2
386 %if strpos
387 push ax
388 mov al, %2
389 xor ah, ah
390 xchg %1, ax
391 pop ax
392 %else
393 xchg %1, ax
394 mov al, %2
395 xor ah, ah
396 xchg %1, ax
397 %endif
398 %endif
399;-----------------------------------
400%else
401 movzx %1, %2
402%endif
403%endmacro
404
405
406;--------------------------------------------------------------------
407; Emulates PUSHA instruction when necessary.
408;
409; ePUSHA
410; Parameters:
411; Nothing
412; Returns:
413; Nothing
414; Corrupts registers:
415; Nothing
416;--------------------------------------------------------------------
417%macro ePUSHA 0
418%ifndef USE_186
419 push ax
420 push cx
421 push dx
422 push bx
423 push sp
424 push bp
425 push si
426 push di
427;-----------------------------------
428%else
429 pusha
430%endif
431%endmacro
432
433
434;--------------------------------------------------------------------
435; Emulates POPA instruction when necessary.
436;
437; ePOPA
438; Parameters:
439; Nothing
440; Returns:
441; Nothing
442; Corrupts registers:
443; Nothing
444;--------------------------------------------------------------------
445%macro ePOPA 0
446%ifndef USE_186
447 pop di
448 pop si
449 pop bp
450 pop ax ; Skip SP
451 pop bx
452 pop dx
453 pop cx
454 pop ax
455;-----------------------------------
456%else
457 popa
458%endif
459%endmacro
460
461
462;--------------------------------------------------------------------
463; Emulates ENTER instruction when necessary.
464;
465; eENTER
466; Parameters:
467; %1: Number of bytes to reserve from stack
468; %2: The lexical nesting level (not emulated, set to 0)
469; Returns:
470; SS:BP: Ptr to old BP
471; ([bp-2] points to highest local stack frame word)
472; Corrupts registers:
473; FLAGS
474;--------------------------------------------------------------------
475%macro eENTER 2
476%ifndef USE_186
477 push bp
478 mov bp, sp
479 sub sp, %1
480;-----------------------------------
481%else
482 enter %1, %2
483%endif
484%endmacro
485
486;--------------------------------------------------------------------
487; Emulates LEAVE instruction when necessary.
488;
489; eLEAVE
490; Parameters:
491; Nothing
492; Returns:
493; BP: What it was before eENTER
494; Corrupts registers:
495; Nothing
496;--------------------------------------------------------------------
497%macro eLEAVE 0
498%ifndef USE_186
499 mov sp, bp
500 pop bp
501;-----------------------------------
502%else
503 leave
504%endif
505%endmacro
506
507
508;--------------------------------------------------------------------
509; Emulates LSS instruction when necessary.
510;
511; eLSS
512; Parameters:
513; %1: Destination register
514; %2: Source memory address without brackets
515; Returns:
516; IF: 0 (interrupts disabled)
517; Corrupts registers:
518; Nothing
519;--------------------------------------------------------------------
520%macro eLSS 2
521%ifndef USE_386
522 cli ; Disable interrupts
523 mov %1, [%2] ; Load offset
524 mov ss, [%2+2] ; Load segment
525;-----------------------------------
526%else
527 lss %1, [%2]
528%endif
529%endmacro
530
531
532;--------------------------------------------------------------------
533; Repeats string instruction with segment override.
534; This macro prevents 8088/8086 restart bug.
535;
536; eSEG_STR
537; Parameters:
538; %1: REP/REPE/REPZ or REPNE/REPNZ prefix
539; %2: Source segment override (destination is always ES)
540; %3: String instruction
541; CX: Repeat count
542; Returns:
543; FLAGS for cmps and scas only
544; Corrupts registers:
545; FLAGS
546;--------------------------------------------------------------------
547%macro eSEG_STR 3
548%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
549 %%Loop:
550 %1 ; REP is the prefix that can be lost
551 %2 ; SEG is the prefix that won't be lost
552 %3 ; String instruction
553FSIS cmps, %3
554%ifn strpos
555 FSIS scas, %3
556%endif
557%if strpos ; Must preserve FLAGS
558 jcxz %%End ; Jump to end if no repeats left (preserves FLAGS)
559 jmp SHORT %%Loop ; Loop while repeats left
560 %%End:
561%else ; No need to preserve FLAGS
562 inc cx
563 loop %%Loop
564%endif
565%else ; No bug on V20/V30 and later, don't know about 188/186
566 %2
567 %1 %3
568%endif
569%endmacro
570
571
572;--------------------------------------------------------------------
573; Bit shifts and rotates with immediate.
574;
575; eSHIFT_IM
576; Parameters:
577; %1: Shift target
578; %2: Number of bits to shift
579; %3: Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
580; Returns:
581; FLAGS
582; Corrupts registers:
583; Nothing
584;--------------------------------------------------------------------
585%macro eSHIFT_IM 3
586%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
587%ifndef USE_186
588 %ifidni %1, cl
589 times %2 %3 %1, 1
590 %elifidni %1, ch
591 times %2 %3 %1, 1
592 %elifidni %1, cx
593 times %2 %3 %1, 1
594 %else
595 %if %2 > 3 ; Size optimized value
596 push cx
597 mov cl, %2
598 %3 %1, cl
599 pop cx
600 %else
601 times %2 %3 %1, 1
602 %endif
603 %endif
604;-----------------------------------
605%else
606 %3 %1, %2
607%endif
608%endif
609%endmacro
610
611%macro eSHR_IM 2
612 eSHIFT_IM %1, %2, shr
613%endmacro
614
615%macro eSHL_IM 2
616%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
617%ifdef USE_386
618 %if %2 = 1
619 FSIS ], %1
620 %if strpos
621 eSHIFT_IM %1, %2, shl
622 %else
623 add %1, %1 ; Same size but faster on 386 and 486.
624 %endif
625 %else
626 eSHIFT_IM %1, %2, shl
627 %endif
628%else
629 eSHIFT_IM %1, %2, shl
630%endif
631%endif
632%endmacro
633
634%macro eROR_IM 2
635 eSHIFT_IM %1, %2, ror
636%endmacro
637
638%macro eROL_IM 2
639 eSHIFT_IM %1, %2, rol
640%endmacro
641
642%macro eRCR_IM 2
643 eSHIFT_IM %1, %2, rcr
644%endmacro
645
646%macro eRCL_IM 2
647%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
648%ifdef USE_386
649 %if %2 = 1
650 FSIS ], %1
651 %if strpos
652 eSHIFT_IM %1, %2, rcl
653 %else
654 adc %1, %1 ; Same size but faster on 386 and 486.
655 %endif
656 %else
657 eSHIFT_IM %1, %2, rcl
658 %endif
659%else
660 eSHIFT_IM %1, %2, rcl
661%endif
662%endif
663%endmacro
664
665
666;--------------------------------------------------------------------
667; Emulates PUSH imm instruction when necessary.
668;
669; ePUSH_I
670; Parameters:
671; %1: Immediate to push
672; Returns:
673; Nothing
674; Corrupts registers:
675; Nothing
676;--------------------------------------------------------------------
677%macro ePUSH_I 1
678%ifndef USE_186
679 push bp ; Immediate goes here
680 push bp
681 mov bp, sp
682 mov WORD [bp+2], %1
683 pop bp
684;-----------------------------------
685%else
686 push %1
687%endif
688%endmacro
689
690
691;--------------------------------------------------------------------
692; Emulates PUSH imm instruction when necessary.
693; ePUSH_T uses temporary register for faster performance
694; and smaller code size than ePUSH_I.
695;
696; ePUSH_T
697; Parameters:
698; %1: Temporary Register
699; %2: Immediate to push
700; Returns:
701; Nothing
702; Corrupts registers:
703; %1
704;--------------------------------------------------------------------
705%macro ePUSH_T 2
706%ifndef USE_186
707 %ifidni %2, 0
708 xor %1, %1
709 %else
710 mov %1, %2
711 %endif
712 push %1
713;-----------------------------------
714%else
715 push %2
716%endif
717%endmacro
718
719
720%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.