1use crate::memory; 2 3const BACKUP_RAM_LEN: usize = memory::BACKUP_RAM_LEN; 4const RAM_CARTRIDGE_LEN: usize = memory::RAM_CARTRIDGE_LEN; 5 6const BACKUP_RAM_FOOTER_LEN: usize = 64; 7 8#[rustfmt::skip] 9const BACKUP_RAM_FOOTER: [u8; BACKUP_RAM_FOOTER_LEN] = [ 10 // $1FC0-$1FCF 11 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x40, 12 // $1FD0-$1FDF 13 0x00, 0x7D, 0x00, 0x7D, 0x00, 0x7D, 0x00, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 14 // $1FE0-$1FEF 15 0x53, 0x45, 0x47, 0x41, 0x5F, 0x43, 0x44, 0x5F, 0x52, 0x4F, 0x4D, 0x00, 0x01, 0x00, 0x00, 0x00, 16 // $1FF0-$1FFF 17 0x52, 0x41, 0x4D, 0x5F, 0x43, 0x41, 0x52, 0x54, 0x52, 0x49, 0x44, 0x47, 0x45, 0x5F, 0x5F, 0x5F, 18]; 19 20#[rustfmt::skip] 21const RAM_CARTRIDGE_FOOTER: [u8; BACKUP_RAM_FOOTER_LEN] = [ 22 // $1FFC0-$1FFCF 23 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x40, 24 // $1FFD0-$1FFDF 25 0x07, 0xFD, 0x07, 0xFD, 0x07, 0xFD, 0x07, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 26 // $1FFE0-$1FFEF 27 0x53, 0x45, 0x47, 0x41, 0x5F, 0x43, 0x44, 0x5F, 0x52, 0x4F, 0x4D, 0x00, 0x01, 0x00, 0x00, 0x00, 28 // $1FFF0-$1FFFF 29 0x52, 0x41, 0x4D, 0x5F, 0x43, 0x41, 0x52, 0x54, 0x52, 0x49, 0x44, 0x47, 0x45, 0x5F, 0x5F, 0x5F, 30]; 31 32// Boxing is desired because these boxed arrays will be large (8KB / 128KB) 33#[allow(clippy::unnecessary_box_returns)] 34fn new_formatted_backup_ram<const LEN: usize>( 35 footer: &[u8; BACKUP_RAM_FOOTER_LEN], 36) -> Box<[u8; LEN]> { 37 // If no backup RAM was provided during construction, initialize it pre-formatted. 38 // Some games (Popful Mail) blow up horribly if backup RAM is not formatted, so it's more 39 // convenient to initialize it already formatted. 40 let mut backup_ram: Box<[u8; LEN]> = vec![0; LEN].into_boxed_slice().try_into().unwrap(); 41 42 // Most of a freshly-formatted backup RAM is filled with 0s, but the last 64 bytes need to be 43 // filled in 44 backup_ram[LEN - BACKUP_RAM_FOOTER_LEN..].copy_from_slice(footer); 45 46 backup_ram 47} 48 49pub fn load_initial_backup_ram( 50 initial_backup_ram: Option<&Vec<u8>>, 51 initial_ram_cartridge: Option<&Vec<u8>>, 52) -> (Box<[u8; BACKUP_RAM_LEN]>, Box<[u8; RAM_CARTRIDGE_LEN]>) { 53 let backup_ram: Box<[u8; BACKUP_RAM_LEN]> = match initial_backup_ram { 54 Some(backup_ram) if backup_ram.len() == BACKUP_RAM_LEN => { 55 backup_ram.clone().into_boxed_slice().try_into().unwrap() 56 } 57 Some(combined_ram) if combined_ram.len() == BACKUP_RAM_LEN + RAM_CARTRIDGE_LEN => { 58 Vec::from(&combined_ram[..BACKUP_RAM_LEN]).into_boxed_slice().try_into().unwrap() 59 } 60 _ => new_formatted_backup_ram(&BACKUP_RAM_FOOTER), 61 }; 62 63 // Prefer to load RAM cartridge from the initial RAM cartridge data, and fall back to looking for 64 // it at the end of the initial backup RAM data 65 let ram_cartridge: Box<[u8; RAM_CARTRIDGE_LEN]> = 66 match (initial_backup_ram, initial_ram_cartridge) { 67 (_, Some(ram_cartridge)) if ram_cartridge.len() == RAM_CARTRIDGE_LEN => { 68 ram_cartridge.clone().into_boxed_slice().try_into().unwrap() 69 } 70 (Some(combined_ram), _) if combined_ram.len() == BACKUP_RAM_LEN + RAM_CARTRIDGE_LEN => { 71 Vec::from(&combined_ram[BACKUP_RAM_LEN..]).into_boxed_slice().try_into().unwrap() 72 } 73 _ => new_formatted_backup_ram(&RAM_CARTRIDGE_FOOTER), 74 }; 75 76 (backup_ram, ram_cartridge) 77}