Page 1 of 1

Blarggs rom test - CPU:2 - Interrupts

Posted: Fri Sep 07, 2012 5:03 pm
by Profetylen
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:

Code: Select all

     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
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: Select all

wreg IF,$04
because, that's a manual triggering of the timer interrupt. This happens, and the interrupt code runs:

Code: Select all

.bank 0 slot 0
.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: Select all

     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
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: Select all

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
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: Select all

; 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
Hope someone can explain what's going on here! :)

Re: Blarggs rom test - CPU:2 - Interrupts

Posted: Sat Sep 08, 2012 9:09 am
by nitro2k01
It seems like you are right. I tried this in BGB and interrupts are disabled at the start of that test, as expected. (On second thought, though, this may not be to test the DI instructions as such, but to check interrupt can be disabled at all. The DI is just there so that individual test could be run independently and set up its own state.)
Shameless plug, btw, if you use IRC, feel free to join #gbdev on EFNet.

Re: Blarggs rom test - CPU:2 - Interrupts

Posted: Tue Sep 11, 2012 6:51 am
by Profetylen
The discussion was continued on the IRC. The conclusions that were made there were the following:

- As nitro2k01 stated in the his post above: The second test probably is just meant to test the behavior for when IME is cleared and the di instruction is just there to make sure the IME flag is cleared irregardless of what have happened earlier in the program.

- The third test works by reading the IF register rather than relying on an interrupt to occur. The IF register is written to irregardless of the IME flag when a timer interrupt occurs, so that it can work even if IME is cleared.

This led to my emulator passing the interrupt-test and by now it passes all of Blargg's cpu instruction tests. Hooray!!! :D

Many thanks to Nitro2k01 for helping me out with this on IRC! :D