I am writing a program on bare metal 16 bit real mode assembly with nasm. I want to sleep (pause execution) for x amount of milliseconds however I have not found a way to do this.
Edit: This is my code. I want to add about 0.3 seconds of delay between each character getting typed to the screen.
[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
CodePudding user response:
One day, I too needed a delay routine capable of doing delays ranging from 0.5 sec to just a few msec. Read all about it in this CodeReview question, and especially the reason why I needed to take this approach.
My solution was to find out how many iterations a delay routine can do in the interval between 2 ticks of the standard 18.2Hz timer. Those ticks are 55 msec apart. Because sometimes measurements can be erratic I only accepted the results if 2 consecutive measurements varied by less than 1%%. Finally I divided the good measurement by 55 to obtain the number of iterations per msec aka SpeedFactor. Hereafter, whenever I wanted to pause the program I multiplied the desired delay expressed in msec by this SpeedFactor and then performed that number of iterations within the delay routine.
The full code:
[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
The code assembles with FASM. For NASM, you will need to change code like
push ax bx dx
...
pop dx bx ax
into
push ax
push bx
push dx
...
pop dx
pop bx
pop ax