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

Last change on this file since 163 was 162, checked in by krille_n_@…, 13 years ago

Changes to all parts of the project:

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