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

Last change on this file since 530 was 510, checked in by aitotat@…, 12 years ago

Changes to Assembly Library:

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