From 5d04b7c3467b0871a792c96aeee4138591d82b08 Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Wed, 13 Oct 2021 19:38:37 -0500 Subject: [PATCH] Modeling the Bus and writing first test for NOP instruction --- src/bin/main.rs | 7 ++++-- src/bus.rs | 60 ++++++++++++++++++++++++++++++++++++++----------- src/console.rs | 23 +++++++++++++++++++ src/cpu.rs | 32 +++++++++++++++++++++++++- src/lib.rs | 2 ++ src/ppu.rs | 7 ++++++ src/rom.rs | 20 +++++++++++++++-- 7 files changed, 133 insertions(+), 18 deletions(-) create mode 100644 src/console.rs create mode 100644 src/ppu.rs diff --git a/src/bin/main.rs b/src/bin/main.rs index b613d5a..3990b8a 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -1,7 +1,10 @@ use rust_boy::rom::ROM; +use rust_boy::console::Console; fn main() -> std::io::Result<()> { - let myrom = ROM::load_file("roms/cpu_instrs.gb".to_string())?; - myrom.print_content(); + /* let myrom = ROM::load_file("roms/cpu_instrs.gb".to_string())?; + myrom.print_content(); */ + let mut console = Console::new(); + console.cpu_run(); Ok(()) } diff --git a/src/bus.rs b/src/bus.rs index 048b8f0..fb37b0d 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -1,3 +1,5 @@ +use crate::rom::ROM; + pub enum MemoryMap { BankZero, BankSwitchable, @@ -15,18 +17,50 @@ pub enum MemoryMap { impl MemoryMap { pub fn get_map(address: u16) -> Self { - if address <= 0x3FFF {return Self::BankZero;} - if address >= 0x4000 && address <= 0x7FFF {return Self::BankSwitchable;} - if address >= 0x8000 && address <= 0x9FFF {return Self::VideoRAM;} - if address >= 0xA000 && address <= 0xBFFF {return Self::ExternalRAM;} - if address >= 0xC000 && address <= 0xCFFF {return Self::WorkRAM1;} - if address >= 0xD000 && address <= 0xDFFF {return Self::WorkRAM2;} - if address >= 0xE000 && address <= 0xFDFF {return Self::EchoRAM;} // Mirror of C000~DDFF - if address >= 0xFE00 && address <= 0xFE9F {return Self::SpriteAttributeTable;} - if address >= 0xFEA0 && address <= 0xFEFF {return Self::NotUsable;} - if address >= 0xFF00 && address <= 0xFF7F {return Self::IORegisters;} - if address >= 0xFF80 && address <= 0xFFFE {return Self::HighRAM;} - if address == 0xFFFF {return Self::InterruptEnableRegister;} - Self::BankZero + match address { + 0x0000..=0x3FFF => Self::BankZero, + 0x4000..=0x7FFF => Self::BankSwitchable, + 0x8000..=0x9FFF => Self::VideoRAM, + 0xA000..=0xBFFF => Self::ExternalRAM, + 0xC000..=0xCFFF => Self::WorkRAM1, + 0xD000..=0xDFFF => Self::WorkRAM2, + 0xE000..=0xFDFF => Self::EchoRAM, // Mirror of C000~DDFF + 0xFE00..=0xFE9F => Self::SpriteAttributeTable, + 0xFEA0..=0xFEFF => Self::NotUsable, + 0xFF00..=0xFF7F => Self::IORegisters, + 0xFF80..=0xFFFE => Self::HighRAM, + 0xFFFF => Self::InterruptEnableRegister, + _ => Self::BankZero, + } + } +} + +pub struct Bus { + game_rom: ROM, + data: [u8; 0xFFFF], +} + +impl Bus { + pub fn new() -> Self { + let game_rom = match ROM::load_file("roms/cpu_instrs.gb".to_string()) { + Ok(rom) => rom, + _ => ROM::from_bytes(&[0; 0xFFFF]) + }; + game_rom.print_content(Some(0x102)); + Self { + data: [0; 0xFFFF], + game_rom, + } + } + + pub fn read(&self, address: u16) -> u8 { + match MemoryMap::get_map(address) { + MemoryMap::BankZero => self.game_rom.read(address), + _ => self.data[address as usize], + } + } + + pub fn write(&mut self, address: u16, data: u8) { + self.data[address as usize] = data; } } diff --git a/src/console.rs b/src/console.rs new file mode 100644 index 0000000..2161cce --- /dev/null +++ b/src/console.rs @@ -0,0 +1,23 @@ +use crate::cpu::CPU; +use crate::ppu::PPU; +use crate::bus::Bus; + +pub struct Console { + cpu: CPU, + ppu: PPU, + bus: Bus, +} + +impl Console { + pub fn new() -> Self { + Self { + cpu: CPU::new(), + ppu: PPU::new(), + bus: Bus::new(), + } + } + + pub fn cpu_run(&mut self) { + self.cpu.run(&mut self.bus); + } +} diff --git a/src/cpu.rs b/src/cpu.rs index cdf1fff..07c0b47 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,4 +1,5 @@ use crate::utils::{BitIndex, get_bit, set_bit}; +use crate::bus::Bus; pub enum Register { A(u8), // Accumulator @@ -43,7 +44,7 @@ impl Registers { pub fn new() -> Self { Self { a: 0, - f: 0b11110000, // The first 4 lower bits are always set to 0 + f: 0b00000000, // The first 4 lower bits are always set to 0 b: 0, c: 0, d: 0, @@ -111,6 +112,10 @@ impl Registers { } } + pub fn increment_pc(&mut self) { + self.pc += 1; + } + fn get_af(&self) -> u16 { ((self.a as u16) << 8) | (self.f as u16) } @@ -249,6 +254,28 @@ pub struct CPU { } impl CPU { + pub fn new() -> Self { + Self { + registers: Registers::new(), + } + } + + // Get the program counter + pub fn get_register(&self, register: Register) -> u16 { + self.registers.get(register) + } + + pub fn run(&mut self, bus: &mut Bus) { + println!("Opcode: {:02X}", bus.read(self.registers.get(Register::PC(0)))); + } + + pub fn exec(&mut self, opcode: CpuOpcode) { + match opcode { + CpuOpcode::NOP => self.registers.increment_pc(), + _ => println!("Illegal instruction"), + }; + } + pub fn parse_opcode(opcode: u8) -> CpuOpcode { match opcode { 0x06 => CpuOpcode::LD(OpcodeParameter::Register_U8(Register::B(0))), @@ -572,5 +599,8 @@ mod tests { #[test] fn test_cpu_instructions() { + let mut cpu = CPU::new(); + cpu.exec(CpuOpcode::NOP); + assert_eq!(cpu.registers.get(Register::PC(0)), 0x101); } } diff --git a/src/lib.rs b/src/lib.rs index c15102f..926e80e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,6 @@ pub mod utils; pub mod cpu; +pub mod ppu; pub mod rom; pub mod bus; +pub mod console; diff --git a/src/ppu.rs b/src/ppu.rs new file mode 100644 index 0000000..70eded6 --- /dev/null +++ b/src/ppu.rs @@ -0,0 +1,7 @@ +pub struct PPU; + +impl PPU { + pub fn new() -> Self { + Self{} + } +} diff --git a/src/rom.rs b/src/rom.rs index 50fc099..cc9849b 100644 --- a/src/rom.rs +++ b/src/rom.rs @@ -15,7 +15,23 @@ impl ROM { }) } - pub fn print_content(&self) { - println!("{:02X?}", self.bytes); + pub fn read(&self, address: u16) -> u8 { + match self.bytes.get(address as usize) { + Some(val) => *val, + None => 0xFF, + } + } + + pub fn from_bytes(bytes: &[u8]) -> Self { + Self { + bytes: bytes.to_vec(), + } + } + + pub fn print_content(&self, address: Option) { + match address { + Some(address) => println!("{:02X?}", self.read(address)), + None => println!("{:02X?}", self.bytes), + }; } }