chore: improve performance of match statements

This commit is contained in:
Rekai Nyangadzayi Musuka 2021-05-19 02:52:32 -05:00
parent e89e89df5b
commit 9ea26d4a05
7 changed files with 99 additions and 89 deletions

View File

@ -113,15 +113,15 @@ impl Bus {
self.var_ram.read_byte(addr) self.var_ram.read_byte(addr)
} }
0xE000..=0xFDFF => { 0xE000..=0xFDFF => {
// Mirror of 0xC000 to 0xDDFF // Mirror of 0xC000 to 0xDDFF (ECHO RAM)
// ECHO RAM match addr & 0x1FFF {
// 0xE000 ..= 0xEFFF
match addr { 0x0000..=0x0FFF => {
0xE000..=0xEFFF => {
// 4KB Work RAM Bank 0 // 4KB Work RAM Bank 0
self.work_ram.read_byte(addr) self.work_ram.read_byte(addr)
} }
0xF000..=0xFDFF => { // 0xF000 ..= 0xFDFF
0x1000..=0x1DFF => {
// 4KB Work RAM Bank 1 -> N // 4KB Work RAM Bank 1 -> N
self.var_ram.read_byte(addr) self.var_ram.read_byte(addr)
} }
@ -139,33 +139,36 @@ impl Bus {
} }
0xFF00..=0xFF7F => { 0xFF00..=0xFF7F => {
// IO Registers // IO Registers
match addr {
0xFF00 => self.joypad.status.into(), // Every address here starts with 0xFF so we can just check the
0xFF01 => self.serial.next, // low byte to figure out which register it is
0xFF02 => self.serial.control.into(), match addr & 0x00FF {
0xFF04 => (self.timer.divider >> 8) as u8, 0x00 => self.joypad.status.into(),
0xFF05 => self.timer.counter, 0x01 => self.serial.next,
0xFF06 => self.timer.modulo, 0x02 => self.serial.control.into(),
0xFF07 => self.timer.control.into(), 0x04 => (self.timer.divider >> 8) as u8,
0xFF0F => self.interrupt_flag().into(), 0x05 => self.timer.counter,
0xFF11 => self.sound.ch1.sound_duty.into(), 0x06 => self.timer.modulo,
0xFF12 => self.sound.ch1.vol_envelope.into(), 0x07 => self.timer.control.into(),
0xFF14 => self.sound.ch1.freq_hi.into(), 0x0F => self.interrupt_flag().into(),
0xFF24 => self.sound.control.channel.into(), 0x11 => self.sound.ch1.sound_duty.into(),
0xFF25 => self.sound.control.output.into(), 0x12 => self.sound.ch1.vol_envelope.into(),
0xFF26 => self.sound.control.status.into(), 0x14 => self.sound.ch1.freq_hi.into(),
0xFF40 => self.ppu.control.into(), 0x24 => self.sound.control.channel.into(),
0xFF41 => self.ppu.stat.into(), 0x25 => self.sound.control.output.into(),
0xFF42 => self.ppu.pos.scroll_y, 0x26 => self.sound.control.status.into(),
0xFF43 => self.ppu.pos.scroll_x, 0x40 => self.ppu.control.into(),
0xFF44 => self.ppu.pos.line_y, 0x41 => self.ppu.stat.into(),
0xFF45 => self.ppu.pos.ly_compare as u8, 0x42 => self.ppu.pos.scroll_y,
0xFF47 => self.ppu.monochrome.bg_palette.into(), 0x43 => self.ppu.pos.scroll_x,
0xFF48 => self.ppu.monochrome.obj_palette_0.into(), 0x44 => self.ppu.pos.line_y,
0xFF49 => self.ppu.monochrome.obj_palette_1.into(), 0x45 => self.ppu.pos.ly_compare as u8,
0xFF4A => self.ppu.pos.window_y, 0x47 => self.ppu.monochrome.bg_palette.into(),
0xFF4B => self.ppu.pos.window_x, 0x48 => self.ppu.monochrome.obj_palette_0.into(),
0xFF4D => 0x00, // Reading from this address is useful on the CGB only 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), _ => unimplemented!("Unable to read {:#06X} in I/O Registers", addr),
} }
} }
@ -216,15 +219,15 @@ impl Bus {
self.var_ram.write_byte(addr, byte); self.var_ram.write_byte(addr, byte);
} }
0xE000..=0xFDFF => { 0xE000..=0xFDFF => {
// Mirror of 0xC000 to 0xDDFF // Mirror of 0xC000 to 0xDDFF (ECHO RAM)
// ECHO RAM match addr & 0x1FFF {
// 0xE000 ..= 0xEFFF
match addr { 0x0000..=0x0FFF => {
0xE000..=0xEFFF => {
// 4KB Work RAM Bank 0 // 4KB Work RAM Bank 0
self.work_ram.write_byte(addr, byte); self.work_ram.write_byte(addr, byte);
} }
0xF000..=0xFDFF => { // 0xF000 ..= 0xFDFF
0x1000..=0x1DFF => {
// 4KB Work RAM Bank 1 -> N // 4KB Work RAM Bank 1 -> N
self.var_ram.write_byte(addr, byte); self.var_ram.write_byte(addr, byte);
} }
@ -241,28 +244,31 @@ impl Bus {
} }
0xFF00..=0xFF7F => { 0xFF00..=0xFF7F => {
// IO Registers // IO Registers
match addr {
0xFF00 => self.joypad.status.update(byte), // Every address here starts with 0xFF so we can just check the
0xFF01 => self.serial.next = byte, // low byte to figure out which register it is
0xFF02 => self.serial.control = byte.into(), match addr & 0x00FF {
0xFF04 => self.timer.divider = 0x0000, 0x00 => self.joypad.status.update(byte),
0xFF05 => self.timer.counter = byte, 0x01 => self.serial.next = byte,
0xFF06 => self.timer.modulo = byte, 0x02 => self.serial.control = byte.into(),
0xFF07 => self.timer.control = byte.into(), 0x04 => self.timer.divider = 0x0000,
0xFF0F => self.set_interrupt_flag(byte), 0x05 => self.timer.counter = byte,
0xFF11 => self.sound.ch1.sound_duty = byte.into(), 0x06 => self.timer.modulo = byte,
0xFF12 => self.sound.ch1.vol_envelope = byte.into(), 0x07 => self.timer.control = byte.into(),
0xFF13 => self.sound.ch1.freq_lo = byte.into(), 0x0F => self.set_interrupt_flag(byte),
0xFF14 => self.sound.ch1.freq_hi = byte.into(), 0x11 => self.sound.ch1.sound_duty = byte.into(),
0xFF24 => self.sound.control.channel = byte.into(), 0x12 => self.sound.ch1.vol_envelope = byte.into(),
0xFF25 => self.sound.control.output = byte.into(), 0x13 => self.sound.ch1.freq_lo = byte.into(),
0xFF26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here? 0x14 => self.sound.ch1.freq_hi = byte.into(),
0xFF40 => self.ppu.control = byte.into(), 0x24 => self.sound.control.channel = byte.into(),
0xFF41 => self.ppu.stat.update(byte), 0x25 => self.sound.control.output = byte.into(),
0xFF42 => self.ppu.pos.scroll_y = byte, 0x26 => self.sound.control.status = byte.into(), // FIXME: Should we control which bytes are written to here?
0xFF43 => self.ppu.pos.scroll_x = byte, 0x40 => self.ppu.control = byte.into(),
0xFF44 => self.ppu.pos.line_y = byte, 0x41 => self.ppu.stat.update(byte),
0xFF45 => { 0x42 => self.ppu.pos.scroll_y = byte,
0x43 => self.ppu.pos.scroll_x = byte,
0x44 => self.ppu.pos.line_y = byte,
0x45 => {
// Update LYC // Update LYC
self.ppu.pos.ly_compare = byte; self.ppu.pos.ly_compare = byte;
@ -275,13 +281,13 @@ impl Bus {
self.ppu.int.set_lcd_stat(true); self.ppu.int.set_lcd_stat(true);
} }
} }
0xFF47 => self.ppu.monochrome.bg_palette = byte.into(), 0x47 => self.ppu.monochrome.bg_palette = byte.into(),
0xFF48 => self.ppu.monochrome.obj_palette_0 = byte.into(), 0x48 => self.ppu.monochrome.obj_palette_0 = byte.into(),
0xFF49 => self.ppu.monochrome.obj_palette_1 = byte.into(), 0x49 => self.ppu.monochrome.obj_palette_1 = byte.into(),
0xFF4A => self.ppu.pos.window_y = byte, 0x4A => self.ppu.pos.window_y = byte,
0xFF4B => self.ppu.pos.window_x = byte, 0x4B => self.ppu.pos.window_x = byte,
0xFF4D => {} // Writing to this address is useful on the CGB only 0x4D => {} // Writing to this address is useful on the CGB only
0xFF50 => { 0x50 => {
// Disable Boot ROM // Disable Boot ROM
if byte != 0 { if byte != 0 {
self.boot = None; self.boot = None;

View File

@ -88,9 +88,11 @@ impl Cartridge {
impl Cartridge { impl Cartridge {
pub fn read_byte(&self, addr: u16) -> u8 { pub fn read_byte(&self, addr: u16) -> u8 {
use MbcResult::*;
match self.mbc.handle_read(addr) { match self.mbc.handle_read(addr) {
MbcResult::Address(addr) => self.memory[addr as usize], Address(addr) => self.memory[addr as usize],
MbcResult::Value(byte) => byte, Value(byte) => byte,
} }
} }
pub fn write_byte(&mut self, addr: u16, byte: u8) { pub fn write_byte(&mut self, addr: u16, byte: u8) {
@ -166,12 +168,14 @@ impl Mbc1 {
} }
fn calc_ram_address(&self, addr: u16) -> u16 { fn calc_ram_address(&self, addr: u16) -> u16 {
use RamSize::*;
match self.ram_size { match self.ram_size {
RamSize::_2KB | RamSize::_8KB => { _2KB | _8KB => {
let ram_size = self.ram_size.as_byte_count() as u16; let ram_size = self.ram_size.as_byte_count() as u16;
(addr - 0xA000) % ram_size (addr - 0xA000) % ram_size
} }
RamSize::_32KB => { _32KB => {
if self.mode { if self.mode {
0x2000 * self.ram_bank as u16 + (addr - 0xA000) 0x2000 * self.ram_bank as u16 + (addr - 0xA000)
} else { } else {

View File

@ -98,7 +98,7 @@ pub enum ButtonState {
impl From<u8> for ButtonState { impl From<u8> for ButtonState {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::Pressed, 0b00 => Self::Pressed,
0b01 => Self::Released, 0b01 => Self::Released,
_ => unreachable!("{:#04X} is not a valid value for ButtonStatus", byte), _ => unreachable!("{:#04X} is not a valid value for ButtonStatus", byte),
@ -129,7 +129,7 @@ enum RowState {
impl From<u8> for RowState { impl From<u8> for RowState {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::Selected, 0b00 => Self::Selected,
0b01 => Self::Deselected, 0b01 => Self::Deselected,
_ => unreachable!("{:#04X} is not a valid value for ButtonRowStatus", byte), _ => unreachable!("{:#04X} is not a valid value for ButtonRowStatus", byte),

View File

@ -52,7 +52,7 @@ pub enum PpuMode {
impl From<u8> for PpuMode { impl From<u8> for PpuMode {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b11 {
0b00 => Self::HBlank, 0b00 => Self::HBlank,
0b01 => Self::VBlank, 0b01 => Self::VBlank,
0b10 => Self::OamScan, 0b10 => Self::OamScan,
@ -129,7 +129,7 @@ impl TileMapAddress {
impl From<u8> for TileMapAddress { impl From<u8> for TileMapAddress {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::X9800, 0b00 => Self::X9800,
0b01 => Self::X9C00, 0b01 => Self::X9C00,
_ => unreachable!("{:#04X} is not a valid value for TileMapRegister", byte), _ => unreachable!("{:#04X} is not a valid value for TileMapRegister", byte),
@ -157,7 +157,7 @@ pub enum TileDataAddress {
impl From<u8> for TileDataAddress { impl From<u8> for TileDataAddress {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::X8800, 0b00 => Self::X8800,
0b01 => Self::X8000, 0b01 => Self::X8000,
_ => unreachable!("{:#04X} is not a valid value for TileDataRegister", byte), _ => unreachable!("{:#04X} is not a valid value for TileDataRegister", byte),
@ -196,7 +196,7 @@ impl ObjectSize {
impl From<u8> for ObjectSize { impl From<u8> for ObjectSize {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::Eight, 0b00 => Self::Eight,
0b01 => Self::Sixteen, 0b01 => Self::Sixteen,
_ => unreachable!("{:#04X} is not a valid value for ObjSize", byte), _ => unreachable!("{:#04X} is not a valid value for ObjSize", byte),
@ -227,7 +227,7 @@ bitfield! {
impl BackgroundPalette { impl BackgroundPalette {
pub fn shade(&self, id: u8) -> GrayShade { pub fn shade(&self, id: u8) -> GrayShade {
match id { match id & 0b11 {
0b00 => self.i0_colour(), 0b00 => self.i0_colour(),
0b01 => self.i1_colour(), 0b01 => self.i1_colour(),
0b10 => self.i2_colour(), 0b10 => self.i2_colour(),
@ -272,7 +272,7 @@ bitfield! {
impl ObjectPalette { impl ObjectPalette {
pub fn shade(&self, id: u8) -> Option<GrayShade> { pub fn shade(&self, id: u8) -> Option<GrayShade> {
match id { match id & 0b11 {
0b00 => None, 0b00 => None,
0b01 => Some(self.i1_colour()), 0b01 => Some(self.i1_colour()),
0b10 => Some(self.i2_colour()), 0b10 => Some(self.i2_colour()),
@ -376,7 +376,7 @@ pub enum ObjectPaletteId {
impl From<u8> for ObjectPaletteId { impl From<u8> for ObjectPaletteId {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => ObjectPaletteId::Zero, 0b00 => ObjectPaletteId::Zero,
0b01 => ObjectPaletteId::One, 0b01 => ObjectPaletteId::One,
_ => unreachable!("{:#04X} is not a valid value for BgPaletteNumber", byte), _ => unreachable!("{:#04X} is not a valid value for BgPaletteNumber", byte),
@ -398,7 +398,7 @@ pub enum RenderPriority {
impl From<u8> for RenderPriority { impl From<u8> for RenderPriority {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::Object, 0b00 => Self::Object,
0b01 => Self::BackgroundAndWindow, 0b01 => Self::BackgroundAndWindow,
_ => unreachable!("{:#04X} is not a valid value for RenderPriority", byte), _ => unreachable!("{:#04X} is not a valid value for RenderPriority", byte),
@ -459,7 +459,7 @@ impl Default for GrayShade {
impl From<u8> for GrayShade { impl From<u8> for GrayShade {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b11 {
0b00 => GrayShade::White, 0b00 => GrayShade::White,
0b01 => GrayShade::LightGray, 0b01 => GrayShade::LightGray,
0b10 => GrayShade::DarkGray, 0b10 => GrayShade::DarkGray,

View File

@ -53,7 +53,7 @@ impl Default for ShiftClock {
impl From<u8> for ShiftClock { impl From<u8> for ShiftClock {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::External, 0b00 => Self::External,
0b01 => Self::Internal, 0b01 => Self::Internal,
_ => unreachable!("{:#04X} is not a valid value for ShiftClock", byte), _ => unreachable!("{:#04X} is not a valid value for ShiftClock", byte),
@ -75,7 +75,7 @@ impl Default for ClockSpeed {
impl From<u8> for ClockSpeed { impl From<u8> for ClockSpeed {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::Normal, 0b00 => Self::Normal,
0b01 => Self::Fast, 0b01 => Self::Fast,
_ => unreachable!("{:#04X} is not a valid value for ClockSpeed", byte), _ => unreachable!("{:#04X} is not a valid value for ClockSpeed", byte),

View File

@ -93,7 +93,7 @@ enum FrequencyType {
impl From<u8> for FrequencyType { impl From<u8> for FrequencyType {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::Counter, 0b00 => Self::Counter,
0b01 => Self::Consecutive, 0b01 => Self::Consecutive,
_ => unreachable!("{:#04X} is not a valid value for FrequencyType"), _ => unreachable!("{:#04X} is not a valid value for FrequencyType"),
@ -191,7 +191,7 @@ enum EnvelopeDirection {
impl From<u8> for EnvelopeDirection { impl From<u8> for EnvelopeDirection {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b01 {
0b00 => Self::Decrease, 0b00 => Self::Decrease,
0b01 => Self::Increase, 0b01 => Self::Increase,
_ => unreachable!("{:#04X} is not a valid value for EnvelopeDirection", byte), _ => unreachable!("{:#04X} is not a valid value for EnvelopeDirection", byte),
@ -259,7 +259,7 @@ impl From<WavePattern> for u8 {
impl From<u8> for WavePattern { impl From<u8> for WavePattern {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b11 {
0b00 => Self::OneEighth, 0b00 => Self::OneEighth,
0b01 => Self::OneQuarter, 0b01 => Self::OneQuarter,
0b10 => Self::OneHalf, 0b10 => Self::OneHalf,

View File

@ -84,7 +84,7 @@ pub enum TimerSpeed {
impl From<u8> for TimerSpeed { impl From<u8> for TimerSpeed {
fn from(byte: u8) -> Self { fn from(byte: u8) -> Self {
match byte { match byte & 0b11 {
0b00 => Self::Hz4096, 0b00 => Self::Hz4096,
0b01 => Self::Hz262144, 0b01 => Self::Hz262144,
0b10 => Self::Hz65536, 0b10 => Self::Hz65536,