Implement writing memory

This commit is contained in:
Simon Gellis 2025-01-18 01:03:22 -05:00
parent 0fff4d427f
commit 5ce39fb70e
4 changed files with 77 additions and 14 deletions

View File

@ -550,6 +550,13 @@ impl Emulator {
sim.read_memory(start, length, &mut buffer);
let _ = done.send(buffer);
}
EmulatorCommand::WriteMemory(sim_id, start, buffer, done) => {
let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
return;
};
sim.write_memory(start, &buffer);
let _ = done.send(buffer);
}
EmulatorCommand::AddBreakpoint(sim_id, address) => {
let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
return;
@ -639,6 +646,7 @@ pub enum EmulatorCommand {
ReadRegister(SimId, VBRegister, oneshot::Sender<u32>),
WriteRegister(SimId, VBRegister, u32),
ReadMemory(SimId, u32, usize, Vec<u8>, oneshot::Sender<Vec<u8>>),
WriteMemory(SimId, u32, Vec<u8>, oneshot::Sender<Vec<u8>>),
AddBreakpoint(SimId, u32),
RemoveBreakpoint(SimId, u32),
AddWatchpoint(SimId, u32, usize, VBWatchpointType),

View File

@ -166,6 +166,8 @@ extern "C" {
fn vb_set_write_callback(sim: *mut VB, callback: Option<OnWrite>) -> Option<OnWrite>;
#[link_name = "vbSizeOf"]
fn vb_size_of() -> usize;
#[link_name = "vbWrite"]
fn vb_write(sim: *mut VB, address: u32, _type: VBDataType, value: i32) -> i32;
}
extern "C" fn on_frame(sim: *mut VB) -> c_int {
@ -476,6 +478,14 @@ impl Sim {
}
}
pub fn write_memory(&mut self, start: u32, buffer: &[u8]) {
let mut address = start;
for byte in buffer {
unsafe { vb_write(self.sim, address, VBDataType::U8, *byte as i32) };
address = address.wrapping_add(1);
}
}
pub fn add_breakpoint(&mut self, address: u32) {
let data = self.get_state();
if let Err(index) = data.breakpoints.binary_search(&address) {

View File

@ -346,22 +346,9 @@ impl GdbConnection {
}
} else if let Some(op) = req.match_some_str(["m", "x"]) {
let mut read_memory = || {
let start = req.match_hex::<u64>()?;
if !req.match_str(",") {
return None;
};
let length = req.match_hex::<usize>()?;
let (start, length) = parse_memory_range(&mut req)?;
let mut buf = self.memory_buf.take().unwrap_or_default();
buf.clear();
// The v810 has a 32-bit address space.
// Addresses wrap within that space, but we don't need to implement that for 64-bit addresses.
// Just refuse to return any info for addresses above 0xffffffff.
let Ok(start) = u32::try_from(start) else {
return Some(buf);
};
let length = length.min((u32::MAX - start) as usize + 1);
if length == 0 {
return Some(buf);
}
@ -395,6 +382,38 @@ impl GdbConnection {
} else {
self.response()
}
} else if let Some(op) = req.match_some_str(["M", "X"]) {
let mut write_memory = || {
let (start, length) = parse_memory_range(&mut req)?;
if length == 0 {
return Some(());
}
if !req.match_str(":") {
return None;
}
let mut buf = self.memory_buf.take().unwrap_or_default();
buf.resize(length, 0);
let successful_read = if op == "M" {
req.match_hex_bytes(&mut buf)
} else {
req.match_bytes(&mut buf)
};
if !successful_read {
self.memory_buf = Some(buf);
return None;
}
let (tx, rx) = ::oneshot::channel();
self.client
.send_command(EmulatorCommand::WriteMemory(self.sim_id, start, buf, tx));
let buf = rx.recv().ok()?;
self.memory_buf = Some(buf);
Some(())
};
if write_memory().is_some() {
self.response().write_str("OK")
} else {
self.response()
}
} else if req.match_str("Z") {
let mut parse_request = || {
let type_ = req.match_hex::<u8>()?;
@ -483,6 +502,23 @@ impl Drop for GdbConnection {
}
}
// parse a memory range into a start and a length.
fn parse_memory_range(req: &mut Request<'_>) -> Option<(u32, usize)> {
let start = req.match_hex::<u64>()?;
if !req.match_str(",") {
return None;
};
let length = req.match_hex::<usize>()?;
let Ok(start) = u32::try_from(start) else {
// The v810 has a 32-bit address space.
// Addresses wrap within that space, but we don't need to implement that for 64-bit addresses.
// Just refuse to return any info for addresses above 0xffffffff.
return Some((0, 0));
};
let length = length.min((u32::MAX - start) as usize + 1);
Some((start, length))
}
fn debug_stop_reason_string(reason: Option<DebugStopReason>) -> String {
let mut result = String::new();
result += if reason.is_some() { "T05;" } else { "T00;" };

View File

@ -74,6 +74,15 @@ impl Request<'_> {
self.buffer = self.buffer.split_at(buffer.len()).1;
true
}
pub fn match_bytes(&mut self, buffer: &mut [u8]) -> bool {
if self.buffer.len() < buffer.len() {
return false;
}
buffer.copy_from_slice(&self.buffer[0..buffer.len()]);
self.buffer = self.buffer.split_at(buffer.len()).1;
true
}
}
pub struct RequestSource<R> {