Sleeping certain amount of time in real mode

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
yasar11732
Member
Member
Posts: 28
Joined: Thu Sep 27, 2018 5:10 pm
Libera.chat IRC: yasar
Location: Turkey
Contact:

Sleeping certain amount of time in real mode

Post by yasar11732 »

Hi,

I am developing a simple snake game in real mode (for fun and educational purposes). I need to run main game loop periodically. I am using following code to set timer frequency to 1000hz.

Code: Select all

    # setup timer freq (once per milliseconds)
    mov $1193,%bx
    mov $0x36,%al
    out %al,$0x43
    mov %bl,%al
    out %al,$0x40
    mov %bh,%al
    out %al,$0x40
I am using this function to sleep certain amount of time.

Code: Select all

/* put milliseconds to sleep in %ax, %ax trashed */
sleep:
    push %bx
    mov timer_ticks,%bx
    add %bx,%ax
sleep0:
    mov timer_ticks,%bx
    cmp %bx,%ax
    jle sleep1
    hlt
    jmp sleep0
sleep1:
    pop %bx
    ret
I am testing this code using Virtualbox. sleep function seems to take more time than I intend. Am I doing everything properly here?

Complete code is accessible here: https://github.com/yasar11732/snakeos/b ... 54/snake.s

Edit:
My interrupt handler:

Code: Select all

irq_return:
    mov $0x20,%al
    out %al,$0x20
    popa
    iret

timer_handler:
    pusha
    incw timer_ticks
    jmp irq_return
Octocontrabass
Member
Member
Posts: 5586
Joined: Mon Mar 25, 2013 7:01 pm

Re: Sleeping certain amount of time in real mode

Post by Octocontrabass »

Virtual machines have trouble keeping time accurately. Does it also run at the wrong speed on bare metal?

If it runs at the correct speed on bare metal, you may need to reconfigure your virtual machine or use a different one.
User avatar
Brendan
Member
Member
Posts: 8561
Joined: Sat Jan 15, 2005 12:00 am
Location: At his keyboard!
Contact:

Re: Sleeping certain amount of time in real mode

Post by Brendan »

Hi,

I can't find a bug in the code that would explain the symptoms; but...
yasar11732 wrote:Am I doing everything properly here?
A signed 16-bit integer has a range from -32768 to +32768 (a total of 65536 values). If it's incremented 1000 times per second it'll overflow every 65536/1000 = 65.536 seconds.

Now let's see what happens when the "timer_ticks" contains +32767 and you call this code with "milliseconds to sleep = 10":

Code: Select all

/* put milliseconds to sleep in %ax, %ax trashed */
sleep:
    push %bx
    mov timer_ticks,%bx          ;bx = +32767
    add %bx,%ax                  ;ax = +32767 + 10 = -32759 due to overflow
sleep0:
    mov timer_ticks,%bx          ;bx = +32767 still
    cmp %bx,%ax
    jle sleep1                   ;if(-32759 <= +32767) exit the loop
    hlt
    jmp sleep0
sleep1:
    pop %bx
    ret
What this means is that sometimes it will return immediately with no delay at all.

Note: It's more common to use unsigned integers (e.g. "jbe sleep1"), but you'd have the same bug in that case (e.g. "65535 + 10 = 9 due to overflow").

To fix both of these, try something like:

Code: Select all

/* put milliseconds to sleep in %ax, %ax trashed */
sleep:
    push %cx
    push %bx
    mov timer_ticks,%cx          ;cx = starting tick
sleep0:
    mov timer_ticks,%bx          ;bx = current tick
    sub %cx,%bx                  ;bx = current tick - starting tick = time passed

    cmp %ax,%bx
    jae sleep1                   ;If time passed >= delay exit the loop
    hlt
    jmp sleep0
sleep1:
    pop %bx
    pop %cx
    ret
This code should be immune to overflows.

Also note that if you ask for a 1 ms delay immediately before the timer IRQ occurs you could delay for almost no time at all. Essentially the code waits for between (AX-1) and AX milliseconds (and doesn't wait for at least AX milliseconds). To fix that you can change the the branch to "ja sleep1".


Cheers,

Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Post Reply