From 208f247cea012d65db75ed05639b91aa82387dc4 Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Sun, 16 Feb 2025 12:31:35 +0000 Subject: [PATCH 1/2] Handle prefixed instructions --- src/emulator/cpu.rs | 65 ++++++++++++++++++++++++++++++++++----------- src/emulator/mod.rs | 4 +-- src/main.rs | 2 +- 3 files changed, 53 insertions(+), 18 deletions(-) diff --git a/src/emulator/cpu.rs b/src/emulator/cpu.rs index 56992a8..49d17e5 100644 --- a/src/emulator/cpu.rs +++ b/src/emulator/cpu.rs @@ -1,9 +1,16 @@ +use core::fmt; use std::collections::HashMap; +use std::os::unix::prelude; +use std::thread::{self, Thread}; +use std::time; use crate::emulator::flags::FlagsRegister; use crate::emulator::mmu::Mmu; use crate::emulator::ppu::Ppu; +const MEMORY_SIZE: u16 = 0xFFFF; +const PREFIXED_OPCODE: u8 = 0xCB; + pub struct Cpu { registers: Registers, pc: u16, @@ -25,23 +32,24 @@ impl Cpu { } } - pub fn step(&mut self, looping: bool, mmu: &mut Mmu, _ppu: &mut Ppu) { - let op_code = mmu.read_byte(self.pc); - if looping { - self.pc = self.pc.wrapping_add(1); - } else { - if self.pc == 0xFFFF { - println!("Running: {:?}", self.running); - println!("Success: {}, fail {}", self.success, self.fail); - return; - } - self.pc += 1; + pub fn step(&mut self, mmu: &mut Mmu, _ppu: &mut Ppu) { + let mut instruction_byte = mmu.read_byte(self.pc); + self.pc = self.pc.wrapping_add(1); + if self.pc == MEMORY_SIZE { + println!("{:?}", self); + thread::sleep(time::Duration::from_secs(5)); + return; + } + + let prefixed = instruction_byte == PREFIXED_OPCODE; + if prefixed { + instruction_byte = mmu.read_byte(self.pc); } - let instruction = match Instruction::from_byte(op_code) { + let instruction = match Instruction::from_byte(instruction_byte, prefixed) { Some(instruction) => instruction, None => { - println!("Unknown instruction: {:X}", op_code); + println!("Unknown instruction: {:X}", instruction_byte); self.fail += 1; return; } @@ -59,6 +67,8 @@ impl Cpu { fn execute_instruction(&mut self, _mmu: &mut Mmu, instruction: Instruction) { match instruction { + Instruction::Nop() => (), + Instruction::Halt() => return, Instruction::Add(target) => match target { ArithmaticTarget::A => { let new_value = self.add(self.registers.a); @@ -95,7 +105,6 @@ impl Cpu { Instruction::Jpnz() => { println!("JPNZ Not implemented"); } - Instruction::Nop() => (), } } @@ -112,17 +121,43 @@ impl Cpu { } } +impl fmt::Debug for Cpu { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "Success: {}, fail: {}, running: {:?}", + self.success, self.fail, self.running + ) + } +} + #[derive(Debug, PartialEq, Hash, Eq, Clone)] enum Instruction { Add(ArithmaticTarget), Nop(), Jpnz(), + Halt(), } impl Instruction { - fn from_byte(byte: u8) -> Option { + fn from_byte(byte: u8, prefixed: bool) -> Option { + if prefixed { + Self::from_byte_prefixed(byte) + } else { + Self::from_byte_non_prefixed(byte) + } + } + + fn from_byte_prefixed(byte: u8) -> Option { + match byte { + _ => None, + } + } + + fn from_byte_non_prefixed(byte: u8) -> Option { match byte { 0x00 => Some(Instruction::Nop()), + 0x76 => Some(Instruction::Halt()), 0x80 => Some(Instruction::Add(ArithmaticTarget::B)), 0x81 => Some(Instruction::Add(ArithmaticTarget::C)), 0x82 => Some(Instruction::Add(ArithmaticTarget::D)), diff --git a/src/emulator/mod.rs b/src/emulator/mod.rs index 74b421b..c792edf 100644 --- a/src/emulator/mod.rs +++ b/src/emulator/mod.rs @@ -37,9 +37,9 @@ impl Emulator { Ok(()) } - pub fn run(&mut self, looping: bool) { + pub fn run(&mut self) { loop { - self.cpu.step(looping, &mut self.mmu, &mut self.ppu); + self.cpu.step(&mut self.mmu, &mut self.ppu); } } } diff --git a/src/main.rs b/src/main.rs index 04c6787..a5de368 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,6 +18,6 @@ fn main() -> Result<()> { let mut gameboy = emulator::Emulator::new(); gameboy.load_rom(rom_path).context("Failed to load ROM")?; - gameboy.run(false); + gameboy.run(); Ok(()) } From 3e2699adab35cf1990c6858659b3ce917e9f7b4b Mon Sep 17 00:00:00 2001 From: OpenSauce Date: Sun, 16 Feb 2025 12:34:37 +0000 Subject: [PATCH 2/2] Linting and from_byte impl --- src/emulator/cpu.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/emulator/cpu.rs b/src/emulator/cpu.rs index 49d17e5..e4a55a6 100644 --- a/src/emulator/cpu.rs +++ b/src/emulator/cpu.rs @@ -1,7 +1,6 @@ use core::fmt; use std::collections::HashMap; -use std::os::unix::prelude; -use std::thread::{self, Thread}; +use std::thread; use std::time; use crate::emulator::flags::FlagsRegister; @@ -68,7 +67,7 @@ impl Cpu { fn execute_instruction(&mut self, _mmu: &mut Mmu, instruction: Instruction) { match instruction { Instruction::Nop() => (), - Instruction::Halt() => return, + Instruction::Halt() => (), Instruction::Add(target) => match target { ArithmaticTarget::A => { let new_value = self.add(self.registers.a); @@ -105,6 +104,9 @@ impl Cpu { Instruction::Jpnz() => { println!("JPNZ Not implemented"); } + Instruction::Rlc(_target) => { + println!("RLC Not implemented"); + } } } @@ -137,6 +139,7 @@ enum Instruction { Nop(), Jpnz(), Halt(), + Rlc(ArithmaticTarget), } impl Instruction { @@ -150,6 +153,7 @@ impl Instruction { fn from_byte_prefixed(byte: u8) -> Option { match byte { + 0x00 => Some(Instruction::Rlc(ArithmaticTarget::B)), _ => None, } }