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

Last change on this file since 628 was 624, checked in by Krister Nordvall, 21 months ago

Changes:

  • The BIOS version string has been changed to show the repository revision number instead of the useless "v2.0.0 beta 3+" string. In other words, the seemingly never ending beta is finally over! The version string is now updated by TortoiseSVN client side hook scripts (residing in \Tools) to be used when committing changes to the repository. It should also be possible to use these scripts with other subversion clients under Windows since they are essentially just regular batch (cmd) files!
  • The eSEG_STR macro has been changed to always disable interrupts. The workaround used for the buggy, early revisions of the 8088/8086 CPUs apparently does not work. Many thanks to Jim Leonard (Trixter) for reporting this problem!
  • Minor optimizations to the eBSF and eBSR macros.
File size: 16.5 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
[623]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
[41]69%endif
70
71;==========================================================================
72
73;--------------------------------------------------------------------
[592]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
[596]103%ifdef USE_NEC_V
104 %include "NEC_V.inc"
105%endif
106
107
[592]108;--------------------------------------------------------------------
[491]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
[568]123; db 0D6h
124 salc
[491]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;--------------------------------------------------------------------
[41]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:
[624]190; %1: Index of lowest order bit from %2
[41]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
[624]198 FSIS ], %2 ; %2 is a memory operand?
199 %if strpos
200 cmp WORD %2, BYTE 0 ; Source operand is zero?
201 je SHORT %%Return ; If so, return with ZF set
202 %else ; No, %2 is a register
203 test %2, %2
204 jz SHORT %%Return
205 %endif
[41]206
[592]207 push cx
[41]208
[624]209%ifdef USE_NEC_V
210 mov cx, -1
211
[41]212ALIGN JUMP_ALIGN
213%%BitLoop:
[624]214 inc cx
215 eTEST1 %2, cl
216 jz SHORT %%BitLoop
217 mov %1, cx
218
219%else ; ~USE_NEC_V
220 mov cx, 1<<15
221 mov %1, -1
222
223ALIGN JUMP_ALIGN
224%%BitLoop:
225 rol cx, 1 ; Prepare to test next bit
226 inc %1 ; Increment bit index
[41]227 test %2, cx ; Bit set?
[624]228 jz SHORT %%BitLoop
229%endif
230
[592]231 pop cx
[624]232
[41]233%%Return:
234;-----------------------------------
[624]235%else ; USE_386
[41]236 bsf %1, %2
237%endif
238%endmacro
239
240
241;--------------------------------------------------------------------
242; Emulates BSR (Bit Scan Reverse) instruction when necessary.
243; BSR is used to find index of most significant bit.
244;
245; eBSR
246; Parameters:
247; %1: Destination WORD Register for bit index (not CX or same as %2!)
248; %2: Source WORD operand where to search bit (not CX or same as %1!)
249; Returns:
250; %1: Index of highest order bit from %2
251; ZF: Set if %2 is zero
252; Cleared if %2 is non-zero
253; Corrupts registers:
254; Nothing
255;--------------------------------------------------------------------
256%macro eBSR 2
257%ifndef USE_386
[624]258 FSIS ], %2 ; %2 is a memory operand?
259 %if strpos
260 cmp WORD %2, BYTE 0 ; Source operand is zero?
261 je SHORT %%Return ; If so, return with ZF set
262 %else ; No, %2 is a register
263 test %2, %2
264 jz SHORT %%Return
265 %endif
[41]266
[592]267 push cx
[41]268
[624]269%ifdef USE_NEC_V
270 mov cx, 16
271
[41]272ALIGN JUMP_ALIGN
273%%BitLoop:
[624]274 dec cx
275 eTEST1 %2, cl
276 jz SHORT %%BitLoop
277 mov %1, cx
278
279%else ; ~USE_NEC_V
280 mov cx, 1
281 mov %1, 16
282
283ALIGN JUMP_ALIGN
284%%BitLoop:
285 ror cx, 1 ; Prepare to test next bit
286 dec %1 ; Decrement bit index
[41]287 test %2, cx ; Bit set?
[624]288 jz SHORT %%BitLoop
289%endif
290
[592]291 pop cx
[624]292
[41]293%%Return:
294;-----------------------------------
[624]295%else ; USE_386
[41]296 bsr %1, %2
297%endif
298%endmacro
299
300
301;--------------------------------------------------------------------
302; Conditional Move.
303;
304; eCMOVcc
305; Parameters:
306; %1: Destination data
307; %2: Source data
308; Returns:
309; Nothing
310; Corrupts registers:
311; Nothing
312;--------------------------------------------------------------------
[146]313%macro eCMOVA 2
314 jbe SHORT %%Return
315 mov %1, %2
316%%Return:
317%endmacro
318
[41]319%macro eCMOVC 2
320 jnc SHORT %%Return
321 mov %1, %2
322%%Return:
323%endmacro
324
[390]325%macro eCMOVNC 2
326 jc SHORT %%Return
327 mov %1, %2
328%%Return:
329%endmacro
330
[64]331%macro eCMOVZ 2
332 jnz SHORT %%Return
333 mov %1, %2
334%%Return:
335%endmacro
336
[94]337%macro eCMOVNZ 2
338 jz SHORT %%Return
[41]339 mov %1, %2
340%%Return:
341%endmacro
342
[94]343%macro eCMOVE 2
[592]344 eCMOVZ %1, %2
[94]345%endmacro
346
347%macro eCMOVNE 2
[592]348 eCMOVNZ %1, %2
[94]349%endmacro
350
[60]351%macro eCMOVB 2
[592]352 eCMOVC %1, %2
[60]353%endmacro
[41]354
[390]355%macro eCMOVS 2
356 jns SHORT %%Return
357 mov %1, %2
358%%Return:
359%endmacro
[41]360
[396]361%macro eCMOVNS 2
362 js SHORT %%Return
363 mov %1, %2
364%%Return:
365%endmacro
[390]366
[396]367
[168]368;--------------------------------------------------------------------
369; Conditional Set.
370;
[592]371; eSETcc
[168]372; Parameters:
373; %1: Destination data
374; Returns:
375; Nothing
376; Corrupts registers:
377; Flags
378;--------------------------------------------------------------------
[592]379%macro eSETZ 1
[168]380 mov %1, 0 ; Clear while preserving flags
381 jnz SHORT %%Return ; Nothing to set
382 inc %1
383%%Return:
384%endmacro
[60]385
[592]386%macro eSETNZ 1
[586]387 mov %1, 0 ; Clear while preserving flags
388 jz SHORT %%Return ; Nothing to set
389 inc %1
390%%Return:
391%endmacro
[168]392
[586]393
[41]394;--------------------------------------------------------------------
395; Moves byte with zero-extending to any Register.
396;
397; eMOVZX
398; Parameters:
399; %1: Destination Register (SP not supported)
400; %2: Byte register or byte address
401; Returns:
402; Nothing
403; Corrupts registers:
404; FLAGS
405;--------------------------------------------------------------------
406%macro eMOVZX 2
407%ifndef USE_386
408 %ifidni %1, ax
409 mov al, %2
410 xor ah, ah
411 %elifidni %1, bx
412 mov bl, %2
413 xor bh, bh ; %2 may use BX in effective address
414 %elifidni %1, cx
415 mov cl, %2
416 xor ch, ch
417 %elifidni %1, dx
418 mov dl, %2
419 xor dh, dh
420 %else ; SI, DI, BP (all may be used in effective address)
[592]421 FSIS %1, %2
422 %if strpos
423 push ax
424 mov al, %2
425 xor ah, ah
426 xchg %1, ax
427 pop ax
428 %else
429 xchg %1, ax
430 mov al, %2
431 xor ah, ah
432 xchg %1, ax
433 %endif
[41]434 %endif
435;-----------------------------------
436%else
437 movzx %1, %2
438%endif
439%endmacro
440
441
442;--------------------------------------------------------------------
443; Emulates PUSHA instruction when necessary.
444;
445; ePUSHA
446; Parameters:
447; Nothing
448; Returns:
449; Nothing
450; Corrupts registers:
451; Nothing
452;--------------------------------------------------------------------
453%macro ePUSHA 0
454%ifndef USE_186
455 push ax
456 push cx
457 push dx
458 push bx
[113]459 push sp
[41]460 push bp
461 push si
462 push di
463;-----------------------------------
464%else
465 pusha
466%endif
467%endmacro
468
469
470;--------------------------------------------------------------------
471; Emulates POPA instruction when necessary.
472;
473; ePOPA
474; Parameters:
475; Nothing
476; Returns:
477; Nothing
478; Corrupts registers:
479; Nothing
480;--------------------------------------------------------------------
481%macro ePOPA 0
482%ifndef USE_186
483 pop di
484 pop si
485 pop bp
[113]486 pop ax ; Skip SP
[41]487 pop bx
488 pop dx
489 pop cx
490 pop ax
491;-----------------------------------
492%else
493 popa
494%endif
495%endmacro
496
497
498;--------------------------------------------------------------------
499; Emulates ENTER instruction when necessary.
500;
501; eENTER
502; Parameters:
503; %1: Number of bytes to reserve from stack
504; %2: The lexical nesting level (not emulated, set to 0)
505; Returns:
506; SS:BP: Ptr to old BP
507; ([bp-2] points to highest local stack frame word)
508; Corrupts registers:
509; FLAGS
510;--------------------------------------------------------------------
511%macro eENTER 2
512%ifndef USE_186
513 push bp
514 mov bp, sp
515 sub sp, %1
516;-----------------------------------
517%else
518 enter %1, %2
519%endif
520%endmacro
521
522;--------------------------------------------------------------------
523; Emulates LEAVE instruction when necessary.
524;
525; eLEAVE
526; Parameters:
527; Nothing
528; Returns:
529; BP: What it was before eENTER
530; Corrupts registers:
531; Nothing
532;--------------------------------------------------------------------
533%macro eLEAVE 0
534%ifndef USE_186
535 mov sp, bp
536 pop bp
537;-----------------------------------
538%else
539 leave
540%endif
541%endmacro
542
543
544;--------------------------------------------------------------------
545; Emulates LSS instruction when necessary.
546;
547; eLSS
548; Parameters:
549; %1: Destination register
550; %2: Source memory address without brackets
551; Returns:
552; IF: 0 (interrupts disabled)
553; Corrupts registers:
554; Nothing
555;--------------------------------------------------------------------
556%macro eLSS 2
557%ifndef USE_386
558 cli ; Disable interrupts
559 mov %1, [%2] ; Load offset
560 mov ss, [%2+2] ; Load segment
561;-----------------------------------
562%else
563 lss %1, [%2]
564%endif
565%endmacro
566
567
568;--------------------------------------------------------------------
569; Repeats string instruction with segment override.
570; This macro prevents 8088/8086 restart bug.
571;
572; eSEG_STR
573; Parameters:
[592]574; %1: REP/REPE/REPZ or REPNE/REPNZ prefix
[41]575; %2: Source segment override (destination is always ES)
576; %3: String instruction
[624]577; %4: An exclamation mark (!) if the state of the IF must
578; be preserved (can not be used together with CMPS or
579; SCAS instructions), otherwise it will be set on
580; return from the macro (i.e. interrupts will be on)
[41]581; CX: Repeat count
582; Returns:
[624]583; FLAGS for CMPS and SCAS only
[41]584; Corrupts registers:
[592]585; FLAGS
[41]586;--------------------------------------------------------------------
[624]587%macro eSEG_STR 3-4
588%ifndef USE_186 ; 8088/8086 has string instruction restart bug when using more than one prefix
589%ifidn %4, ! ; Preserve the IF
590 FSIS cmps, %3
[592]591%ifn strpos
592 FSIS scas, %3
593%endif
[624]594%if strpos
595 %error "The state of the IF can not be preserved when using CMPS or SCAS!"
[592]596%endif
[624]597 pushf
598 cli
599 %1 ; REP is the prefix that can be lost
600 %2 ; SEG is the prefix that won't be lost
601 %3 ; String instruction
602 popf
603%else ; No need to preserve the IF
604 cli
605 %1
[223]606 %2
[624]607 %3
608 sti
609%endif
610%else ; No bug on V20/V30/188/186 and later
611 %2
[223]612 %1 %3
[41]613%endif
614%endmacro
615
616
617;--------------------------------------------------------------------
618; Bit shifts and rotates with immediate.
619;
620; eSHIFT_IM
621; Parameters:
622; %1: Shift target
623; %2: Number of bits to shift
624; %3: Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
625; Returns:
626; FLAGS
627; Corrupts registers:
628; Nothing
629;--------------------------------------------------------------------
630%macro eSHIFT_IM 3
[488]631%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
[41]632%ifndef USE_186
633 %ifidni %1, cl
634 times %2 %3 %1, 1
635 %elifidni %1, ch
636 times %2 %3 %1, 1
637 %elifidni %1, cx
638 times %2 %3 %1, 1
639 %else
[181]640 %if %2 > 3 ; Size optimized value
[41]641 push cx
642 mov cl, %2
643 %3 %1, cl
644 pop cx
645 %else
646 times %2 %3 %1, 1
647 %endif
648 %endif
649;-----------------------------------
650%else
651 %3 %1, %2
652%endif
[488]653%endif
[41]654%endmacro
[420]655
[41]656%macro eSHR_IM 2
657 eSHIFT_IM %1, %2, shr
658%endmacro
[445]659
[41]660%macro eSHL_IM 2
[489]661%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
[445]662%ifdef USE_386
663 %if %2 = 1
[592]664 FSIS ], %1
665 %if strpos
666 eSHIFT_IM %1, %2, shl
667 %else
668 add %1, %1 ; Same size but faster on 386 and 486.
669 %endif
[445]670 %else
671 eSHIFT_IM %1, %2, shl
672 %endif
673%else
[41]674 eSHIFT_IM %1, %2, shl
[445]675%endif
[489]676%endif
[41]677%endmacro
[445]678
[41]679%macro eROR_IM 2
680 eSHIFT_IM %1, %2, ror
681%endmacro
[445]682
[41]683%macro eROL_IM 2
684 eSHIFT_IM %1, %2, rol
685%endmacro
[445]686
[41]687%macro eRCR_IM 2
688 eSHIFT_IM %1, %2, rcr
689%endmacro
[445]690
[41]691%macro eRCL_IM 2
[589]692%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
693%ifdef USE_386
694 %if %2 = 1
[592]695 FSIS ], %1
696 %if strpos
697 eSHIFT_IM %1, %2, rcl
698 %else
699 adc %1, %1 ; Same size but faster on 386 and 486.
700 %endif
[589]701 %else
702 eSHIFT_IM %1, %2, rcl
703 %endif
704%else
[41]705 eSHIFT_IM %1, %2, rcl
[589]706%endif
707%endif
[41]708%endmacro
709
710
711;--------------------------------------------------------------------
712; Emulates PUSH imm instruction when necessary.
713;
714; ePUSH_I
715; Parameters:
716; %1: Immediate to push
717; Returns:
718; Nothing
719; Corrupts registers:
720; Nothing
721;--------------------------------------------------------------------
722%macro ePUSH_I 1
723%ifndef USE_186
724 push bp ; Immediate goes here
725 push bp
726 mov bp, sp
727 mov WORD [bp+2], %1
728 pop bp
729;-----------------------------------
730%else
731 push %1
732%endif
733%endmacro
734
735
736;--------------------------------------------------------------------
737; Emulates PUSH imm instruction when necessary.
738; ePUSH_T uses temporary register for faster performance
739; and smaller code size than ePUSH_I.
740;
741; ePUSH_T
742; Parameters:
743; %1: Temporary Register
744; %2: Immediate to push
745; Returns:
746; Nothing
747; Corrupts registers:
748; %1
749;--------------------------------------------------------------------
750%macro ePUSH_T 2
751%ifndef USE_186
752 %ifidni %2, 0
753 xor %1, %1
754 %else
755 mov %1, %2
756 %endif
757 push %1
758;-----------------------------------
759%else
760 push %2
761%endif
762%endmacro
763
764
765%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.