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

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

Changes to Assembly Library:

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