Emulating the MMU and MBC Emulating the GPU Emulating the timer and keypad Putting the pieces together: Rust GameBoy emulator code walk Closing thoughts Surprise! Q&A 2
replica Basic structure of an emulator CPU, Memory, User input, Display and sound, etc. Emulation is hard Complex hardware design, many edge cases, runtime overhead, accuracy issues, lack of documentation, etc... 4
from memory Look up opcode Call opcode function Store cycles taken Interrupts: Check actions from outside the CPU Handle them to perform I/O, etc. (keypad, serial port, etc.) 8
// decrease current stack pointer to the current function self.registers.stack_pointer -= 2; // write address of the current instruction forward self.mmu.write_word( self.registers.stack_pointer, oldregs.program_counter + 2 ); // point the program counter to the current function self.registers.program_counter = self.read_word(); 6 // cycles taken to perform operation }, 9
{ let r = self.registers.a & b; self.registers.flag(Z, r == 0); self.registers.flag(H, true); self.registers.flag(C, false); self.registers.flag(N, false); self.registers.a = r; } Perform basic operations Store result in register 10
Read VRAM / OAM data Horizontal blank Move from end of line to start of next line Vertical blank Move from bottom right to top left Timed like the original hardware 18
BG & window Y position based on current line 2. For each X until the total width of the screen: 1. Set pixel data from this line 2. Set background priority based on color 3. Calculate color from raw graphic data 4. Fetch graphic data from VRAM 5. Calculate base addresses to read from VRAM 19
maximum objects stored in OAM 2. Check sprite is in the current line 3. Calculate position on the screen 4. Check object attributes: Y Flip (need to flip pixels) 5. Draw sprite pixels (8 pixels) 1. Check sprite pixel is still on screen 2. Check pixel priority (above or below) 3. Calculate color and save pixel to pixels Vector 20
Up, Down, Right, Left Read and written by the MMU When a key is pressed, an interrupt is triggered Push stack to save current position Point to interrupt handling position Opcode is fetched and interrupt handled Return to previous stack to continue execution 22
Normally it's ok with some degree of accuracy In more complex systems things get complicated! GameCube, Nintendo 64, etc. Many, many games-specific hacks Gigantic hardware design and no documentation makes for difficult emulation! 100% accuracy emulation is slow! Emulating 100% takes a lot of power SNES 100% accurate requires >3GHZ processor! 100% accuracy is accurate: no hacks required for specific games 26
"ñapas": what a surprise! Designing hardware and software are actually quite similar activities Hardware decisions are more tough: Once shipped, it's already there! Need to think thoroughly about the architecture Changes to hardware requires... people buying your new version! Hardware design is intrinsically more difficult: working with bits, basic operations, simple data structures to handle complex operations, etc. 27
that implement what you need Doesn't matter the language, focus on the architecture Understand every line! “ I like to totally understand every line of code I wrote - my method of understanding code is always the same and independent of language. Find an example program that works then reduce lines until I can reduce no more making a minimal example that works - then understand every line. - Joe Amstrong 28
Even simple hardware (like the GameBoy) reveal a vast and complex array of undocumented internal behavior. Simplicity Betrayed “ What is troublesome is the increased effort required by the host CPU to pull this off. The work involved is many times greater than before. [...] It is hard to believe that drawing a 30-year-old computer's display takes up so much of a modern system. This is one reason why accurate emulation takes so long to perfect. We can decide to make a better display, but today's platforms may not have the horsepower to accomplish it. 29
Solution: Extract boot loader bit by bit! Steps: Open GameBoy hardware and desolder Z80 chip Put the chip under a electron microscope Observe the wires and extract the data bit by bit 31