Skip to content

Commit 3db1414

Browse files
committed
rom bank mapping
1 parent f8f7131 commit 3db1414

2 files changed

Lines changed: 113 additions & 1 deletion

File tree

src/domain/cartridge.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
use super::rom::{RomHeader, RomHeaderError};
22

33
const ROM_BANK_SIZE: usize = 0x4000;
4+
const ROM_FIXED_START: usize = 0x0000;
5+
const ROM_FIXED_END: usize = 0x3FFF;
6+
const ROM_SWITCH_START: usize = 0x4000;
7+
const ROM_SWITCH_END: usize = 0x7FFF;
8+
const OPEN_BUS: u8 = 0xFF;
49

510
#[derive(Debug, Clone, PartialEq, Eq)]
611
pub struct Cartridge {
@@ -18,6 +23,14 @@ impl Cartridge {
1823
RomBankView::new(&self.bytes)
1924
}
2025

26+
pub fn rom_mapping(&self) -> RomBankMapping<'_> {
27+
RomBankMapping::new(&self.bytes)
28+
}
29+
30+
pub fn read_rom(&self, addr: u16, switchable_bank: usize) -> u8 {
31+
RomBankMapping::with_switchable_bank(&self.bytes, switchable_bank).read(addr)
32+
}
33+
2134
pub fn declared_bank_count(&self) -> Option<usize> {
2235
self.header.rom_size.bank_count()
2336
}
@@ -55,6 +68,64 @@ impl<'a> RomBankView<'a> {
5568
}
5669
}
5770

71+
#[derive(Debug, Clone, Copy)]
72+
pub struct RomBankMapping<'a> {
73+
bytes: &'a [u8],
74+
switchable_bank: usize,
75+
}
76+
77+
impl<'a> RomBankMapping<'a> {
78+
pub fn new(bytes: &'a [u8]) -> Self {
79+
Self {
80+
bytes,
81+
switchable_bank: 1,
82+
}
83+
}
84+
85+
pub fn with_switchable_bank(bytes: &'a [u8], switchable_bank: usize) -> Self {
86+
Self {
87+
bytes,
88+
switchable_bank,
89+
}
90+
}
91+
92+
pub fn switchable_bank(&self) -> usize {
93+
self.switchable_bank
94+
}
95+
96+
pub fn set_switchable_bank(&mut self, bank: usize) {
97+
self.switchable_bank = bank;
98+
}
99+
100+
pub fn read(&self, addr: u16) -> u8 {
101+
let addr = addr as usize;
102+
match addr {
103+
ROM_FIXED_START..=ROM_FIXED_END => self.read_at(addr),
104+
ROM_SWITCH_START..=ROM_SWITCH_END => {
105+
let offset = addr - ROM_SWITCH_START;
106+
self.read_bank(self.switchable_bank, offset)
107+
}
108+
_ => OPEN_BUS,
109+
}
110+
}
111+
112+
fn read_bank(&self, bank: usize, offset: usize) -> u8 {
113+
let base = match bank.checked_mul(ROM_BANK_SIZE) {
114+
Some(base) => base,
115+
None => return OPEN_BUS,
116+
};
117+
let index = match base.checked_add(offset) {
118+
Some(index) => index,
119+
None => return OPEN_BUS,
120+
};
121+
self.read_at(index)
122+
}
123+
124+
fn read_at(&self, index: usize) -> u8 {
125+
self.bytes.get(index).copied().unwrap_or(OPEN_BUS)
126+
}
127+
}
128+
58129
#[cfg(test)]
59130
mod tests {
60131
use super::{Cartridge, ROM_BANK_SIZE};
@@ -81,4 +152,45 @@ mod tests {
81152
assert_eq!(banks.bank(0).expect("bank 0").len(), ROM_BANK_SIZE);
82153
assert_eq!(banks.bank(1).expect("bank 1").len(), 1);
83154
}
155+
156+
#[test]
157+
fn rom_mapping_reads_fixed_and_switchable_banks() {
158+
let mut bytes = vec![0; ROM_BANK_SIZE * 2];
159+
bytes[..ROM_BANK_SIZE].fill(0xAA);
160+
bytes[ROM_BANK_SIZE..].fill(0xBB);
161+
162+
let cart = Cartridge::from_bytes(bytes).expect("cartridge");
163+
let mapping = cart.rom_mapping();
164+
165+
assert_eq!(mapping.read(0x0000), 0xAA);
166+
assert_eq!(mapping.read(0x3FFF), 0xAA);
167+
assert_eq!(mapping.read(0x4000), 0xBB);
168+
assert_eq!(mapping.read(0x7FFF), 0xBB);
169+
}
170+
171+
#[test]
172+
fn rom_mapping_switches_banks() {
173+
let mut bytes = vec![0; ROM_BANK_SIZE * 3];
174+
bytes[..ROM_BANK_SIZE].fill(0x11);
175+
bytes[ROM_BANK_SIZE..ROM_BANK_SIZE * 2].fill(0x22);
176+
bytes[ROM_BANK_SIZE * 2..].fill(0x33);
177+
178+
let cart = Cartridge::from_bytes(bytes).expect("cartridge");
179+
let mut mapping = cart.rom_mapping();
180+
181+
mapping.set_switchable_bank(2);
182+
assert_eq!(mapping.read(0x4000), 0x33);
183+
184+
mapping.set_switchable_bank(0);
185+
assert_eq!(mapping.read(0x4000), 0x11);
186+
}
187+
188+
#[test]
189+
fn rom_mapping_returns_open_bus_for_unmapped_addrs() {
190+
let bytes = vec![0; ROM_BANK_SIZE];
191+
let cart = Cartridge::from_bytes(bytes).expect("cartridge");
192+
let mapping = cart.rom_mapping();
193+
194+
assert_eq!(mapping.read(0x8000), 0xFF);
195+
}
84196
}

src/domain/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ pub mod cartridge;
22
pub mod emulator;
33
pub mod rom;
44

5-
pub use cartridge::{Cartridge, RomBankView};
5+
pub use cartridge::{Cartridge, RomBankMapping, RomBankView};
66
pub use emulator::Emulator;
77
pub use rom::{
88
CartridgeType, CgbFlag, Destination, Licensee, RamSize, RomHeader, RomHeaderError, RomSize,

0 commit comments

Comments
 (0)