Implement fake stdout
This commit is contained in:
@@ -230,7 +230,7 @@ extern "C" fn on_write(
|
||||
sim: *mut VB,
|
||||
address: u32,
|
||||
_type: VBDataType,
|
||||
_value: *mut i32,
|
||||
value: *mut i32,
|
||||
_cycles: *mut u32,
|
||||
_cancel: *mut c_int,
|
||||
) -> c_int {
|
||||
@@ -238,6 +238,14 @@ extern "C" fn on_write(
|
||||
// There is no way for the userdata to be null or otherwise invalid.
|
||||
let data: &mut VBState = unsafe { &mut *vb_get_user_data(sim).cast() };
|
||||
|
||||
// If we're monitoring stdout, track this write
|
||||
if let Some(stdout) = data.stdout.as_mut() {
|
||||
let normalized_hw_address = address & 0x0700003f;
|
||||
if normalized_hw_address == 0x02000030 {
|
||||
stdout.push(unsafe { *value } as u8);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(start) = data.write_watchpoints.start_of_range_containing(address) {
|
||||
let watch = if data.read_watchpoints.contains(address) {
|
||||
VBWatchpointType::Access
|
||||
@@ -263,6 +271,7 @@ struct VBState {
|
||||
breakpoints: Vec<u32>,
|
||||
read_watchpoints: AddressSet,
|
||||
write_watchpoints: AddressSet,
|
||||
stdout: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl VBState {
|
||||
@@ -306,6 +315,7 @@ impl Sim {
|
||||
breakpoints: vec![],
|
||||
read_watchpoints: AddressSet::new(),
|
||||
write_watchpoints: AddressSet::new(),
|
||||
stdout: None,
|
||||
};
|
||||
unsafe { vb_set_user_data(sim, Box::into_raw(Box::new(state)).cast()) };
|
||||
unsafe { vb_set_frame_callback(sim, Some(on_frame)) };
|
||||
@@ -564,7 +574,9 @@ impl Sim {
|
||||
state.write_watchpoints.remove(address, length);
|
||||
let needs_execute = state.needs_execute_callback();
|
||||
if state.write_watchpoints.is_empty() {
|
||||
unsafe { vb_set_write_callback(self.sim, None) };
|
||||
if state.stdout.is_none() {
|
||||
unsafe { vb_set_write_callback(self.sim, None) };
|
||||
}
|
||||
if !needs_execute {
|
||||
unsafe { vb_set_execute_callback(self.sim, None) };
|
||||
}
|
||||
@@ -586,11 +598,40 @@ impl Sim {
|
||||
data.breakpoints.clear();
|
||||
data.read_watchpoints.clear();
|
||||
data.write_watchpoints.clear();
|
||||
let needs_write = data.stdout.is_some();
|
||||
unsafe { vb_set_read_callback(self.sim, None) };
|
||||
unsafe { vb_set_write_callback(self.sim, None) };
|
||||
if !needs_write {
|
||||
unsafe { vb_set_write_callback(self.sim, None) };
|
||||
}
|
||||
unsafe { vb_set_execute_callback(self.sim, None) };
|
||||
}
|
||||
|
||||
pub fn watch_stdout(&mut self, watch: bool) {
|
||||
let data = self.get_state();
|
||||
if watch {
|
||||
if data.stdout.is_none() {
|
||||
data.stdout = Some(vec![]);
|
||||
unsafe { vb_set_write_callback(self.sim, Some(on_write)) };
|
||||
}
|
||||
} else {
|
||||
data.stdout.take();
|
||||
if data.write_watchpoints.is_empty() {
|
||||
unsafe { vb_set_write_callback(self.sim, None) };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn take_stdout(&mut self) -> Option<String> {
|
||||
let data = self.get_state();
|
||||
let stdout = data.stdout.take()?;
|
||||
let string = match String::from_utf8(stdout) {
|
||||
Ok(str) => str,
|
||||
Err(err) => String::from_utf8_lossy(err.as_bytes()).into_owned(),
|
||||
};
|
||||
data.stdout = Some(vec![]);
|
||||
Some(string)
|
||||
}
|
||||
|
||||
pub fn stop_reason(&mut self) -> Option<StopReason> {
|
||||
let data = self.get_state();
|
||||
let reason = data.stop_reason.take();
|
||||
|
||||
Reference in New Issue
Block a user