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

Last change on this file since 41 was 41, checked in by aitotat, 14 years ago

Initial commit for Assembly Library.

File size: 12.5 KB
Line 
1; File name     :   emulate.inc
2; Project name  :   Emulation library
3; Created date  :   21.10.2009
4; Last update   :   29.7.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    ;eENTER %1, 0
321    ;sub        bp, %1          ; SS:BP now points to struct
322%endmacro
323
324;--------------------------------------------------------------------
325; eLEAVE_STRUCT
326;   Parameters:
327;       %1:     Number of bytes reserved with eENTER_STRUCT
328;   Returns:
329;       BP:     What it was before eENTER_STRUCT
330;   Corrupts registers:
331;       FLAGS
332;--------------------------------------------------------------------
333%macro eLEAVE_STRUCT 1
334    add     sp, %1
335    pop     bp
336    ;add        bp, %1          ; Restore BP to what it was after eENTER
337    ;eLEAVE
338%endmacro
339
340
341;--------------------------------------------------------------------
342; Emulates LSS instruction when necessary.
343;
344; eLSS
345;   Parameters:
346;       %1:     Destination register
347;       %2:     Source memory address without brackets
348;   Returns:
349;       IF:     0 (interrupts disabled)
350;   Corrupts registers:
351;       Nothing
352;--------------------------------------------------------------------
353%macro eLSS 2
354%ifndef USE_386
355    cli                         ; Disable interrupts
356    mov     %1, [%2]            ; Load offset
357    mov     ss, [%2+2]          ; Load segment
358;-----------------------------------
359%else
360    lss     %1, [%2]
361%endif
362%endmacro
363
364
365;--------------------------------------------------------------------
366; Segment override prefix instruction.
367;
368; eSEG
369;   Parameters:
370;       %1:     Name of the segment (ES, CS, SS, DS, FS or GS)
371;   Returns:
372;       Nothing
373;   Corrupts registers:
374;       Nothing
375;--------------------------------------------------------------------
376%macro eSEG 1
377    %ifidni %1, es
378        db  00100110b
379    %elifidni %1, cs
380        db  00101110b
381    %elifidni %1, ss
382        db  00110110b
383    %elifidni %1, ds
384        db  00111110b
385    %elifidni %1, fs
386        db  01100100b
387    %elifidni %1, gs
388        db  01100101b
389    %else
390        %error "Invalid segment overried passed to eSEG!"
391    %endif
392%endmacro
393
394
395;--------------------------------------------------------------------
396; Repeats string instruction with segment override.
397; This macro prevents 8088/8086 restart bug.
398;
399; eSEG_STR
400;   Parameters:
401;       %1:     REP/REPNE or REPE prefix
402;       %2:     Source segment override (destination is always ES)
403;       %3:     String instruction
404;       CX:     Repeat count
405;   Returns:
406;       FLAGS for cmps and scas only
407;   Corrupts registers:
408;       Nothing
409;--------------------------------------------------------------------
410%macro eSEG_STR 3
411%ifndef USE_186 ; 8088/8086 has string instruction restart bug when more than one prefix
412     %%Loop:
413        %1                      ; REP is the prefix that can be lost
414        eSEG    %2              ; SEG is the prefix that won't be lost
415        %3                      ; String instruction
416        jcxz    %%End           ; Jump to end if no repeats left (preserves FLAGS)
417        jmp     SHORT %%Loop    ; Loop while repeats left
418     %%End:
419%else   ; No bug on V20/V30 and later, don't know about 188/186
420    eSEG    %2
421    %1      %3
422%endif
423%endmacro
424
425
426;--------------------------------------------------------------------
427; Bit shifts and rotates with immediate.
428;
429; eSHIFT_IM
430;   Parameters:
431;       %1:     Shift target
432;       %2:     Number of bits to shift
433;       %3:     Instruction (SHL, SHR, ROL, ROR, RCL, RCR)
434;   Returns:
435;       FLAGS
436;   Corrupts registers:
437;       Nothing
438;--------------------------------------------------------------------
439%macro eSHIFT_IM 3
440%ifndef USE_186
441    %ifidni %1, cl
442        times %2    %3      %1, 1
443    %elifidni %1, ch
444        times %2    %3      %1, 1
445    %elifidni %1, cx
446        times %2    %3      %1, 1
447    %else
448        %if %2 > 7
449            push    cx
450            mov     cl, %2
451            %3      %1, cl
452            pop     cx
453        %else
454            times %2    %3      %1, 1
455        %endif
456    %endif
457;-----------------------------------
458%else
459    %3      %1, %2
460%endif
461%endmacro
462%macro eSHR_IM 2
463    eSHIFT_IM   %1, %2, shr
464%endmacro
465%macro eSHL_IM 2
466    eSHIFT_IM   %1, %2, shl
467%endmacro
468%macro eROR_IM 2
469    eSHIFT_IM   %1, %2, ror
470%endmacro
471%macro eROL_IM 2
472    eSHIFT_IM   %1, %2, rol
473%endmacro
474%macro eRCR_IM 2
475    eSHIFT_IM   %1, %2, rcr
476%endmacro
477%macro eRCL_IM 2
478    eSHIFT_IM   %1, %2, rcl
479%endmacro
480
481
482;--------------------------------------------------------------------
483; Emulates PUSH imm instruction when necessary.
484;
485; ePUSH_I
486;   Parameters:
487;       %1:     Immediate to push
488;   Returns:
489;       Nothing
490;   Corrupts registers:
491;       Nothing
492;--------------------------------------------------------------------
493%macro ePUSH_I 1
494%ifndef USE_186
495    push    bp                  ; Immediate goes here
496    push    bp
497    mov     bp, sp
498    mov     WORD [bp+2], %1
499    pop     bp
500;-----------------------------------
501%else
502    push    %1
503%endif
504%endmacro
505
506
507;--------------------------------------------------------------------
508; Emulates PUSH imm instruction when necessary.
509; ePUSH_T uses temporary register for faster performance
510; and smaller code size than ePUSH_I.
511;
512; ePUSH_T
513;   Parameters:
514;       %1:     Temporary Register
515;       %2:     Immediate to push
516;   Returns:
517;       Nothing
518;   Corrupts registers:
519;       %1
520;--------------------------------------------------------------------
521%macro ePUSH_T 2
522%ifndef USE_186
523    %ifidni %2, 0
524        xor     %1, %1
525    %else
526        mov     %1, %2
527    %endif
528    push    %1
529;-----------------------------------
530%else
531    push    %2
532%endif
533%endmacro
534
535
536%endif ; EMULATE_INC
Note: See TracBrowser for help on using the repository browser.