mirror of
https://github.com/FranLMSP/snes.git
synced 2026-10-03 16:05:18 -04:00
display PPU registers and VRAM debug info
This commit is contained in:
@@ -36,8 +36,6 @@ pub const M7B: u16 = 0x211C; // Rotation/Scaling Parameter B (and Math
|
|||||||
pub const M7C: u16 = 0x211D; // Rotation/Scaling Parameter C (W)
|
pub const M7C: u16 = 0x211D; // Rotation/Scaling Parameter C (W)
|
||||||
pub const M7D: u16 = 0x211E; // Rotation/Scaling Parameter D (W)
|
pub const M7D: u16 = 0x211E; // Rotation/Scaling Parameter D (W)
|
||||||
|
|
||||||
pub const M7HOFS: u16 = 0x210D; // BG1 Horizontal Scroll (X) (W)
|
|
||||||
pub const M7VOFS: u16 = 0x210E; // BG1 Vertical Scroll (Y) (W)
|
|
||||||
pub const M7X: u16 = 0x211F; // Rotation/Scaling Center Coordinate X (W)
|
pub const M7X: u16 = 0x211F; // Rotation/Scaling Center Coordinate X (W)
|
||||||
pub const M7Y: u16 = 0x2120; // Rotation/Scaling Center Coordinate Y (W)
|
pub const M7Y: u16 = 0x2120; // Rotation/Scaling Center Coordinate Y (W)
|
||||||
|
|
||||||
@@ -156,6 +154,14 @@ impl PPURegisters {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn registers(&self) -> &[u8] {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vram(&self) -> &[u8] {
|
||||||
|
&self.vram
|
||||||
|
}
|
||||||
|
|
||||||
fn _read(&self, address: u16) -> u8 {
|
fn _read(&self, address: u16) -> u8 {
|
||||||
self.data[(address as usize) - 0x2100]
|
self.data[(address as usize) - 0x2100]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -298,13 +298,28 @@ fn main() {
|
|||||||
.size([300.0, 400.0], Condition::FirstUseEver)
|
.size([300.0, 400.0], Condition::FirstUseEver)
|
||||||
.build(&ui, || {
|
.build(&ui, || {
|
||||||
ui.text("Backgrounds:");
|
ui.text("Backgrounds:");
|
||||||
|
|
||||||
for bgdebug in state.ppudebug.backgrounds.iter_mut() {
|
for bgdebug in state.ppudebug.backgrounds.iter_mut() {
|
||||||
ui.checkbox(
|
ui.checkbox(
|
||||||
format!("Show {:?}", bgdebug.background),
|
format!("Show {:?}", bgdebug.background),
|
||||||
&mut bgdebug.is_enabled,
|
&mut bgdebug.is_enabled,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
ui.text("Registers:");
|
||||||
|
ui.checkbox(
|
||||||
|
"Show PPU Registers",
|
||||||
|
&mut state.ppudebug.show_registers,
|
||||||
|
);
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
ui.text("VRAM:");
|
||||||
|
ui.checkbox(
|
||||||
|
"Show PPU VRAM",
|
||||||
|
&mut state.ppudebug.show_vram,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
for bgdebug in state.ppudebug.backgrounds.iter_mut() {
|
for bgdebug in state.ppudebug.backgrounds.iter_mut() {
|
||||||
ppu_render::background_window(
|
ppu_render::background_window(
|
||||||
@@ -315,6 +330,23 @@ fn main() {
|
|||||||
&queue,
|
&queue,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if state.ppudebug.show_registers {
|
||||||
|
ppu_render::registers_window(
|
||||||
|
&emulator.bus.ppu.registers,
|
||||||
|
&mut state.ppudebug.show_registers,
|
||||||
|
&ui,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if state.ppudebug.show_vram {
|
||||||
|
ppu_render::vram_window(
|
||||||
|
&emulator.bus.ppu.registers,
|
||||||
|
&mut state.ppudebug.vram_map,
|
||||||
|
&mut state.ppudebug.show_vram,
|
||||||
|
&ui,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if state.debug_options.show_cpu_registers {
|
if state.debug_options.show_cpu_registers {
|
||||||
|
|||||||
+115
-4
@@ -8,7 +8,8 @@ use snes_core::ppu::registers::{
|
|||||||
use imgui_wgpu::Renderer;
|
use imgui_wgpu::Renderer;
|
||||||
use imgui::TextureId;
|
use imgui::TextureId;
|
||||||
use wgpu::{Device, Queue};
|
use wgpu::{Device, Queue};
|
||||||
use super::state::BgDebug;
|
|
||||||
|
use super::state::{BgDebug, VRAMMap};
|
||||||
|
|
||||||
|
|
||||||
pub fn background_texture(
|
pub fn background_texture(
|
||||||
@@ -63,12 +64,122 @@ pub fn background_window(bgdebug: &mut BgDebug, registers: &PPURegisters, ui: &i
|
|||||||
|
|
||||||
let tex = renderer.textures.get_mut(texture_id).unwrap();
|
let tex = renderer.textures.get_mut(texture_id).unwrap();
|
||||||
tex.write(queue, &bgdebug.framebuffer, MAX_BG_WIDTH as u32, MAX_BG_HEIGHT as u32);
|
tex.write(queue, &bgdebug.framebuffer, MAX_BG_WIDTH as u32, MAX_BG_HEIGHT as u32);
|
||||||
let game_window = imgui::Window::new(format!("BG: {:?}", bgdebug.background));
|
let bg_window = imgui::Window::new(format!("BG: {:?}", bgdebug.background));
|
||||||
game_window
|
bg_window
|
||||||
.size([MAX_BG_WIDTH as f32, MAX_BG_HEIGHT as f32], imgui::Condition::FirstUseEver)
|
.size([MAX_BG_WIDTH as f32, MAX_BG_HEIGHT as f32], imgui::Condition::FirstUseEver)
|
||||||
.opened(&mut bgdebug.is_enabled)
|
.opened(&mut bgdebug.is_enabled)
|
||||||
.build(ui, || {
|
.build(ui, || {
|
||||||
let game_image = imgui::Image::new(texture_id, [MAX_BG_WIDTH as f32, MAX_BG_HEIGHT as f32]);
|
let game_image = imgui::Image::new(texture_id, [MAX_BG_WIDTH as f32, MAX_BG_HEIGHT as f32]);
|
||||||
game_image.build(&ui);
|
game_image.build(&ui);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_register_name(register: u16) -> &'static str {
|
||||||
|
match register {
|
||||||
|
snes_core::ppu::registers::INIDISP => "INIDISP",
|
||||||
|
snes_core::ppu::registers::TM => "TM ",
|
||||||
|
snes_core::ppu::registers::TS => "TS ",
|
||||||
|
snes_core::ppu::registers::SETINI => "SETINI ",
|
||||||
|
snes_core::ppu::registers::BGMODE => "BGMODE ",
|
||||||
|
snes_core::ppu::registers::MOSAIC => "MOSAIC ",
|
||||||
|
snes_core::ppu::registers::BG1SC => "BG1SC ",
|
||||||
|
snes_core::ppu::registers::BG2SC => "BG2SC ",
|
||||||
|
snes_core::ppu::registers::BG3SC => "BG3SC ",
|
||||||
|
snes_core::ppu::registers::BG4SC => "BG4SC ",
|
||||||
|
snes_core::ppu::registers::BG12NBA => "BG12NBA",
|
||||||
|
snes_core::ppu::registers::BG34NBA => "BG34NBA",
|
||||||
|
snes_core::ppu::registers::BG1HOFS => "BG1HOFS",
|
||||||
|
snes_core::ppu::registers::BG2HOFS => "BG2HOFS",
|
||||||
|
snes_core::ppu::registers::BG3HOFS => "BG3HOFS",
|
||||||
|
snes_core::ppu::registers::BG4HOFS => "BG4HOFS",
|
||||||
|
snes_core::ppu::registers::M7SEL => "M7SEL ",
|
||||||
|
snes_core::ppu::registers::M7A => "M7A ",
|
||||||
|
snes_core::ppu::registers::M7B => "M7B ",
|
||||||
|
snes_core::ppu::registers::M7C => "M7C ",
|
||||||
|
snes_core::ppu::registers::M7D => "M7D ",
|
||||||
|
snes_core::ppu::registers::M7X => "M7X ",
|
||||||
|
snes_core::ppu::registers::M7Y => "M7Y ",
|
||||||
|
snes_core::ppu::registers::OBSEL => "OBSEL ",
|
||||||
|
snes_core::ppu::registers::WH0 => "WH0 ",
|
||||||
|
snes_core::ppu::registers::WH1 => "WH1 ",
|
||||||
|
snes_core::ppu::registers::WH2 => "WH2 ",
|
||||||
|
snes_core::ppu::registers::WH3 => "WH3 ",
|
||||||
|
snes_core::ppu::registers::W12SEL => "W12SEL ",
|
||||||
|
snes_core::ppu::registers::W34SEL => "W34SEL ",
|
||||||
|
snes_core::ppu::registers::WOBJSEL => "WOBJSEL",
|
||||||
|
snes_core::ppu::registers::WBGLOG => "WBGLOG ",
|
||||||
|
snes_core::ppu::registers::WOBJLOG => "WOBJLOG",
|
||||||
|
snes_core::ppu::registers::TMW => "TMW ",
|
||||||
|
snes_core::ppu::registers::TSW => "TSW ",
|
||||||
|
snes_core::ppu::registers::RDNMI => "RDNMI ",
|
||||||
|
snes_core::ppu::registers::VMAIN => "VMAIN ",
|
||||||
|
snes_core::ppu::registers::VMADDH => "VMADDH ",
|
||||||
|
snes_core::ppu::registers::VMDATAL => "VMDATAL",
|
||||||
|
snes_core::ppu::registers::VMDATAH => "VMDATAH",
|
||||||
|
snes_core::ppu::registers::RDVRAML => "RDVRAML",
|
||||||
|
snes_core::ppu::registers::RDVRAMH => "RDVRAMH",
|
||||||
|
_ => "N/A ",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn registers_window(ppu_registers: &PPURegisters, show_registers: &mut bool, ui: &imgui::Ui) {
|
||||||
|
let window = imgui::Window::new("PPU Registers");
|
||||||
|
window
|
||||||
|
.size([300.0, 400.0], imgui::Condition::FirstUseEver)
|
||||||
|
.opened(show_registers)
|
||||||
|
.build(ui, || {
|
||||||
|
ui.text("Registers:");
|
||||||
|
for (index, register_value) in ppu_registers.registers().iter().enumerate() {
|
||||||
|
let register = (index as u16) + 0x2100;
|
||||||
|
let register_name = get_register_name(register);
|
||||||
|
ui.text(format!("{:04X} {}: {:02X} {:08b}", register, register_name, register_value, register_value));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn vram_window(ppu_registers: &PPURegisters, vram_debug: &mut VRAMMap, show_vram: &mut bool, ui: &imgui::Ui) {
|
||||||
|
let window = imgui::Window::new("VRAM");
|
||||||
|
window
|
||||||
|
.size([300.0, 400.0], imgui::Condition::FirstUseEver)
|
||||||
|
.opened(show_vram)
|
||||||
|
.build(ui, || {
|
||||||
|
let address_start_input = ui.input_text(
|
||||||
|
"Address start",
|
||||||
|
&mut vram_debug.address_start_input
|
||||||
|
);
|
||||||
|
address_start_input.build();
|
||||||
|
|
||||||
|
let address_end_input = ui.input_text(
|
||||||
|
"Address end",
|
||||||
|
&mut vram_debug.address_end_input,
|
||||||
|
);
|
||||||
|
address_end_input.build();
|
||||||
|
|
||||||
|
if ui.button("Apply") {
|
||||||
|
vram_debug.set_values_from_inputs();
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
let address_start = vram_debug.address_start;
|
||||||
|
let address_end = vram_debug.address_end;
|
||||||
|
let mut header = String::from(" | ");
|
||||||
|
for page in 0x00..=0x0F {
|
||||||
|
header = format!("{}{:02X} ", header, page);
|
||||||
|
}
|
||||||
|
ui.text(header);
|
||||||
|
let mut divider = String::from("-----|-");
|
||||||
|
for _ in 0x00..=0x0F {
|
||||||
|
divider = format!("{}---", divider);
|
||||||
|
}
|
||||||
|
ui.text(divider);
|
||||||
|
let vector = (address_start..=address_end).collect::<Vec<u16>>();
|
||||||
|
let chunks = vector.chunks(0x10);
|
||||||
|
for row in chunks {
|
||||||
|
let mut address_row = format!("{:04X} | ", row[0]);
|
||||||
|
for address in row {
|
||||||
|
address_row = format!("{}{:02X} ", address_row, ppu_registers.vram()[(*address) as usize]);
|
||||||
|
}
|
||||||
|
ui.text(address_row);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -78,6 +78,50 @@ impl MemoryMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct VRAMMap {
|
||||||
|
pub address_start: u16,
|
||||||
|
pub address_end: u16,
|
||||||
|
pub address_start_input: String,
|
||||||
|
pub address_end_input: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VRAMMap {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
address_start: 0x0000,
|
||||||
|
address_end: 0x00FF,
|
||||||
|
address_start_input: String::from("0000"),
|
||||||
|
address_end_input: String::from("0100"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_values(&mut self) {
|
||||||
|
if self.address_start > self.address_end {
|
||||||
|
self.address_start = self.address_end;
|
||||||
|
}
|
||||||
|
if self.address_end < self.address_start {
|
||||||
|
self.address_end = self.address_start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_values_from_inputs(&mut self) {
|
||||||
|
let address_regex = Regex::new(r"^(0x)?[0-9a-fA-F]{4,4}$").unwrap();
|
||||||
|
|
||||||
|
if !address_regex.is_match(&self.address_start_input) {
|
||||||
|
println!("Addr start didn't match");
|
||||||
|
self.address_start_input = String::from("0x0000");
|
||||||
|
}
|
||||||
|
if !address_regex.is_match(&self.address_end_input) {
|
||||||
|
println!("Addr end didn't match");
|
||||||
|
self.address_end_input = String::from("0x0000");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.address_start = u16::from_str_radix(&self.address_start_input.trim_start_matches("0x"), 16).unwrap();
|
||||||
|
self.address_end = u16::from_str_radix(&self.address_end_input.trim_start_matches("0x"), 16).unwrap();
|
||||||
|
self.validate_values()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DebugOptions {
|
pub struct DebugOptions {
|
||||||
pub is_enabled: bool,
|
pub is_enabled: bool,
|
||||||
pub show_debug_window: bool,
|
pub show_debug_window: bool,
|
||||||
@@ -134,19 +178,25 @@ impl BgDebug {
|
|||||||
|
|
||||||
pub struct PPUDebug {
|
pub struct PPUDebug {
|
||||||
pub is_enabled: bool,
|
pub is_enabled: bool,
|
||||||
|
pub show_registers: bool,
|
||||||
|
pub show_vram: bool,
|
||||||
pub backgrounds: [BgDebug; 4],
|
pub backgrounds: [BgDebug; 4],
|
||||||
|
pub vram_map: VRAMMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PPUDebug {
|
impl PPUDebug {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
is_enabled: true,
|
is_enabled: true,
|
||||||
|
show_registers: true,
|
||||||
|
show_vram: true,
|
||||||
backgrounds: [
|
backgrounds: [
|
||||||
BgDebug::new(PPUBg::Bg1),
|
BgDebug::new(PPUBg::Bg1),
|
||||||
BgDebug::new(PPUBg::Bg2),
|
BgDebug::new(PPUBg::Bg2),
|
||||||
BgDebug::new(PPUBg::Bg3),
|
BgDebug::new(PPUBg::Bg3),
|
||||||
BgDebug::new(PPUBg::Bg4),
|
BgDebug::new(PPUBg::Bg4),
|
||||||
],
|
],
|
||||||
|
vram_map: VRAMMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user