source: xtideuniversalbios/trunk/XTIDE_Universal_BIOS/Inc/emulate.inc@ 15

Last change on this file since 15 was 3, checked in by Tomi Tilli, 15 years ago
File size: 11.1 KB
Line 
1; File name : emulate.inc
2; Project name : Emulation library
3; Created date : 21.10.2009
4; Last update : 4.4.2010
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; Moves byte with zero-extending to any Register.
141;
142; eMOVZX
143; Parameters:
144; %1: Destination Register (SP not supported)
145; %2: Byte register or byte address
146; Returns:
147; Nothing
148; Corrupts registers:
149; FLAGS
150;--------------------------------------------------------------------
151%macro eMOVZX 2
152%ifndef USE_386
153 %ifidni %1, ax
154 xor ax, ax
155 mov al, %2
156 %elifidni %1, bx
157 mov bl, %2
158 xor bh, bh ; %2 may use BX in effective address
159 %elifidni %1, cx
160 xor cx, cx
161 mov cl, %2
162 %elifidni %1, dx
163 xor dx, dx
164 mov dl, %2
165 %else ; SI, DI, BP (all may be used in effective address)
166 push ax
167 xor ax, ax
168 mov al, %2
169 xchg ax, %1
170 pop ax
171 %endif
172;-----------------------------------
173%else
174 movzx %1, %2
175%endif
176%endmacro
177
178
179;--------------------------------------------------------------------
180; Emulates PUSHA instruction when necessary.
181;
182; ePUSHA
183; Parameters:
184; Nothing
185; Returns:
186; Nothing
187; Corrupts registers:
188; Nothing
189;--------------------------------------------------------------------
190%macro ePUSHA 0
191%ifndef USE_186
192 push ax
193 push cx
194 push dx
195 push bx
196 ; SP before first push should be pushed here
197 push bp
198 push si
199 push di
200;-----------------------------------
201%else
202 pusha
203%endif
204%endmacro
205
206
207;--------------------------------------------------------------------
208; Emulates POPA instruction when necessary.
209;
210; ePOPA
211; Parameters:
212; Nothing
213; Returns:
214; Nothing
215; Corrupts registers:
216; Nothing
217;--------------------------------------------------------------------
218%macro ePOPA 0
219%ifndef USE_186
220 pop di
221 pop si
222 pop bp
223 ; Old SP should be skipped here
224 pop bx
225 pop dx
226 pop cx
227 pop ax
228;-----------------------------------
229%else
230 popa
231%endif
232%endmacro
233
234
235;--------------------------------------------------------------------
236; Emulates ENTER instruction when necessary.
237;
238; eENTER
239; Parameters:
240; %1: Number of bytes to reserve from stack
241; %2: The lexical nesting level (not emulated)
242; Returns:
243; SS:BP: Ptr to old BP
244; ([bp-2] points to highest local stack frame word)
245; Corrupts registers:
246; FLAGS
247;--------------------------------------------------------------------
248%macro eENTER 2
249%ifndef USE_186
250 push bp
251 mov bp, sp
252 sub sp, %1
253;-----------------------------------
254%else
255 enter %1, %2
256%endif
257%endmacro
258
259
260;--------------------------------------------------------------------
261; Emulates LEAVE instruction when necessary.
262;
263; eLEAVE
264; Parameters:
265; Nothing
266; Returns:
267; Nothing
268; Corrupts registers:
269; Nothing
270;--------------------------------------------------------------------
271%macro eLEAVE 0
272%ifndef USE_186
273 mov sp, bp
274 pop bp
275;-----------------------------------
276%else
277 leave
278%endif
279%endmacro
280
281
282;--------------------------------------------------------------------
283; Emulates LSS instruction when necessary.
284;
285; eLSS
286; Parameters:
287; %1: Destination register
288; %2: Source memory address without brackets
289; Returns:
290; IF: 0 (interrupts disabled)
291; Corrupts registers:
292; Nothing
293;--------------------------------------------------------------------
294%macro eLSS 2
295%ifndef USE_386
296 cli ; Disable interrupts
297 mov %1, [%2] ; Load offset
298 mov ss, [%2+2] ; Load segment
299;-----------------------------------
300%else
301 lss %1, [%2]
302%endif
303%endmacro
304
305
306;--------------------------------------------------------------------
307; Segment override prefix instruction.
308;
309; eSEG
310; Parameters:
311; %1: Name of the segment (ES, CS, SS, DS, FS or GS)
312; Returns:
313; Nothing
314; Corrupts registers:
315; Nothing
316;--------------------------------------------------------------------
317%macro eSEG 1
318 %ifidni %1, es
319 db 00100110b
320 %elifidni %1, cs
321 db 00101110b
322 %elifidni %1, ss
323 db 00110110b
324 %elifidni %1, ds
325 db 00111110b
326 %elifidni %1, fs
327 db 01100100b
328 %elifidni %1, gs
329 db 01100101b
330 %else
331 %error "Invalid segment overried passed to eSEG!"
332 %endif
333%endmacro
334
335
336;--------------------------------------------------------------------
337; Repeats string instruction with segment override.
338; This macro prevents 8088/8086 restart bug.
339;
340; eSEG_STR
341; Parameters:
342; %1: REP/REPNE or REPE prefix
343; %2: Source segment override (destination is always ES)
344; %3: String instruction
345; CX: Repeat count
346; Returns:
347; FLAGS for cmps and scas only
348; Corrupts registers:
349; Nothing
350;--------------------------------------------------------------------
351%macro eSEG_STR 3
352%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
353 %%Loop:
354 %1 ; REP is the prefix that can be lost
355 eSEG %2 ; SEG is the prefix that won't be lost
356 %3 ; String instruction
357 jcxz %%End ; Jump to end if no repeats left (preserves FLAGS)
358 jmp SHORT %%Loop ; Loop while repeats left
359 %%End:
360%else ; No bug on V20/V30 and later, don't know about 188/186
361 eSEG %2
362 %1 %3
363%endif
364%endmacro
365
366
367;--------------------------------------------------------------------
368; Bit shifts and rotates with immediate.
369;
370; eSHIFT_IM
371; Parameters:
372; %1: Shift target
373; %2: Number of bits to shift
374; %3: Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
375; Returns:
376; FLAGS
377; Corrupts registers:
378; Nothing
379;--------------------------------------------------------------------
380%macro eSHIFT_IM 3
381%ifndef USE_186
382 %ifidni %1, cl
383 times %2 %3 %1, 1
384 %elifidni %1, ch
385 times %2 %3 %1, 1
386 %elifidni %1, cx
387 times %2 %3 %1, 1
388 %else
389 %if %2 > 7
390 push cx
391 mov cl, %2
392 %3 %1, cl
393 pop cx
394 %else
395 times %2 %3 %1, 1
396 %endif
397 %endif
398;-----------------------------------
399%else
400 %3 %1, %2
401%endif
402%endmacro
403%macro eSHR_IM 2
404 eSHIFT_IM %1, %2, shr
405%endmacro
406%macro eSHL_IM 2
407 eSHIFT_IM %1, %2, shl
408%endmacro
409%macro eROR_IM 2
410 eSHIFT_IM %1, %2, ror
411%endmacro
412%macro eROL_IM 2
413 eSHIFT_IM %1, %2, rol
414%endmacro
415%macro eRCR_IM 2
416 eSHIFT_IM %1, %2, rcr
417%endmacro
418%macro eRCL_IM 2
419 eSHIFT_IM %1, %2, rcl
420%endmacro
421
422
423;--------------------------------------------------------------------
424; Emulates PUSH imm instruction when necessary.
425;
426; ePUSH_I
427; Parameters:
428; %1: Immediate to push
429; Returns:
430; Nothing
431; Corrupts registers:
432; Nothing
433;--------------------------------------------------------------------
434%macro ePUSH_I 1
435%ifndef USE_186
436 push bp ; Immediate goes here
437 push bp
438 mov bp, sp
439 mov WORD [bp+2], %1
440 pop bp
441;-----------------------------------
442%else
443 push %1
444%endif
445%endmacro
446
447
448;--------------------------------------------------------------------
449; Emulates PUSH imm instruction when necessary.
450; ePUSH_T uses temporary register for faster performance
451; and smaller code size than ePUSH_I.
452;
453; ePUSH_T
454; Parameters:
455; %1: Temporary Register
456; %2: Immediate to push
457; Returns:
458; Nothing
459; Corrupts registers:
460; %1
461;--------------------------------------------------------------------
462%macro ePUSH_T 2
463%ifndef USE_186
464 %ifidni %2, 0
465 xor %1, %1
466 %else
467 mov %1, %2
468 %endif
469 push %1
470;-----------------------------------
471%else
472 push %2
473%endif
474%endmacro
475
476
477%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.