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

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

Changes to Assembly Library:
Removed Memory_ExchangeSSBPwithESDI since it obviously corrupted stack.
CGA detection is now only done once when initializing Display Context.
Moved File Library defines to File.inc.

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