debug.rsannotateddebug.rssource284 lines · 7.9 KB · raw
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}