debug.rsannotateddebug.rssource155 lines · 5.5 KB · raw
1use crate::vdp::{VRAM_LEN, Vdp, convert_gg_color, convert_sms_color, get_color_id};
2
3use crate::SmsGgHardware;
4use jgenesis_common::frontend::Color;
5
6impl Vdp {
7    pub fn copy_cram(&self, out: &mut [Color]) {
8        match self.registers.version.hardware() {
9            SmsGgHardware::MasterSystem => {
10                for (out_color, &cram_byte) in out.iter_mut().zip(&self.color_ram[..32]) {
11                    *out_color = sms_color_to_rgb(cram_byte);
12                }
13            }
14            SmsGgHardware::GameGear => {
15                let colors_iter = self
16                    .color_ram
17                    .as_chunks::<2>()
18                    .0
19                    .iter()
20                    .map(|&chunk| u16::from_le_bytes(chunk));
21
22                for (out_color, cram_color) in out.iter_mut().zip(colors_iter) {
23                    *out_color = gg_color_to_rgb(cram_color);
24                }
25            }
26            SmsGgHardware::Sg1000 => {
27                // SG-1000 has no CRAM
28                out.fill(Color::BLACK);
29            }
30        }
31    }
32
33    pub fn copy_vram(&self, out: &mut [Color], palette: u8, row_len: usize) {
34        for pattern in 0..VRAM_LEN / 32 {
35            let tile = &self.vram[32 * pattern..32 * (pattern + 1)];
36            let base_idx = pattern / row_len * row_len * 64 + (pattern % row_len) * 8;
37
38            for row in 0..8 {
39                for col in 0..8 {
40                    let row_offset = row * row_len * 8;
41                    let out_idx = base_idx + row_offset + col;
42
43                    let color_id = get_color_id(tile, row as u16, col as u16, false);
44                    let color = self.read_color_ram_word((palette << 4) | color_id);
45
46                    out[out_idx] = match self.registers.version.hardware() {
47                        SmsGgHardware::MasterSystem => sms_color_to_rgb(color as u8),
48                        SmsGgHardware::GameGear => gg_color_to_rgb(color),
49                        SmsGgHardware::Sg1000 => {
50                            // SG-1000 has no CRAM
51                            Color::BLACK
52                        }
53                    };
54                }
55            }
56        }
57    }
58
59    pub fn dump_registers(&self, mut callback: impl FnMut(u32, &[(&str, &str)])) {
60        let mode_str = self.registers.mode.to_string();
61
62        callback(
63            0,
64            &[
65                ("Vertical scroll lock", bool_str(self.registers.vertical_scroll_lock)),
66                ("Horizontal scroll lock", bool_str(self.registers.horizontal_scroll_lock)),
67                ("Hide left column", bool_str(self.registers.hide_left_column)),
68                ("Horizontal interrupt enabled", bool_str(self.registers.line_interrupt_enabled)),
69                ("Shift sprites left", bool_str(self.registers.sprite.shift_sprites_left)),
70                ("M3", if self.registers.mode_bits[3] { "1" } else { "0" }),
71                ("M1", if self.registers.mode_bits[1] { "1" } else { "0" }),
72                ("Mode", &mode_str),
73            ],
74        );
75
76        callback(
77            1,
78            &[
79                ("Display enabled", bool_str(self.registers.display_enabled)),
80                ("Vertical interrupt enabled", bool_str(self.registers.frame_interrupt_enabled)),
81                ("M0", if self.registers.mode_bits[0] { "1" } else { "0" }),
82                ("M2", if self.registers.mode_bits[2] { "1" } else { "0" }),
83                ("Mode", &mode_str),
84                ("Double sprite height", bool_str(self.registers.sprite.double_sprite_height)),
85                ("Double sprite size", bool_str(self.registers.sprite.double_sprite_size)),
86            ],
87        );
88
89        callback(
90            2,
91            &[("Nametable address", &format!("${:04X}", self.registers.base_name_table_address))],
92        );
93
94        callback(
95            3,
96            &[(
97                "Color table address (TMS9918)",
98                &format!("${:04X}", self.registers.color_table_address),
99            )],
100        );
101
102        callback(
103            4,
104            &[(
105                "Pattern generator address (TMS9918)",
106                &format!("${:04X}", self.registers.pattern_generator_address),
107            )],
108        );
109
110        callback(
111            5,
112            &[(
113                "Sprite attribute table address",
114                &format!("${:04X}", self.registers.sprite.base_sprite_table_address),
115            )],
116        );
117
118        callback(
119            6,
120            &[(
121                "Sprite pattern generator address",
122                &format!("${:04X}", self.registers.sprite.base_sprite_pattern_address),
123            )],
124        );
125
126        callback(7, &[("Backdrop color ID", &self.registers.backdrop_color.to_string())]);
127
128        callback(8, &[("Horizontal scroll", &self.registers.x_scroll.to_string())]);
129
130        callback(9, &[("Vertical scroll", &self.registers.y_scroll.to_string())]);
131
132        callback(
133            10,
134            &[("HINT counter reload value", &self.registers.line_counter_reload_value.to_string())],
135        );
136    }
137}
138
139fn bool_str(b: bool) -> &'static str {
140    if b { "true" } else { "false" }
141}
142
143fn sms_color_to_rgb(cram_byte: u8) -> Color {
144    let r = convert_sms_color((cram_byte & 0x03).into());
145    let g = convert_sms_color(((cram_byte >> 2) & 0x03).into());
146    let b = convert_sms_color(((cram_byte >> 4) & 0x03).into());
147    Color::rgb(r, g, b)
148}
149
150fn gg_color_to_rgb(gg_color: u16) -> Color {
151    let r = convert_gg_color(gg_color & 0x0F);
152    let g = convert_gg_color((gg_color >> 4) & 0x0F);
153    let b = convert_gg_color((gg_color >> 8) & 0x0F);
154    Color::rgb(r, g, b)
155}