中断0x15函数0x86(BIOS WAIT)在真实硬件上的运行速度远远低于虚拟机吗?

时间:2017-08-18 21:51:35

标签: assembly delay interrupt bootloader bios

我已经在汇编(游戏)中编写了一个bootloader。引导加载程序使用bios WAIT函数(int 0x15,ah 0x86)来处理帧之间的延迟。我用BOCHS进行调试,一切都很精彩(时机非常完美)。我还使用isogenimage工具制作了一个可引导的iso,并在virtualbox中测试了我的引导程序,一切都按预期工作。所以我认为延迟在虚拟环境中工作是安全的。

现在这里有一个特殊的部分:当我将引导加载程序写入USB驱动器并从中启动时,WAIT功能等待的时间比虚拟机上的时间长。我估计它的时间要长2-3倍。至少。帧之间的这种长时间延迟对于游戏来说是绝对不可接受的。

世界上有什么可能导致这种行为?我的有害生物钟可能以较慢的速度(> 18微秒)运行吗?但肯定会违反一些IBM标准?这对我来说是莫名其妙的。

顺便说一句,如果我删除WAIT中断,引导加载程序会按预期运行(对于我的目的而言太快),所以它不是我的实际代码运行缓慢。另外,我在最近的~2013笔记本电脑上运行,所以它不能因为性能低下而无法运行。

任何见解,谢谢!

编辑:我有想法在另一台物理计算机上进行测试,而且它也非常轻松!所以也许它不是一个"糟糕的bios" :)它在两台计算机上运行缓慢的几率非常低(我认为),所以这可能意味着......

CODE:

;MACRO CONSTANTS
%define p_width 10      ; player width
%define p_left_offset   20  ; space between left margin and player's left side
%define p_right_offset  290 ; space between right margin and player's right side; for linear player drawing purposes (xres - p_width - p_left_offset)
%define beak_width  5

%define xres    320     ; VGA resolution width
%define yres    200     ; VGA resolution height
%define buffer_addr 0x1000  ; start of offscrean buffer

[bits 16]
[org 0x7c00]

section .text
boot:
    jmp start
    times 3-($-$$) DB 0x90   ; Support 2 or 3 byte encoded JMPs before BPB.

        ; Dos 4.0 EBPB 1.44MB floppy
        OEMname:           db    "mkfs.fat"  ; mkfs.fat is what OEMname mkdosfs uses
        bytesPerSector:    dw    512
        sectPerCluster:    db    1
        reservedSectors:   dw    1
        numFAT:            db    2
        numRootDirEntries: dw    224
        numSectors:        dw    2880
        mediaType:         db    0xf0
    numFATsectors:     dw    9
        sectorsPerTrack:   dw    18
        numHeads:          dw    2
        numHiddenSectors:  dd    0
        numSectorsHuge:    dd    0
        driveNum:          db    0
        reserved:          db    0
        signature:         db    0x29
        volumeID:          dd    0x2d7e5a1a
        volumeLabel:       db    "NO NAME    "
        fileSysType:       db    "FAT12   "


start:
    mov ax, 0x13        ; VGA 16bit colors 320x200 mode
    int     0x10            ; call video update bios
    mov ax, 0xA000      ; Video memory startaddr
    mov es, ax          ; Real buffer video segment into segment register (for segment:offset format)
    mov ax, buffer_addr     ; temp storage of virtual buffer addr
    mov gs, ax          ; Virtual buffer segment stored in GS

    xor ax, ax
    mov ds, ax          ; zero offset to access vars defined in ;Data secition

   gameloop:
    call    clear_buffer        ; prepare to draw by clearing memory buffer
    call    draw_player     ; draw player to memory buffer
    call    switch_buffers      ; copy memory buffer to vram

    add     word [y_offset], 0x03   ; downward velocity, moves player around

   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ; HERE IS THE WAIT INTERRUPT THAT CAUSES THE PROBLEM ON REAL HARDWARE
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
   ; WAIT (sleep) for a little bit
    mov ah, 0x86        ; specify for int 0x15 WAIT interupt
    mov cx, 0x0006      ; high word of wait time 
    mov dx, 0xffff      ; low word of wait time 
    int     0x15            ; waits for cx:dx 1,000,000ths of a second
    jmp     gameloop    
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    hlt


; Draws the player square on screen, with y offset of y_offset
draw_player:
    xor     si, si          ; make sure si is 0; this will be pixel offset accumulatore
    xor bx, bx          ; this will be row counter; paintnig will stop if bl == p_width

    mov ax, xres        ; used to get space above player
    mul     word [y_offset]     ; result will be in dx:ax (high, low bytes)
    add si, ax          ; add top offset to pixel accumulator

   accum_p_offset:  
    inc bl          ; keep track of rows drawn.
    add si, p_left_offset   ; now offset is at starting point to paint
    mov cx, si          ; cx looks into the future
    add cx, p_width     ; cx will be the goal pixel

   draw_p_pixel:            ; draws the player pixels
    inc si          ; go to next pixel (compensate for 0-start)
    mov [gs:si], byte 0x0E  ; move white pixel to virtual memory at offset ax
    cmp si, cx          ; check if ax caught up with cx
    jne draw_p_pixel        ; if not, draw next player pixel

    ret


clear_buffer:  
    mov cx, 32000       ; number of times loop is performaned. 320 * 200 / 2 (because moving words)
    xor     si, si          ; clear si to make sure acumulator starts at first pixel
   zero_buf:
    mov     [gs:si], word 0x0101    ; set background to blue
    add si, 2           ; increment accumulator
    loop    zero_buf        ; jumps to zero_buf if cx is not equal to 0, then decrements cx

    ret


; copies contents from memory buffer to vram
switch_buffers:
    push    ds          ; save old data-segment (needed for getting the address of databytes later on)
    mov si, gs          ; use si as temp for gs (virtual memory segment)
    mov ds, si          ; move into datasegment the addr of virtual memory segment for movsw instruction

    xor si, si          ; clear accumulators for string operation
    xor di, di

    mov     cx, 32000       ; how many words to copy 320 * 200 / 2
    cld             ; copy direction
    rep     movsw           ; repeat copy from ds:si to es:di until cx is 0 (copies buffer from memory to vram)
    pop     ds          ; restores data segment to reference databytes properly after switch_buffers

    ret


;DATA
y_offset:
    dw  0x16

; FILLER
times 510 - ($-$$) db 0
dw 0xaa55

0 个答案:

没有答案