Sega CD memory map and sub CPU bus interface

3use bincode::{Decode, Encode};
4use jgenesis_proc_macros::{FakeDecode, FakeEncode};
5use std::array;
6use std::ops::Deref;
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}