1use crate::sa1::mmc::{BwramBitmapBits, BwramMapSource, Sa1Mmc}; 2use crate::sa1::registers::{InterruptVectorSource, Sa1Registers}; 3use crate::sa1::timer::Sa1Timer; 4use crate::sa1::{Iram, Sa1}; 5use jgenesis_common::num::U16Ext; 6use wdc65816_emu::traits::BusInterface; 7 8impl Sa1 { 9 pub fn snes_read(&mut self, address: u32) -> Option<u8> { 10 let bank = (address >> 16) & 0xFF; 11 let offset = address & 0xFFFF; 12 match (bank, offset) { 13 (0x00..=0x3F | 0x80..=0xBF, 0x8000..=0xFFFF) | (0xC0..=0xFF, _) => { 14 // ROM 15 16 // Check for NMI/IRQ vector reads first 17 let nmi_vector_source = self.registers.snes_nmi_vector_source; 18 let irq_vector_source = self.registers.snes_irq_vector_source; 19 match (bank, offset) { 20 (0x00, 0xFFEA) if nmi_vector_source == InterruptVectorSource::IoPorts => { 21 Some(self.registers.snes_nmi_vector.lsb()) 22 } 23 (0x00, 0xFFEB) if nmi_vector_source == InterruptVectorSource::IoPorts => { 24 Some(self.registers.snes_nmi_vector.msb()) 25 } 26 (0x00, 0xFFEE) if irq_vector_source == InterruptVectorSource::IoPorts => { 27 Some(self.registers.snes_irq_vector.lsb()) 28 } 29 (0x00, 0xFFEF) if irq_vector_source == InterruptVectorSource::IoPorts => { 30 Some(self.registers.snes_irq_vector.msb()) 31 } 32 _ => self 33 .mmc 34 .map_rom_address(address) 35 .and_then(|rom_addr| self.rom.get(rom_addr as usize).copied()), 36 } 37 } 38 (0x00..=0x3F | 0x80..=0xBF, 0x2300..=0x230F) => { 39 // SA-1 internal registers 40 self.registers.snes_read(address) 41 } 42 (0x00..=0x3F | 0x80..=0xBF, 0x3000..=0x37FF) => { 43 // I-RAM 44 Some(self.iram[(address & 0x7FF) as usize]) 45 } 46 (0x00..=0x3F | 0x80..=0xBF, 0x6000..=0x7FFF) => { 47 // BW-RAM 8KB block 48 let bwram_addr = (self.mmc.snes_bwram_base_addr | (address & 0x1FFF)) 49 & (self.bwram.len() as u32 - 1); 50 Some(self.bwram[bwram_addr as usize]) 51 } 52 (0x40..=0x4F, _) => { 53 // BW-RAM in full 54 // If character conversion DMA type 1 is in progress, ignore the address and return 55 // the next CCDMA byte 56 if self.registers.ccdma_transfer_in_progress { 57 Some(self.registers.next_ccdma_byte(&mut self.iram, &self.bwram)) 58 } else { 59 let bwram_addr = (address as usize) & (self.bwram.len() - 1); 60 Some(self.bwram[bwram_addr]) 61 } 62 } 63 _ => None, 64 } 65 } 66 67 pub fn snes_write(&mut self, address: u32, value: u8) { 68 let bank = (address >> 16) & 0xFF; 69 let offset = address & 0xFFFF; 70 match (bank, offset) { 71 (0x00..=0x3F | 0x80..=0xBF, 0x2200..=0x22FF) => { 72 // SA-1 internal registers 73 self.registers.snes_write(address, value, &mut self.mmc); 74 } 75 (0x00..=0x3F | 0x80..=0xBF, 0x3000..=0x37FF) => { 76 // I-RAM 77 let iram_addr = address & 0x7FF; 78 let write_protect_idx = iram_addr >> 8; 79 if self.registers.snes_iram_writes_enabled[write_protect_idx as usize] { 80 self.iram[iram_addr as usize] = value; 81 } 82 } 83 (0x00..=0x3F | 0x80..=0xBF, 0x6000..=0x7FFF) => { 84 // BW-RAM 8KB block 85 let bwram_addr = (self.mmc.snes_bwram_base_addr | (address & 0x1FFF)) 86 & (self.bwram.len() as u32 - 1); 87 if self.registers.can_write_bwram(bwram_addr) { 88 self.bwram[bwram_addr as usize] = value; 89 } 90 } 91 (0x40..=0x4F, _) => { 92 // BW-RAM in full 93 let bwram_addr = (address as usize) & (self.bwram.len() - 1); 94 if self.registers.can_write_bwram(bwram_addr as u32) { 95 self.bwram[bwram_addr] = value; 96 } 97 } 98 _ => {} 99 } 100 } 101} 102 103pub struct Sa1Bus<'a> { 104 pub rom: &'a [u8], 105 pub iram: &'a mut Iram, 106 pub bwram: &'a mut [u8], 107 pub mmc: &'a mut Sa1Mmc, 108 pub registers: &'a mut Sa1Registers, 109 pub timer: &'a mut Sa1Timer, 110 pub bwram_wait_cycles: u64, 111} 112 113impl BusInterface for Sa1Bus<'_> { 114 #[inline] 115 fn read(&mut self, address: u32) -> u8 { 116 let bank = (address >> 16) & 0xFF; 117 let offset = address & 0xFFFF; 118 match (bank, offset) { 119 (0x00..=0x3F | 0x80..=0xBF, 0x8000..=0xFFFF) | (0xC0..=0xFF, _) => { 120 // ROM 121 122 // Check for NMI/IRQ/RESET vector reads first 123 match (bank, offset) { 124 (0x00, 0xFFEA) => self.registers.sa1_nmi_vector.lsb(), 125 (0x00, 0xFFEB) => self.registers.sa1_nmi_vector.msb(), 126 (0x00, 0xFFEE) => self.registers.sa1_irq_vector.lsb(), 127 (0x00, 0xFFEF) => self.registers.sa1_irq_vector.msb(), 128 (0x00, 0xFFFC) => self.registers.sa1_reset_vector.lsb(), 129 (0x00, 0xFFFD) => self.registers.sa1_reset_vector.msb(), 130 _ => self 131 .mmc 132 .map_rom_address(address) 133 .and_then(|rom_addr| self.rom.get(rom_addr as usize).copied()) 134 .unwrap_or(0), 135 } 136 } 137 (0x00..=0x3F | 0x80..=0xBF, 0x2300..=0x230F) => { 138 // SA-1 internal registers 139 self.registers.sa1_read(address, self.timer) 140 } 141 (0x00..=0x3F | 0x80..=0xBF, 0x0000..=0x07FF | 0x3000..=0x37FF) => { 142 // I-RAM (mapped to both $0000-$07FF and $3000-$37FF for SA-1 CPU) 143 self.iram[(address & 0x7FF) as usize] 144 } 145 (0x00..=0x3F | 0x80..=0xBF, 0x6000..=0x7FFF) => { 146 // BW-RAM 8KB block 147 self.bwram_wait_cycles += 1; 148 149 match self.mmc.sa1_bwram_source { 150 BwramMapSource::Normal => { 151 let bwram_addr = ((self.mmc.sa1_bwram_base_addr & 0x3E000) 152 | (address & 0x01FFF)) 153 & (self.bwram.len() as u32 - 1); 154 self.bwram[bwram_addr as usize] 155 } 156 BwramMapSource::Bitmap => { 157 let bitmap_addr = self.mmc.sa1_bwram_base_addr | (address & 0x1FFF); 158 read_bwram_bitmap(bitmap_addr, self.mmc, self.bwram) 159 } 160 } 161 } 162 (0x40..=0x4F, _) => { 163 // BW-RAM in full 164 self.bwram_wait_cycles += 1; 165 166 let bwram_addr = (address as usize) & (self.bwram.len() - 1); 167 self.bwram[bwram_addr] 168 } 169 (0x60..=0x6F, _) => { 170 // BW-RAM bitmap view 171 self.bwram_wait_cycles += 1; 172 173 read_bwram_bitmap(address, self.mmc, self.bwram) 174 } 175 _ => 0, 176 } 177 } 178 179 #[inline] 180 fn write(&mut self, address: u32, value: u8) { 181 let bank = (address >> 16) & 0xFF; 182 let offset = address & 0xFFFF; 183 match (bank, offset) { 184 (0x00..=0x3F | 0x80..=0xBF, 0x2200..=0x22FF) => { 185 // SA-1 internal registers 186 self.registers.sa1_write(address, value, self.timer, self.mmc, self.rom, self.iram); 187 } 188 (0x00..=0x3F | 0x80..=0xBF, 0x0000..=0x07FF | 0x3000..=0x37FF) => { 189 // I-RAM (mapped to both $0000-$07FF and $3000-$37FF for SA-1 CPU) 190 let iram_addr = address & 0x7FF; 191 let write_protect_idx = iram_addr >> 8; 192 if self.registers.sa1_iram_writes_enabled[write_protect_idx as usize] { 193 self.iram[iram_addr as usize] = value; 194 } 195 } 196 (0x00..=0x3F | 0x80..=0xBF, 0x6000..=0x7FFF) => { 197 // BW-RAM 8KB block 198 self.bwram_wait_cycles += 1; 199 200 match self.mmc.sa1_bwram_source { 201 BwramMapSource::Normal => { 202 let bwram_addr = ((self.mmc.sa1_bwram_base_addr & 0x3E000) 203 | (address & 0x01FFF)) 204 & (self.bwram.len() as u32 - 1); 205 if self.registers.can_write_bwram(bwram_addr) { 206 self.bwram[bwram_addr as usize] = value; 207 } 208 } 209 BwramMapSource::Bitmap => { 210 let bitmap_addr = self.mmc.sa1_bwram_base_addr | (address & 0x1FFF); 211 write_bwram_bitmap(bitmap_addr, value, self.mmc, self.bwram); 212 } 213 } 214 } 215 (0x40..=0x4F, _) => { 216 // BW-RAM in full (256KB max, mirrored every 4 banks) 217 self.bwram_wait_cycles += 1; 218 219 let bwram_addr = (address as usize) & (self.bwram.len() - 1); 220 if self.registers.can_write_bwram(bwram_addr as u32) { 221 self.bwram[bwram_addr] = value; 222 } 223 } 224 (0x60..=0x6F, _) => { 225 // BW-RAM bitmap view 226 self.bwram_wait_cycles += 1; 227 228 write_bwram_bitmap(address, value, self.mmc, self.bwram); 229 } 230 _ => {} 231 } 232 } 233 234 #[inline] 235 fn idle(&mut self) {} 236 237 #[inline] 238 fn nmi(&self) -> bool { 239 self.registers.sa1_nmi_enabled && self.registers.sa1_nmi 240 } 241 242 #[inline] 243 fn acknowledge_nmi(&mut self) {} 244 245 #[inline] 246 fn irq(&self) -> bool { 247 (self.registers.sa1_irq_from_snes_enabled && self.registers.sa1_irq_from_snes) 248 || (self.registers.timer_irq_enabled && self.timer.irq_pending) 249 || (self.registers.dma_irq_enabled && self.registers.sa1_dma_irq) 250 } 251 252 #[inline] 253 fn halt(&self) -> bool { 254 self.registers.sa1_wait 255 } 256 257 #[inline] 258 fn reset(&self) -> bool { 259 self.registers.sa1_reset 260 } 261} 262 263fn read_bwram_bitmap(address: u32, mmc: &Sa1Mmc, bwram: &[u8]) -> u8 { 264 match mmc.bwram_bitmap_format { 265 BwramBitmapBits::Two => { 266 let address = address & 0xFFFFF; 267 let bwram_addr = (address >> 2) & (bwram.len() as u32 - 1); 268 let bwram_shift = 2 * (address & 0x03); 269 270 (bwram[bwram_addr as usize] >> bwram_shift) & 0x03 271 } 272 BwramBitmapBits::Four => { 273 let address = address & 0x7FFFF; 274 let bwram_addr = (address >> 1) & (bwram.len() as u32 - 1); 275 let bwram_shift = 4 * (address & 0x01); 276 277 (bwram[bwram_addr as usize] >> bwram_shift) & 0x0F 278 } 279 } 280} 281 282fn write_bwram_bitmap(address: u32, value: u8, mmc: &Sa1Mmc, bwram: &mut [u8]) { 283 match mmc.bwram_bitmap_format { 284 BwramBitmapBits::Two => { 285 let address = address & 0xFFFFF; 286 let bwram_addr = (address >> 2) & (bwram.len() as u32 - 1); 287 let shift = 2 * (address & 0x03); 288 289 let existing_value = bwram[bwram_addr as usize]; 290 let new_value = (existing_value & !(0x03 << shift)) | ((value & 0x03) << shift); 291 bwram[bwram_addr as usize] = new_value; 292 } 293 BwramBitmapBits::Four => { 294 let address = address & 0x7FFFF; 295 let bwram_addr = (address >> 1) & (bwram.len() as u32 - 1); 296 let shift = 4 * (address & 0x01); 297 298 let existing_value = bwram[bwram_addr as usize]; 299 let new_value = (existing_value & !(0x0F << shift)) | ((value & 0x0F) << shift); 300 bwram[bwram_addr as usize] = new_value; 301 } 302 } 303}