diff --git a/src/emulator.rs b/src/emulator.rs index 8748a10..4f84103 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -15,8 +15,8 @@ use anyhow::Result; use egui_toast::{Toast, ToastKind, ToastOptions}; use crate::{audio::Audio, graphics::TextureSink}; -pub use shrooms_vb_core::VBKey; use shrooms_vb_core::{Sim, EXPECTED_FRAME_SIZE}; +pub use shrooms_vb_core::{VBKey, VBRegister}; mod shrooms_vb_core; @@ -390,6 +390,13 @@ impl Emulator { } } } + EmulatorCommand::ReadRegister(sim_id, register, done) => { + let Some(sim) = self.sims.get_mut(sim_id.to_index()) else { + return; + }; + let value = sim.read_register(register); + let _ = done.send(value); + } EmulatorCommand::SetAudioEnabled(p1, p2) => { self.audio_on[SimId::Player1.to_index()].store(p1, Ordering::Release); self.audio_on[SimId::Player2.to_index()].store(p2, Ordering::Release); @@ -447,6 +454,7 @@ pub enum EmulatorCommand { StopSecondSim, Pause, Resume, + ReadRegister(SimId, VBRegister, oneshot::Sender), SetAudioEnabled(bool, bool), Link, Unlink, diff --git a/src/emulator/shrooms_vb_core.rs b/src/emulator/shrooms_vb_core.rs index 2c9510a..507de03 100644 --- a/src/emulator/shrooms_vb_core.rs +++ b/src/emulator/shrooms_vb_core.rs @@ -55,6 +55,13 @@ bitflags! { } } +#[derive(Clone, Copy, Debug)] +pub enum VBRegister { + Program(u32), + System(u32), + PC, +} + type OnFrame = extern "C" fn(sim: *mut VB) -> c_int; #[link(name = "vb")] @@ -77,6 +84,10 @@ extern "C" { right_stride_x: c_int, right_stride_y: c_int, ); + #[link_name = "vbGetProgramCounter"] + fn vb_get_program_counter(sim: *mut VB) -> u32; + #[link_name = "vbGetProgramRegister"] + fn vb_get_program_register(sim: *mut VB, index: c_uint) -> i32; #[link_name = "vbGetSamples"] fn vb_get_samples( sim: *mut VB, @@ -84,6 +95,8 @@ extern "C" { capacity: *mut c_uint, position: *mut c_uint, ) -> *mut c_void; + #[link_name = "vbGetSystemRegister"] + fn vb_get_system_register(sim: *mut VB, index: c_uint) -> i32; #[link_name = "vbGetUserData"] fn vb_get_user_data(sim: *mut VB) -> *mut c_void; #[link_name = "vbInit"] @@ -291,6 +304,16 @@ impl Sim { pub fn set_keys(&mut self, keys: VBKey) { unsafe { vb_set_keys(self.sim, keys.bits()) }; } + + pub fn read_register(&mut self, register: VBRegister) -> u32 { + match register { + VBRegister::Program(index) => unsafe { + vb_get_program_register(self.sim, index) as u32 + }, + VBRegister::System(index) => unsafe { vb_get_system_register(self.sim, index) as u32 }, + VBRegister::PC => unsafe { vb_get_program_counter(self.sim) }, + } + } } impl Drop for Sim { diff --git a/src/gdbserver.rs b/src/gdbserver.rs index 70ef3a9..056ae08 100644 --- a/src/gdbserver.rs +++ b/src/gdbserver.rs @@ -227,12 +227,23 @@ impl GdbConnection { self.client.send_command(EmulatorCommand::Resume); // Don't send a response until we hit a breakpoint or get interrupted } else if req.match_str("p") { - let Some(register) = req.match_hex::() else { + let mut read_register = || { + let register_index = req.match_hex::()?; + let register = REGISTERS.get(register_index)?.to_vb_register(); + let (tx, rx) = ::oneshot::channel(); + self.client.send_command(EmulatorCommand::ReadRegister( + self.sim_id, + register, + tx, + )); + rx.recv().ok() + }; + let Some(value) = read_register() else { let res = self.response(); self.send(res).await?; continue; }; - let res = self.response().write_hex(register); + let res = self.response().write_hex(value); self.send(res).await?; } else if req.match_str("m") { let mut read_params = || { diff --git a/src/gdbserver/registers.rs b/src/gdbserver/registers.rs index ad5f5f4..370e52e 100644 --- a/src/gdbserver/registers.rs +++ b/src/gdbserver/registers.rs @@ -1,5 +1,7 @@ +use crate::emulator::VBRegister; + pub struct RegisterInfo { - index: usize, + dwarf: u32, name: &'static str, set: &'static str, alt_name: Option<&'static str>, @@ -14,48 +16,59 @@ impl RegisterInfo { } string.push_str(&format!( ";bitsize:32;offset:{};encoding:uint;format:hex;set:{};dwarf:{}", - self.index * 4, + self.dwarf * 4, self.set, - self.index + self.dwarf )); if let Some(generic) = self.generic { string.push_str(&format!(";generic:{}", generic)); } string } + + pub fn to_vb_register(&self) -> VBRegister { + match self.dwarf { + 0..32 => VBRegister::Program(self.dwarf), + 32..40 => VBRegister::System(self.dwarf - 32), + 40..42 => VBRegister::System(self.dwarf - 16), + 42..45 => VBRegister::System(self.dwarf - 13), + 45 => VBRegister::PC, + other => panic!("unexpected DWARF register {other}"), + } + } } macro_rules! register { - ($set:expr, $index:expr, $name:expr) => { + ($set:expr, $dwarf:expr, $name:expr) => { RegisterInfo { - index: $index, + dwarf: $dwarf, name: $name, set: $set, alt_name: None, generic: None, } }; - ($set:expr, $index:expr, $name:expr, alt: $alt:expr) => { + ($set:expr, $dwarf:expr, $name:expr, alt: $alt:expr) => { RegisterInfo { - index: $index, + dwarf: $dwarf, name: $name, set: $set, alt_name: Some($alt), generic: None, } }; - ($set:expr, $index:expr, $name:expr, generic: $generic:expr) => { + ($set:expr, $dwarf:expr, $name:expr, generic: $generic:expr) => { RegisterInfo { - index: $index, + dwarf: $dwarf, name: $name, set: $set, alt_name: None, generic: Some($generic), } }; - ($set:expr, $index:expr, $name:expr, alt: $alt:expr, generic: $generic:expr) => { + ($set:expr, $dwarf:expr, $name:expr, alt: $alt:expr, generic: $generic:expr) => { RegisterInfo { - index: $index, + dwarf: $dwarf, name: $name, set: $set, alt_name: Some($alt),