debug.rsannotateddebug.rssource113 lines · 3.5 KB · raw
1use crate::vdp::registers::Registers;
2use crate::vdp::{ColorTables, Cram, FrameBufferRam, Vdp, VdpConfig, u16_to_rgb};
3use genesis_components::debug::CramEntry;
4use jgenesis_common::debug::{DebugMemoryView, DebugWordsView, Endian};
5
6#[derive(Debug, Clone)]
7pub struct VdpDebugState {
8    frame_buffer_0: Box<FrameBufferRam>,
9    frame_buffer_1: Box<FrameBufferRam>,
10    cram: Box<Cram>,
11    registers: Registers,
12    config: VdpConfig,
13}
14
15impl Vdp {
16    pub fn to_debug_state(&self) -> VdpDebugState {
17        VdpDebugState {
18            frame_buffer_0: self.frame_buffer_0.clone().into(),
19            frame_buffer_1: self.frame_buffer_1.clone().into(),
20            cram: self.cram.clone().into(),
21            registers: self.registers.clone(),
22            config: self.config.clone(),
23        }
24    }
25
26    pub fn debug_frame_buffer_view(&mut self, frame_buffer: usize) -> impl DebugMemoryView {
27        let frame_buffer = match frame_buffer {
28            0 => &mut self.frame_buffer_0,
29            _ => &mut self.frame_buffer_1,
30        };
31
32        DebugWordsView(frame_buffer.as_mut_slice(), Endian::Big)
33    }
34
35    pub fn debug_palette_ram_view(&mut self) -> impl DebugMemoryView {
36        DebugWordsView(self.cram.as_mut_slice(), Endian::Big)
37    }
38}
39
40impl VdpDebugState {
41    pub fn hen_bit(&self) -> bool {
42        self.registers.h_interrupt_in_vblank
43    }
44
45    pub fn h_interrupt_interval(&self) -> u16 {
46        self.registers.h_interrupt_interval
47    }
48
49    pub fn debug_frame_buffer_view(&mut self, frame_buffer: usize) -> impl DebugMemoryView {
50        let frame_buffer = match frame_buffer {
51            0 => &mut self.frame_buffer_0,
52            _ => &mut self.frame_buffer_1,
53        };
54
55        DebugWordsView(frame_buffer.as_mut_slice(), Endian::Big)
56    }
57
58    pub fn debug_palette_ram_view(&mut self) -> impl DebugMemoryView {
59        DebugWordsView(self.cram.as_mut_slice(), Endian::Big)
60    }
61
62    pub fn copy_palette(&self, out: &mut [CramEntry]) {
63        let color_tables = ColorTables::from_tint(self.config.color_tint);
64
65        for (i, entry) in out[..256].iter_mut().enumerate() {
66            let s32x_color = self.cram[i];
67            *entry = CramEntry { value: s32x_color, color: u16_to_rgb(s32x_color, color_tables) };
68        }
69    }
70
71    pub fn dump_registers(&self, mut callback: impl FnMut(&str, &[(&str, &str)])) {
72        callback(
73            "$4100 / $A15180",
74            &[
75                ("Mode", &self.registers.frame_buffer_mode.to_string()),
76                ("Vertical resolution", &self.registers.v_resolution.to_string()),
77                ("Invert priority", bool_str(self.registers.priority)),
78            ],
79        );
80
81        callback(
82            "$4102 / $A15182",
83            &[("Shift screen left", bool_str(self.registers.screen_left_shift))],
84        );
85
86        callback(
87            "$4104 / $A15184",
88            &[("Auto fill length", &self.registers.auto_fill_length.to_string())],
89        );
90
91        callback(
92            "$4106 / $A15186",
93            &[(
94                "Auto fill start address",
95                &format!("${:05X}", u32::from(self.registers.auto_fill_start_address) << 1),
96            )],
97        );
98
99        callback(
100            "$4108 / $A15188",
101            &[("Auto fill data", &format!("0x{:04X}", self.registers.auto_fill_data))],
102        );
103
104        callback(
105            "$410A / $A1518A",
106            &[("Display frame buffer", ["0", "1"][self.registers.display_frame_buffer as usize])],
107        );
108    }
109}
110
111fn bool_str(b: bool) -> &'static str {
112    if b { "true" } else { "false" }
113}