Implement writing memory
This commit is contained in:
		
							parent
							
								
									0fff4d427f
								
							
						
					
					
						commit
						5ce39fb70e
					
				| 
						 | 
					@ -550,6 +550,13 @@ impl Emulator {
 | 
				
			||||||
                sim.read_memory(start, length, &mut buffer);
 | 
					                sim.read_memory(start, length, &mut buffer);
 | 
				
			||||||
                let _ = done.send(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) => {
 | 
					            EmulatorCommand::AddBreakpoint(sim_id, address) => {
 | 
				
			||||||
                let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
 | 
					                let Some(sim) = self.sims.get_mut(sim_id.to_index()) else {
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
| 
						 | 
					@ -639,6 +646,7 @@ pub enum EmulatorCommand {
 | 
				
			||||||
    ReadRegister(SimId, VBRegister, oneshot::Sender<u32>),
 | 
					    ReadRegister(SimId, VBRegister, oneshot::Sender<u32>),
 | 
				
			||||||
    WriteRegister(SimId, VBRegister, u32),
 | 
					    WriteRegister(SimId, VBRegister, u32),
 | 
				
			||||||
    ReadMemory(SimId, u32, usize, Vec<u8>, oneshot::Sender<Vec<u8>>),
 | 
					    ReadMemory(SimId, u32, usize, Vec<u8>, oneshot::Sender<Vec<u8>>),
 | 
				
			||||||
 | 
					    WriteMemory(SimId, u32, Vec<u8>, oneshot::Sender<Vec<u8>>),
 | 
				
			||||||
    AddBreakpoint(SimId, u32),
 | 
					    AddBreakpoint(SimId, u32),
 | 
				
			||||||
    RemoveBreakpoint(SimId, u32),
 | 
					    RemoveBreakpoint(SimId, u32),
 | 
				
			||||||
    AddWatchpoint(SimId, u32, usize, VBWatchpointType),
 | 
					    AddWatchpoint(SimId, u32, usize, VBWatchpointType),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -166,6 +166,8 @@ extern "C" {
 | 
				
			||||||
    fn vb_set_write_callback(sim: *mut VB, callback: Option<OnWrite>) -> Option<OnWrite>;
 | 
					    fn vb_set_write_callback(sim: *mut VB, callback: Option<OnWrite>) -> Option<OnWrite>;
 | 
				
			||||||
    #[link_name = "vbSizeOf"]
 | 
					    #[link_name = "vbSizeOf"]
 | 
				
			||||||
    fn vb_size_of() -> usize;
 | 
					    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 {
 | 
					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) {
 | 
					    pub fn add_breakpoint(&mut self, address: u32) {
 | 
				
			||||||
        let data = self.get_state();
 | 
					        let data = self.get_state();
 | 
				
			||||||
        if let Err(index) = data.breakpoints.binary_search(&address) {
 | 
					        if let Err(index) = data.breakpoints.binary_search(&address) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -346,22 +346,9 @@ impl GdbConnection {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else if let Some(op) = req.match_some_str(["m", "x"]) {
 | 
					        } else if let Some(op) = req.match_some_str(["m", "x"]) {
 | 
				
			||||||
            let mut read_memory = || {
 | 
					            let mut read_memory = || {
 | 
				
			||||||
                let start = req.match_hex::<u64>()?;
 | 
					                let (start, length) = parse_memory_range(&mut req)?;
 | 
				
			||||||
                if !req.match_str(",") {
 | 
					 | 
				
			||||||
                    return None;
 | 
					 | 
				
			||||||
                };
 | 
					 | 
				
			||||||
                let length = req.match_hex::<usize>()?;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                let mut buf = self.memory_buf.take().unwrap_or_default();
 | 
					                let mut buf = self.memory_buf.take().unwrap_or_default();
 | 
				
			||||||
                buf.clear();
 | 
					                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 {
 | 
					                if length == 0 {
 | 
				
			||||||
                    return Some(buf);
 | 
					                    return Some(buf);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
| 
						 | 
					@ -395,6 +382,38 @@ impl GdbConnection {
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                self.response()
 | 
					                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") {
 | 
					        } else if req.match_str("Z") {
 | 
				
			||||||
            let mut parse_request = || {
 | 
					            let mut parse_request = || {
 | 
				
			||||||
                let type_ = req.match_hex::<u8>()?;
 | 
					                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 {
 | 
					fn debug_stop_reason_string(reason: Option<DebugStopReason>) -> String {
 | 
				
			||||||
    let mut result = String::new();
 | 
					    let mut result = String::new();
 | 
				
			||||||
    result += if reason.is_some() { "T05;" } else { "T00;" };
 | 
					    result += if reason.is_some() { "T05;" } else { "T00;" };
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,6 +74,15 @@ impl Request<'_> {
 | 
				
			||||||
        self.buffer = self.buffer.split_at(buffer.len()).1;
 | 
					        self.buffer = self.buffer.split_at(buffer.len()).1;
 | 
				
			||||||
        true
 | 
					        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> {
 | 
					pub struct RequestSource<R> {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue