Home > Blockchain >  Sleep for x milliseconds in 16 bit bare metal nasm assembly
Sleep for x milliseconds in 16 bit bare metal nasm assembly

Time:10-16

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
  • Related