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

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

Changes to Assembly Library:

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