1use crate::api::debug::{SegaCdDebugView, SegaCdDebugger}; 2use crate::bus::SegaCdBus; 3use m68000_emu::debug::M68000Debugger; 4use m68000_emu::{BusInterface, M68000}; 5 6pub struct DebugSegaCdBus<'bus, 'debugger, Debugger> { 7 bus: &'bus mut SegaCdBus, 8 debugger: &'debugger mut Debugger, 9} 10 11impl<'bus, 'debugger, Debugger> DebugSegaCdBus<'bus, 'debugger, Debugger> { 12 pub fn new(bus: &'bus mut SegaCdBus, debugger: &'debugger mut Debugger) -> Self { 13 Self { bus, debugger } 14 } 15} 16 17impl SegaCdBus { 18 pub fn as_debug_view<'slf, 'cpu, 'ret>( 19 &'slf mut self, 20 sub_cpu: &'cpu mut M68000, 21 ) -> SegaCdDebugView<'ret> 22 where 23 'slf: 'ret, 24 'cpu: 'ret, 25 { 26 SegaCdDebugView { 27 sub_cpu, 28 bios_rom: self.bios.0.as_mut(), 29 prg_ram: self.prg_ram.as_mut_slice(), 30 word_ram: &mut self.word_ram, 31 pcm: &mut self.pcm, 32 cdc: self.disc_drive.cdc_mut(), 33 prg_ram_bank: self.registers.prg_ram_bank, 34 } 35 } 36} 37 38pub struct BusDebugView<'debugbus, 'bus, 'debugger, Debugger>( 39 &'debugbus mut DebugSegaCdBus<'bus, 'debugger, Debugger>, 40); 41 42impl<Debugger: SegaCdDebugger> M68000Debugger for BusDebugView<'_, '_, '_, Debugger> { 43 fn check_read<const WORD: bool>(&mut self, address: u32, cpu: &mut M68000) { 44 if self.0.debugger.check_sub_read_breakpoint::<WORD>(address) { 45 log::info!("Sub 68000 triggered read breakpoint: {address:06X}"); 46 47 let debug_view = self.0.bus.as_debug_view(cpu); 48 self.0.debugger.handle_sub_breakpoint(debug_view); 49 } 50 } 51 52 fn check_write<const WORD: bool>(&mut self, address: u32, value: u16, cpu: &mut M68000) { 53 if self.0.debugger.check_sub_write_breakpoint::<WORD>(address, value) { 54 log::info!("Sub 68000 triggered write breakpoint: {address:06X} {value:04X}"); 55 56 let debug_view = self.0.bus.as_debug_view(cpu); 57 self.0.debugger.handle_sub_breakpoint(debug_view); 58 } 59 } 60 61 fn check_execute(&mut self, pc: u32, cpu: &mut M68000) { 62 if self.0.debugger.check_sub_execute_breakpoint(pc) { 63 log::info!("Sub 68000 triggered execute breakpoint: PC={pc:06X}"); 64 65 let debug_view = self.0.bus.as_debug_view(cpu); 66 self.0.debugger.handle_sub_breakpoint(debug_view); 67 } 68 } 69 70 fn check_interrupt(&mut self, interrupt_level: u8, cpu: &mut M68000) { 71 if self.0.debugger.check_sub_interrupt_breakpoint(interrupt_level) { 72 log::info!( 73 "Sub 68000 triggered interrupt breakpoint, interrupt level {interrupt_level}" 74 ); 75 76 let debug_view = self.0.bus.as_debug_view(cpu); 77 self.0.debugger.handle_sub_breakpoint(debug_view); 78 } 79 } 80} 81 82impl<'bus, 'debugger, Debugger: SegaCdDebugger> BusInterface 83 for DebugSegaCdBus<'bus, 'debugger, Debugger> 84{ 85 type DebugView<'a> 86 = BusDebugView<'a, 'bus, 'debugger, Debugger> 87 where 88 Self: 'a; 89 90 #[inline] 91 fn read_byte(&mut self, address: u32) -> u8 { 92 self.bus.read_byte(address) 93 } 94 95 #[inline] 96 fn read_word(&mut self, address: u32) -> u16 { 97 self.bus.read_word(address) 98 } 99 100 #[inline] 101 fn write_byte(&mut self, address: u32, value: u8) { 102 self.bus.write_byte(address, value); 103 } 104 105 #[inline] 106 fn write_word(&mut self, address: u32, value: u16) { 107 self.bus.write_word(address, value); 108 } 109 110 #[inline] 111 fn interrupt_level(&self) -> u8 { 112 self.bus.interrupt_level() 113 } 114 115 #[inline] 116 fn acknowledge_interrupt(&mut self, interrupt_level: u8) { 117 self.bus.acknowledge_interrupt(interrupt_level); 118 } 119 120 #[inline] 121 fn halt(&self) -> bool { 122 self.bus.halt() 123 } 124 125 #[inline] 126 fn reset(&self) -> bool { 127 <SegaCdBus as BusInterface>::reset(self.bus) 128 } 129 130 #[inline] 131 fn debug_view(&mut self) -> Option<Self::DebugView<'_>> { 132 Some(BusDebugView(self)) 133 } 134}