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

Last change on this file since 507 was 491, checked in by krille_n_@…, 12 years ago

Changes:

  • Added a new define (USE_UNDOC_INTEL) that enables optimizations possible by using undocumented instructions available on all Intel processors and truly compatible clones. AFAIK the only exceptions are the NEC V-series and the Sony CXQ70108 processors so this option should be safe for use on the AT builds.
  • Building BIOSDRVS or the BIOS without MODULE_STRINGS_COMPRESSED would fail due to the recent code exclusions so I changed them a bit. Also fixed the mistaken change to Main.asm
  • Changed the Tandy specific info in Configuration_FullMode.txt so it matches the info in the Wiki.
  • Optimizations and fixes in general.
File size: 14.1 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
26%endif
27
28%ifdef USE_386
29 CPU 386 ; Allow instructions up to 386
[41]30%elifdef USE_286
[293]31 CPU 286 ; Allow instructions up to 286
32%elifdef USE_186
33 CPU 186 ; Allow instructions up to 188/186/V20/V30
34%else
35 CPU 8086 ; Allow 8088/8086 instructions only
[41]36%endif
[293]37
[41]38BITS 16 ; Set 16 bit code generation
39
40; Alignments for jump targets.
41; Following values are optimal for different processor types:
42; 286 and 386SX WORD (16-bit, 2 bytes)
43; 386DX and 486 DWORD (32-bit, 4 bytes)
44; Pentium and later QWORD (64-bit, 8 bytes)
45%ifdef USE_AT
46 %ifdef USE_386
47 JUMP_ALIGN EQU 4
48 WORD_ALIGN EQU 2
49 %else ; USE_286
50 JUMP_ALIGN EQU 2
51 WORD_ALIGN EQU 2
52 %endif
53%else ; XT
54 JUMP_ALIGN EQU 1
55 WORD_ALIGN EQU 1
56%endif
57
58;==========================================================================
59
60;--------------------------------------------------------------------
[491]61; The undocumented instruction SALC (Set AL According to CF).
62; Available on all Intel processors and truly compatible clones.
63; Does not work on the NEC V20/V30 or Sony CXQ70108 processors.
64;
65; eSALC
66; Parameters:
67; Nothing
68; Returns:
69; AL: FFh if CF=1
70; 00h if CF=0
71; Corrupts registers:
72; Nothing
73;--------------------------------------------------------------------
74%macro eSALC 0
75 db 0D6h
76%endmacro
77
78
79;--------------------------------------------------------------------
80; The AAD instruction (ASCII Adjust before Division).
81; Available on all Intel processors and truly compatible clones.
82; Does not work on the NEC V20/V30 or Sony CXQ70108 processors
83; unless %1 is 10 (0Ah).
84;
85; eAAD
86; Parameters:
87; %1: Any 8 bit number (0...255)
88; Returns:
89; AL: AH * %1 + AL
90; AH: 0
91; Flags: Set according to result
92; Corrupts registers:
93; Nothing
94;--------------------------------------------------------------------
95%macro eAAD 1
96%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
97 %if %1 > 255
98 %error Invalid parameter passed to eAAD (%1 > 255)
99 %else
100 db 0D5h, %1
101 %endif
102%endif
103%endmacro
104
105
106;--------------------------------------------------------------------
107; The AAM instruction (ASCII Adjust after Multiplication).
108; Available on all Intel processors and truly compatible clones.
109; Does not work on the NEC V20/V30 or Sony CXQ70108 processors
110; unless %1 is 10 (0Ah).
111;
112; eAAM
113; Parameters:
114; %1: Any 8 bit number except 0 (1...255)
115; Returns:
116; AL: AL MOD %1
117; AH: AL / %1
118; Flags: Set according to result
119; Corrupts registers:
120; Nothing
121;--------------------------------------------------------------------
122%macro eAAM 1
123%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
124 %if %1 > 255
125 %error Invalid parameter passed to eAAM (%1 > 255)
126 %elif %1 = 0
127 %error Invalid parameter passed to eAAM (%1 = 0). This would cause a divide-by-zero exception!
128 %else
129 db 0D4h, %1
130 %endif
131%endif
132%endmacro
133
134
135;--------------------------------------------------------------------
[41]136; Emulates BSF (Bit Scan Forward) instruction when necessary.
137; BSF is used to find index of least significant bit.
138;
139; eBSF
140; Parameters:
141; %1: Destination WORD Register for bit index (not CX or same as %2!)
142; %2: Source WORD operand where to search bit (not CX or same as %1!)
143; Returns:
144; %1: Index of highest order bit from %2
145; ZF: Set if %2 is zero
146; Cleared if %2 is non-zero
147; Corrupts registers:
148; Nothing
149;--------------------------------------------------------------------
150%macro eBSF 2
151%ifndef USE_386
152 push cx
153 cmp WORD %2, BYTE 0 ; Source operand is zero?
154 je SHORT %%Return ; If so, return with ZF set
155
156 ; Set destination to zero and load mask for bit 0
157 xor %1, %1
158 mov cx, 1
159
160ALIGN JUMP_ALIGN
161%%BitLoop:
162 test %2, cx ; Bit set?
163 jnz SHORT %%Return ; If so, return with ZF cleared
164 shl cx, 1 ; Prepare to test next bit
165 inc %1 ; Increment bit index
166 jmp SHORT %%BitLoop ; Loop until bit found
167%%Return:
168 pop cx
169;-----------------------------------
170%else
171 bsf %1, %2
172%endif
173%endmacro
174
175
176;--------------------------------------------------------------------
177; Emulates BSR (Bit Scan Reverse) instruction when necessary.
178; BSR is used to find index of most significant bit.
179;
180; eBSR
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 eBSR 2
192%ifndef USE_386
193 push cx
194 cmp WORD %2, BYTE 0 ; Source operand is zero?
195 je SHORT %%Return ; If so, return with ZF set
196
197 ; Load mask for highest order bit
198 mov cx, 1<<15
199 mov %1, 15
200
201ALIGN JUMP_ALIGN
202%%BitLoop:
203 test %2, cx ; Bit set?
204 jnz SHORT %%Return ; If so, return with ZF cleared
205 shr cx, 1 ; Prepare to test next bit
206 dec %1 ; Decrement bit index
207 jmp SHORT %%BitLoop ; Loop until bit found
208%%Return:
209 pop cx
210;-----------------------------------
211%else
212 bsr %1, %2
213%endif
214%endmacro
215
216
217;--------------------------------------------------------------------
218; Conditional Move.
219;
220; eCMOVcc
221; Parameters:
222; %1: Destination data
223; %2: Source data
224; Returns:
225; Nothing
226; Corrupts registers:
227; Nothing
228;--------------------------------------------------------------------
[146]229%macro eCMOVA 2
230 jbe SHORT %%Return
231 mov %1, %2
232%%Return:
233%endmacro
234
[41]235%macro eCMOVC 2
236 jnc SHORT %%Return
237 mov %1, %2
238%%Return:
239%endmacro
240
[390]241%macro eCMOVNC 2
242 jc SHORT %%Return
243 mov %1, %2
244%%Return:
245%endmacro
246
[64]247%macro eCMOVZ 2
248 jnz SHORT %%Return
249 mov %1, %2
250%%Return:
251%endmacro
252
[94]253%macro eCMOVNZ 2
254 jz SHORT %%Return
[41]255 mov %1, %2
256%%Return:
257%endmacro
258
[94]259%macro eCMOVE 2
260 eCMOVZ %1, %2
261%endmacro
262
263%macro eCMOVNE 2
264 eCMOVNZ %1, %2
265%endmacro
266
[60]267%macro eCMOVB 2
268 jnb SHORT %%Return
269 mov %1, %2
270%%Return:
271%endmacro
[41]272
[390]273%macro eCMOVS 2
274 jns SHORT %%Return
275 mov %1, %2
276%%Return:
277%endmacro
[41]278
[396]279%macro eCMOVNS 2
280 js SHORT %%Return
281 mov %1, %2
282%%Return:
283%endmacro
[390]284
[396]285
[168]286;--------------------------------------------------------------------
287; Conditional Set.
288;
289; eCSETcc
290; Parameters:
291; %1: Destination data
292; Returns:
293; Nothing
294; Corrupts registers:
295; Flags
296;--------------------------------------------------------------------
297%macro eCSETZ 1
298 mov %1, 0 ; Clear while preserving flags
299 jnz SHORT %%Return ; Nothing to set
300 inc %1
301%%Return:
302%endmacro
[60]303
[168]304
[41]305;--------------------------------------------------------------------
306; Moves byte with zero-extending to any Register.
307;
308; eMOVZX
309; Parameters:
310; %1: Destination Register (SP not supported)
311; %2: Byte register or byte address
312; Returns:
313; Nothing
314; Corrupts registers:
315; FLAGS
316;--------------------------------------------------------------------
317%macro eMOVZX 2
318%ifndef USE_386
319 %ifidni %1, ax
320 mov al, %2
321 xor ah, ah
322 %elifidni %1, bx
323 mov bl, %2
324 xor bh, bh ; %2 may use BX in effective address
325 %elifidni %1, cx
326 mov cl, %2
327 xor ch, ch
328 %elifidni %1, dx
329 mov dl, %2
330 xor dh, dh
331 %else ; SI, DI, BP (all may be used in effective address)
332 push ax
333 mov al, %2
334 xor ah, ah
335 xchg ax, %1
336 pop ax
337 %endif
338;-----------------------------------
339%else
340 movzx %1, %2
341%endif
342%endmacro
343
344
345;--------------------------------------------------------------------
346; Emulates PUSHA instruction when necessary.
347;
348; ePUSHA
349; Parameters:
350; Nothing
351; Returns:
352; Nothing
353; Corrupts registers:
354; Nothing
355;--------------------------------------------------------------------
356%macro ePUSHA 0
357%ifndef USE_186
358 push ax
359 push cx
360 push dx
361 push bx
[113]362 push sp
[41]363 push bp
364 push si
365 push di
366;-----------------------------------
367%else
368 pusha
369%endif
370%endmacro
371
372
373;--------------------------------------------------------------------
374; Emulates POPA instruction when necessary.
375;
376; ePOPA
377; Parameters:
378; Nothing
379; Returns:
380; Nothing
381; Corrupts registers:
382; Nothing
383;--------------------------------------------------------------------
384%macro ePOPA 0
385%ifndef USE_186
386 pop di
387 pop si
388 pop bp
[113]389 pop ax ; Skip SP
[41]390 pop bx
391 pop dx
392 pop cx
393 pop ax
394;-----------------------------------
395%else
396 popa
397%endif
398%endmacro
399
400
401;--------------------------------------------------------------------
402; Emulates ENTER instruction when necessary.
403;
404; eENTER
405; Parameters:
406; %1: Number of bytes to reserve from stack
407; %2: The lexical nesting level (not emulated, set to 0)
408; Returns:
409; SS:BP: Ptr to old BP
410; ([bp-2] points to highest local stack frame word)
411; Corrupts registers:
412; FLAGS
413;--------------------------------------------------------------------
414%macro eENTER 2
415%ifndef USE_186
416 push bp
417 mov bp, sp
418 sub sp, %1
419;-----------------------------------
420%else
421 enter %1, %2
422%endif
423%endmacro
424
425;--------------------------------------------------------------------
426; Emulates LEAVE instruction when necessary.
427;
428; eLEAVE
429; Parameters:
430; Nothing
431; Returns:
432; BP: What it was before eENTER
433; Corrupts registers:
434; Nothing
435;--------------------------------------------------------------------
436%macro eLEAVE 0
437%ifndef USE_186
438 mov sp, bp
439 pop bp
440;-----------------------------------
441%else
442 leave
443%endif
444%endmacro
445
446
447;--------------------------------------------------------------------
448; Emulates LSS instruction when necessary.
449;
450; eLSS
451; Parameters:
452; %1: Destination register
453; %2: Source memory address without brackets
454; Returns:
455; IF: 0 (interrupts disabled)
456; Corrupts registers:
457; Nothing
458;--------------------------------------------------------------------
459%macro eLSS 2
460%ifndef USE_386
461 cli ; Disable interrupts
462 mov %1, [%2] ; Load offset
463 mov ss, [%2+2] ; Load segment
464;-----------------------------------
465%else
466 lss %1, [%2]
467%endif
468%endmacro
469
470
471;--------------------------------------------------------------------
472; Repeats string instruction with segment override.
473; This macro prevents 8088/8086 restart bug.
474;
475; eSEG_STR
476; Parameters:
477; %1: REP/REPNE or REPE prefix
478; %2: Source segment override (destination is always ES)
479; %3: String instruction
480; CX: Repeat count
481; Returns:
482; FLAGS for cmps and scas only
483; Corrupts registers:
484; Nothing
485;--------------------------------------------------------------------
486%macro eSEG_STR 3
487%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
[223]488 %%Loop:
489 %1 ; REP is the prefix that can be lost
490 %2 ; SEG is the prefix that won't be lost
491 %3 ; String instruction
492 jcxz %%End ; Jump to end if no repeats left (preserves FLAGS)
493 jmp SHORT %%Loop ; Loop while repeats left
494 %%End:
[41]495%else ; No bug on V20/V30 and later, don't know about 188/186
[223]496 %2
497 %1 %3
[41]498%endif
499%endmacro
500
501
502;--------------------------------------------------------------------
503; Bit shifts and rotates with immediate.
504;
505; eSHIFT_IM
506; Parameters:
507; %1: Shift target
508; %2: Number of bits to shift
509; %3: Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
510; Returns:
511; FLAGS
512; Corrupts registers:
513; Nothing
514;--------------------------------------------------------------------
515%macro eSHIFT_IM 3
[488]516%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
[41]517%ifndef USE_186
518 %ifidni %1, cl
519 times %2 %3 %1, 1
520 %elifidni %1, ch
521 times %2 %3 %1, 1
522 %elifidni %1, cx
523 times %2 %3 %1, 1
524 %else
[181]525 %if %2 > 3 ; Size optimized value
[41]526 push cx
527 mov cl, %2
528 %3 %1, cl
529 pop cx
530 %else
531 times %2 %3 %1, 1
532 %endif
533 %endif
534;-----------------------------------
535%else
536 %3 %1, %2
537%endif
[488]538%endif
[41]539%endmacro
[420]540
[41]541%macro eSHR_IM 2
542 eSHIFT_IM %1, %2, shr
543%endmacro
[445]544
[41]545%macro eSHL_IM 2
[489]546%ifndef CHECK_FOR_UNUSED_ENTRYPOINTS
[445]547%ifdef USE_386
548 %if %2 = 1
549 add %1, %1 ; Same size but faster on 386 and 486. Fails if %1 is a memory operand.
550 %else
551 eSHIFT_IM %1, %2, shl
552 %endif
553%else
[41]554 eSHIFT_IM %1, %2, shl
[445]555%endif
[489]556%endif
[41]557%endmacro
[445]558
[41]559%macro eROR_IM 2
560 eSHIFT_IM %1, %2, ror
561%endmacro
[445]562
[41]563%macro eROL_IM 2
564 eSHIFT_IM %1, %2, rol
565%endmacro
[445]566
[41]567%macro eRCR_IM 2
568 eSHIFT_IM %1, %2, rcr
569%endmacro
[445]570
[41]571%macro eRCL_IM 2
572 eSHIFT_IM %1, %2, rcl
573%endmacro
574
575
576;--------------------------------------------------------------------
577; Emulates PUSH imm instruction when necessary.
578;
579; ePUSH_I
580; Parameters:
581; %1: Immediate to push
582; Returns:
583; Nothing
584; Corrupts registers:
585; Nothing
586;--------------------------------------------------------------------
587%macro ePUSH_I 1
588%ifndef USE_186
589 push bp ; Immediate goes here
590 push bp
591 mov bp, sp
592 mov WORD [bp+2], %1
593 pop bp
594;-----------------------------------
595%else
596 push %1
597%endif
598%endmacro
599
600
601;--------------------------------------------------------------------
602; Emulates PUSH imm instruction when necessary.
603; ePUSH_T uses temporary register for faster performance
604; and smaller code size than ePUSH_I.
605;
606; ePUSH_T
607; Parameters:
608; %1: Temporary Register
609; %2: Immediate to push
610; Returns:
611; Nothing
612; Corrupts registers:
613; %1
614;--------------------------------------------------------------------
615%macro ePUSH_T 2
616%ifndef USE_186
617 %ifidni %2, 0
618 xor %1, %1
619 %else
620 mov %1, %2
621 %endif
622 push %1
623;-----------------------------------
624%else
625 push %2
626%endif
627%endmacro
628
629
630%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.