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

Last change on this file since 88 was 64, checked in by Tomi Tilli, 14 years ago

Changes to Assembly Library:

  • Progress dialog now prevents max progress value from being zero.
File size: 12.5 KB
RevLine 
[41]1; File name : emulate.inc
2; Project name : Emulation library
3; Created date : 21.10.2009
[64]4; Last update : 30.11.2010
[41]5; Author : Tomi Tilli
6; Description : Macros for emulating later x86 instruction with older
7; processors.
8; Macros are used so optimized builds could be done
9; easily for different processors.
10;
11; This file must be first to be included to
12; any source file.
13%ifndef EMULATE_INC
14%define EMULATE_INC
15
16; Defines for processor support. Unsupported instructions will be
17; emulated using macros.
18; If using 286, define USE_186 and USE_286
19; If using 386, define USE_186, USE_286 and USE_386
20; If AT class PC is used (instead of XT), define USE_AT
21;%define USE_186 ; Define to use 18x/V20/V30 instructions
22;%define USE_286 ; Define to use 286 instructions
23;%define USE_386 ; Define to use 386 instructions
24;%define USE_AT ; Define for AT class machine
25; Above defines should be set on makefile!
26
27CPU 8086 ; Allow 8088/8086 instructions only
28%ifdef USE_186
29CPU 186 ; Allow instructions up to 188/186/V20/V30
30%elifdef USE_286
31CPU 286 ; Allow instructions up to 286
32%elifdef USE_386
33CPU 386 ; Allow instructions up to 386
34%endif
35BITS 16 ; Set 16 bit code generation
36
37; Alignments for jump targets.
38; Following values are optimal for different processor types:
39; 286 and 386SX WORD (16-bit, 2 bytes)
40; 386DX and 486 DWORD (32-bit, 4 bytes)
41; Pentium and later QWORD (64-bit, 8 bytes)
42%ifdef USE_AT
43 %ifdef USE_386
44 JUMP_ALIGN EQU 4
45 WORD_ALIGN EQU 2
46 %else ; USE_286
47 JUMP_ALIGN EQU 2
48 WORD_ALIGN EQU 2
49 %endif
50%else ; XT
51 JUMP_ALIGN EQU 1
52 WORD_ALIGN EQU 1
53%endif
54
55;==========================================================================
56
57;--------------------------------------------------------------------
58; Emulates BSF (Bit Scan Forward) instruction when necessary.
59; BSF is used to find index of least significant bit.
60;
61; eBSF
62; Parameters:
63; %1: Destination WORD Register for bit index (not CX or same as %2!)
64; %2: Source WORD operand where to search bit (not CX or same as %1!)
65; Returns:
66; %1: Index of highest order bit from %2
67; ZF: Set if %2 is zero
68; Cleared if %2 is non-zero
69; Corrupts registers:
70; Nothing
71;--------------------------------------------------------------------
72%macro eBSF 2
73%ifndef USE_386
74 push cx
75 cmp WORD %2, BYTE 0 ; Source operand is zero?
76 je SHORT %%Return ; If so, return with ZF set
77
78 ; Set destination to zero and load mask for bit 0
79 xor %1, %1
80 mov cx, 1
81
82ALIGN JUMP_ALIGN
83%%BitLoop:
84 test %2, cx ; Bit set?
85 jnz SHORT %%Return ; If so, return with ZF cleared
86 shl cx, 1 ; Prepare to test next bit
87 inc %1 ; Increment bit index
88 jmp SHORT %%BitLoop ; Loop until bit found
89%%Return:
90 pop cx
91;-----------------------------------
92%else
93 bsf %1, %2
94%endif
95%endmacro
96
97
98;--------------------------------------------------------------------
99; Emulates BSR (Bit Scan Reverse) instruction when necessary.
100; BSR is used to find index of most significant bit.
101;
102; eBSR
103; Parameters:
104; %1: Destination WORD Register for bit index (not CX or same as %2!)
105; %2: Source WORD operand where to search bit (not CX or same as %1!)
106; Returns:
107; %1: Index of highest order bit from %2
108; ZF: Set if %2 is zero
109; Cleared if %2 is non-zero
110; Corrupts registers:
111; Nothing
112;--------------------------------------------------------------------
113%macro eBSR 2
114%ifndef USE_386
115 push cx
116 cmp WORD %2, BYTE 0 ; Source operand is zero?
117 je SHORT %%Return ; If so, return with ZF set
118
119 ; Load mask for highest order bit
120 mov cx, 1<<15
121 mov %1, 15
122
123ALIGN JUMP_ALIGN
124%%BitLoop:
125 test %2, cx ; Bit set?
126 jnz SHORT %%Return ; If so, return with ZF cleared
127 shr cx, 1 ; Prepare to test next bit
128 dec %1 ; Decrement bit index
129 jmp SHORT %%BitLoop ; Loop until bit found
130%%Return:
131 pop cx
132;-----------------------------------
133%else
134 bsr %1, %2
135%endif
136%endmacro
137
138
139;--------------------------------------------------------------------
140; Conditional Move.
141;
142; eCMOVcc
143; Parameters:
144; %1: Destination data
145; %2: Source data
146; Returns:
147; Nothing
148; Corrupts registers:
149; Nothing
150;--------------------------------------------------------------------
151%macro eCMOVC 2
152 jnc SHORT %%Return
153 mov %1, %2
154%%Return:
155%endmacro
156
[64]157%macro eCMOVZ 2
158 jnz SHORT %%Return
159 mov %1, %2
160%%Return:
161%endmacro
162
[41]163%macro eCMOVE 2
164 jne SHORT %%Return
165 mov %1, %2
166%%Return:
167%endmacro
168
[60]169%macro eCMOVB 2
170 jnb SHORT %%Return
171 mov %1, %2
172%%Return:
173%endmacro
[41]174
175
[60]176
[41]177;--------------------------------------------------------------------
178; Moves byte with zero-extending to any Register.
179;
180; eMOVZX
181; Parameters:
182; %1: Destination Register (SP not supported)
183; %2: Byte register or byte address
184; Returns:
185; Nothing
186; Corrupts registers:
187; FLAGS
188;--------------------------------------------------------------------
189%macro eMOVZX 2
190%ifndef USE_386
191 %ifidni %1, ax
192 mov al, %2
193 xor ah, ah
194 %elifidni %1, bx
195 mov bl, %2
196 xor bh, bh ; %2 may use BX in effective address
197 %elifidni %1, cx
198 mov cl, %2
199 xor ch, ch
200 %elifidni %1, dx
201 mov dl, %2
202 xor dh, dh
203 %else ; SI, DI, BP (all may be used in effective address)
204 push ax
205 mov al, %2
206 xor ah, ah
207 xchg ax, %1
208 pop ax
209 %endif
210;-----------------------------------
211%else
212 movzx %1, %2
213%endif
214%endmacro
215
216
217;--------------------------------------------------------------------
218; Emulates PUSHA instruction when necessary.
219;
220; ePUSHA
221; Parameters:
222; Nothing
223; Returns:
224; Nothing
225; Corrupts registers:
226; Nothing
227;--------------------------------------------------------------------
228%macro ePUSHA 0
229%ifndef USE_186
230 push ax
231 push cx
232 push dx
233 push bx
234 ; SP before first push should be pushed here
235 push bp
236 push si
237 push di
238;-----------------------------------
239%else
240 pusha
241%endif
242%endmacro
243
244
245;--------------------------------------------------------------------
246; Emulates POPA instruction when necessary.
247;
248; ePOPA
249; Parameters:
250; Nothing
251; Returns:
252; Nothing
253; Corrupts registers:
254; Nothing
255;--------------------------------------------------------------------
256%macro ePOPA 0
257%ifndef USE_186
258 pop di
259 pop si
260 pop bp
261 ; Old SP should be skipped here
262 pop bx
263 pop dx
264 pop cx
265 pop ax
266;-----------------------------------
267%else
268 popa
269%endif
270%endmacro
271
272
273;--------------------------------------------------------------------
274; Emulates ENTER instruction when necessary.
275;
276; eENTER
277; Parameters:
278; %1: Number of bytes to reserve from stack
279; %2: The lexical nesting level (not emulated, set to 0)
280; Returns:
281; SS:BP: Ptr to old BP
282; ([bp-2] points to highest local stack frame word)
283; Corrupts registers:
284; FLAGS
285;--------------------------------------------------------------------
286%macro eENTER 2
287%ifndef USE_186
288 push bp
289 mov bp, sp
290 sub sp, %1
291;-----------------------------------
292%else
293 enter %1, %2
294%endif
295%endmacro
296
297;--------------------------------------------------------------------
298; Emulates LEAVE instruction when necessary.
299;
300; eLEAVE
301; Parameters:
302; Nothing
303; Returns:
304; BP: What it was before eENTER
305; Corrupts registers:
306; Nothing
307;--------------------------------------------------------------------
308%macro eLEAVE 0
309%ifndef USE_186
310 mov sp, bp
311 pop bp
312;-----------------------------------
313%else
314 leave
315%endif
316%endmacro
317
318
319;--------------------------------------------------------------------
320; eENTER_STRUCT
321; Parameters:
322; %1: Number of bytes to reserve from stack
323; Returns:
324; SS:BP: Ptr to beginning of struct reserved from stack
325; Corrupts registers:
326; FLAGS
327;--------------------------------------------------------------------
328%macro eENTER_STRUCT 1
329 push bp
330 sub sp, %1
331 mov bp, sp
332%endmacro
333
334;--------------------------------------------------------------------
335; eLEAVE_STRUCT
336; Parameters:
337; %1: Number of bytes reserved with eENTER_STRUCT
338; Returns:
339; BP: What it was before eENTER_STRUCT
340; Corrupts registers:
341; FLAGS
342;--------------------------------------------------------------------
343%macro eLEAVE_STRUCT 1
344 add sp, %1
345 pop bp
346%endmacro
347
348
349;--------------------------------------------------------------------
350; Emulates LSS instruction when necessary.
351;
352; eLSS
353; Parameters:
354; %1: Destination register
355; %2: Source memory address without brackets
356; Returns:
357; IF: 0 (interrupts disabled)
358; Corrupts registers:
359; Nothing
360;--------------------------------------------------------------------
361%macro eLSS 2
362%ifndef USE_386
363 cli ; Disable interrupts
364 mov %1, [%2] ; Load offset
365 mov ss, [%2+2] ; Load segment
366;-----------------------------------
367%else
368 lss %1, [%2]
369%endif
370%endmacro
371
372
373;--------------------------------------------------------------------
374; Segment override prefix instruction.
375;
376; eSEG
377; Parameters:
378; %1: Name of the segment (ES, CS, SS, DS, FS or GS)
379; Returns:
380; Nothing
381; Corrupts registers:
382; Nothing
383;--------------------------------------------------------------------
384%macro eSEG 1
385 %ifidni %1, es
386 db 00100110b
387 %elifidni %1, cs
388 db 00101110b
389 %elifidni %1, ss
390 db 00110110b
391 %elifidni %1, ds
392 db 00111110b
393 %elifidni %1, fs
394 db 01100100b
395 %elifidni %1, gs
396 db 01100101b
397 %else
398 %error "Invalid segment overried passed to eSEG!"
399 %endif
400%endmacro
401
402
403;--------------------------------------------------------------------
404; Repeats string instruction with segment override.
405; This macro prevents 8088/8086 restart bug.
406;
407; eSEG_STR
408; Parameters:
409; %1: REP/REPNE or REPE prefix
410; %2: Source segment override (destination is always ES)
411; %3: String instruction
412; CX: Repeat count
413; Returns:
414; FLAGS for cmps and scas only
415; Corrupts registers:
416; Nothing
417;--------------------------------------------------------------------
418%macro eSEG_STR 3
419%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
420 %%Loop:
421 %1 ; REP is the prefix that can be lost
422 eSEG %2 ; SEG is the prefix that won't be lost
423 %3 ; String instruction
424 jcxz %%End ; Jump to end if no repeats left (preserves FLAGS)
425 jmp SHORT %%Loop ; Loop while repeats left
426 %%End:
427%else ; No bug on V20/V30 and later, don't know about 188/186
428 eSEG %2
429 %1 %3
430%endif
431%endmacro
432
433
434;--------------------------------------------------------------------
435; Bit shifts and rotates with immediate.
436;
437; eSHIFT_IM
438; Parameters:
439; %1: Shift target
440; %2: Number of bits to shift
441; %3: Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
442; Returns:
443; FLAGS
444; Corrupts registers:
445; Nothing
446;--------------------------------------------------------------------
447%macro eSHIFT_IM 3
448%ifndef USE_186
449 %ifidni %1, cl
450 times %2 %3 %1, 1
451 %elifidni %1, ch
452 times %2 %3 %1, 1
453 %elifidni %1, cx
454 times %2 %3 %1, 1
455 %else
456 %if %2 > 7
457 push cx
458 mov cl, %2
459 %3 %1, cl
460 pop cx
461 %else
462 times %2 %3 %1, 1
463 %endif
464 %endif
465;-----------------------------------
466%else
467 %3 %1, %2
468%endif
469%endmacro
470%macro eSHR_IM 2
471 eSHIFT_IM %1, %2, shr
472%endmacro
473%macro eSHL_IM 2
474 eSHIFT_IM %1, %2, shl
475%endmacro
476%macro eROR_IM 2
477 eSHIFT_IM %1, %2, ror
478%endmacro
479%macro eROL_IM 2
480 eSHIFT_IM %1, %2, rol
481%endmacro
482%macro eRCR_IM 2
483 eSHIFT_IM %1, %2, rcr
484%endmacro
485%macro eRCL_IM 2
486 eSHIFT_IM %1, %2, rcl
487%endmacro
488
489
490;--------------------------------------------------------------------
491; Emulates PUSH imm instruction when necessary.
492;
493; ePUSH_I
494; Parameters:
495; %1: Immediate to push
496; Returns:
497; Nothing
498; Corrupts registers:
499; Nothing
500;--------------------------------------------------------------------
501%macro ePUSH_I 1
502%ifndef USE_186
503 push bp ; Immediate goes here
504 push bp
505 mov bp, sp
506 mov WORD [bp+2], %1
507 pop bp
508;-----------------------------------
509%else
510 push %1
511%endif
512%endmacro
513
514
515;--------------------------------------------------------------------
516; Emulates PUSH imm instruction when necessary.
517; ePUSH_T uses temporary register for faster performance
518; and smaller code size than ePUSH_I.
519;
520; ePUSH_T
521; Parameters:
522; %1: Temporary Register
523; %2: Immediate to push
524; Returns:
525; Nothing
526; Corrupts registers:
527; %1
528;--------------------------------------------------------------------
529%macro ePUSH_T 2
530%ifndef USE_186
531 %ifidni %2, 0
532 xor %1, %1
533 %else
534 mov %1, %2
535 %endif
536 push %1
537;-----------------------------------
538%else
539 push %2
540%endif
541%endmacro
542
543
544%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.