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

Last change on this file since 465 was 445, checked in by krille_n_@…, 12 years ago

Changes:

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