Implement GDB/LLDB compatible server #3
|
@ -15,8 +15,8 @@ use anyhow::Result;
|
||||||
use egui_toast::{Toast, ToastKind, ToastOptions};
|
use egui_toast::{Toast, ToastKind, ToastOptions};
|
||||||
|
|
||||||
use crate::{audio::Audio, graphics::TextureSink};
|
use crate::{audio::Audio, graphics::TextureSink};
|
||||||
pub use shrooms_vb_core::VBKey;
|
|
||||||
use shrooms_vb_core::{Sim, EXPECTED_FRAME_SIZE};
|
use shrooms_vb_core::{Sim, EXPECTED_FRAME_SIZE};
|
||||||
|
pub use shrooms_vb_core::{VBKey, VBRegister};
|
||||||
|
|
||||||
mod shrooms_vb_core;
|
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) => {
|
EmulatorCommand::SetAudioEnabled(p1, p2) => {
|
||||||
self.audio_on[SimId::Player1.to_index()].store(p1, Ordering::Release);
|
self.audio_on[SimId::Player1.to_index()].store(p1, Ordering::Release);
|
||||||
self.audio_on[SimId::Player2.to_index()].store(p2, Ordering::Release);
|
self.audio_on[SimId::Player2.to_index()].store(p2, Ordering::Release);
|
||||||
|
@ -447,6 +454,7 @@ pub enum EmulatorCommand {
|
||||||
StopSecondSim,
|
StopSecondSim,
|
||||||
Pause,
|
Pause,
|
||||||
Resume,
|
Resume,
|
||||||
|
ReadRegister(SimId, VBRegister, oneshot::Sender<u32>),
|
||||||
SetAudioEnabled(bool, bool),
|
SetAudioEnabled(bool, bool),
|
||||||
Link,
|
Link,
|
||||||
Unlink,
|
Unlink,
|
||||||
|
|
|
@ -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;
|
type OnFrame = extern "C" fn(sim: *mut VB) -> c_int;
|
||||||
|
|
||||||
#[link(name = "vb")]
|
#[link(name = "vb")]
|
||||||
|
@ -77,6 +84,10 @@ extern "C" {
|
||||||
right_stride_x: c_int,
|
right_stride_x: c_int,
|
||||||
right_stride_y: 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"]
|
#[link_name = "vbGetSamples"]
|
||||||
fn vb_get_samples(
|
fn vb_get_samples(
|
||||||
sim: *mut VB,
|
sim: *mut VB,
|
||||||
|
@ -84,6 +95,8 @@ extern "C" {
|
||||||
capacity: *mut c_uint,
|
capacity: *mut c_uint,
|
||||||
position: *mut c_uint,
|
position: *mut c_uint,
|
||||||
) -> *mut c_void;
|
) -> *mut c_void;
|
||||||
|
#[link_name = "vbGetSystemRegister"]
|
||||||
|
fn vb_get_system_register(sim: *mut VB, index: c_uint) -> i32;
|
||||||
#[link_name = "vbGetUserData"]
|
#[link_name = "vbGetUserData"]
|
||||||
fn vb_get_user_data(sim: *mut VB) -> *mut c_void;
|
fn vb_get_user_data(sim: *mut VB) -> *mut c_void;
|
||||||
#[link_name = "vbInit"]
|
#[link_name = "vbInit"]
|
||||||
|
@ -291,6 +304,16 @@ impl Sim {
|
||||||
pub fn set_keys(&mut self, keys: VBKey) {
|
pub fn set_keys(&mut self, keys: VBKey) {
|
||||||
unsafe { vb_set_keys(self.sim, keys.bits()) };
|
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 {
|
impl Drop for Sim {
|
||||||
|
|
|
@ -227,12 +227,23 @@ impl GdbConnection {
|
||||||
self.client.send_command(EmulatorCommand::Resume);
|
self.client.send_command(EmulatorCommand::Resume);
|
||||||
// Don't send a response until we hit a breakpoint or get interrupted
|
// Don't send a response until we hit a breakpoint or get interrupted
|
||||||
} else if req.match_str("p") {
|
} else if req.match_str("p") {
|
||||||
let Some(register) = req.match_hex::<u32>() else {
|
let mut read_register = || {
|
||||||
|
let register_index = req.match_hex::<usize>()?;
|
||||||
|
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();
|
let res = self.response();
|
||||||
self.send(res).await?;
|
self.send(res).await?;
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let res = self.response().write_hex(register);
|
let res = self.response().write_hex(value);
|
||||||
self.send(res).await?;
|
self.send(res).await?;
|
||||||
} else if req.match_str("m") {
|
} else if req.match_str("m") {
|
||||||
let mut read_params = || {
|
let mut read_params = || {
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
use crate::emulator::VBRegister;
|
||||||
|
|
||||||
pub struct RegisterInfo {
|
pub struct RegisterInfo {
|
||||||
index: usize,
|
dwarf: u32,
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
set: &'static str,
|
set: &'static str,
|
||||||
alt_name: Option<&'static str>,
|
alt_name: Option<&'static str>,
|
||||||
|
@ -14,48 +16,59 @@ impl RegisterInfo {
|
||||||
}
|
}
|
||||||
string.push_str(&format!(
|
string.push_str(&format!(
|
||||||
";bitsize:32;offset:{};encoding:uint;format:hex;set:{};dwarf:{}",
|
";bitsize:32;offset:{};encoding:uint;format:hex;set:{};dwarf:{}",
|
||||||
self.index * 4,
|
self.dwarf * 4,
|
||||||
self.set,
|
self.set,
|
||||||
self.index
|
self.dwarf
|
||||||
));
|
));
|
||||||
if let Some(generic) = self.generic {
|
if let Some(generic) = self.generic {
|
||||||
string.push_str(&format!(";generic:{}", generic));
|
string.push_str(&format!(";generic:{}", generic));
|
||||||
}
|
}
|
||||||
string
|
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 {
|
macro_rules! register {
|
||||||
($set:expr, $index:expr, $name:expr) => {
|
($set:expr, $dwarf:expr, $name:expr) => {
|
||||||
RegisterInfo {
|
RegisterInfo {
|
||||||
index: $index,
|
dwarf: $dwarf,
|
||||||
name: $name,
|
name: $name,
|
||||||
set: $set,
|
set: $set,
|
||||||
alt_name: None,
|
alt_name: None,
|
||||||
generic: None,
|
generic: None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($set:expr, $index:expr, $name:expr, alt: $alt:expr) => {
|
($set:expr, $dwarf:expr, $name:expr, alt: $alt:expr) => {
|
||||||
RegisterInfo {
|
RegisterInfo {
|
||||||
index: $index,
|
dwarf: $dwarf,
|
||||||
name: $name,
|
name: $name,
|
||||||
set: $set,
|
set: $set,
|
||||||
alt_name: Some($alt),
|
alt_name: Some($alt),
|
||||||
generic: None,
|
generic: None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($set:expr, $index:expr, $name:expr, generic: $generic:expr) => {
|
($set:expr, $dwarf:expr, $name:expr, generic: $generic:expr) => {
|
||||||
RegisterInfo {
|
RegisterInfo {
|
||||||
index: $index,
|
dwarf: $dwarf,
|
||||||
name: $name,
|
name: $name,
|
||||||
set: $set,
|
set: $set,
|
||||||
alt_name: None,
|
alt_name: None,
|
||||||
generic: Some($generic),
|
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 {
|
RegisterInfo {
|
||||||
index: $index,
|
dwarf: $dwarf,
|
||||||
name: $name,
|
name: $name,
|
||||||
set: $set,
|
set: $set,
|
||||||
alt_name: Some($alt),
|
alt_name: Some($alt),
|
||||||
|
|
Loading…
Reference in New Issue