1//! GBA internal memory 2 3use crate::api::{GbaEmulatorConfig, GbaLoadError}; 4use bincode::{Decode, Encode}; 5use jgenesis_common::boxedarray::BoxedByteArray; 6use jgenesis_common::debug::{DebugBytesView, DebugMemoryView}; 7use jgenesis_common::num::GetBit; 8use std::array; 9 10const BIOS_ROM_LEN: usize = 16 * 1024; 11const IWRAM_LEN: usize = 32 * 1024; 12const EWRAM_LEN: usize = 256 * 1024; 13 14#[derive(Debug, Clone, Encode, Decode)] 15pub struct MemoryControl { 16 pub sram_cycles: u64, 17 // There are only 3 waitstate areas, but making arrays len 4 avoids a bounds check on access 18 pub cartridge_n_cycles: [u64; 4], 19 pub cartridge_s_cycles: [u64; 4], 20 pub prefetch_enabled: bool, 21 pub raw_value: u16, 22} 23 24impl MemoryControl { 25 const SRAM_CYCLES: [u64; 4] = [5, 4, 3, 9]; 26 const CARTRIDGE_N_CYCLES: [u64; 4] = [5, 4, 3, 9]; 27 const CARTRIDGE_0_S_CYCLES: [u64; 2] = [3, 2]; 28 const CARTRIDGE_1_S_CYCLES: [u64; 2] = [5, 2]; 29 const CARTRIDGE_2_S_CYCLES: [u64; 2] = [9, 2]; 30 31 pub fn new() -> Self { 32 Self { 33 sram_cycles: Self::SRAM_CYCLES[0], 34 cartridge_n_cycles: array::from_fn(|_| Self::CARTRIDGE_N_CYCLES[0]), 35 cartridge_s_cycles: [ 36 Self::CARTRIDGE_0_S_CYCLES[0], 37 Self::CARTRIDGE_1_S_CYCLES[0], 38 Self::CARTRIDGE_2_S_CYCLES[0], 39 0, 40 ], 41 prefetch_enabled: false, 42 raw_value: 0x0000, 43 } 44 } 45 46 pub fn read(&self) -> u16 { 47 self.raw_value 48 } 49 50 pub fn write(&mut self, value: u16) { 51 self.sram_cycles = Self::SRAM_CYCLES[(value & 3) as usize]; 52 self.cartridge_n_cycles[0] = Self::CARTRIDGE_N_CYCLES[((value >> 2) & 3) as usize]; 53 self.cartridge_n_cycles[1] = Self::CARTRIDGE_N_CYCLES[((value >> 5) & 3) as usize]; 54 self.cartridge_n_cycles[2] = Self::CARTRIDGE_N_CYCLES[((value >> 8) & 3) as usize]; 55 self.cartridge_s_cycles[0] = Self::CARTRIDGE_0_S_CYCLES[usize::from(value.bit(4))]; 56 self.cartridge_s_cycles[1] = Self::CARTRIDGE_1_S_CYCLES[usize::from(value.bit(7))]; 57 self.cartridge_s_cycles[2] = Self::CARTRIDGE_2_S_CYCLES[usize::from(value.bit(10))]; 58 self.prefetch_enabled = value.bit(14); 59 60 // Highest bit is not writable; DK King of Swing depends on this 61 self.raw_value = value & 0x7FFF; 62 63 log::debug!("WAITCNT write: {value:04X}"); 64 log::debug!(" SRAM cycles: {}", self.sram_cycles); 65 log::debug!(" Cartridge 0 N cycles: {}", self.cartridge_n_cycles[0]); 66 log::debug!(" Cartridge 0 S cycles: {}", self.cartridge_s_cycles[0]); 67 log::debug!(" Cartridge 1 N cycles: {}", self.cartridge_n_cycles[1]); 68 log::debug!(" Cartridge 1 S cycles: {}", self.cartridge_s_cycles[1]); 69 log::debug!(" Cartridge 2 N cycles: {}", self.cartridge_n_cycles[2]); 70 log::debug!(" Cartridge 2 S cycles: {}", self.cartridge_s_cycles[2]); 71 log::debug!(" Cartridge ROM prefetch enabled: {}", self.prefetch_enabled); 72 } 73 74 pub fn rom_n_cycles(&self, address: u32) -> u64 { 75 self.cartridge_n_cycles[wait_states_area(address)] 76 } 77 78 pub fn rom_s_cycles(&self, address: u32) -> u64 { 79 self.cartridge_s_cycles[wait_states_area(address)] 80 } 81} 82 83fn wait_states_area(address: u32) -> usize { 84 // Area 0: $08000000-$09FFFFFF 85 // Area 1: $0A000000-$0BFFFFFF 86 // Area 2: $0C000000-$0DFFFFFF 87 debug_assert!((0x08000000..0x0E000000).contains(&address), "{address:08X}"); 88 ((address >> 25) & 3) as usize 89} 90 91#[derive(Debug, Clone, Encode, Decode)] 92pub struct Memory { 93 bios_rom: BoxedByteArray<BIOS_ROM_LEN>, 94 iwram: BoxedByteArray<IWRAM_LEN>, 95 ewram: BoxedByteArray<EWRAM_LEN>, 96 memory_control: MemoryControl, 97 post_boot: bool, 98} 99 100impl Memory { 101 pub fn new(bios_rom: Vec<u8>, config: GbaEmulatorConfig) -> Result<Self, GbaLoadError> { 102 if bios_rom.len() != BIOS_ROM_LEN { 103 return Err(GbaLoadError::InvalidBiosLength { 104 expected: BIOS_ROM_LEN, 105 actual: bios_rom.len(), 106 }); 107 } 108 109 let bios_rom: Box<[u8; BIOS_ROM_LEN]> = bios_rom.into_boxed_slice().try_into().unwrap(); 110 111 Ok(Self { 112 bios_rom: bios_rom.into(), 113 iwram: BoxedByteArray::new(), 114 ewram: BoxedByteArray::new(), 115 memory_control: MemoryControl::new(), 116 post_boot: config.skip_bios_animation, 117 }) 118 } 119 120 pub fn read_bios_rom(&self, address: u32) -> u32 { 121 let word_addr = (address as usize) & (BIOS_ROM_LEN - 1) & !3; 122 u32::from_le_bytes(self.bios_rom[word_addr..word_addr + 4].try_into().unwrap()) 123 } 124 125 pub fn read_iwram_byte(&self, address: u32) -> u8 { 126 read_byte(&self.iwram, address) 127 } 128 129 pub fn read_iwram_halfword(&self, address: u32) -> u16 { 130 read_halfword(&self.iwram, address) 131 } 132 133 pub fn read_iwram_word(&self, address: u32) -> u32 { 134 read_word(&self.iwram, address) 135 } 136 137 pub fn read_ewram_byte(&self, address: u32) -> u8 { 138 read_byte(&self.ewram, address) 139 } 140 141 pub fn read_ewram_halfword(&self, address: u32) -> u16 { 142 read_halfword(&self.ewram, address) 143 } 144 145 pub fn read_ewram_word(&self, address: u32) -> u32 { 146 read_word(&self.ewram, address) 147 } 148 149 pub fn write_iwram_byte(&mut self, address: u32, value: u8) { 150 write_byte(&mut self.iwram, address, value); 151 } 152 153 pub fn write_iwram_halfword(&mut self, address: u32, value: u16) { 154 write_halfword(&mut self.iwram, address, value); 155 } 156 157 pub fn write_iwram_word(&mut self, address: u32, value: u32) { 158 write_word(&mut self.iwram, address, value); 159 } 160 161 pub fn write_ewram_byte(&mut self, address: u32, value: u8) { 162 write_byte(&mut self.ewram, address, value); 163 } 164 165 pub fn write_ewram_halfword(&mut self, address: u32, value: u16) { 166 write_halfword(&mut self.ewram, address, value); 167 } 168 169 pub fn write_ewram_word(&mut self, address: u32, value: u32) { 170 write_word(&mut self.ewram, address, value); 171 } 172 173 pub fn control(&self) -> &MemoryControl { 174 &self.memory_control 175 } 176 177 // $4000204: WAITCNT (Waitstate control) 178 pub fn read_waitcnt(&self) -> u16 { 179 self.memory_control.read() 180 } 181 182 // $4000204: WAITCNT (Waitstate control) 183 pub fn write_waitcnt(&mut self, value: u16) { 184 self.memory_control.write(value); 185 } 186 187 // $4000300: POSTFLG (Post boot flag) 188 pub fn read_postflg(&self) -> u8 { 189 self.post_boot.into() 190 } 191 192 // $4000300: POSTFLG (Post boot flag) 193 pub fn write_postflg(&mut self, value: u8) { 194 // POSTFLG can only change from 0 to 1 195 self.post_boot |= value.bit(0); 196 log::trace!("POSTFLG write {value:02X}"); 197 } 198 199 pub fn clone_bios_rom(&mut self) -> Vec<u8> { 200 self.bios_rom.to_vec() 201 } 202 203 pub fn debug_ewram_view(&mut self) -> impl DebugMemoryView { 204 DebugBytesView(self.ewram.as_mut_slice()) 205 } 206 207 pub fn debug_iwram_view(&mut self) -> impl DebugMemoryView { 208 DebugBytesView(self.iwram.as_mut_slice()) 209 } 210 211 pub fn debug_bios_view(&mut self) -> impl DebugMemoryView { 212 DebugBytesView(self.bios_rom.as_mut_slice()) 213 } 214} 215 216fn read_byte<const LEN: usize>(memory: &[u8; LEN], address: u32) -> u8 { 217 let memory_addr = (address as usize) & (LEN - 1); 218 memory[memory_addr] 219} 220 221fn read_halfword<const LEN: usize>(memory: &[u8; LEN], address: u32) -> u16 { 222 let memory_addr = (address as usize) & (LEN - 1) & !1; 223 u16::from_le_bytes(memory[memory_addr..memory_addr + 2].try_into().unwrap()) 224} 225 226fn read_word<const LEN: usize>(memory: &[u8; LEN], address: u32) -> u32 { 227 let memory_addr = (address as usize) & (LEN - 1) & !3; 228 u32::from_le_bytes(memory[memory_addr..memory_addr + 4].try_into().unwrap()) 229} 230 231fn write_byte<const LEN: usize>(memory: &mut [u8; LEN], address: u32, value: u8) { 232 let memory_addr = (address as usize) & (LEN - 1); 233 memory[memory_addr] = value; 234} 235 236fn write_halfword<const LEN: usize>(memory: &mut [u8; LEN], address: u32, value: u16) { 237 let memory_addr = (address as usize) & (LEN - 1) & !1; 238 memory[memory_addr..memory_addr + 2].copy_from_slice(&value.to_le_bytes()); 239} 240 241fn write_word<const LEN: usize>(memory: &mut [u8; LEN], address: u32, value: u32) { 242 let memory_addr = (address as usize) & (LEN - 1) & !3; 243 memory[memory_addr..memory_addr + 4].copy_from_slice(&value.to_le_bytes()); 244}