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

Last change on this file since 587 was 586, checked in by Tomi Tilli, 10 years ago

Changes to Assembly Library:

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