1- use std:: { convert:: TryInto , io:: Read } ;
1+ use std:: { convert:: TryInto , fmt :: Write , io:: Read } ;
22
33use crate :: save_state:: { LoadStateError , SaveState , SaveStateContext } ;
44
@@ -8,6 +8,31 @@ const NINTENDOO_LOGO: [u8; 48] = [
88 0xBB , 0xBB , 0x67 , 0x63 , 0x6E , 0x0E , 0xEC , 0xCC , 0xDD , 0xDC , 0x99 , 0x9F , 0xBB , 0xB9 , 0x33 , 0x3E ,
99] ;
1010
11+ // The size of the ROM in bytes, for each type of ROM size.
12+ const ROM_SIZES : & [ usize ] = & [
13+ 2 * 0x4000 , // no ROM Banking
14+ 4 * 0x4000 ,
15+ 8 * 0x4000 ,
16+ 16 * 0x4000 ,
17+ 32 * 0x4000 ,
18+ 64 * 0x4000 ,
19+ 128 * 0x4000 ,
20+ 256 * 0x4000 ,
21+ 512 * 0x4000 ,
22+ // 72 * 0x2000,
23+ // 80 * 0x2000,
24+ // 96 * 0x2000,
25+ ] ;
26+
27+ const RAM_SIZES : & [ usize ] = & [
28+ 0 ,
29+ 0x800 ,
30+ 0x2000 , // Single Bank
31+ 4 * 0x2000 ,
32+ 16 * 0x2000 ,
33+ 8 * 0x2000 ,
34+ ] ;
35+
1136fn mbc_type_name ( code : u8 ) -> & ' static str {
1237 match code {
1338 0x00 => "ROM ONLY" ,
@@ -114,27 +139,9 @@ impl CartridgeHeader {
114139 self . logo [ ..0x18 ] == NINTENDOO_LOGO [ ..0x18 ]
115140 }
116141
117- pub fn rom_size_in_bytes ( & self ) -> Result < usize , String > {
118- let rom_sizes = [
119- 2 * 0x4000 , // no ROM Banking
120- 4 * 0x4000 ,
121- 8 * 0x4000 ,
122- 16 * 0x4000 ,
123- 32 * 0x4000 ,
124- 64 * 0x4000 ,
125- 128 * 0x4000 ,
126- 256 * 0x4000 ,
127- 512 * 0x4000 ,
128- // 72 * 0x2000,
129- // 80 * 0x2000,
130- // 96 * 0x2000,
131- ] ;
142+ pub fn rom_size_in_bytes ( & self ) -> Option < usize > {
132143 let rom_size_type = self . rom_size ;
133- let rom_size = rom_sizes
134- . get ( rom_size_type as usize )
135- . copied ( )
136- . ok_or_else ( || format ! ( "Rom size '{:02x}' is no supported" , rom_size_type) ) ?;
137- Ok ( rom_size)
144+ ROM_SIZES . get ( rom_size_type as usize ) . copied ( )
138145 }
139146
140147 pub fn title_as_string ( & self ) -> String {
@@ -170,6 +177,21 @@ pub struct Cartridge {
170177 pub ram : Vec < u8 > ,
171178 mbc : Mbc ,
172179}
180+
181+ impl std:: fmt:: Debug for Cartridge {
182+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
183+ f. debug_struct ( "Cartridge" )
184+ // .field("header", &self.header)
185+ . field ( "lower_bank" , & self . lower_bank )
186+ . field ( "upper_bank" , & self . upper_bank )
187+ . field ( "rom.len()" , & self . rom . len ( ) )
188+ . field ( "ram.len()" , & self . ram . len ( ) )
189+ // .field("mbc", &self.mbc)
190+ . field ( "kind_name" , & self . kind_name ( ) )
191+ . finish ( )
192+ }
193+ }
194+
173195impl SaveState for Cartridge {
174196 fn save_state (
175197 & self ,
@@ -208,21 +230,49 @@ impl SaveState for Cartridge {
208230 }
209231}
210232impl Cartridge {
211- pub fn new ( rom : Vec < u8 > ) -> Result < Self , String > {
233+ /// Create a new cartridge from the given ROM. If the ROM is invalid, return the a error
234+ /// message and a deduced cartridge, if possible.
235+ #[ allow( clippy:: result_large_err) ]
236+ pub fn new ( mut rom : Vec < u8 > ) -> Result < Self , ( String , Option < Self > ) > {
237+ let mut error = String :: new ( ) ;
238+
212239 let header = match CartridgeHeader :: from_bytes ( & rom) {
213- Ok ( x) | Err ( ( Some ( x) , _) ) => x,
214- Err ( ( None , err) ) => return Err ( err) ,
240+ Ok ( x) => x,
241+ Err ( ( Some ( x) , err) ) => {
242+ writeln ! ( & mut error, "{}" , err) . unwrap ( ) ;
243+ x
244+ }
245+ Err ( ( None , err) ) => return Err ( ( err, None ) ) ,
215246 } ;
216247
217- let rom_size = header. rom_size_in_bytes ( ) ?;
218-
219- if rom_size != rom. len ( ) {
220- return Err ( format ! (
221- "In the rom header the expected size is '{}' bytes, but the given rom has '{}' bytes" ,
222- rom_size,
223- rom. len( )
224- ) ) ;
225- }
248+ let rom_size = header
249+ . rom_size_in_bytes ( )
250+ . ok_or_else ( || format ! ( "Rom size type '{:02x}' is not supported" , header. rom_size) ) ;
251+
252+ match rom_size {
253+ Ok ( rom_size) if rom_size != rom. len ( ) => {
254+ let size = * ROM_SIZES . iter ( ) . find ( |& & x| x >= rom. len ( ) ) . unwrap ( ) ;
255+ writeln ! (
256+ & mut error,
257+ "The ROM header expected rom size as '{}' bytes, but the given rom has '{}' bytes. Deducing size from ROM size as {}." ,
258+ rom_size,
259+ rom. len( ) ,
260+ size,
261+ ) . unwrap ( ) ;
262+ rom. resize ( size, 0 ) ;
263+ }
264+ Ok ( _) => { }
265+ Err ( err) => {
266+ let size = * ROM_SIZES . iter ( ) . find ( |& & x| x >= rom. len ( ) ) . unwrap ( ) ;
267+ writeln ! (
268+ & mut error,
269+ "{}, deducing size from ROM size as {}" ,
270+ err, size,
271+ )
272+ . unwrap ( ) ;
273+ rom. resize ( size, 0 ) ;
274+ }
275+ } ;
226276
227277 // Cartridge Type
228278 let mbc_kind = header. cartridge_type ;
@@ -252,44 +302,57 @@ impl Cartridge {
252302 0x0F ..=0x13 => Mbc :: Mbc3 ( Mbc3 :: new ( ) ) ,
253303 0x19 ..=0x1E => Mbc :: Mbc5 ( Mbc5 :: new ( ) ) ,
254304 _ => {
255- return Err ( format ! (
305+ writeln ! (
306+ & mut error,
256307 "MBC type '{}' ({:02x}) is not supported" ,
257308 mbc_type_name( mbc_kind) ,
258309 mbc_kind
259- ) )
310+ )
311+ . unwrap ( ) ;
312+ return Err ( ( error, None ) ) ;
260313 }
261314 } ;
262315
263- let ram_sizes = [
264- 0 ,
265- 0x800 ,
266- 0x2000 , // Single Bank
267- 4 * 0x2000 ,
268- 16 * 0x2000 ,
269- 8 * 0x2000 ,
270- ] ;
271316 let ram_size_type = header. ram_size ;
272317
273318 let ram_size = if let Mbc :: Mbc2 ( _) = mbc {
274319 if ram_size_type != 0 {
275- return Err ( format ! ( "Cartridge use MBC2, with a integrated ram (type '00'), but report the ram type '{:02x}'" , ram_size_type) ) ;
320+ writeln ! (
321+ & mut error,
322+ "Cartridge use MBC2, with a integrated ram (type '00'), but report the ram type '{:02x}'" ,
323+ ram_size_type,
324+ ) . unwrap ( ) ;
276325 }
277326 0x200
278327 } else {
279- ram_sizes
280- . get ( ram_size_type as usize )
281- . copied ( )
282- . ok_or_else ( || format ! ( "Ram size '{:02x}' is no supported" , ram_size_type) ) ?
328+ match RAM_SIZES . get ( ram_size_type as usize ) . copied ( ) {
329+ Some ( x) => x,
330+ None => {
331+ writeln ! (
332+ & mut error,
333+ "Ram size type '{:02x}' is not supported, using RAM size as 0x2000" ,
334+ ram_size_type,
335+ )
336+ . unwrap ( ) ;
337+ 0x2000
338+ }
339+ }
283340 } ;
284341
285- Ok ( Self {
342+ let cartridge = Self {
286343 header,
287344 lower_bank : 0 ,
288345 upper_bank : 1 ,
289346 rom,
290347 ram : vec ! [ 0 ; ram_size] ,
291348 mbc,
292- } )
349+ } ;
350+
351+ if !error. is_empty ( ) {
352+ return Err ( ( error, Some ( cartridge) ) ) ;
353+ }
354+
355+ Ok ( cartridge)
293356 }
294357
295358 /// A Cartridge filled with HALT instructions. Used as a test cartridge, when the CPU does not
0 commit comments