11use super :: rom:: { RomHeader , RomHeaderError } ;
22
33const 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 ) ]
611pub 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) ]
59130mod 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}
0 commit comments