From 15da6cb7d2358bc12cdb348fc57d04812dca6528 Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Sun, 21 Mar 2021 01:52:29 -0500 Subject: [PATCH] fix: squash several bugs in MBC1 implementation --- src/cartridge.rs | 147 ++++++++++++++++++++++------------------------- src/main.rs | 2 + src/ppu.rs | 6 +- 3 files changed, 76 insertions(+), 79 deletions(-) diff --git a/src/cartridge.rs b/src/cartridge.rs index afbb030..d70185f 100644 --- a/src/cartridge.rs +++ b/src/cartridge.rs @@ -90,8 +90,8 @@ impl Cartridge { #[derive(Debug, Clone, Default)] struct MBC1 { - current_rom_bank: u8, // 5-bit Number - current_ram_bank: u8, // 2-bit number + rom_bank: u8, // 5-bit Number + ram_bank: u8, // 2-bit number mode: bool, ram_size: RamSize, ram: Vec, @@ -101,30 +101,32 @@ struct MBC1 { impl MBC1 { fn calc_zero_bank_number(&self) -> u8 { + use BankCount::*; + match self.bank_count { - BankCount::ThirtyTwo | BankCount::Sixteen | BankCount::Eight | BankCount::Four => 0, - BankCount::SixtyFour => (self.current_ram_bank & 0x01) << 5, - BankCount::OneHundredTwentyEight => self.current_ram_bank << 5, - _ => unreachable!("{#:?} is not a valid ROM Bank Number for MBC1"), + ThirtyTwo | Sixteen | Eight | Four => 0, + SixtyFour => (self.ram_bank & 0x01) << 5, + OneHundredTwentyEight => self.ram_bank << 5, + _ => unreachable!("{:#?} is not a valid MBC1 BankCount", self.bank_count), } } fn calc_high_bank_number(&self) -> u8 { + use BankCount::*; + match self.bank_count { - BankCount::ThirtyTwo | BankCount::Sixteen | BankCount::Eight | BankCount::Four => { - self.apply_rom_size_bitmask(self.current_rom_bank) - } - BankCount::SixtyFour => { - let mut num = self.apply_rom_size_bitmask(self.current_rom_bank); + None | Four | Eight | Sixteen | ThirtyTwo => self.apply_rom_size_bitmask(self.rom_bank), + SixtyFour => { + let mut num = self.apply_rom_size_bitmask(self.rom_bank); num &= !(0x01 << 5); - num | ((self.current_ram_bank & 0x01) << 5) + num | ((self.ram_bank & 0x01) << 5) } - BankCount::OneHundredTwentyEight => { - let mut num = self.apply_rom_size_bitmask(self.current_rom_bank); + OneHundredTwentyEight => { + let mut num = self.apply_rom_size_bitmask(self.rom_bank); num &= !(0x03 << 5); - num | ((self.current_ram_bank) << 5) + num | ((self.ram_bank) << 5) } - _ => unreachable!("{#:?} is not a valid ROM Bank Number for MBC1"), + _ => unreachable!("{:#?} is not a valid MBC1 BankCount", self.bank_count), } } @@ -138,7 +140,24 @@ impl MBC1 { ThirtyTwo => byte & 0b00011111, SixtyFour => byte & 0b00011111, OneHundredTwentyEight => byte & 0b00011111, - _ => unreachable!("{#:?} is not a valid ROM Bank Number for MBC1"), + _ => unreachable!("{:#?} does not have a bitmask in MBC1", self.bank_count), + } + } + + fn calc_ram_address(&self, addr: u16) -> u16 { + match self.ram_size { + RamSize::_2KB | RamSize::_8KB => { + let ram_size = self.ram_size.to_byte_count() as u16; + (addr - 0xA000) % ram_size + } + RamSize::_32KB => { + if self.mode { + 0x2000 * self.ram_bank as u16 + (addr - 0xA000) + } else { + addr - 0xA000 + } + } + _ => unreachable!("RAM size can not be greater than 32KB on MBC1"), } } } @@ -150,35 +169,22 @@ impl MemoryBankController for MBC1 { match addr { 0x0000..=0x3FFF => { if self.mode { - let zero_bank_number = self.calc_zero_bank_number() as u16; - Address(0x4000 * zero_bank_number + addr) + let zero_bank = self.calc_zero_bank_number() as u16; + Address(0x4000 * zero_bank + addr) } else { Address(addr) } } 0x4000..=0x7FFF => { - let high_bank_number = self.calc_high_bank_number() as u16; - Address(0x4000 * high_bank_number * (addr - 0x4000)) + let high_bank = self.calc_high_bank_number() as u16; + Address(0x4000 * high_bank + (addr - 0x4000)) } 0xA000..=0xBFFF => { if self.ram_enabled { - let ram_addr = match self.ram_size { - RamSize::_2KB | RamSize::_8KB => { - (addr as u32 - 0xA000) % self.ram_size.to_byte_count() - } - RamSize::_32KB => { - if self.mode { - 0x2000 * self.current_ram_bank as u32 + (addr as u32 - 0xA000) - } else { - addr as u32 - 0xA000 - } - } - _ => unreachable!(""), - }; - + let ram_addr = self.calc_ram_address(addr); Value(self.ram[ram_addr as usize]) } else { - Address(0x00FF) + Value(0xFF) } } _ => unimplemented!(), @@ -189,30 +195,17 @@ impl MemoryBankController for MBC1 { match addr { 0x0000..=0x1FFF => self.ram_enabled = (byte & 0x0F) == 0x0A, 0x2000..=0x3FFF => { - self.current_rom_bank = self.apply_rom_size_bitmask(byte); + self.rom_bank = self.apply_rom_size_bitmask(byte); - if self.current_rom_bank == 0 { - self.current_rom_bank = 1; + if self.rom_bank == 0 { + self.rom_bank = 1; } } - 0x4000..=0x5FFF => self.current_ram_bank = byte & 0x03, - 0x6000..=0x7FFF => self.mode = byte >> 7 == 0x01, + 0x4000..=0x5FFF => self.ram_bank = byte & 0b11, + 0x6000..=0x7FFF => self.mode = (byte & 0x01) == 0x01, 0xA000..=0xBFFF => { if self.ram_enabled { - let ram_addr = match self.ram_size { - RamSize::_2KB | RamSize::_8KB => { - (addr as u32 - 0xA000) % self.ram_size.to_byte_count() - } - RamSize::_32KB => { - if self.mode { - 0x2000 * (self.current_ram_bank as u32) + (addr as u32 - 0xA000) - } else { - addr as u32 - 0xA000 - } - } - _ => unreachable!("RAM size can not be greater than 32KB on MBC1"), - }; - + let ram_addr = self.calc_ram_address(addr); self.ram[ram_addr as usize] = byte; } } @@ -259,12 +252,12 @@ impl Default for MBCKind { #[derive(Debug, Clone, Copy)] enum RamSize { - None = 0, - _2KB = 1, - _8KB = 2, - _32KB = 3, // Split into 4 RAM banks - _128KB = 4, // Split into 16 RAM banks - _64KB = 5, // Split into 8 RAm Banks + None = 0x00, + _2KB = 0x01, + _8KB = 0x02, + _32KB = 0x03, // Split into 4 RAM banks + _128KB = 0x04, // Split into 16 RAM banks + _64KB = 0x05, // Split into 8 RAm Banks } impl RamSize { @@ -297,8 +290,8 @@ impl From for RamSize { 0x01 => _2KB, 0x02 => _8KB, 0x03 => _32KB, - 0x04 => _64KB, - 0x05 => _128KB, + 0x04 => _128KB, + 0x05 => _64KB, _ => unreachable!("{:#04X} is an invalid value for RAMSize"), } } @@ -306,18 +299,18 @@ impl From for RamSize { #[derive(Debug, Clone, Copy)] enum BankCount { - None = 0, // 32KB - Four = 1, // 64KB - Eight = 2, // 128KB - Sixteen = 3, // 256KB - ThirtyTwo = 4, // 512KB - SixtyFour = 5, // 1MB - OneHundredTwentyEight = 6, // 2MB - TwoHundredFiftySix = 7, // 4MB - FiveHundredTwelve = 8, // 8MB - SeventyTwo = 0x52, // 1.1MB - Eighty = 0x53, // 1.2MB - NinetySix = 0x54, // 1.5MB + None = 0x00, // 32KB + Four = 0x01, // 64KB + Eight = 0x02, // 128KB + Sixteen = 0x03, // 256KB + ThirtyTwo = 0x04, // 512KB + SixtyFour = 0x05, // 1MB + OneHundredTwentyEight = 0x06, // 2MB + TwoHundredFiftySix = 0x07, // 4MB + FiveHundredTwelve = 0x08, // 8MB + SeventyTwo = 0x52, // 1.1MB + Eighty = 0x53, // 1.2MB + NinetySix = 0x54, // 1.5MB } impl Default for BankCount { @@ -328,7 +321,7 @@ impl Default for BankCount { impl BankCount { // https://hacktix.github.io/GBEDG/mbcs/#rom-size - pub fn to_byte_count(&self) -> u32 { + pub fn to_rom_size(&self) -> u32 { use BankCount::*; match *self { @@ -365,7 +358,7 @@ impl From for BankCount { 0x52 => SeventyTwo, 0x53 => Eighty, 0x54 => NinetySix, - _ => unreachable!("{:#04X} is an invalid value for BankCount"), + _ => unreachable!("{:#04X} is an invalid value for BankCount", byte), } } } diff --git a/src/main.rs b/src/main.rs index c93c4ef..d73f016 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,9 @@ fn main() -> Result<()> { None => LR35902::new(), }; + // game_boy.load_cartridge("bin/instr_timing.gb"); game_boy.load_cartridge("bin/cpu_instrs.gb"); + // game_boy.load_cartridge("bin/tetris.gb"); let mut now = Instant::now(); let mut cycles_in_frame = Cycles::default(); diff --git a/src/ppu.rs b/src/ppu.rs index 73e78bd..25df9da 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -123,14 +123,16 @@ impl Ppu { TileMapAddress::X9C00 => 0x9C00, }; - let y_pos = self.pos.line_y as u16 + self.pos.scroll_y as u16; + // let y_pos = self.pos.line_y as u16 + self.pos.scroll_y as u16; + let y_pos = self.pos.line_y as u16; // There are always 20 rows of tiles in the LCD Viewport // 160 / 20 = 8, so we can figure out the row of a tile with the following let tile_row: u16 = y_pos as u16 / 8; for (line_x, chunk) in scanline.chunks_mut(4).enumerate() { - let x_pos = line_x as u16 + self.pos.scroll_x as u16; + // let x_pos = line_x as u16 + self.pos.scroll_x as u16; + let x_pos = line_x as u16; // There are always 18 columns of tiles in the LCD Viewport // 144 / 18 = 8, so we can figure out the column of a tile with the following