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

Last change on this file since 60 was 60, checked in by aitotat, 13 years ago

Changes to Assembly Library:

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