1use crate::WordRam; 2use crate::api::SegaCd; 3use crate::cddrive::cdc::Rchip; 4use crate::rf5c164::Rf5c164; 5use jgenesis_common::debug::{DebugMemoryView, DebugWordsView, Endian}; 6use jgenesis_proc_macros::EnumAll; 7use m68000_emu::M68000; 8 9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumAll)] 10pub enum SegaCdMemoryArea { 11 BiosRom, 12 PrgRam, 13 WordRam, 14 PcmRam, 15 CdcRam, 16} 17 18#[derive(Debug, Clone)] 19pub struct SegaCdDebugState { 20 sub_cpu: M68000, 21 bios_rom: Box<[u16]>, 22 prg_ram: Box<[u16]>, 23 word_ram: WordRam, 24 pcm: Rf5c164, 25 cdc: Rchip, 26 prg_ram_bank: u8, 27} 28 29impl SegaCdDebugState { 30 #[must_use] 31 pub fn sub_cpu(&self) -> &M68000 { 32 &self.sub_cpu 33 } 34 35 #[must_use] 36 pub fn bios_rom(&self) -> &[u16] { 37 &self.bios_rom 38 } 39 40 #[must_use] 41 pub fn prg_ram(&self) -> &[u16] { 42 &self.prg_ram 43 } 44 45 #[must_use] 46 pub fn main_cpu_prg_ram_bank(&self) -> u8 { 47 self.prg_ram_bank 48 } 49 50 #[must_use] 51 pub fn word_ram(&self) -> &WordRam { 52 &self.word_ram 53 } 54 55 #[must_use] 56 pub fn scd_memory_view( 57 &mut self, 58 memory_area: SegaCdMemoryArea, 59 ) -> Box<dyn DebugMemoryView + '_> { 60 match memory_area { 61 SegaCdMemoryArea::BiosRom => Box::new(DebugWordsView(&mut self.bios_rom, Endian::Big)), 62 SegaCdMemoryArea::PrgRam => Box::new(DebugWordsView(&mut self.prg_ram, Endian::Big)), 63 SegaCdMemoryArea::WordRam => Box::new(self.word_ram.debug_view()), 64 SegaCdMemoryArea::PcmRam => Box::new(self.pcm.debug_ram_view()), 65 SegaCdMemoryArea::CdcRam => Box::new(self.cdc.debug_ram_view()), 66 } 67 } 68} 69 70pub struct SegaCdDebugView<'scd> { 71 pub(crate) sub_cpu: &'scd mut M68000, 72 pub(crate) bios_rom: &'scd mut [u16], 73 pub(crate) prg_ram: &'scd mut [u16], 74 pub(crate) word_ram: &'scd mut WordRam, 75 pub(crate) pcm: &'scd mut Rf5c164, 76 pub(crate) cdc: &'scd mut Rchip, 77 pub(crate) prg_ram_bank: u8, 78} 79 80impl SegaCdDebugView<'_> { 81 #[must_use] 82 pub fn to_debug_state(&self) -> SegaCdDebugState { 83 SegaCdDebugState { 84 sub_cpu: self.sub_cpu.clone(), 85 bios_rom: self.bios_rom.to_vec().into_boxed_slice(), 86 prg_ram: self.prg_ram.to_vec().into_boxed_slice(), 87 word_ram: self.word_ram.clone(), 88 pcm: self.pcm.clone(), 89 cdc: self.cdc.clone(), 90 prg_ram_bank: self.prg_ram_bank, 91 } 92 } 93 94 pub fn apply_memory_edit(&mut self, memory_area: SegaCdMemoryArea, address: usize, value: u8) { 95 match memory_area { 96 SegaCdMemoryArea::BiosRom => { 97 DebugWordsView(self.bios_rom, Endian::Big).write(address, value); 98 } 99 SegaCdMemoryArea::PrgRam => { 100 DebugWordsView(self.prg_ram, Endian::Big).write(address, value); 101 } 102 SegaCdMemoryArea::WordRam => { 103 self.word_ram.debug_view().write(address, value); 104 } 105 SegaCdMemoryArea::PcmRam => { 106 self.pcm.debug_ram_view().write(address, value); 107 } 108 SegaCdMemoryArea::CdcRam => { 109 self.cdc.debug_ram_view().write(address, value); 110 } 111 } 112 } 113} 114 115impl SegaCd { 116 pub fn as_debug_view(&mut self) -> SegaCdDebugView<'_> { 117 self.bus.as_debug_view(&mut self.sub_cpu) 118 } 119} 120 121pub trait SegaCdDebugger { 122 fn check_sub_read_breakpoint<const WORD: bool>(&mut self, address: u32) -> bool; 123 124 fn check_sub_write_breakpoint<const WORD: bool>(&mut self, address: u32, value: u16) -> bool; 125 126 fn check_sub_execute_breakpoint(&mut self, pc: u32) -> bool; 127 128 fn check_sub_interrupt_breakpoint(&mut self, interrupt_level: u8) -> bool; 129 130 fn handle_sub_breakpoint(&mut self, debug_view: SegaCdDebugView<'_>); 131} 132 133pub struct DummySegaCdDebugger; 134 135#[allow(unused_variables)] 136impl SegaCdDebugger for DummySegaCdDebugger { 137 #[inline(always)] 138 fn check_sub_read_breakpoint<const WORD: bool>(&mut self, address: u32) -> bool { 139 false 140 } 141 142 #[inline(always)] 143 fn check_sub_write_breakpoint<const WORD: bool>(&mut self, address: u32, value: u16) -> bool { 144 false 145 } 146 147 #[inline(always)] 148 fn check_sub_execute_breakpoint(&mut self, pc: u32) -> bool { 149 false 150 } 151 152 #[inline(always)] 153 fn check_sub_interrupt_breakpoint(&mut self, interrupt_level: u8) -> bool { 154 false 155 } 156 157 #[inline(always)] 158 fn handle_sub_breakpoint(&mut self, debug_view: SegaCdDebugView<'_>) {} 159}