在 16 位裸机 nasm 程序集中休眠 x 毫秒

Sleep for x milliseconds in 16 bit bare metal nasm assembly

我正在使用 nasm 在裸机 16 位实模式汇编上编写程序。我想休眠(暂停执行)x 毫秒,但是我还没有找到执行此操作的方法。

编辑:这是我的代码。我想在屏幕上输入每个字符之间增加大约 0.3 秒的延迟。

[bits 16]    ; use 16 bits
[org 0x7c00] ; sets the start address

init: 
  mov si, msg  ; loads the address of "msg" into SI register
  mov ah, 0x0e ; sets AH to 0xe (function teletype)
print_char:
  lodsb     ; loads the current byte from SI into AL and increments the address in SI
  cmp al, 0 ; compares AL to zero
  je done   ; if AL == 0, jump to "done"
  int 0x10  ; print to screen using function 0xe of interrupt 0x10
  jmp print_char ; repeat with next byte
done:
  hlt ; stop execution

msg: db "The quick brown fox jumps over the lazy dog.", 0 ; we need to explicitely put the zero byte here

times 510-($-$$) db 0           ; fill the output file with zeroes until 510 bytes are full
dw 0xaa55                       ; magic number that tells the BIOS this is bootable

有一天,我也需要一个延迟例程,能够进行从 0.5 秒到 几毫秒 的延迟。在 this CodeReview question 中阅读所有相关内容,尤其是我需要采用这种方法的原因。

我的解决方案是找出延迟例程在标准 18.2Hz 计时器的 2 个滴答之间的间隔内可以进行多少次迭代。这些滴答声相隔 55 毫秒。因为有时测量值可能会不稳定,所以我只接受连续 2 次测量值变化小于 1%% 的结果。最后,我将良好的测量值除以 55 以获得每毫秒的迭代次数,也称为 SpeedFactor。此后,每当我想暂停程序时,我都会将以毫秒表示的所需延迟乘以此 SpeedFactor,然后在延迟例程中执行该迭代次数

完整代码:

[bits 16]
[org 0x7C00]

                xor     ax, ax
                mov     ds, ax
                mov     es, ax
                mov     ss, ax
                mov     sp, 0x7C00
                cld

; Measure the number of iterations (within the ShortWait routine) per msec
; Only accept if consecutive measurements vary by less than 1%%
; If measurements remain erratic than do accept the last one
                mov     bp, 10                  ; Max try
                call    GetSpeedFactor          ; -> DX:AX
.a:             xchg    si, ax                  ; 'mov si, ax'
                mov     di, dx
                call    GetSpeedFactor          ; -> DX:AX
                push    ax dx                   ; (1)
.b:             sub     ax, si
                sbb     dx, di
                jnb     .c
                add     ax, si
                adc     dx, di
                xchg    si, ax
                xchg    di, dx
                jmp     .b
.c:             mov     cx, 1000
                xchg    ax, cx
                mul     dx
                xchg    ax, cx
                mov     dx, 1000
                mul     dx
                add     dx, cx
                sub     si, ax
                sbb     di, dx
                pop     dx ax                   ;(1)
                cmc
                dec     bp
                jnbe    .a
                mov     [SpeedFactor], ax
                mov     [SpeedFactor+2], dx

                mov     si, msg
                lodsb
More:           mov     bx, 0x0007              ; BH DisplayPage 0, BL GraphicsColor 7
                mov     ah, 0x0E                ; BIOS.Teletype
                int     10h
                mov     bx, 300                 ; 0.3 sec 
                call    Pause
                lodsb
                cmp     al, 0
                jne     More

                cli
                hlt
                jmps    $-2

msg             db      "The quick brown fox jumps over the lazy dog.", 0
SpeedFactor     dd      0
; ----------------------------------------------
; IN () OUT (dx:ax)
; Wait for the start of a new TimerTick period (54.9254 msec)
; Then measure a 4 tick period (219.7016 msec)
GetSpeedFactor: push    bx cx
                mov     bx, 1
                call    .ShortWait              ; -> DX:AX BX=0
                mov     bl, 4                   ; BH=0
                call    .ShortWait              ; -> DX:AX BX=0
                mov     cx, 10
                xchg    ax, cx
                mul     dx
                xchg    ax, cx
                mov     dx, 10
                mul     dx
                add     dx, cx
                mov     cx, 2197
                xchg    ax, bx                  ; BX=0
                xchg    dx, ax
                div     cx
                xchg    ax, bx
                div     cx
                mov     dx, bx
                pop     cx bx
                ret
; - - - - - - - - - - - - - - - - - - - - - - -
.ShortWait:     mov     ax, -1
                cwd
; ---   ---   ---   ---   ---   ---   ---   ---
; IN (dx:ax,bx) OUT (dx:ax,bx)
; Do DX:AX iterations or loop until Timer did BX Ticks
ShortWait:      push    ds cx si di
                xchg    si, ax                  ; 'mov si, ax'
                mov     di, dx
                xor     ax, ax
                cwd
                mov     ds, ax
.a:             mov     cx, [046Ch]             ; BIOS Timer
.b:             sub     si, 1
                sbb     di, 0
                jb      .c
                add     ax, 1
                adc     dx, 0
                cmp     cx, [046Ch]
                je      .b
                dec     bx
                jnz     .a
.c:             pop     di si cx ds
                ret
; ----------------------------------------------
; IN (bx) OUT ()
Pause:          push    ax bx dx
                mov     ax, [SpeedFactor+2]
                mul     bx
                xchg    bx, ax
                mul     word [SpeedFactor]
                add     dx, bx
                mov     bx, -1
                call    ShortWait               ; -> DX:AX BX
                pop     dx bx ax
                ret
; ----------------------------------------------

times 510-($-$$) db 0
dw 0xAA55   

代码用FASM汇编。对于 NASM,您需要更改代码,如

push ax bx dx
...
pop  dx bx ax

进入

push ax
push bx
push dx
...
pop  dx
pop  bx
pop  ax