I'm writing a gameboy emulator and is currently debugging it by running Blargg's GB rom tests.
In Blargg's GB rom tests for the CPU instructions, test number 2, the interrupts, this code is used to check EI:
Here the IME flag is turned on with help of the EI-instruction and an interrupt is expected to occur due to this line:
because, that's a manual triggering of the timer interrupt. This happens, and the interrupt code runs:
When the interrupt is triggered, the IME flag should be set to 0 according to the pandocs: http://nocash.emubase.de/pandocs.htm#interrupts. This IME is not enabled by the interrupt routine as RET is used instead of RETI (which would have re-enabled the IME flag upon returning from the interrupt routine). After this test, the next test, which tests the DI instruction is run:
The test seems to be designed for checking that the IME flag is disabled when executing the DI instruction. However, since I don't see anything enabling the IME flag after it was disabled in the previous test, nor does my emulator enable it, I would think this test has a bug in it and will always pass (unless, of course there are other bugs making it fail for some unrelated reason). Is that so or am I just missing something?
I actually think I am missing something is more likely because of the following in the next test:
Here it seems to be relayed on that a timer interrupt is generated at the right timing. That is during the second "delay 500" macro, so that it is the timer interrupt bit in IF is disabled. However, I don't see where the IME flag is turned on in this code again nor does my emulator turn it on. What's even more strange is the I'm running the debugger of bgb (which passes all the tests) and all of a sudden has IF set to 0xE4 from 0xE0 (I think the E part is a bug, but it shouldn't matter for this, I guess). I can't check the IME flag in the debugger because it only shows a dot (.), I guess that's a bug too.
For convenience I post the entire test code:
Hope someone can explain what's going on here!
In Blargg's GB rom tests for the CPU instructions, test number 2, the interrupts, this code is used to check EI:
Code:
set_test 2,"EI"
ei
ld bc,0
push bc
pop bc
inc b
wreg IF,$04
interrupt_addr:
dec b
jp nz,test_failed
ld hl,sp-2
ldi a,(hl)
cp <interrupt_addr
jp nz,test_failed
ld a,(hl)
cp >interrupt_addr
jp nz,test_failed
lda IF
and $04
jp nz,test_failed
ei
ld bc,0
push bc
pop bc
inc b
wreg IF,$04
interrupt_addr:
dec b
jp nz,test_failed
ld hl,sp-2
ldi a,(hl)
cp <interrupt_addr
jp nz,test_failed
ld a,(hl)
cp >interrupt_addr
jp nz,test_failed
lda IF
and $04
jp nz,test_failed
Here the IME flag is turned on with help of the EI-instruction and an interrupt is expected to occur due to this line:
Code:
wreg IF,$04
because, that's a manual triggering of the timer interrupt. This happens, and the interrupt code runs:
Code:
.bank 0 slot 0
.org $50
inc a
ret
.org $50
inc a
ret
When the interrupt is triggered, the IME flag should be set to 0 according to the pandocs: http://nocash.emubase.de/pandocs.htm#interrupts. This IME is not enabled by the interrupt routine as RET is used instead of RETI (which would have re-enabled the IME flag upon returning from the interrupt routine). After this test, the next test, which tests the DI instruction is run:
Code:
set_test 3,"DI"
di
ld bc,0
push bc
pop bc
wreg IF,$04
ld hl,sp-2
ldi a,(hl)
or (hl)
jp nz,test_failed
lda IF
and $04
jp z,test_failed
di
ld bc,0
push bc
pop bc
wreg IF,$04
ld hl,sp-2
ldi a,(hl)
or (hl)
jp nz,test_failed
lda IF
and $04
jp z,test_failed
The test seems to be designed for checking that the IME flag is disabled when executing the DI instruction. However, since I don't see anything enabling the IME flag after it was disabled in the previous test, nor does my emulator enable it, I would think this test has a bug in it and will always pass (unless, of course there are other bugs making it fail for some unrelated reason). Is that so or am I just missing something?
I actually think I am missing something is more likely because of the following in the next test:
Code:
set_test 4,"Timer doesn't work"
wreg TAC,$05
wreg TIMA,0
wreg IF,0
delay 500
lda IF
delay 500
and $04
jp nz,test_failed
delay 500
lda IF
and $04
jp z,test_failed
pop af
wreg TAC,$05
wreg TIMA,0
wreg IF,0
delay 500
lda IF
delay 500
and $04
jp nz,test_failed
delay 500
lda IF
and $04
jp z,test_failed
pop af
Here it seems to be relayed on that a timer interrupt is generated at the right timing. That is during the second "delay 500" macro, so that it is the timer interrupt bit in IF is disabled. However, I don't see where the IME flag is turned on in this code again nor does my emulator turn it on. What's even more strange is the I'm running the debugger of bgb (which passes all the tests) and all of a sudden has IF set to 0xE4 from 0xE0 (I think the E part is a bug, but it shouldn't matter for this, I guess). I can't check the IME flag in the debugger because it only shows a dot (.), I guess that's a bug too.
For convenience I post the entire test code:
Code:
; Tests DI, EI, and HALT (STOP proved untestable)
.include "shell.inc"
main:
wreg IE,$04
set_test 2,"EI"
ei
ld bc,0
push bc
pop bc
inc b
wreg IF,$04
interrupt_addr:
dec b
jp nz,test_failed
ld hl,sp-2
ldi a,(hl)
cp <interrupt_addr
jp nz,test_failed
ld a,(hl)
cp >interrupt_addr
jp nz,test_failed
lda IF
and $04
jp nz,test_failed
set_test 3,"DI"
di
ld bc,0
push bc
pop bc
wreg IF,$04
ld hl,sp-2
ldi a,(hl)
or (hl)
jp nz,test_failed
lda IF
and $04
jp z,test_failed
set_test 4,"Timer doesn't work"
wreg TAC,$05
wreg TIMA,0
wreg IF,0
delay 500
lda IF
delay 500
and $04
jp nz,test_failed
delay 500
lda IF
and $04
jp z,test_failed
pop af
set_test 5,"HALT"
wreg TAC,$05
wreg TIMA,0
wreg IF,0
halt ; timer interrupt will exit halt
nop ; avoids DMG bug
lda IF
and $04
jp z,test_failed
jp tests_passed
.bank 0 slot 0
.org $50
inc a
ret
.include "shell.inc"
main:
wreg IE,$04
set_test 2,"EI"
ei
ld bc,0
push bc
pop bc
inc b
wreg IF,$04
interrupt_addr:
dec b
jp nz,test_failed
ld hl,sp-2
ldi a,(hl)
cp <interrupt_addr
jp nz,test_failed
ld a,(hl)
cp >interrupt_addr
jp nz,test_failed
lda IF
and $04
jp nz,test_failed
set_test 3,"DI"
di
ld bc,0
push bc
pop bc
wreg IF,$04
ld hl,sp-2
ldi a,(hl)
or (hl)
jp nz,test_failed
lda IF
and $04
jp z,test_failed
set_test 4,"Timer doesn't work"
wreg TAC,$05
wreg TIMA,0
wreg IF,0
delay 500
lda IF
delay 500
and $04
jp nz,test_failed
delay 500
lda IF
and $04
jp z,test_failed
pop af
set_test 5,"HALT"
wreg TAC,$05
wreg TIMA,0
wreg IF,0
halt ; timer interrupt will exit halt
nop ; avoids DMG bug
lda IF
and $04
jp z,test_failed
jp tests_passed
.bank 0 slot 0
.org $50
inc a
ret
Hope someone can explain what's going on here!