added step(n) feature to emulator, allowing for stepping n instructions at a time
This commit is contained in:
@@ -27,6 +27,7 @@ pub fn run_emulator(
|
|||||||
println!("INFO: Starting emulator.");
|
println!("INFO: Starting emulator.");
|
||||||
|
|
||||||
let mut running = Running::Paused;
|
let mut running = Running::Paused;
|
||||||
|
let mut step = 0;
|
||||||
let mut addr;
|
let mut addr;
|
||||||
let mut history = Vec::<(u32, Instruction)>::new();
|
let mut history = Vec::<(u32, Instruction)>::new();
|
||||||
let size = 256;
|
let size = 256;
|
||||||
@@ -39,7 +40,7 @@ pub fn run_emulator(
|
|||||||
let mut update = false;
|
let mut update = false;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let cmd = if running == Running::Running {
|
let cmd = if running == Running::Running || step > 0 {
|
||||||
match cmd_rx.try_recv() {
|
match cmd_rx.try_recv() {
|
||||||
Ok(cmd) => Some(cmd),
|
Ok(cmd) => Some(cmd),
|
||||||
Err(mpsc::TryRecvError::Empty) => {
|
Err(mpsc::TryRecvError::Empty) => {
|
||||||
@@ -96,26 +97,8 @@ pub fn run_emulator(
|
|||||||
|
|
||||||
processor.reset();
|
processor.reset();
|
||||||
}
|
}
|
||||||
Command::Step => {
|
Command::Step(x) => {
|
||||||
update = true;
|
step = x;
|
||||||
|
|
||||||
running = Running::Paused;
|
|
||||||
|
|
||||||
// Execute one cycle.
|
|
||||||
match processor.cycle() {
|
|
||||||
Ok((addr, instruction)) => {
|
|
||||||
history.push((addr, instruction));
|
|
||||||
}
|
|
||||||
Err(why) => {
|
|
||||||
let pcx = processor.get(Register::Pcx);
|
|
||||||
eprintln!(
|
|
||||||
"Could not decode instruction at {pcx:x}. Reason: {why}"
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
instruction_count += 1;
|
|
||||||
}
|
}
|
||||||
Command::Write(offset, data) => {
|
Command::Write(offset, data) => {
|
||||||
update = true;
|
update = true;
|
||||||
@@ -200,6 +183,31 @@ pub fn run_emulator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if step > 0 {
|
||||||
|
step -= 1;
|
||||||
|
update = true;
|
||||||
|
running = Running::Paused;
|
||||||
|
|
||||||
|
// Execute one cycle.
|
||||||
|
match processor.cycle() {
|
||||||
|
Ok((addr, instruction)) => {
|
||||||
|
history.push((addr, instruction));
|
||||||
|
}
|
||||||
|
Err(why) => {
|
||||||
|
let pcx = processor.get(Register::Pcx);
|
||||||
|
report_err(
|
||||||
|
state_tx,
|
||||||
|
&format!(
|
||||||
|
"Could not decode instruction at {pcx:x}. Reason: {why}"
|
||||||
|
),
|
||||||
|
&mut processor,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instruction_count += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if running == Running::Running {
|
if running == Running::Running {
|
||||||
update = true;
|
update = true;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ pub enum Command {
|
|||||||
// set emulator state.
|
// set emulator state.
|
||||||
Start,
|
Start,
|
||||||
Stop,
|
Stop,
|
||||||
Step,
|
Step(usize),
|
||||||
Reset(usize),
|
Reset(usize),
|
||||||
Interrupt(Interrupt),
|
Interrupt(Interrupt),
|
||||||
Write(Address, Vec<u8>),
|
Write(Address, Vec<u8>),
|
||||||
|
|||||||
@@ -64,10 +64,7 @@ impl Processor {
|
|||||||
let instruction = Instruction::decode(val)
|
let instruction = Instruction::decode(val)
|
||||||
.map_err(|_| ProcessorError::InvalidInstruction(val))?;
|
.map_err(|_| ProcessorError::InvalidInstruction(val))?;
|
||||||
|
|
||||||
log(&instruction.to_string());
|
|
||||||
|
|
||||||
instruction.execute(self)?;
|
instruction.execute(self)?;
|
||||||
|
|
||||||
Ok((addr, instruction))
|
Ok((addr, instruction))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,18 @@ use common::{instructions::Register, prelude::Instruction};
|
|||||||
|
|
||||||
pub struct ControlPanel {
|
pub struct ControlPanel {
|
||||||
visible: bool,
|
visible: bool,
|
||||||
|
step_amount_input: String,
|
||||||
|
step_amount: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ControlPanel {
|
impl ControlPanel {
|
||||||
#[allow(clippy::must_use_candidate)]
|
#[allow(clippy::must_use_candidate)]
|
||||||
pub const fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { visible: false }
|
Self {
|
||||||
|
visible: false,
|
||||||
|
step_amount_input: String::from("1"),
|
||||||
|
step_amount: 1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,9 +65,12 @@ impl Component for ControlPanel {
|
|||||||
|
|
||||||
// Step
|
// Step
|
||||||
if ui.button("Step").clicked() {
|
if ui.button("Step").clicked() {
|
||||||
state.cmd_sender.send(Command::Step).unwrap_or_else(|_| {
|
state
|
||||||
state.error_log.push("Failed to send command".to_string());
|
.cmd_sender
|
||||||
});
|
.send(Command::Step(self.step_amount))
|
||||||
|
.unwrap_or_else(|_| {
|
||||||
|
state.error_log.push("Failed to send command".to_string());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resets the emulator and all attached devices
|
// Resets the emulator and all attached devices
|
||||||
@@ -98,6 +107,21 @@ impl Component for ControlPanel {
|
|||||||
|
|
||||||
state.send(Command::RegisterRequest);
|
state.send(Command::RegisterRequest);
|
||||||
state.send(Command::RunningRequest);
|
state.send(Command::RunningRequest);
|
||||||
|
state.send(Command::InstructionCountRequest);
|
||||||
|
|
||||||
|
if ui
|
||||||
|
.text_edit_singleline(&mut self.step_amount_input)
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
self.step_amount = if let Ok(amount) = self.step_amount_input.parse() {
|
||||||
|
amount
|
||||||
|
} else {
|
||||||
|
state
|
||||||
|
.error_log
|
||||||
|
.push("Unable to parse step amount".to_string());
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Status info
|
// Status info
|
||||||
ui.label(format!(
|
ui.label(format!(
|
||||||
|
|||||||
Reference in New Issue
Block a user