Devlog 11 - Input, Interrupts, and (semi-functional) Sprites
The next thing I added was joypad input. I had already set up a basic keyboard key checker with SDL events, so I had to connect it to the Gameboy. The joypad in the Gameboy writes to address 0xFF00. The Gameboy uses this as basically a 2x4 matrix. When bit 4 is set, the d-pad buttons are readable, and when bit 5 is set, the A, B, select, and start buttons are readable. I based my implementation of this off of jsGB again, which means I basically just made an array of 2 bytes; one representing the first row of the matrix, and another representing the second. Then when a button is pressed down, I set the corresponding bit to 0, and when it is released, set it back to 1. Then when the Gameboy tries to write to the register, I instead set a column variable, and when it tries to read it, I check the current column and return the correct row.
Then, I tried to implement some basic sprite rendering. You can see this in a few of the screenshots below, although my implementation is currently broken. It (should) work like the background renderer, only instead checking each of the 40 sprites in the OAM section of memory, and seeing if they are part of the current line. However currently, I forgot to implement one of the ways to copy sprite data to OAM, meaning that the rendering only actually works in some specific test ROMs, and not Tetris at the moment.
Then, I implemented some of the CPU interrupts, namely the VBLANK interrupt, which is the only one Tetris needs to boot. Interrupts have a register (0xFFFF) to enable each one individually, which each bit corresponding to an interrupt. Then, if an interrupt is enabled, when a source triggers it, the corresponding interrupt flag in 0xFF0F is set. On the next CPU step, it checks the interrupt flags, and if one is set, it then calls the specific interrupt handler for that interrupt. Currently, the only fully implemented one is the VBLANK interrupt, which is simply called when the PPU enters the VBLANK mode. This allows Tetris to boot.
Unfortunately, I spent a lot of the time in the devlog trying to actually get Tetris in game, as although after implementing interrupts, I could get through the menus, it just spat out a garbled screen when I actually tried to play the game or even watch the title screen demo. At first, I thought this was a rendering bug, so I spend a lot of time scrutinising the PPU code. I used the dmg-acid2 PPU test to try to troubleshoot this (you can see the current, still inaccurate result below), and although I did find out that my placeholder halt code was causing some issues, it didn’t manage to solve the problem. I found a reddit thread that seemed to have the same issue, and a frustratingly deleted comment that seemed to have a solution but obviously I couldn’t use that. However, I managed to find an archiving tool that showed me what the comment was; Tetris incorrectly writes to some area of the ROM, which causes a crash. All I had to do to fix this was block writes to the ROM area in memory, and it finally worked, although the sprites didn’t work as mentioned previously.
Next devlog, I want to fix sprite rendering, hopefully get the PPU more accurate, and implement some of the timer functions, as Tetris uses those to get random blocks, and without them, all the block are squares.
Comments 0
No comments yet. Be the first!
Sign in to join the conversation.