diff --git a/rustboyadvance-core/src/cartridge/builder.rs b/rustboyadvance-core/src/cartridge/builder.rs index 3e9f87f..c9e4d1b 100644 --- a/rustboyadvance-core/src/cartridge/builder.rs +++ b/rustboyadvance-core/src/cartridge/builder.rs @@ -7,6 +7,7 @@ use super::super::{GBAError, GBAResult}; use super::backup::eeprom::*; use super::backup::flash::*; use super::backup::{BackupFile, BackupType}; +use super::gpio::Gpio; use super::header; use super::BackupMedia; use super::Cartridge; @@ -126,9 +127,12 @@ impl GamepakBuilder { let backup = create_backup(self.save_type, self.save_path); + let gpio = Gpio::new(); + let size = bytes.len(); Ok(Cartridge { header: header, + gpio: gpio, bytes: bytes.into_boxed_slice(), size: size, backup: backup, diff --git a/rustboyadvance-core/src/cartridge/gpio.rs b/rustboyadvance-core/src/cartridge/gpio.rs new file mode 100644 index 0000000..a7e1c9e --- /dev/null +++ b/rustboyadvance-core/src/cartridge/gpio.rs @@ -0,0 +1,90 @@ +use super::rtc::Rtc; +use super::{GPIO_PORT_CONTROL, GPIO_PORT_DATA, GPIO_PORT_DIRECTION}; + +use bit::BitIndex; +use serde::{Deserialize, Serialize}; + +use std::cell::RefCell; + +#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)] +enum GpioDirection { + In = 0, + Out = 1, +} + +#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq)] +enum GpioPortControl { + WriteOnly = 0, + ReadWrite = 1, +} + +trait GpioDevice: Sized { + fn write(&mut self); + fn read(&mut self); +} + +enum GpioDeviceType { + Rtc, + SolarSensor, + Gyro, + None, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Gpio { + rtc: Option>, + direction: [GpioDirection; 4], + control: GpioPortControl, +} + +impl Gpio { + pub fn new() -> Self { + Gpio { + rtc: None, + direction: [GpioDirection::In; 4], + control: GpioPortControl::WriteOnly, + } + } + + pub fn is_readable(&self) -> bool { + self.control != GpioPortControl::WriteOnly + } + + pub fn read(&self, addr: u32) -> u16 { + match addr { + GPIO_PORT_DATA => unimplemented!(), + GPIO_PORT_DIRECTION => { + let mut direction = 0u16; + for i in 0..4 { + direction.set_bit(i, self.direction[i] == GpioDirection::Out); + } + direction + } + GPIO_PORT_CONTROL => self.control as u16, + _ => unreachable!(), + } + } + + pub fn write(&mut self, addr: u32) -> u16 { + match addr { + GPIO_PORT_DATA => unimplemented!(), + GPIO_PORT_DIRECTION => { + let mut direction = 0u16; + for i in 0..4 { + direction.set_bit(i, self.direction[i] == GpioDirection::Out); + } + direction + } + GPIO_PORT_CONTROL => self.control as u16, + _ => unreachable!(), + } + } +} + +#[cfg(test)] +mod tests { + #[test] + fn test_gpio() { + unimplemented!(); + } +} diff --git a/rustboyadvance-core/src/cartridge/mod.rs b/rustboyadvance-core/src/cartridge/mod.rs index 5866a2f..4aa1000 100644 --- a/rustboyadvance-core/src/cartridge/mod.rs +++ b/rustboyadvance-core/src/cartridge/mod.rs @@ -13,10 +13,18 @@ use backup::flash::Flash; pub use backup::BackupType; use backup::{BackupFile, BackupMemoryInterface}; +mod gpio; +mod rtc; +use gpio::Gpio; + mod builder; mod loader; pub use builder::GamepakBuilder; +pub const GPIO_PORT_DATA: u32 = 0x0800_00C4; +pub const GPIO_PORT_DIRECTION: u32 = 0x0800_00C6; +pub const GPIO_PORT_CONTROL: u32 = 0x0800_00C8; + #[derive(Serialize, Deserialize, Clone, Debug)] pub enum BackupMedia { Sram(BackupFile), @@ -32,6 +40,7 @@ pub struct Cartridge { pub header: CartridgeHeader, bytes: Box<[u8]>, size: usize, + gpio: Gpio, symbols: Option, // TODO move it somewhere else pub(in crate) backup: BackupMedia, } @@ -46,6 +55,13 @@ use super::sysbus::consts::*; pub const EEPROM_BASE_ADDR: u32 = 0x0DFF_FF00; +fn is_gpio_access(addr: u32) -> bool { + match addr { + GPIO_PORT_DATA | GPIO_PORT_DIRECTION | GPIO_PORT_CONTROL => true, + _ => false, + } +} + impl Bus for Cartridge { fn read_8(&self, addr: Addr) -> u8 { let offset = (addr & 0x01ff_ffff) as usize; @@ -66,6 +82,10 @@ impl Bus for Cartridge { } fn read_16(&self, addr: u32) -> u16 { + if is_gpio_access(addr) && self.gpio.is_readable() { + return self.gpio.read(addr); + } + if addr & 0xff000000 == GAMEPAK_WS2_HI && (self.bytes.len() <= 16 * 1024 * 1024 || addr >= EEPROM_BASE_ADDR) { @@ -88,6 +108,11 @@ impl Bus for Cartridge { } fn write_16(&mut self, addr: u32, value: u16) { + if is_gpio_access(addr) { + self.gpio.write(addr); + return; + } + if addr & 0xff000000 == GAMEPAK_WS2_HI && (self.bytes.len() <= 16 * 1024 * 1024 || addr >= EEPROM_BASE_ADDR) { diff --git a/rustboyadvance-core/src/cartridge/rtc.rs b/rustboyadvance-core/src/cartridge/rtc.rs new file mode 100644 index 0000000..1c71cfd --- /dev/null +++ b/rustboyadvance-core/src/cartridge/rtc.rs @@ -0,0 +1,27 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +enum Port { + #[doc("Serial Clock")] + Sck = 0, + #[doc("Serial IO")] + Sio = 1, + #[doc("Chip Select")] + Cs = 2, +} + +/// Model of the S3511 8pin RTC +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Rtc {} + +impl Rtc { + pub fn new() -> Self { + Rtc {} + } + + pub fn read_port(port: usize) -> u8 { + 0 + } + + pub fn write_port(port: usize) {} +}