Page 1 of 1
Can you spot the error???
Posted: Fri Feb 19, 2010 9:45 am
by DLBuunk
Can you spot the error I made in my timer code? It took me two days to find it.
Code: Select all
IRQ0:
push ax
mov byte [.flag],01h
mov al,20h
out 20h,al
pop ax
iret
.flag: db 00h
timer: ;cx is number of 18.2 Hz ticks to wait
hlt
cmp byte [IRQ0.flag],01h
jne timer
mov byte [IRQ0.flag],01h
dec cx
cmp cx,00h
jne timer
ret
When I test it with the following code it appears to work fine:
Code: Select all
timertest: ;print 1 '!' per second to the screen (infinite loop)
mov cx,12h
call timer
mov ax,0E21h
int 10h
jmp timertest
Re: Can you spot the error???
Posted: Fri Feb 19, 2010 11:18 am
by Gigasoft
Well, you're setting IRQ0.flag to 1, which it already is, instead of some other value. You also ought to know that the DEC instruction updates ZF, and that the LOOP instruction performs the same function as DEC CX / JNZ.
Re: Can you spot the error???
Posted: Fri Feb 19, 2010 5:39 pm
by Combuster
Four seconds. Memory operand with undefined segment register contents. (line 3)
Re: Can you spot the error???
Posted: Sat Feb 20, 2010 12:07 am
by bitshifter
A more elegant way...
Code: Select all
IRQ0:
inc [.ticks]
iret
.ticks dw 0
timer: ; cx = number of ticks to wait...
push cx
add cx,[IRQ0.ticks]
.wait:
cmp [IRQ0.ticks],cx
jl .wait
call print
pop cx
ret
Re: Can you spot the error???
Posted: Sat Feb 20, 2010 4:04 am
by Brendan
Hi,
Combuster wrote:Four seconds. Memory operand with undefined segment register contents. (line 3)
That may be intentional. I do my OS like that - data segment registers treated as constants, with some tricky "general protection fault" handler code to reset them if some idiot changes them (and no hope or desire to support Virtual8086). Segment register loads are slow...
bitshifter wrote:A more elegant way...
A more buggy way (you forgot to send the EOI to the PIC, there's "roll over" bugs, and you don't HLT to save power).
Cheers,
Brendan
Re: Can you spot the error???
Posted: Sat Feb 20, 2010 6:02 am
by Owen
Isn't DS going to change every time you enter user space anyway? Or is your OS x86_64 only? (I can't ascertain with the OP's but I'd guess not)
Particularly on i386 I'd be wary about using wrong segment registers since any API I'd define for x86 would have LDT support (Some things require the ability to create their own segments - an example is WINE)
Re: Can you spot the error???
Posted: Sat Feb 20, 2010 6:14 am
by Combuster
Brendan wrote:Hi,
Combuster wrote:Four seconds. Memory operand with undefined segment register contents. (line 3)
That may be intentional. I do my OS like that - data segment registers treated as constants, with some tricky "general protection fault" handler code to reset them if some idiot changes them (and no hope or desire to support Virtual8086). Segment register loads are slow...
Given the use of 16-bits registers throughout, including as arguments to an interrupt call within the intel-reserved range (another potential bug), I assumed it was written for real mode.
And who said the bug was not a GPF?
Re: Can you spot the error???
Posted: Sat Feb 20, 2010 6:34 am
by Owen
Combuster wrote:Brendan wrote:Hi,
Combuster wrote:Four seconds. Memory operand with undefined segment register contents. (line 3)
That may be intentional. I do my OS like that - data segment registers treated as constants, with some tricky "general protection fault" handler code to reset them if some idiot changes them (and no hope or desire to support Virtual8086). Segment register loads are slow...
Given the use of 16-bits registers throughout, including as arguments to an interrupt call within the intel-reserved range (another potential bug), I assumed it was written for real mode.
And who said the bug was not a GPF?
It could be 16-bit protected mode...
(Yeah, right...)
Re: Can you spot the error???
Posted: Sat Feb 20, 2010 11:53 am
by Gigasoft
bitshifter wrote:A more elegant way...
This has the same lack of CS: override as above, and it also introduces 3 new problems. It doesn't perform an EOI, it doesn't conserve energy, and it has an integer overflow problem. Here's a more correct version that waits for an exact number of 18.2ths of a second:
Code: Select all
IRQ0:
push ax
mov byte [cs:.flag],01h
mov al,20h
out 20h,al
pop ax
iret
.flag: db 00h
timer: ;cx is number of 18.2 Hz ticks to wait
mov al,34h ; Reset timer
out 43h,al
mov al,0
out 40h,al
out 40h,al
.tmr2:
mov [IRQ0.flag],0
.tmr1:
hlt
cmp byte [IRQ0.flag],0
jz .tmr1
loop .tmr2
ret