在 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
我正在使用 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