diff --git a/src/bus.rs b/src/bus.rs index 4ef1851..e37fb6c 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -113,15 +113,15 @@ impl Bus { self.var_ram.read_byte(addr) } 0xE000..=0xFDFF => { - // Mirror of 0xC000 to 0xDDFF - // ECHO RAM - - match addr { - 0xE000..=0xEFFF => { + // Mirror of 0xC000 to 0xDDFF (ECHO RAM) + match addr & 0x1FFF { + // 0xE000 ..= 0xEFFF + 0x0000..=0x0FFF => { // 4KB Work RAM Bank 0 self.work_ram.read_byte(addr) } - 0xF000..=0xFDFF => { + // 0xF000 ..= 0xFDFF + 0x1000..=0x1DFF => { // 4KB Work RAM Bank 1 -> N self.var_ram.read_byte(addr) } @@ -139,33 +139,36 @@ impl Bus { } 0xFF00..=0xFF7F => { // IO Registers - match addr { - 0xFF00 => self.joypad.status.into(), - 0xFF01 => self.serial.next, - 0xFF02 => self.serial.control.into(), - 0xFF04 => (self.timer.divider >> 8) as u8, - 0xFF05 => self.timer.counter, - 0xFF06 => self.timer.modulo, - 0xFF07 => self.timer.control.into(), - 0xFF0F => self.interrupt_flag().into(), - 0xFF11 => self.sound.ch1.sound_duty.into(), - 0xFF12 => self.sound.ch1.vol_envelope.into(), - 0xFF14 => self.sound.ch1.freq_hi.into(), - 0xFF24 => self.sound.control.channel.into(), - 0xFF25 => self.sound.control.output.into(), - 0xFF26 => self.sound.control.status.into(), - 0xFF40 => self.ppu.control.into(), - 0xFF41 => self.ppu.stat.into(), - 0xFF42 => self.ppu.pos.scroll_y, - 0xFF43 => self.ppu.pos.scroll_x, - 0xFF44 => self.ppu.pos.line_y, - 0xFF45 => self.ppu.pos.ly_compare as u8, - 0xFF47 => self.ppu.monochrome.bg_palette.into(), - 0xFF48 => self.ppu.monochrome.obj_palette_0.into(), - 0xFF49 => self.ppu.monochrome.obj_palette_1.into(), - 0xFF4A => self.ppu.pos.window_y, - 0xFF4B => self.ppu.pos.window_x, - 0xFF4D => 0x00, // Reading from this address is useful on the CGB only + + // Every address here starts with 0xFF so we can just check the + // low byte to figure out which register it is + match addr & 0x00FF { + 0x00 => self.joypad.status.into(), + 0x01 => self.serial.next, + 0x02 => self.serial.control.into(), + 0x04 => (self.timer.divider >> 8) as u8, + 0x05 => self.timer.counter, + 0x06 => self.timer.modulo, + 0x07 => self.timer.control.into(), + 0x0F => self.interrupt_flag().into(), + 0x11 => self.sound.ch1.sound_duty.into(), + 0x12 => self.sound.ch1.vol_envelope.into(), + 0x14 => self.sound.ch1.freq_hi.into(), + 0x24 => self.sound.control.channel.into(), + 0x25 => self.sound.control.output.into(), + 0x26 => self.sound.control.status.into(), + 0x40 => self.ppu.control.into(), + 0x41 => self.ppu.stat.into(), + 0x42 => self.ppu.pos.scroll_y, + 0x43 => self.ppu.pos.scroll_x, + 0x44 => self.ppu.pos.line_y, + 0x45 => self.ppu.pos.ly_compare as u8, + 0x47 => self.ppu.monochrome.bg_palette.into(), + 0x48 => self.ppu.monochrome.obj_palette_0.into(), + 0x49 => self.ppu.monochrome.obj_palette_1.into(), + 0x4A => self.ppu.pos.window_y, + 0x4B => self.ppu.pos.window_x, + 0x4D => 0x00, // Reading from this address is useful on the CGB only _ => unimplemented!("Unable to read {:#06X} in I/O Registers", addr), } } @@ -216,15 +219,15 @@ impl Bus { self.var_ram.write_byte(addr, byte); } 0xE000..=0xFDFF => { - // Mirror of 0xC000 to 0xDDFF - // ECHO RAM - - match addr { - 0xE000..=0xEFFF => { + // Mirror of 0xC000 to 0xDDFF (ECHO RAM) + match addr & 0x1FFF { + // 0xE000 ..= 0xEFFF + 0x0000..=0x0FFF => { // 4KB Work RAM Bank 0 self.work_ram.write_byte(addr, byte); } - 0xF000..=0xFDFF => { + // 0xF000 ..= 0xFDFF + 0x1000..=0x1DFF => { // 4KB Work RAM Bank 1 -> N self.var_ram.write_byte(addr, byte); } @@ -241,28 +244,31 @@ impl Bus { } 0xFF00..=0xFF7F => { // IO Registers - match addr { - 0xFF00 => self.joypad.status.update(byte), - 0xFF01 => self.serial.next = byte, - 0xFF02 => self.serial.control = byte.into(), - 0xFF04 => self.timer.divider = 0x0000, - 0xFF05 => self.timer.counter = byte, - 0xFF06 => self.timer.modulo = byte, - 0xFF07 => self.timer.control = byte.into(), - 0xFF0F => self.set_interrupt_flag(byte), - 0xFF11 => self.sound.ch1.sound_duty = byte.into(), - 0xFF12 => self.sound.ch1.vol_envelope = byte.into(), - 0xFF13 => self.sound.ch1.freq_lo = byte.into(), - 0xFF14 => self.sound.ch1.freq_hi = byte.into(), - 0xFF24 => self.sound.control.channel = byte.into(), - 0xFF25 => self.sound.control.output = byte.into(), - 0xFF26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here? - 0xFF40 => self.ppu.control = byte.into(), - 0xFF41 => self.ppu.stat.update(byte), - 0xFF42 => self.ppu.pos.scroll_y = byte, - 0xFF43 => self.ppu.pos.scroll_x = byte, - 0xFF44 => self.ppu.pos.line_y = byte, - 0xFF45 => { + + // Every address here starts with 0xFF so we can just check the + // low byte to figure out which register it is + match addr & 0x00FF { + 0x00 => self.joypad.status.update(byte), + 0x01 => self.serial.next = byte, + 0x02 => self.serial.control = byte.into(), + 0x04 => self.timer.divider = 0x0000, + 0x05 => self.timer.counter = byte, + 0x06 => self.timer.modulo = byte, + 0x07 => self.timer.control = byte.into(), + 0x0F => self.set_interrupt_flag(byte), + 0x11 => self.sound.ch1.sound_duty = byte.into(), + 0x12 => self.sound.ch1.vol_envelope = byte.into(), + 0x13 => self.sound.ch1.freq_lo = byte.into(), + 0x14 => self.sound.ch1.freq_hi = byte.into(), + 0x24 => self.sound.control.channel = byte.into(), + 0x25 => self.sound.control.output = byte.into(), + 0x26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here? + 0x40 => self.ppu.control = byte.into(), + 0x41 => self.ppu.stat.update(byte), + 0x42 => self.ppu.pos.scroll_y = byte, + 0x43 => self.ppu.pos.scroll_x = byte, + 0x44 => self.ppu.pos.line_y = byte, + 0x45 => { // Update LYC self.ppu.pos.ly_compare = byte; @@ -275,13 +281,13 @@ impl Bus { self.ppu.int.set_lcd_stat(true); } } - 0xFF47 => self.ppu.monochrome.bg_palette = byte.into(), - 0xFF48 => self.ppu.monochrome.obj_palette_0 = byte.into(), - 0xFF49 => self.ppu.monochrome.obj_palette_1 = byte.into(), - 0xFF4A => self.ppu.pos.window_y = byte, - 0xFF4B => self.ppu.pos.window_x = byte, - 0xFF4D => {} // Writing to this address is useful on the CGB only - 0xFF50 => { + 0x47 => self.ppu.monochrome.bg_palette = byte.into(), + 0x48 => self.ppu.monochrome.obj_palette_0 = byte.into(), + 0x49 => self.ppu.monochrome.obj_palette_1 = byte.into(), + 0x4A => self.ppu.pos.window_y = byte, + 0x4B => self.ppu.pos.window_x = byte, + 0x4D => {} // Writing to this address is useful on the CGB only + 0x50 => { // Disable Boot ROM if byte != 0 { self.boot = None; diff --git a/src/cartridge.rs b/src/cartridge.rs index 1485c46..c68542a 100644 --- a/src/cartridge.rs +++ b/src/cartridge.rs @@ -88,9 +88,11 @@ impl Cartridge { impl Cartridge { pub fn read_byte(&self, addr: u16) -> u8 { + use MbcResult::*; + match self.mbc.handle_read(addr) { - MbcResult::Address(addr) => self.memory[addr as usize], - MbcResult::Value(byte) => byte, + Address(addr) => self.memory[addr as usize], + Value(byte) => byte, } } pub fn write_byte(&mut self, addr: u16, byte: u8) { @@ -166,12 +168,14 @@ impl Mbc1 { } fn calc_ram_address(&self, addr: u16) -> u16 { + use RamSize::*; + match self.ram_size { - RamSize::_2KB | RamSize::_8KB => { + _2KB | _8KB => { let ram_size = self.ram_size.as_byte_count() as u16; (addr - 0xA000) % ram_size } - RamSize::_32KB => { + _32KB => { if self.mode { 0x2000 * self.ram_bank as u16 + (addr - 0xA000) } else { diff --git a/src/joypad.rs b/src/joypad.rs index b6fea58..bd6dc6c 100644 --- a/src/joypad.rs +++ b/src/joypad.rs @@ -98,7 +98,7 @@ pub enum ButtonState { impl From for ButtonState { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::Pressed, 0b01 => Self::Released, _ => unreachable!("{:#04X} is not a valid value for ButtonStatus", byte), @@ -129,7 +129,7 @@ enum RowState { impl From for RowState { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::Selected, 0b01 => Self::Deselected, _ => unreachable!("{:#04X} is not a valid value for ButtonRowStatus", byte), diff --git a/src/ppu/registers.rs b/src/ppu/registers.rs index d07847a..0831065 100644 --- a/src/ppu/registers.rs +++ b/src/ppu/registers.rs @@ -52,7 +52,7 @@ pub enum PpuMode { impl From for PpuMode { fn from(byte: u8) -> Self { - match byte { + match byte & 0b11 { 0b00 => Self::HBlank, 0b01 => Self::VBlank, 0b10 => Self::OamScan, @@ -129,7 +129,7 @@ impl TileMapAddress { impl From for TileMapAddress { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::X9800, 0b01 => Self::X9C00, _ => unreachable!("{:#04X} is not a valid value for TileMapRegister", byte), @@ -157,7 +157,7 @@ pub enum TileDataAddress { impl From for TileDataAddress { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::X8800, 0b01 => Self::X8000, _ => unreachable!("{:#04X} is not a valid value for TileDataRegister", byte), @@ -196,7 +196,7 @@ impl ObjectSize { impl From for ObjectSize { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::Eight, 0b01 => Self::Sixteen, _ => unreachable!("{:#04X} is not a valid value for ObjSize", byte), @@ -227,7 +227,7 @@ bitfield! { impl BackgroundPalette { pub fn shade(&self, id: u8) -> GrayShade { - match id { + match id & 0b11 { 0b00 => self.i0_colour(), 0b01 => self.i1_colour(), 0b10 => self.i2_colour(), @@ -272,7 +272,7 @@ bitfield! { impl ObjectPalette { pub fn shade(&self, id: u8) -> Option { - match id { + match id & 0b11 { 0b00 => None, 0b01 => Some(self.i1_colour()), 0b10 => Some(self.i2_colour()), @@ -376,7 +376,7 @@ pub enum ObjectPaletteId { impl From for ObjectPaletteId { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => ObjectPaletteId::Zero, 0b01 => ObjectPaletteId::One, _ => unreachable!("{:#04X} is not a valid value for BgPaletteNumber", byte), @@ -398,7 +398,7 @@ pub enum RenderPriority { impl From for RenderPriority { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::Object, 0b01 => Self::BackgroundAndWindow, _ => unreachable!("{:#04X} is not a valid value for RenderPriority", byte), @@ -459,7 +459,7 @@ impl Default for GrayShade { impl From for GrayShade { fn from(byte: u8) -> Self { - match byte { + match byte & 0b11 { 0b00 => GrayShade::White, 0b01 => GrayShade::LightGray, 0b10 => GrayShade::DarkGray, diff --git a/src/serial.rs b/src/serial.rs index dcebdbb..4fba589 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -53,7 +53,7 @@ impl Default for ShiftClock { impl From for ShiftClock { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::External, 0b01 => Self::Internal, _ => unreachable!("{:#04X} is not a valid value for ShiftClock", byte), @@ -75,7 +75,7 @@ impl Default for ClockSpeed { impl From for ClockSpeed { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::Normal, 0b01 => Self::Fast, _ => unreachable!("{:#04X} is not a valid value for ClockSpeed", byte), diff --git a/src/sound.rs b/src/sound.rs index 1c938fb..eea5d17 100644 --- a/src/sound.rs +++ b/src/sound.rs @@ -93,7 +93,7 @@ enum FrequencyType { impl From for FrequencyType { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::Counter, 0b01 => Self::Consecutive, _ => unreachable!("{:#04X} is not a valid value for FrequencyType"), @@ -191,7 +191,7 @@ enum EnvelopeDirection { impl From for EnvelopeDirection { fn from(byte: u8) -> Self { - match byte { + match byte & 0b01 { 0b00 => Self::Decrease, 0b01 => Self::Increase, _ => unreachable!("{:#04X} is not a valid value for EnvelopeDirection", byte), @@ -259,7 +259,7 @@ impl From for u8 { impl From for WavePattern { fn from(byte: u8) -> Self { - match byte { + match byte & 0b11 { 0b00 => Self::OneEighth, 0b01 => Self::OneQuarter, 0b10 => Self::OneHalf, diff --git a/src/timer.rs b/src/timer.rs index dac1972..971c753 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -84,7 +84,7 @@ pub enum TimerSpeed { impl From for TimerSpeed { fn from(byte: u8) -> Self { - match byte { + match byte & 0b11 { 0b00 => Self::Hz4096, 0b01 => Self::Hz262144, 0b10 => Self::Hz65536,