2020-01-26 00:06:44 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2019-07-15 05:30:52 +01:00
|
|
|
|
2020-01-31 12:24:41 +00:00
|
|
|
use super::{Addr, Bus};
|
2019-08-07 07:50:33 +01:00
|
|
|
|
2020-01-31 12:24:41 +00:00
|
|
|
mod header;
|
|
|
|
use header::CartridgeHeader;
|
2020-01-26 00:06:44 +00:00
|
|
|
|
2020-01-31 12:24:41 +00:00
|
|
|
mod backup;
|
|
|
|
use backup::eeprom::SpiController;
|
|
|
|
use backup::flash::Flash;
|
|
|
|
use backup::{BackupFile, BackupMemoryInterface};
|
2019-07-02 23:40:08 +01:00
|
|
|
|
2020-01-31 12:24:41 +00:00
|
|
|
mod builder;
|
|
|
|
pub use builder::GamepakBuilder;
|
2019-07-02 23:40:08 +01:00
|
|
|
|
2020-01-26 00:06:44 +00:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
|
|
|
pub enum BackupMedia {
|
2020-01-31 12:24:41 +00:00
|
|
|
Sram(BackupFile),
|
2020-01-26 00:16:54 +00:00
|
|
|
Flash(Flash),
|
2020-01-31 12:24:41 +00:00
|
|
|
Eeprom(SpiController<BackupFile>),
|
2020-01-26 00:06:44 +00:00
|
|
|
Undetected,
|
|
|
|
}
|
|
|
|
|
2020-01-16 18:06:22 +00:00
|
|
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
2019-07-02 23:40:08 +01:00
|
|
|
pub struct Cartridge {
|
|
|
|
pub header: CartridgeHeader,
|
|
|
|
bytes: Box<[u8]>,
|
2020-01-16 23:39:25 +00:00
|
|
|
size: usize,
|
2020-01-31 10:41:13 +00:00
|
|
|
pub(in crate) backup: BackupMedia,
|
2019-07-02 23:40:08 +01:00
|
|
|
}
|
|
|
|
|
2020-01-28 08:25:52 +00:00
|
|
|
use super::sysbus::consts::*;
|
|
|
|
|
2020-01-31 10:41:13 +00:00
|
|
|
pub const EEPROM_BASE_ADDR: u32 = 0x0DFF_FF00;
|
2020-01-26 00:06:44 +00:00
|
|
|
|
2019-07-02 23:40:08 +01:00
|
|
|
impl Bus for Cartridge {
|
2019-07-15 05:30:52 +01:00
|
|
|
fn read_8(&self, addr: Addr) -> u8 {
|
2020-01-26 00:06:44 +00:00
|
|
|
let offset = (addr & 0x01ff_ffff) as usize;
|
|
|
|
match addr & 0xff000000 {
|
|
|
|
SRAM_LO | SRAM_HI => match &self.backup {
|
|
|
|
BackupMedia::Sram(memory) => memory.read((addr & 0x7FFF) as usize),
|
2020-01-26 00:16:54 +00:00
|
|
|
BackupMedia::Flash(flash) => flash.read(addr),
|
2020-01-26 00:06:44 +00:00
|
|
|
_ => 0,
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
if offset >= self.size {
|
|
|
|
0xDD // TODO - open bus implementation
|
|
|
|
} else {
|
|
|
|
self.bytes[offset as usize]
|
|
|
|
}
|
|
|
|
}
|
2020-01-16 23:39:25 +00:00
|
|
|
}
|
2019-07-15 05:30:52 +01:00
|
|
|
}
|
|
|
|
|
2020-01-28 08:25:52 +00:00
|
|
|
fn read_16(&self, addr: u32) -> u16 {
|
2020-01-31 10:41:13 +00:00
|
|
|
if addr & 0xff000000 == GAMEPAK_WS2_HI
|
|
|
|
&& (self.bytes.len() <= 16 * 1024 * 1024 || addr >= EEPROM_BASE_ADDR)
|
|
|
|
{
|
2020-01-28 08:25:52 +00:00
|
|
|
if let BackupMedia::Eeprom(spi) = &self.backup {
|
2020-01-31 10:41:13 +00:00
|
|
|
return spi.read_half(addr);
|
2020-01-28 08:25:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
self.default_read_16(addr)
|
|
|
|
}
|
|
|
|
|
2020-01-26 00:06:44 +00:00
|
|
|
fn write_8(&mut self, addr: u32, value: u8) {
|
|
|
|
match addr & 0xff000000 {
|
|
|
|
SRAM_LO | SRAM_HI => match &mut self.backup {
|
2020-01-26 00:16:54 +00:00
|
|
|
BackupMedia::Flash(flash) => flash.write(addr, value),
|
2020-01-26 00:06:44 +00:00
|
|
|
BackupMedia::Sram(memory) => memory.write((addr & 0x7FFF) as usize, value),
|
|
|
|
_ => {}
|
|
|
|
},
|
2020-01-31 10:41:13 +00:00
|
|
|
_ => {} // TODO allow the debugger to write
|
2020-01-26 00:06:44 +00:00
|
|
|
};
|
2019-07-15 05:30:52 +01:00
|
|
|
}
|
2020-01-28 08:25:52 +00:00
|
|
|
|
|
|
|
fn write_16(&mut self, addr: u32, value: u16) {
|
2020-01-31 10:41:13 +00:00
|
|
|
if addr & 0xff000000 == GAMEPAK_WS2_HI
|
|
|
|
&& (self.bytes.len() <= 16 * 1024 * 1024 || addr >= EEPROM_BASE_ADDR)
|
|
|
|
{
|
2020-01-28 08:25:52 +00:00
|
|
|
if let BackupMedia::Eeprom(spi) = &mut self.backup {
|
2020-01-31 10:41:13 +00:00
|
|
|
return spi.write_half(addr, value);
|
2020-01-28 08:25:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
self.default_write_16(addr, value);
|
|
|
|
}
|
2019-07-02 23:40:08 +01:00
|
|
|
}
|