1//! Sega CD memory map and sub CPU bus interface 2 3use bincode::{Decode, Encode}; 4use jgenesis_proc_macros::{FakeDecode, FakeEncode}; 5use std::array; 6use std::ops::Deref; 7 8pub const BIOS_LEN: usize = 128 * 1024; 9pub const PRG_RAM_LEN_WORDS: usize = 512 * 1024 / 2; 10pub const BACKUP_RAM_LEN: usize = 8 * 1024; 11pub const RAM_CARTRIDGE_LEN: usize = 128 * 1024; 12 13#[derive(Debug, Clone, Encode, Decode)] 14pub struct SegaCdRegisters { 15 // $FF8000/$A12000: Reset / BUSREQ 16 pub software_interrupt_pending: bool, 17 pub sub_cpu_busreq: bool, 18 pub sub_cpu_reset: bool, 19 pub led_green: bool, 20 pub led_red: bool, 21 // $FF8002/$A12002: Memory mode / PRG RAM bank select 22 pub prg_ram_write_protect: u8, 23 pub prg_ram_bank: u8, 24 // $A12006: HINT vector 25 pub h_interrupt_vector: u16, 26 // $FF800C: Stopwatch 27 pub stopwatch_counter: u16, 28 // $FF800E: Communication flags 29 pub sub_cpu_communication_flags: u8, 30 pub main_cpu_communication_flags: u8, 31 // $FF8010-$FF801E: Communication commands 32 pub communication_commands: [u16; 8], 33 // $FF8020-$FF802E: Communication statuses 34 pub communication_statuses: [u16; 8], 35 // $FF8030: General-purpose timer w/ INT3 36 pub timer_counter: u8, 37 pub timer_interval: u8, 38 pub timer_interrupt_pending: bool, 39 // $FF8032: Interrupt mask control 40 pub subcode_interrupt_enabled: bool, 41 pub cdc_interrupt_enabled: bool, 42 pub cdd_interrupt_enabled: bool, 43 pub timer_interrupt_enabled: bool, 44 pub software_interrupt_enabled: bool, 45 pub graphics_interrupt_enabled: bool, 46 // $FF8036: CDD control 47 pub cdd_host_clock_on: bool, 48 // $FF8042-$FF804B: CDD command buffer 49 pub cdd_command: [u8; 10], 50} 51 52impl SegaCdRegisters { 53 pub fn new() -> Self { 54 Self { 55 software_interrupt_pending: false, 56 sub_cpu_busreq: true, 57 sub_cpu_reset: true, 58 led_green: true, 59 led_red: false, 60 prg_ram_write_protect: 0, 61 prg_ram_bank: 0, 62 h_interrupt_vector: 0xFFFF, 63 stopwatch_counter: 0, 64 sub_cpu_communication_flags: 0, 65 main_cpu_communication_flags: 0, 66 communication_commands: [0; 8], 67 communication_statuses: [0; 8], 68 timer_counter: 0, 69 timer_interval: 0, 70 timer_interrupt_pending: false, 71 subcode_interrupt_enabled: false, 72 cdc_interrupt_enabled: false, 73 cdd_interrupt_enabled: false, 74 timer_interrupt_enabled: false, 75 software_interrupt_enabled: false, 76 graphics_interrupt_enabled: false, 77 cdd_host_clock_on: false, 78 cdd_command: array::from_fn(|_| 0), 79 } 80 } 81 82 pub fn main_prg_ram_addr(&self, address: u32) -> u32 { 83 (u32::from(self.prg_ram_bank) << 17) | (address & 0x1FFFF) 84 } 85} 86 87#[derive(Debug, Clone, Default, FakeEncode, FakeDecode)] 88pub struct Bios(pub Box<[u16]>); 89 90impl Deref for Bios { 91 type Target = Box<[u16]>; 92 93 fn deref(&self) -> &Self::Target { 94 &self.0 95 } 96}