1use crate::api::debug::{GenesisCpu, GenesisDebugView, GenesisDebugger, genesis_components}; 2use crate::bus::GenesisBus; 3use m68000_emu::M68000; 4use m68000_emu::debug::M68000Debugger; 5use s32x_core::api::Sega32X; 6use segacd_core::api::SegaCd; 7use z80_emu::Z80; 8use z80_emu::debug::Z80Debugger; 9use z80_emu::traits::InterruptLine; 10 11impl GenesisBus { 12 pub fn as_debug_view<'bus, 'z80, 'm68k>( 13 &'bus mut self, 14 m68k: &'m68k mut M68000, 15 z80: &'z80 mut Z80, 16 ) -> GenesisDebugView<'m68k, 'z80, 'bus, 'bus, 'bus, 'bus> { 17 let components = genesis_components!(self); 18 19 let (s32x_debug_view, s32x_cartridge) = 20 match self.sega_32x.as_mut().map(Sega32X::as_debug_view) { 21 Some((debug_view, cartridge)) => (Some(debug_view), cartridge), 22 None => (None, None), 23 }; 24 let cartridge = s32x_cartridge.or(self.cartridge.as_mut()); 25 26 components.into_debug_view( 27 m68k, 28 z80, 29 self.sega_cd.as_mut().map(SegaCd::as_debug_view), 30 s32x_debug_view, 31 cartridge, 32 ) 33 } 34} 35 36pub struct Debug68000Bus<'bus, 'z80, 'debugger> { 37 bus: &'bus mut GenesisBus, 38 z80: &'z80 mut Z80, 39 debugger: &'debugger mut GenesisDebugger, 40} 41 42impl<'bus, 'z80, 'debugger> Debug68000Bus<'bus, 'z80, 'debugger> { 43 pub fn new( 44 bus: &'bus mut GenesisBus, 45 z80: &'z80 mut Z80, 46 debugger: &'debugger mut GenesisDebugger, 47 ) -> Self { 48 Self { bus, z80, debugger } 49 } 50} 51 52pub struct M68000DebugView<'debugbus, 'bus, 'z80, 'debugger>( 53 &'debugbus mut Debug68000Bus<'bus, 'z80, 'debugger>, 54); 55 56impl M68000Debugger for M68000DebugView<'_, '_, '_, '_> { 57 #[inline] 58 fn check_read<const WORD: bool>(&mut self, address: u32, cpu: &mut M68000) { 59 if self.0.debugger.m68k_breakpoints().check_read::<WORD>(address) { 60 log::info!("68000 triggered read breakpoint: {address:06X}"); 61 62 self.0.debugger.handle_breakpoint( 63 GenesisCpu::M68k, 64 &mut self.0.bus.as_debug_view(cpu, self.0.z80), 65 ); 66 } 67 } 68 69 #[inline] 70 fn check_write<const WORD: bool>(&mut self, address: u32, value: u16, cpu: &mut M68000) { 71 if self.0.debugger.m68k_breakpoints().check_write::<WORD>(address) { 72 log::info!("68000 triggered write breakpoint: {address:06X} {value:04X}"); 73 74 self.0.debugger.handle_breakpoint( 75 GenesisCpu::M68k, 76 &mut self.0.bus.as_debug_view(cpu, self.0.z80), 77 ); 78 } 79 } 80 81 #[inline] 82 fn check_execute(&mut self, pc: u32, cpu: &mut M68000) { 83 let execute = self.0.debugger.m68k_breakpoints().update_pc_and_check_execute(pc); 84 let step = self.0.debugger.m68k_breakpoints().check_break_step(); 85 86 if execute { 87 log::info!("68000 triggered execute breakpoint: PC={pc:06X}"); 88 } 89 90 if execute || step { 91 self.0.debugger.handle_breakpoint( 92 GenesisCpu::M68k, 93 &mut self.0.bus.as_debug_view(cpu, self.0.z80), 94 ); 95 } 96 } 97 98 #[inline] 99 fn check_interrupt(&mut self, interrupt_level: u8, cpu: &mut M68000) { 100 if self.0.debugger.m68k_breakpoints().check_interrupt(interrupt_level) { 101 log::info!("68000 triggered interrupt breakpoint; interrupt level {interrupt_level}"); 102 103 self.0.debugger.handle_breakpoint( 104 GenesisCpu::M68k, 105 &mut self.0.bus.as_debug_view(cpu, self.0.z80), 106 ); 107 } 108 } 109} 110 111impl<'bus, 'z80, 'debugger> m68000_emu::BusInterface for Debug68000Bus<'bus, 'z80, 'debugger> { 112 type DebugView<'a> 113 = M68000DebugView<'a, 'bus, 'z80, 'debugger> 114 where 115 Self: 'a; 116 117 #[inline] 118 fn read_byte(&mut self, address: u32) -> u8 { 119 self.bus.read_byte(address) 120 } 121 122 #[inline] 123 fn read_word(&mut self, address: u32) -> u16 { 124 self.bus.read_word(address) 125 } 126 127 #[inline] 128 fn write_byte(&mut self, address: u32, value: u8) { 129 self.bus.write_byte(address, value); 130 } 131 132 #[inline] 133 fn write_word(&mut self, address: u32, value: u16) { 134 self.bus.write_word(address, value); 135 } 136 137 #[inline] 138 fn interrupt_level(&self) -> u8 { 139 self.bus.interrupt_level() 140 } 141 142 #[inline] 143 fn acknowledge_interrupt(&mut self, interrupt_level: u8) { 144 self.bus.acknowledge_interrupt(interrupt_level); 145 } 146 147 #[inline] 148 fn halt(&self) -> bool { 149 self.bus.halt() 150 } 151 152 #[inline] 153 fn reset(&self) -> bool { 154 <GenesisBus as m68000_emu::BusInterface>::reset(self.bus) 155 } 156 157 #[inline] 158 fn debug_view(&mut self) -> Option<Self::DebugView<'_>> { 159 Some(M68000DebugView(self)) 160 } 161} 162 163pub struct DebugZ80Bus<'bus, 'm68k, 'debugger> { 164 bus: &'bus mut GenesisBus, 165 m68k: &'m68k mut M68000, 166 debugger: &'debugger mut GenesisDebugger, 167} 168 169impl<'bus, 'm68k, 'debugger> DebugZ80Bus<'bus, 'm68k, 'debugger> { 170 pub fn new( 171 bus: &'bus mut GenesisBus, 172 m68k: &'m68k mut M68000, 173 debugger: &'debugger mut GenesisDebugger, 174 ) -> Self { 175 Self { bus, m68k, debugger } 176 } 177} 178 179pub struct Z80DebugView<'debugbus, 'bus, 'm68k, 'debugger>( 180 &'debugbus mut DebugZ80Bus<'bus, 'm68k, 'debugger>, 181); 182 183impl Z80Debugger for Z80DebugView<'_, '_, '_, '_> { 184 #[inline] 185 fn check_read_memory(&mut self, address: u16, cpu: &mut Z80) { 186 if self.0.debugger.z80_breakpoints().check_read(address) { 187 log::info!("Z80 triggered read breakpoint: {address:04X}"); 188 189 self.0.debugger.handle_breakpoint( 190 GenesisCpu::Z80, 191 &mut self.0.bus.as_debug_view(self.0.m68k, cpu), 192 ); 193 } 194 } 195 196 #[inline(always)] 197 #[allow(unused_variables)] 198 fn check_read_io(&mut self, address: u16, cpu: &mut Z80) {} 199 200 #[inline] 201 fn check_write_memory(&mut self, address: u16, value: u8, cpu: &mut Z80) { 202 if self.0.debugger.z80_breakpoints().check_write(address) { 203 log::info!("Z80 triggered write breakpoint: {address:04X} {value:02X}"); 204 205 self.0.debugger.handle_breakpoint( 206 GenesisCpu::Z80, 207 &mut self.0.bus.as_debug_view(self.0.m68k, cpu), 208 ); 209 } 210 } 211 212 #[inline(always)] 213 #[allow(unused_variables)] 214 fn check_write_io(&mut self, address: u16, value: u8, cpu: &mut Z80) {} 215 216 #[inline] 217 fn check_execute(&mut self, pc: u16, cpu: &mut Z80) { 218 let execute = self.0.debugger.z80_breakpoints().update_pc_and_check_execute(pc); 219 let step = self.0.debugger.z80_breakpoints().check_break_step(); 220 221 if execute { 222 log::info!("Z80 triggered execute breakpoint: PC={pc:04X}"); 223 } 224 225 if execute || step { 226 self.0.debugger.handle_breakpoint( 227 GenesisCpu::Z80, 228 &mut self.0.bus.as_debug_view(self.0.m68k, cpu), 229 ); 230 } 231 } 232} 233 234impl<'bus, 'm68k, 'debugger> z80_emu::BusInterface for DebugZ80Bus<'bus, 'm68k, 'debugger> { 235 type DebugView<'a> 236 = Z80DebugView<'a, 'bus, 'm68k, 'debugger> 237 where 238 Self: 'a; 239 240 #[inline] 241 fn read_memory(&mut self, address: u16) -> u8 { 242 self.bus.read_memory(address) 243 } 244 245 #[inline] 246 fn write_memory(&mut self, address: u16, value: u8) { 247 self.bus.write_memory(address, value); 248 } 249 250 #[inline] 251 fn read_io(&mut self, address: u16) -> u8 { 252 self.bus.read_io(address) 253 } 254 255 #[inline] 256 fn write_io(&mut self, address: u16, value: u8) { 257 self.bus.write_io(address, value); 258 } 259 260 #[inline] 261 fn nmi(&self) -> InterruptLine { 262 self.bus.nmi() 263 } 264 265 #[inline] 266 fn int(&self) -> InterruptLine { 267 self.bus.int() 268 } 269 270 #[inline] 271 fn busreq(&self) -> bool { 272 self.bus.busreq() 273 } 274 275 #[inline] 276 fn reset(&self) -> bool { 277 <GenesisBus as z80_emu::BusInterface>::reset(self.bus) 278 } 279 280 #[inline] 281 fn debug_view(&mut self) -> Option<Self::DebugView<'_>> { 282 Some(Z80DebugView(self)) 283 } 284}