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}