So, I'm writing a Gameboy emulator and I'm currently trying to implement an accurate timer. I'm running Blargg's intstr_timing test and is getting "failed #255" because the timer fails to initialize. I was checking out what happens with the debugger of bgb (which by the way passes that test) and found out some strange behavior of the timer.
When the timer is being confiugred this code runs:
This sets up the timer to count at 0x40000 Hz, so since the gameboy clock counts at 0x400000 Hz this makes the timer count at 0x400000 / 0x40000 = 0x10 Hz, that is every 16 cycles, right?
If the above is correct, then I can't understand the behavior you get when you debug this with bgb. This is what happens:
When the timer is being confiugred this code runs:
Code:
ld a, 00
ld (FF00+06), a ; TMA
ld a, 05
ld (FF00+07), a ; TAC
ld a, 00
ld (FF00+0F), a ; int flag
ld a, EC
ld (FF00+05), a ; TIMA
push af
ld a, 29
ld (FF00+06), a ; TMA
ld a, 05
ld (FF00+07), a ; TAC
ld a, 00
ld (FF00+0F), a ; int flag
ld a, EC
ld (FF00+05), a ; TIMA
push af
ld a, 29
This sets up the timer to count at 0x40000 Hz, so since the gameboy clock counts at 0x400000 Hz this makes the timer count at 0x400000 / 0x40000 = 0x10 Hz, that is every 16 cycles, right?
If the above is correct, then I can't understand the behavior you get when you debug this with bgb. This is what happens:
Code:
; TIMA is 0 when the program gets here
ld a, 00
ld (FF00+06), a ; TMA
ld a, 05
ld (FF00+07), a ; TAC
; Here, the timer counts for the first time, since TIMA gets 1 here.
; Since the previous instruction (E0) takes 12 cycles and the timer
; overflowed, the new remainder of the timer should be either is 0, 4 or 8 cycles.
ld a, 00
; 3E (which executes in 8 cycles) were executed and TIMA were
; increased to 2, so the remainder must have been 8 in the previous
; instruction for this to happen and is now therefore 0.
ld (FF00+0F), a ; int flag
; TIMA didn't increase (as expected) and the remainder should
; therefore be 12, since another E0 was executed.
ld a, EC
; TIMA got 3 and another 3E was executed, so the remainder should
; now be 4 cycles.
ld (FF00+05), a ; TIMA
; TIMA is here overwritten and set to the a register, that is, EC. TIMA
; should first have turned 4 and then overwritten by to EC, so here
; the remainder should be 0, since another 12-cycle E0 was executed.
push af
; The previous instruction, F5, takes 16 cycles and TIMA was
; increased to ED, so the remainder should still be 0.
ld a, 29
; 3E was executed again, adding another 8 cycles which shouldn't
; increase TIMA since the remainder was just 0 and that only makes
; a total of 8 cycles. However, TIMA is now EE, and I wonder
; what the explanation for this is.
ld a, 00
ld (FF00+06), a ; TMA
ld a, 05
ld (FF00+07), a ; TAC
; Here, the timer counts for the first time, since TIMA gets 1 here.
; Since the previous instruction (E0) takes 12 cycles and the timer
; overflowed, the new remainder of the timer should be either is 0, 4 or 8 cycles.
ld a, 00
; 3E (which executes in 8 cycles) were executed and TIMA were
; increased to 2, so the remainder must have been 8 in the previous
; instruction for this to happen and is now therefore 0.
ld (FF00+0F), a ; int flag
; TIMA didn't increase (as expected) and the remainder should
; therefore be 12, since another E0 was executed.
ld a, EC
; TIMA got 3 and another 3E was executed, so the remainder should
; now be 4 cycles.
ld (FF00+05), a ; TIMA
; TIMA is here overwritten and set to the a register, that is, EC. TIMA
; should first have turned 4 and then overwritten by to EC, so here
; the remainder should be 0, since another 12-cycle E0 was executed.
push af
; The previous instruction, F5, takes 16 cycles and TIMA was
; increased to ED, so the remainder should still be 0.
ld a, 29
; 3E was executed again, adding another 8 cycles which shouldn't
; increase TIMA since the remainder was just 0 and that only makes
; a total of 8 cycles. However, TIMA is now EE, and I wonder
; what the explanation for this is.