From af8c6c35f1fc8035df1a0274ac403c429fbe7e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Freitas?= Date: Fri, 26 Jul 2024 16:59:45 +0100 Subject: [PATCH] Simplify public exports from memory --- fpt/src/memory/lib.rs | 277 -------------------------------- fpt/src/memory/mbc3.rs | 3 +- fpt/src/memory/mbc_builder.rs | 4 +- fpt/src/memory/mod.rs | 286 +++++++++++++++++++++++++++++++++- 4 files changed, 283 insertions(+), 287 deletions(-) delete mode 100644 fpt/src/memory/lib.rs diff --git a/fpt/src/memory/lib.rs b/fpt/src/memory/lib.rs deleted file mode 100644 index 7de0e20..0000000 --- a/fpt/src/memory/lib.rs +++ /dev/null @@ -1,277 +0,0 @@ -use std::cell::{Ref, RefCell, RefMut}; -use std::ops::Range; -use std::rc::Rc; - -use crate::bw; -use crate::memory::map; -use crate::memory::{create_empty_mbc, create_mbc, Cartridge}; - -pub type Address = usize; -pub type MemoryRange = Range
; - -pub struct Memory { - mem: Vec, - pub bootrom_loaded: bool, - pub cartridge: Box>, - bootrom: &'static [u8; 256], - code_listing: Vec>, - pub buttons: Buttons, -} - -#[derive(Clone, Copy, Default, Debug)] -pub struct Buttons { - pub a: bool, - pub b: bool, - pub start: bool, - pub select: bool, - pub up: bool, - pub right: bool, - pub down: bool, - pub left: bool, -} - -impl PartialEq for Memory { - fn eq(&self, other: &Self) -> bool { - self.slice(map::WRAM) == other.slice(map::WRAM) - } -} - -impl Default for Memory { - fn default() -> Self { - Self::new() - } -} - -impl Memory { - pub fn new() -> Self { - const ARRAY_REPEAT_VALUE: Option = None; - Self { - mem: vec![0; 65536], - bootrom_loaded: false, - cartridge: create_empty_mbc(), - bootrom: include_bytes!("../../dmg.bin"), - code_listing: vec![ARRAY_REPEAT_VALUE; 0xffff + 1], - buttons: Buttons::default(), - } - } - - fn array_ref(&self, from: Address) -> &[u8; N] { - self.mem[from..from + N].try_into().unwrap() // guaranteed to have size N - } - - pub fn slice(&self, range: MemoryRange) -> &[u8] { - &self.mem[range] - } - - pub fn slice_mut(&mut self, range: MemoryRange) -> &mut [u8] { - &mut self.mem[range] - } - - pub fn code_listing(&self) -> &[Option] { - &self.code_listing - } - - pub fn set_code_listing_at(&mut self, pc: u16, v: String) { - self.code_listing[pc as usize] = Some(v); - } -} - -#[derive(Clone, PartialEq)] -pub struct Bus(Rc>); - -impl Bus { - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Bus(Rc::new(RefCell::new(Memory::new()))) - } - - pub fn memory(&self) -> Ref { - self.0.borrow() - } - - pub fn memory_mut(&self) -> RefMut { - self.0.borrow_mut() - } - - pub fn load_bootrom(&mut self) { - self.memory_mut().bootrom_loaded = true; - } - - pub fn unload_bootrom(&mut self) { - self.memory_mut().bootrom_loaded = false; - } - - pub fn load_rom(&mut self, rom: &[u8]) { - self.memory_mut().cartridge = - create_mbc(rom).expect("Given rom cannot be interpreted as a valid cartridge type"); - } - - pub fn read(&self, address: Address) -> u8 { - if map::BOOTROM.contains(&address) && self.memory().bootrom_loaded { - self.memory().bootrom[address] - } else if map::ROM_BANK0.contains(&address) - || map::ROM_BANK1.contains(&address) - || map::EXT_WRAM.contains(&address) - { - self.memory().cartridge.borrow().read(address) - } else if address == map::JOYP { - self.joyp() - } else if map::IO_REGISTERS.contains(&address) - || map::VRAM.contains(&address) - || map::HRAM.contains(&address) - || map::WRAM.contains(&address) - || map::NOT_USABLE2.contains(&address) - || map::OAM.contains(&address) - || address == map::IE - { - self.memory().mem[address as Address] - } else if map::NOT_USABLE1.contains(&address) { - self.memory().mem[(address - 0x2000) as Address] - } else { - panic!(); - } - } - - pub fn write(&mut self, address: Address, value: u8) { - if map::ROM_BANK0.contains(&address) - || map::ROM_BANK1.contains(&address) - || map::EXT_WRAM.contains(&address) - { - self.memory_mut() - .cartridge - .borrow_mut() - .write(address, value); - } else if map::IO_REGISTERS.contains(&address) - || map::VRAM.contains(&address) - || map::HRAM.contains(&address) - || map::WRAM.contains(&address) - || map::NOT_USABLE2.contains(&address) - || map::OAM.contains(&address) - || address == map::IE - { - self.memory_mut().mem[address as Address] = value; - } else if map::NOT_USABLE1.contains(&address) { - self.memory_mut().mem[address - 0x2000 as Address] = value; - } else { - panic!(); - } - } - - pub fn clone_from_slice(&mut self, range: MemoryRange, slice: &[u8]) { - self.memory_mut().mem[range.start..range.end].clone_from_slice(slice); - } - - pub fn copy_range(&self, range: MemoryRange) -> Vec { - self.memory_mut().mem[range.start..range.end].to_vec() - } - - pub fn with_slice(&self, range: MemoryRange, reader: impl FnOnce(&[u8]) -> T) -> T { - reader(&self.memory().mem[range]) - } - - /// Runs closure `reader` with access to a fixed-size slice of `N` bytes. - pub fn with_span( - &self, - start: Address, - reader: impl FnOnce(&[u8; N]) -> T, - ) -> T { - reader(self.memory().array_ref(start)) - } - - // registers - pub fn lcdc(&self) -> u8 { - self.read(map::LCDC) - } - - pub fn set_lcdc(&mut self, value: u8) { - self.write(map::LCDC, value); - } - - pub fn stat(&self) -> u8 { - self.read(map::STAT) - } - - pub fn set_stat(&mut self, value: u8) { - self.write(map::STAT, value); - } - - pub fn scy(&self) -> u8 { - self.read(map::SCY) - } - - pub fn set_scy(&mut self, value: u8) { - self.write(map::SCY, value); - } - - pub fn scx(&self) -> u8 { - self.read(map::SCX) - } - - pub fn set_scx(&mut self, value: u8) { - self.write(map::SCX, value); - } - - pub fn ly(&self) -> u8 { - self.read(map::LY) - } - - pub fn set_ly(&mut self, value: u8) { - self.write(map::LY, value); - } - - pub fn lyc(&self) -> u8 { - self.read(map::LYC) - } - - pub fn set_lyc(&mut self, value: u8) { - self.write(map::LYC, value) - } - - pub fn with_vram(&self, reader: impl FnOnce(&[u8]) -> R) -> R { - reader(&self.memory().mem[map::VRAM]) - } - - fn joyp(&self) -> u8 { - let buttons = self.buttons(); - let joyp = self.memory().mem[map::JOYP]; - let sel_buttons = !bw::test_bit8::<5>(joyp); - let sel_dpad = !bw::test_bit8::<4>(joyp); - let b = if sel_dpad && sel_buttons { - 0 - } else if sel_dpad { - ((buttons.down as u8) << 3) - + ((buttons.up as u8) << 2) - + ((buttons.left as u8) << 1) - + (buttons.right as u8) - } else if sel_buttons { - ((buttons.start as u8) << 3) - + ((buttons.select as u8) << 2) - + ((buttons.b as u8) << 1) - + (buttons.a as u8) - } else { - 0 - }; - // Setting higher 2 bits (which are ignored) to 1 just because SameBoy does it too - ((joyp & 0xf0) + (!b & 0x0f)) | 0b1100_0000 - } - - pub fn buttons(&self) -> Buttons { - self.memory().buttons - } - - pub fn set_buttons(&mut self, buttons: &Buttons) { - self.memory_mut().buttons = *buttons; - } - - pub fn ie(&self) -> u8 { - self.read(map::IE) - } - - pub fn iflag(&self) -> u8 { - self.read(map::IF) - } - - pub fn set_iflag(&mut self, value: u8) { - self.write(map::IF, value) - } -} diff --git a/fpt/src/memory/mbc3.rs b/fpt/src/memory/mbc3.rs index c7e6f58..a2f4c71 100644 --- a/fpt/src/memory/mbc3.rs +++ b/fpt/src/memory/mbc3.rs @@ -1,5 +1,6 @@ +use super::cartridge::Cartridge; use super::cartridge::{convert_ram_size, convert_rom_size, get_ram_size, get_rom_size}; -use super::{map, Address, Cartridge, MemoryRange}; +use super::{map, Address, MemoryRange}; pub struct Mbc3Cartridge { memory: Vec, diff --git a/fpt/src/memory/mbc_builder.rs b/fpt/src/memory/mbc_builder.rs index bd4ce80..d7f319b 100644 --- a/fpt/src/memory/mbc_builder.rs +++ b/fpt/src/memory/mbc_builder.rs @@ -1,9 +1,9 @@ use std::cell::RefCell; +use super::cartridge::Cartridge; use super::cartridge::{get_cartridge_type, EmptyCartridge}; -use super::mbc_none::NoMbcCartridge; use super::mbc3::Mbc3Cartridge; -use super::Cartridge; +use super::mbc_none::NoMbcCartridge; pub fn create_mbc(cartridge_data: &[u8]) -> Option>> { // https://gbdev.io/pandocs/The_Cartridge_Header.html#0147--cartridge-type diff --git a/fpt/src/memory/mod.rs b/fpt/src/memory/mod.rs index 78d155d..e95c60a 100644 --- a/fpt/src/memory/mod.rs +++ b/fpt/src/memory/mod.rs @@ -1,12 +1,284 @@ mod cartridge; -mod lib; pub mod map; +mod mbc3; mod mbc_builder; mod mbc_none; -mod mbc3; -pub use cartridge::Cartridge; -pub use lib::{Address, Bus, Buttons, MemoryRange}; -pub use mbc_builder::{create_empty_mbc, create_mbc}; -pub use mbc_none::NoMbcCartridge; -pub use mbc3::Mbc3Cartridge; +use std::cell::{Ref, RefCell, RefMut}; +use std::ops::Range; +use std::rc::Rc; + +use cartridge::Cartridge; +use mbc_builder::{create_empty_mbc, create_mbc}; + +use crate::bw; + +pub type Address = usize; +pub type MemoryRange = Range
; + +pub struct Memory { + mem: Vec, + pub bootrom_loaded: bool, + pub cartridge: Box>, + bootrom: &'static [u8; 256], + code_listing: Vec>, + pub buttons: Buttons, +} + +#[derive(Clone, Copy, Default, Debug)] +pub struct Buttons { + pub a: bool, + pub b: bool, + pub start: bool, + pub select: bool, + pub up: bool, + pub right: bool, + pub down: bool, + pub left: bool, +} + +impl PartialEq for Memory { + fn eq(&self, other: &Self) -> bool { + self.slice(map::WRAM) == other.slice(map::WRAM) + } +} + +impl Default for Memory { + fn default() -> Self { + Self::new() + } +} + +impl Memory { + pub fn new() -> Self { + const ARRAY_REPEAT_VALUE: Option = None; + Self { + mem: vec![0; 65536], + bootrom_loaded: false, + cartridge: create_empty_mbc(), + bootrom: include_bytes!("../../dmg.bin"), + code_listing: vec![ARRAY_REPEAT_VALUE; 0xffff + 1], + buttons: Buttons::default(), + } + } + + fn array_ref(&self, from: Address) -> &[u8; N] { + self.mem[from..from + N].try_into().unwrap() // guaranteed to have size N + } + + pub fn slice(&self, range: MemoryRange) -> &[u8] { + &self.mem[range] + } + + pub fn slice_mut(&mut self, range: MemoryRange) -> &mut [u8] { + &mut self.mem[range] + } + + pub fn code_listing(&self) -> &[Option] { + &self.code_listing + } + + pub fn set_code_listing_at(&mut self, pc: u16, v: String) { + self.code_listing[pc as usize] = Some(v); + } +} + +#[derive(Clone, PartialEq)] +pub struct Bus(Rc>); + +impl Bus { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Bus(Rc::new(RefCell::new(Memory::new()))) + } + + pub fn memory(&self) -> Ref { + self.0.borrow() + } + + pub fn memory_mut(&self) -> RefMut { + self.0.borrow_mut() + } + + pub fn load_bootrom(&mut self) { + self.memory_mut().bootrom_loaded = true; + } + + pub fn unload_bootrom(&mut self) { + self.memory_mut().bootrom_loaded = false; + } + + pub fn load_rom(&mut self, rom: &[u8]) { + self.memory_mut().cartridge = + create_mbc(rom).expect("Given rom cannot be interpreted as a valid cartridge type"); + } + + pub fn read(&self, address: Address) -> u8 { + if map::BOOTROM.contains(&address) && self.memory().bootrom_loaded { + self.memory().bootrom[address] + } else if map::ROM_BANK0.contains(&address) + || map::ROM_BANK1.contains(&address) + || map::EXT_WRAM.contains(&address) + { + self.memory().cartridge.borrow().read(address) + } else if address == map::JOYP { + self.joyp() + } else if map::IO_REGISTERS.contains(&address) + || map::VRAM.contains(&address) + || map::HRAM.contains(&address) + || map::WRAM.contains(&address) + || map::NOT_USABLE2.contains(&address) + || map::OAM.contains(&address) + || address == map::IE + { + self.memory().mem[address as Address] + } else if map::NOT_USABLE1.contains(&address) { + self.memory().mem[(address - 0x2000) as Address] + } else { + panic!(); + } + } + + pub fn write(&mut self, address: Address, value: u8) { + if map::ROM_BANK0.contains(&address) + || map::ROM_BANK1.contains(&address) + || map::EXT_WRAM.contains(&address) + { + self.memory_mut() + .cartridge + .borrow_mut() + .write(address, value); + } else if map::IO_REGISTERS.contains(&address) + || map::VRAM.contains(&address) + || map::HRAM.contains(&address) + || map::WRAM.contains(&address) + || map::NOT_USABLE2.contains(&address) + || map::OAM.contains(&address) + || address == map::IE + { + self.memory_mut().mem[address as Address] = value; + } else if map::NOT_USABLE1.contains(&address) { + self.memory_mut().mem[address - 0x2000 as Address] = value; + } else { + panic!(); + } + } + + pub fn clone_from_slice(&mut self, range: MemoryRange, slice: &[u8]) { + self.memory_mut().mem[range.start..range.end].clone_from_slice(slice); + } + + pub fn copy_range(&self, range: MemoryRange) -> Vec { + self.memory_mut().mem[range.start..range.end].to_vec() + } + + pub fn with_slice(&self, range: MemoryRange, reader: impl FnOnce(&[u8]) -> T) -> T { + reader(&self.memory().mem[range]) + } + + /// Runs closure `reader` with access to a fixed-size slice of `N` bytes. + pub fn with_span( + &self, + start: Address, + reader: impl FnOnce(&[u8; N]) -> T, + ) -> T { + reader(self.memory().array_ref(start)) + } + + // registers + pub fn lcdc(&self) -> u8 { + self.read(map::LCDC) + } + + pub fn set_lcdc(&mut self, value: u8) { + self.write(map::LCDC, value); + } + + pub fn stat(&self) -> u8 { + self.read(map::STAT) + } + + pub fn set_stat(&mut self, value: u8) { + self.write(map::STAT, value); + } + + pub fn scy(&self) -> u8 { + self.read(map::SCY) + } + + pub fn set_scy(&mut self, value: u8) { + self.write(map::SCY, value); + } + + pub fn scx(&self) -> u8 { + self.read(map::SCX) + } + + pub fn set_scx(&mut self, value: u8) { + self.write(map::SCX, value); + } + + pub fn ly(&self) -> u8 { + self.read(map::LY) + } + + pub fn set_ly(&mut self, value: u8) { + self.write(map::LY, value); + } + + pub fn lyc(&self) -> u8 { + self.read(map::LYC) + } + + pub fn set_lyc(&mut self, value: u8) { + self.write(map::LYC, value) + } + + pub fn with_vram(&self, reader: impl FnOnce(&[u8]) -> R) -> R { + reader(&self.memory().mem[map::VRAM]) + } + + fn joyp(&self) -> u8 { + let buttons = self.buttons(); + let joyp = self.memory().mem[map::JOYP]; + let sel_buttons = !bw::test_bit8::<5>(joyp); + let sel_dpad = !bw::test_bit8::<4>(joyp); + let b = if sel_dpad && sel_buttons { + 0 + } else if sel_dpad { + ((buttons.down as u8) << 3) + + ((buttons.up as u8) << 2) + + ((buttons.left as u8) << 1) + + (buttons.right as u8) + } else if sel_buttons { + ((buttons.start as u8) << 3) + + ((buttons.select as u8) << 2) + + ((buttons.b as u8) << 1) + + (buttons.a as u8) + } else { + 0 + }; + // Setting higher 2 bits (which are ignored) to 1 just because SameBoy does it too + ((joyp & 0xf0) + (!b & 0x0f)) | 0b1100_0000 + } + + pub fn buttons(&self) -> Buttons { + self.memory().buttons + } + + pub fn set_buttons(&mut self, buttons: &Buttons) { + self.memory_mut().buttons = *buttons; + } + + pub fn ie(&self) -> u8 { + self.read(map::IE) + } + + pub fn iflag(&self) -> u8 { + self.read(map::IF) + } + + pub fn set_iflag(&mut self, value: u8) { + self.write(map::IF, value) + } +}