### Install and Start DMG-01 JS Emulator Source: https://github.com/rylev/dmg-01/blob/master/dmg-01-js/README.md Installs project dependencies and starts the development server for the DMG-01 JS emulator. ```bash npm install npm run start ``` -------------------------------- ### Bitwise AND with Hexadecimal Example Source: https://github.com/rylev/dmg-01/blob/master/book/src/appendix/bit_manipulation.md Demonstrates the bitwise AND operation using hexadecimal numbers. It's recommended to convert to binary for clarity. ```text 0x8 1000 & 0x3 0011 ------ ---- 0x0 0000 ``` -------------------------------- ### Bitwise OR Example (Binary) Source: https://github.com/rylev/dmg-01/blob/master/public/book/appendix/bit_manipulation.html Demonstrates the bitwise OR operation on two 4-bit binary numbers. ```plaintext 1001 | 1100 ``` -------------------------------- ### Bitwise OR Example Source: https://github.com/rylev/dmg-01/blob/master/public/book/print.html Illustrates the bitwise OR operation on two binary numbers. This can be used to combine binary values or ensure specific bits are set. ```Binary 1001 | 1100 ------ 1101 ``` -------------------------------- ### Bitwise AND Example Source: https://github.com/rylev/dmg-01/blob/master/public/book/print.html Demonstrates the bitwise AND operation on two binary numbers. This operation is useful for bit masking to extract specific bits or bytes. ```Binary 1001 & 1100 ------ 1000 ``` -------------------------------- ### Bitwise AND Operation Example Source: https://github.com/rylev/dmg-01/blob/master/book/src/appendix/bit_manipulation.md Illustrates the bitwise AND operation between two binary numbers. This operation results in a 1 only if both corresponding bits are 1. ```text 1001 & 1100 ------ 1000 ``` -------------------------------- ### Hexadecimal Bitwise AND Example Source: https://github.com/rylev/dmg-01/blob/master/public/book/print.html Shows how to perform bitwise AND on hexadecimal numbers by converting them to binary first. Useful for understanding bitwise operations on hex values. ```Hexadecimal 0x8 1000 & 0x3 0011 ------ ---- 0x0 0000 ``` -------------------------------- ### Handling Prefix Instructions (0xCB) Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/executing_instructions.md Initializes logic to detect and handle prefix instructions starting with the 0xCB byte, which indicates a subsequent instruction byte should be interpreted differently. ```rust # enum IncDecTarget { BC } # enum PrefixTarget { B } # enum Instruction { INC(IncDecTarget), RLC(PrefixTarget) } # struct CPU { pc: u16, bus: Bus } # struct Bus {} # impl Bus { fn read_byte(&self, a: u16) -> u8 { 0 } } ``` -------------------------------- ### Bitwise OR Operation Example Source: https://github.com/rylev/dmg-01/blob/master/book/src/appendix/bit_manipulation.md Illustrates the bitwise OR operation between two binary numbers. This operation results in a 1 if at least one of the corresponding bits is 1. ```text 1001 | 1100 ------ 1101 ``` -------------------------------- ### Bitwise Left Shift Example Source: https://github.com/rylev/dmg-01/blob/master/book/src/appendix/bit_manipulation.md Demonstrates the effect of left shifting a binary number by different positions. Bits shifted off the left are discarded, and zeros are introduced on the right. ```text 1101 << 1 == 1010 1101 << 2 == 0100 1101 << 3 == 1000 1101 << 4 == 0000 ``` -------------------------------- ### Bitwise Right Shift Example Source: https://github.com/rylev/dmg-01/blob/master/book/src/appendix/bit_manipulation.md Shows the effect of right shifting a binary number by different positions. Bits shifted off the right are discarded, and zeros are introduced on the left. ```text 1001 >> 1 == 0100 1001 >> 2 == 0010 1001 >> 3 == 0001 1001 >> 4 == 0000 ``` -------------------------------- ### Bitwise OR Example Source: https://github.com/rylev/dmg-01/blob/master/public/book/appendix/bit_manipulation.html Bitwise OR can be used to combine two binary values. For instance, to ensure the least significant bit is set to 1, OR the value with 0b1. ```plaintext 1101 ``` -------------------------------- ### Tile Pixel Encoding Example Source: https://github.com/rylev/dmg-01/blob/master/book/src/graphics/tile_ram.md Illustrates how two bytes of tile data encode the first row of an 8x8 pixel tile. The first byte holds the most significant bit for each pixel, and the second byte holds the least significant bit. ```ignore Bit Position A 7 6 5 4 3 2 1 0 d +-----------------+ d 0x8000 | 1 0 1 1 0 1 0 1 | r |-----------------| e 0x8001 | 0 1 1 0 0 1 0 1 | s +-----------------+ D L W D B W B W Color ``` -------------------------------- ### Implement 16-bit BC Register Access Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/registers.md Provides methods to get and set the 16-bit 'bc' register by combining the 'b' and 'c' 8-bit registers. This involves bit manipulation using bitwise shift, AND, and OR operators. ```rust # struct Registers { a: u8, b: u8, c: u8, d: u8, e: u8, f: u8, h: u8, l: u8, } impl Registers { fn get_bc(&self) -> u16 { (self.b as u16) << 8 | self.c as u16 } fn set_bc(&mut self, value: u16) { self.b = ((value & 0xFF00) >> 8) as u8; self.c = (value & 0xFF) as u8; } } ``` -------------------------------- ### Execute Method Returning Next Program Counter Source: https://github.com/rylev/dmg-01/blob/master/public/book/cpu/executing_instructions.html Modifies the `execute` method of the CPU to return the next program counter value after executing an instruction. This example shows handling the ADD instruction with target C. ```rust # #![allow(unused_variables)] #fn main() { # struct Registers { a:u8, c: u8 } # struct CPU { pc: u16, registers: Registers } # enum Instruction { ADD(ArithmeticTarget), } # enum ArithmeticTarget { A, B, C, D, E, H, L, } impl CPU { fn execute(&mut self, instruction: Instruction) -> u16 { match instruction { Instruction::ADD(target) => { match target { ArithmeticTarget::C => { let value = self.registers.c; let new_value = self.add(value); self.registers.a = new_value; self.pc.wrapping_add(1) } _ => { /* TODO: support more targets */ self.pc } } } _ => { /* TODO: support more instructions */ self.pc } } } # fn add(&self, value: u8) -> u8 { # 0 # } } #} ``` -------------------------------- ### Initialize Theme and Sidebar Settings Source: https://github.com/rylev/dmg-01/blob/master/public/book/appendix/index.html This script initializes theme and sidebar visibility based on local storage settings. It ensures proper display by setting body and html classes. ```javascript var path_to_root = "../"; try { var theme = localStorage.getItem('mdbook-theme'); var sidebar = localStorage.getItem('mdbook-sidebar'); if (theme.startsWith('"') && theme.endsWith('"')) { localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); } if (sidebar.startsWith('"') && sidebar.endsWith('"')) { localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); } } catch (e) { } var theme; try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } if (theme === null || theme === undefined) { theme = 'light'; } document.body.className = theme; document.querySelector('html').className = theme + ' js'; var html = document.querySelector('html'); var sidebar = 'hidden'; if (document.body.clientWidth >= 1080) { try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } sidebar = sidebar || 'visible'; } html.classList.remove('sidebar-visible'); html.classList.add("sidebar-" + sidebar); ``` -------------------------------- ### Initialize Theme and Sidebar Source: https://github.com/rylev/dmg-01/blob/master/public/book/index.html This script initializes the theme and sidebar visibility based on local storage settings. It ensures proper theme application and sidebar state persistence. ```javascript var path_to_root = ""; try { var theme = localStorage.getItem('mdbook-theme'); var sidebar = localStorage.getItem('mdbook-sidebar'); if (theme.startsWith('"') && theme.endsWith('"')) { localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); } if (sidebar.startsWith('"') && sidebar.endsWith('"')) { localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); } } catch (e) { } var theme; try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } if (theme === null || theme === undefined) { theme = 'light'; } document.body.className = theme; document.querySelector('html').className = theme + ' js'; var html = document.querySelector('html'); var sidebar = 'hidden'; if (document.body.clientWidth >= 1080) { try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } sidebar = sidebar || 'visible'; } html.classList.remove('sidebar-visible'); html.classList.add("sidebar-" + sidebar); ``` -------------------------------- ### Run DMG-01 Emulator Source: https://github.com/rylev/dmg-01/blob/master/dmg-01/README.md Command to run the emulator with specified boot ROM and game ROM paths. Ensure the environment variables BOOT_ROM and GAME_ROM are set. ```bash cargo run -- -b $BOOT_ROM -r $GAME_ROM ``` -------------------------------- ### Theme and Sidebar Initialization Source: https://github.com/rylev/dmg-01/blob/master/public/book/appendix/cartridge_header.html Initializes theme and sidebar visibility based on localStorage settings. Handles potential string quoting issues. ```javascript var path_to_root = "../"; try { var theme = localStorage.getItem('mdbook-theme'); var sidebar = localStorage.getItem('mdbook-sidebar'); if (theme.startsWith('"') && theme.endsWith('"')) { localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1)); } if (sidebar.startsWith('"') && sidebar.endsWith('"')) { localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1)); } } catch (e) { } var theme; try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { } if (theme === null || theme === undefined) { theme = 'light'; } document.body.className = theme; document.querySelector('html').className = theme + ' js'; var html = document.querySelector('html'); var sidebar = 'hidden'; if (document.body.clientWidth >= 1080) { try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { } sidebar = sidebar || 'visible'; } html.classList.remove('sidebar-visible'); html.classList.add("sidebar-" + sidebar); ``` -------------------------------- ### Create a New Rust Project with Cargo Source: https://github.com/rylev/dmg-01/blob/master/book/src/introduction.md Use Cargo, Rust's build tool and package manager, to create a new project directory for your emulator. This command initializes the project structure. ```bash cargo new emulator ``` -------------------------------- ### Advance System State by Cycles Source: https://github.com/rylev/dmg-01/blob/master/book/src/graphics/rendering_basics.md Implement a step function on the MemoryBus to advance subsystems, like the GPU, by a specified number of CPU cycles. This function will be expanded to include other subsystems later. ```rust impl MemoryBus { fn step(&mut self, cycles: u8) { self.gpu.step(cycles); } } ``` -------------------------------- ### Get BC Register Value Source: https://github.com/rylev/dmg-01/blob/master/public/book/cpu/registers.html Combines the `b` and `c` registers into a single `u16` value. The `b` register is shifted left by 8 bits to occupy the most significant byte. ```rust fn get_bc(&self) -> u16 { (self.b as u16) << 8 | self.c as u16 } ``` -------------------------------- ### Run a Rust Project with Cargo Source: https://github.com/rylev/dmg-01/blob/master/book/src/introduction.md Execute your Rust project using Cargo. This command compiles and runs the main executable of your project. ```bash cargo run ``` -------------------------------- ### GPU Struct Definition in Rust Source: https://github.com/rylev/dmg-01/blob/master/book/src/graphics/tile_ram.md Defines a basic `GPU` struct in Rust to manage graphics-related data, including video RAM and tile set information. This serves as a starting point for Game Boy graphics emulation. ```rust struct GPU { video_ram: Vec, tile_set: Vec, } struct Tile { rows: [TileRow; 8], } struct TileRow { pixels: [TileValue; 8], } enum TileValue { Black, DarkGray, LightGray, White, } ``` -------------------------------- ### CPU Instruction Stepping Logic Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/executing_instructions.md Implements the `step` method for the CPU, which fetches an instruction byte using the program counter, translates it into an Instruction enum, executes it, and updates the program counter to the next instruction's address. Panics if an unknown instruction byte is encountered. ```rust # enum Instruction { } # struct CPU { pc: u16, bus: Bus } # struct Bus {} # impl Bus { # fn read_byte(&self, a: u16) -> u8 { 0 } # } # impl CPU { # fn execute(&self, i: Instruction) -> u16 { 0 } # } # impl Instruction { # fn from_byte(b: u8) -> Option { None } # } impl CPU { fn step(&mut self) { let mut instruction_byte = self.bus.read_byte(self.pc); let next_pc = if let Some(instruction) = Instruction::from_byte(instruction_byte) { self.execute(instruction) } else { panic!("Unkown instruction found for: 0x{:x}", instruction_byte); }; self.pc = next_pc; } } ``` -------------------------------- ### CPU execute method with ADD instruction pattern matching Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/register_data_instructions.md Implements the execute method on the CPU to handle different instructions. This snippet shows the pattern matching for the ADD instruction and its target. ```Rust # struct CPU {} # enum Instruction { ADD(ArithmeticTarget), } # enum ArithmeticTarget { A, B, C, D, E, H, L, } impl CPU { fn execute(&mut self, instruction: Instruction) { match instruction { Instruction::ADD(target) => { match target { ArithmeticTarget::C => { // TODO: implement ADD on register C } _ => { /* TODO: support more targets */ } } } _ => { /* TODO: support more instructions */ } } } } ``` -------------------------------- ### Handle Prefix CB Instructions in CPU Step Source: https://github.com/rylev/dmg-01/blob/master/public/book/print.html Adds logic to the CPU's step method to detect and handle prefix instructions. If a 0xCB byte is read, it reads a second byte to determine the actual prefix instruction. ```rust # #![allow(unused_variables)] #fn main() { # enum IncDecTarget { BC } # enum PrefixTarget { B } # enum Instruction { INC(IncDecTarget), RLC(PrefixTarget) } # struct CPU { pc: u16, bus: Bus } # struct Bus {} # impl Bus { fn read_byte(&self, a: u16) -> u8 { 0 } } # impl CPU { fn execute(&self, i: Instruction) -> u16 { 0 } } impl CPU { fn step(&mut self) { let mut instruction_byte = self.bus.read_byte(self.pc); let prefixed = instruction_byte == 0xCB; if prefixed { instruction_byte = self.bus.read_byte(self.pc + 1); } let next_pc = if let Some(instruction) = Instruction::from_byte(instruction_byte, prefixed) { self.execute(instruction) } else { ``` -------------------------------- ### CPU Step Execution Logic Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/executing_instructions.md Implements the main CPU step function, which reads the program counter, decodes instructions (handling prefixed instructions), executes them, and updates the program counter. ```rust impl CPU { fn step(&mut self) { let mut instruction_byte = self.bus.read_byte(self.pc); let prefixed = instruction_byte == 0xCB; if prefixed { instruction_byte = self.bus.read_byte(self.pc + 1); } let next_pc = if let Some(instruction) = Instruction::from_byte(instruction_byte, prefixed) { self.execute(instruction) } else { let description = format!("0x{}{:x}", if prefixed { "cb" } else { "" }, instruction_byte); panic!("Unkown instruction found for: {}", description) }; self.pc = next_pc; } } ``` -------------------------------- ### Tile RAM Constants and Structures Source: https://github.com/rylev/dmg-01/blob/master/book/src/graphics/tile_ram.md Defines constants for VRAM boundaries and size, an enum for pixel values, a type alias for a Tile, a function to create an empty tile, and the GPU struct holding VRAM and the tile set. ```rust const VRAM_BEGIN: usize = 0x8000; const VRAM_END: usize = 0x9FFF; const VRAM_SIZE: usize = VRAM_END - VRAM_BEGIN + 1; #[derive(Copy,Clone)] enum TilePixelValue { Zero, One, Two, Three, } type Tile = [[TilePixelValue; 8]; 8]; fn empty_tile() -> Tile { [[TilePixelValue::Zero; 8]; 8] } struct GPU{ vram: [u8; VRAM_SIZE], tile_set: [Tile; 384], } ``` -------------------------------- ### Executing ADD Instruction Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/executing_instructions.md Implements the execution of the ADD instruction, specifically for the 'C' target, updating the accumulator and program counter. ```rust # struct Registers { a:u8, c: u8 } # struct CPU { pc: u16, registers: Registers } # enum Instruction { ADD(ArithmeticTarget) } # enum ArithmeticTarget { A, B, C, D, E, H, L } impl CPU { fn execute(&mut self, instruction: Instruction) -> u16 { match instruction { Instruction::ADD(target) => { match target { ArithmeticTarget::C => { let value = self.registers.c; let new_value = self.add(value); self.registers.a = new_value; self.pc.wrapping_add(1) } _ => { /* TODO: support more targets */ self.pc } } } _ => { /* TODO: support more instructions */ self.pc } } } # fn add(&self, value: u8) -> u8 { # 0 # } } ``` -------------------------------- ### CPU Structure for Instruction Execution Source: https://github.com/rylev/dmg-01/blob/master/public/book/cpu/executing_instructions.html Defines the basic structure of a CPU, including registers, program counter (pc), and a memory bus. This is foundational for understanding instruction fetching. ```rust # #![allow(unused_variables)] #fn main() { # struct Registers {} struct CPU { registers: Registers, pc: u16, bus: MemoryBus, } struct MemoryBus { memory: [u8; 0xFFFF] } impl MemoryBus { fn read_byte(&self, address: u16) -> u8 { self.memory[address as usize] } } #} ``` -------------------------------- ### Implement PUSH Instruction Source: https://github.com/rylev/dmg-01/blob/master/public/book/cpu/reading_and_writing_memory.html Implements the PUSH instruction for the CPU, which pushes a 16-bit value onto the stack. It decrements the stack pointer twice and writes the most and least significant bytes of the value to memory. ```rust # #![allow(unused_variables)] #fn main() { # struct Registers { } # impl Registers { fn get_bc(&self) -> u16 { 0 } } # struct CPU { pc: u16, bus: Bus, sp: u16, registers: Registers } # struct Bus {} # impl Bus { fn write_byte(&self, addr: u16, value: u8) { } } # enum Instruction { PUSH(StackTarget), } # enum StackTarget { BC, DE } impl CPU { fn execute(&mut self, instruction: Instruction) -> u16 { match instruction { Instruction::PUSH(target) => { let value = match target { StackTarget::BC => self.registers.get_bc(), _ => { panic!("TODO: support more targets") } }; self.push(value); self.pc.wrapping_add(1) } _ => { panic!("TODO: support more instructions") } } } fn push(&mut self, value: u16) { self.sp = self.sp.wrapping_sub(1); self.bus.write_byte(self.sp, ((value & 0xFF00) >> 8) as u8); self.sp = self.sp.wrapping_sub(1); self.bus.write_byte(self.sp, (value & 0xFF) as u8); } } #} ``` -------------------------------- ### CPU Instruction Execution Logic Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/executing_instructions.md Handles the execution of different CPU instructions, specifically the JP (jump) instruction with various jump conditions. ```rust impl CPU { fn execute(&mut self, instruction: Instruction) -> u16 { match instruction { Instruction::JP(test) => { let jump_condition = match test { JumpTest::NotZero => !self.registers.f.zero, JumpTest::NotCarry => !self.registers.f.carry, JumpTest::Zero => self.registers.f.zero, JumpTest::Carry => self.registers.f.carry, JumpTest::Always => true }; self.jump(jump_condition) } _ => { /* TODO: support more instructions */ self.pc } } } ``` -------------------------------- ### CPU with Program Counter and Addressable Memory Source: https://github.com/rylev/dmg-01/blob/master/public/book/cpu/executing_instructions.html This code defines a basic CPU structure including a program counter and memory that can be addressed by the CPU. This is a foundational step for instruction execution. ```rust struct CPU { pc: u16, // Program Counter memory: [u8; 0xFFFF], // 65,536 bytes of memory // ... other registers } impl CPU { fn new() -> Self { CPU { pc: 0, memory: [0; 0xFFFF], // ... initialize other registers } } // ... methods for instruction fetching and execution } ``` -------------------------------- ### CPU CALL and RET Instruction Implementation Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/reading_and_writing_memory.md Implements the CALL and RET instructions for the CPU, enabling function calls and returns. The CALL instruction pushes the next program counter onto the stack and jumps to a new address, while RET pops an address from the stack and jumps back. ```rust # struct FlagsRegister { zero: bool } # struct Registers { f: FlagsRegister } # struct CPU { pc: u16, registers: Registers } # enum Instruction { CALL(JumpTest), RET(JumpTest)} # enum JumpTest { NotZero } # impl CPU { # fn read_next_word(&self) -> u16 { 0 } # fn push(&self, value: u16) { } # fn pop(&self) -> u16 { 0 } } impl CPU { fn execute(&mut self, instruction: Instruction) -> u16 { match instruction { Instruction::CALL(test) => { let jump_condition = match test { JumpTest::NotZero => !self.registers.f.zero, _ => { panic!("TODO: support more conditions") } }; self.call(jump_condition) } Instruction::RET(test) => { let jump_condition = match test { JumpTest::NotZero => !self.registers.f.zero, _ => { panic!("TODO: support more conditions") } }; self.return_(jump_condition) } _ => { panic!("TODO: support more instructions") } } } fn call(&mut self, should_jump: bool) -> u16 { let next_pc = self.pc.wrapping_add(3); if should_jump { self.push(next_pc); self.read_next_word() } else { next_pc } } fn return_(&mut self, should_jump: bool) -> u16 { if should_jump { self.pop() } else { self.pc.wrapping_add(1) } } } ``` -------------------------------- ### CPU Instruction Execution with Jump Logic Source: https://github.com/rylev/dmg-01/blob/master/public/book/cpu/executing_instructions.html Implements the execution of a JP (Jump) instruction, evaluating jump conditions based on CPU flags and determining the next program counter value. Handles both jumping and not jumping scenarios, accounting for the instruction's byte width. ```rust # struct FlagsRegister { zero: bool, carry: bool } # struct Registers { f: FlagsRegister } # struct CPU { registers: Registers, bus: Bus, pc: u16 } # struct Bus {} # impl Bus { fn read_byte(&self, addr: u16) -> u8 { 0 } } enum JumpTest { NotZero, Zero, NotCarry, Carry, Always } enum Instruction { JP(JumpTest), } impl CPU { fn execute(&mut self, instruction: Instruction) -> u16 { match instruction { Instruction::JP(test) => { let jump_condition = match test { JumpTest::NotZero => !self.registers.f.zero, JumpTest::NotCarry => !self.registers.f.carry, JumpTest::Zero => self.registers.f.zero, JumpTest::Carry => self.registers.f.carry, JumpTest::Always => true }; self.jump(jump_condition) } _ => { /* TODO: support more instructions */ self.pc } } } fn jump(&self, should_jump: bool) -> u16 { if should_jump { // Gameboy is little endian so read pc + 2 as most significant bit // and pc + 1 as least significant bit let least_significant_byte = self.bus.read_byte(self.pc + 1) as u16; let most_significant_byte = self.bus.read_byte(self.pc + 2) as u16; (most_significant_byte << 8) | least_significant_byte } else { // If we don't jump we need to still move the program // counter forward by 3 since the jump instruction is // 3 bytes wide (1 byte for tag and 2 bytes for jump address) self.pc.wrapping_add(3) } } } ``` -------------------------------- ### Implement Addition with Flag Setting Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/register_data_instructions.md This Rust code implements an addition operation for the CPU, calculating the new value and updating the Zero, Subtract, Carry, and Half Carry flags based on the operation's result. The Half Carry flag is specifically checked by adding the lower nibbles of the operands and comparing the sum to 0xF. ```rust # struct FlagsRegister { zero: bool, subtract: bool, half_carry: bool, carry: bool } # struct Registers { a: u8, f: FlagsRegister } # struct CPU { registers: Registers } impl CPU { fn add(&mut self, value: u8) -> u8 { let (new_value, did_overflow) = self.registers.a.overflowing_add(value); self.registers.f.zero = new_value == 0; self.registers.f.subtract = false; self.registers.f.carry = did_overflow; // Half Carry is set if adding the lower nibbles of the value and register A // together result in a value bigger than 0xF. If the result is larger than 0xF // than the addition caused a carry from the lower nibble to the upper nibble. self.registers.f.half_carry = (self.registers.a & 0xF) + (value & 0xF) > 0xF; new_value } } ``` -------------------------------- ### Implementing PUSH Operation Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/reading_and_writing_memory.md Implements the PUSH instruction for the Game Boy CPU, which writes a 16-bit value from a register to the stack. The stack pointer is decremented twice, and the most and least significant bytes are written to memory. ```rust # struct Registers { } # impl Registers { fn get_bc(&self) -> u16 { 0 } } # struct CPU { pc: u16, bus: Bus, sp: u16, registers: Registers } # struct Bus {} # impl Bus { fn write_byte(&self, addr: u16, value: u8) { } } # enum Instruction { PUSH(StackTarget), } # enum StackTarget { BC, DE } impl CPU { fn execute(&mut self, instruction: Instruction) -> u16 { match instruction { Instruction::PUSH(target) => { let value = match target { StackTarget::BC => self.registers.get_bc(), _ => { panic!("TODO: support more targets") } }; self.push(value); self.pc.wrapping_add(1) } _ => { panic!("TODO: support more instructions") } } } fn push(&mut self, value: u16) { self.sp = self.sp.wrapping_sub(1); self.bus.write_byte(self.sp, ((value & 0xFF00) >> 8) as u8); self.sp = self.sp.wrapping_sub(1); self.bus.write_byte(self.sp, (value & 0xFF) as u8); } } ``` -------------------------------- ### GPU read_vram Implementation Source: https://github.com/rylev/dmg-01/blob/master/book/src/graphics/tile_ram.md A simple implementation of `read_vram` that directly reads from the GPU's internal VRAM buffer. ```rust # struct GPU { vram: Vec } impl GPU { fn read_vram(&self, address: usize) -> u8 { self.vram[address] } } ``` -------------------------------- ### CPU Structure with Stack Pointer Source: https://github.com/rylev/dmg-01/blob/master/book/src/cpu/reading_and_writing_memory.md Defines the basic structure of the CPU, including the stack pointer (sp) register, which is essential for stack operations. ```rust # struct Registers {} # struct MemoryBus {} struct CPU { registers: Registers, pc: u16, sp: u16, bus: MemoryBus, } ``` -------------------------------- ### Implement POP Instruction Source: https://github.com/rylev/dmg-01/blob/master/public/book/print.html Handles the POP instruction, which reads two bytes from the stack, combines them into a 16-bit value, and increments the stack pointer twice. Used for retrieving data pushed onto the stack. ```rust #![allow(unused_variables)] fn main() { struct Registers { } impl Registers { fn set_bc(&self, value: u16) { } } struct CPU { pc: u16, bus: Bus, sp: u16, registers: Registers } struct Bus {} impl Bus { fn read_byte(&self, addr: u16) -> u8 { 0 } } enum Instruction { POP(StackTarget), } enum StackTarget { BC, DE } impl CPU { fn execute(&mut self, instruction: Instruction) -> u16 { match instruction { Instruction::POP(target) => { let result = self.pop(); match target { StackTarget::BC => self.registers.set_bc(result), _ => { panic!("TODO: support more targets") } }; self.pc.wrapping_add(1) } _ => { panic!("TODO: support more instructions") } } } fn pop(&mut self) -> u16 { let lsb = self.bus.read_byte(self.sp) as u16; self.sp = self.sp.wrapping_add(1); let msb = self.bus.read_byte(self.sp) as u16; self.sp = self.sp.wrapping_add(1); (msb << 8) | lsb } } } ``` -------------------------------- ### Rust GPU and Tile Structure Source: https://github.com/rylev/dmg-01/blob/master/public/book/print.html Defines constants for VRAM, an enum for tile pixel values, a type alias for a tile, and a basic GPU struct to manage video RAM and tile sets. ```rust #![allow(unused_variables)] fn main() { const VRAM_BEGIN: usize = 0x8000; const VRAM_END: usize = 0x9FFF; const VRAM_SIZE: usize = VRAM_END - VRAM_BEGIN + 1; #[derive(Copy,Clone)] enum TilePixelValue { Zero, One, Two, Three, } type Tile = [[TilePixelValue; 8]; 8]; fn empty_tile() -> Tile { [[TilePixelValue::Zero; 8]; 8] } struct GPU{ vram: [u8; VRAM_SIZE], tile_set: [Tile; 384], } } ``` -------------------------------- ### Instruction Decoding from Byte Source: https://github.com/rylev/dmg-01/blob/master/public/book/cpu/executing_instructions.html Defines the `from_byte` method for the `Instruction` enum, mapping specific byte values to corresponding instructions like INC BC or INC DE. Incomplete mappings are marked with TODO. ```rust # #![allow(unused_variables)] #fn main() { # enum IncDecTarget { BC, DE } # enum Instruction { INC(IncDecTarget) } impl Instruction { fn from_byte(byte: u8) -> Option { match byte { 0x02 => Some(Instruction::INC(IncDecTarget::BC)), 0x13 => Some(Instruction::INC(IncDecTarget::DE)), _ => /* TODO: Add mapping for rest of instructions */ None } } } #} ```