fixed a bug in the emulator where halting would break the state.
This commit is contained in:
@@ -1,21 +1,21 @@
|
||||
#![feature(likely_unlikely)]
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::thread::{JoinHandle, Thread};
|
||||
use std::time::Duration;
|
||||
use common::prelude::{Instruction, Register};
|
||||
use crate::config::{IoMap, MemoryMap};
|
||||
use crate::InternalImplementation::{Handle, Owned};
|
||||
use crate::config::{IoMap, MemoryMap};
|
||||
use crate::memory::PhysAddr;
|
||||
use crate::memory::ram::MemoryBank;
|
||||
use crate::processor::{Interrupt, RunningState, SharedState};
|
||||
use common::prelude::Register;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::thread;
|
||||
use std::thread::JoinHandle;
|
||||
use std::time::Duration;
|
||||
|
||||
pub mod processor;
|
||||
pub mod memory;
|
||||
pub mod config;
|
||||
pub mod devices;
|
||||
pub mod memory;
|
||||
pub mod processor;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DsaError {
|
||||
@@ -64,7 +64,6 @@ pub struct EmulatorHandle {
|
||||
}
|
||||
|
||||
impl EmulatorHandle {
|
||||
|
||||
pub fn read_byte(&self, addr: PhysAddr) -> u8 {
|
||||
self.memory.read_byte(addr)
|
||||
}
|
||||
@@ -81,10 +80,11 @@ impl EmulatorHandle {
|
||||
self.memory.write_bytes(addr, data);
|
||||
}
|
||||
|
||||
|
||||
pub fn interrupt(&mut self, code: Interrupt) -> Result<(), DsaError> {
|
||||
self.state.interrupt_queue.send(code)
|
||||
.map_err(|_| DsaError::CommunicationError("interrupt failed".into()) )
|
||||
self.state
|
||||
.interrupt_queue
|
||||
.send(code)
|
||||
.map_err(|_| DsaError::CommunicationError("interrupt failed".into()))
|
||||
}
|
||||
|
||||
pub fn status(&self) -> RunningState {
|
||||
@@ -97,7 +97,6 @@ impl EmulatorHandle {
|
||||
self.state.proc.load().time
|
||||
}
|
||||
|
||||
|
||||
/// Request that the dsa_emulator backend provide an updated copy of its current internal state to `state.proc`
|
||||
pub fn request_update(&mut self) {
|
||||
self.state.update_requested.store(true, Ordering::Relaxed);
|
||||
@@ -112,7 +111,9 @@ impl EmulatorHandle {
|
||||
pub fn when_paused(&mut self, f: impl FnOnce(&mut Self)) {
|
||||
self.request_pause();
|
||||
|
||||
while self.state.proc.load().running != RunningState::Paused {
|
||||
while self.state.proc.load().running != RunningState::Paused
|
||||
&& self.state.proc.load().running != RunningState::Ready
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -162,7 +163,6 @@ impl AsMut<EmulatorHandle> for EmulatorController {
|
||||
}
|
||||
|
||||
impl EmulatorController {
|
||||
|
||||
pub fn new(mut emulator: Box<dyn DsaImplementation>) -> Self {
|
||||
Self {
|
||||
handle: EmulatorHandle {
|
||||
@@ -177,14 +177,16 @@ impl EmulatorController {
|
||||
const STACK_SIZE: usize = 1024 * 1024 * 16;
|
||||
|
||||
let Some(Owned(mut handle)) = self.internal.take() else {
|
||||
return Err(DsaError::CriticalException(String::from("owned dsa_emulator returned none!")))
|
||||
return Err(DsaError::CriticalException(String::from(
|
||||
"owned dsa_emulator returned none!",
|
||||
)));
|
||||
};
|
||||
|
||||
self.internal = Some(Handle(
|
||||
thread::Builder::new()
|
||||
.stack_size(STACK_SIZE)
|
||||
.spawn(move || {handle.run().unwrap() })
|
||||
.unwrap()
|
||||
.spawn(move || handle.run().unwrap())
|
||||
.unwrap(),
|
||||
));
|
||||
|
||||
Ok(())
|
||||
@@ -212,24 +214,4 @@ impl EmulatorController {
|
||||
}
|
||||
self.internal = None;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ use crate::config::{IoMap, MemoryMap, RegionType};
|
||||
use crate::memory::mmu::MMU;
|
||||
use crate::memory::ram::{MemoryBank, Page};
|
||||
use crate::processor::interrupts::Interrupt;
|
||||
use crate::processor::state::RunningState::Running;
|
||||
use crate::processor::state::ProcessorSnapshot;
|
||||
use crate::processor::state::RunningState::Running;
|
||||
use common::isa::instructions::Opcode;
|
||||
use common::prelude::{Instruction, Register};
|
||||
|
||||
@@ -36,6 +36,8 @@ impl DsaProcessor {
|
||||
self.mmio_region = None;
|
||||
self.memory_map = None;
|
||||
self.__mmap_configured = false;
|
||||
|
||||
self.internal_state = ProcessorSnapshot::default();
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
@@ -209,8 +211,9 @@ impl DsaProcessor {
|
||||
}
|
||||
|
||||
Some(Opcode::Sub) => {
|
||||
*self.mut_reg(word.dest_uc()) =
|
||||
self.reg(word.src1_uc()) - self.reg(word.src2_uc());
|
||||
*self.mut_reg(word.dest_uc()) = self
|
||||
.reg(word.src1_uc())
|
||||
.wrapping_sub(self.reg(word.src2_uc()));
|
||||
}
|
||||
|
||||
Some(Opcode::Shl) => {
|
||||
@@ -228,7 +231,8 @@ impl DsaProcessor {
|
||||
}
|
||||
|
||||
Some(Opcode::Subi) => {
|
||||
*self.mut_reg(word.dest_uc()) = self.reg(word.src1_uc()) - word.imm16() as u32;
|
||||
*self.mut_reg(word.dest_uc()) =
|
||||
self.reg(word.src1_uc()).wrapping_sub(word.imm16() as u32);
|
||||
}
|
||||
|
||||
// Utility
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::config::{IoMap, MemoryMap};
|
||||
use crate::memory::ram::MemoryBank;
|
||||
use crate::processor::RunningState::Ready;
|
||||
use crate::processor::dsa_core::{DsaProcessor, ExecutionResult};
|
||||
use crate::processor::interrupts::Interrupt;
|
||||
use crate::processor::state::RunningState::{Halted, Paused, Running, Shutdown};
|
||||
@@ -7,11 +8,9 @@ use crate::processor::state::{RunningState, SharedState};
|
||||
use crate::{DsaError, DsaImplementation};
|
||||
use common::prelude::{Instruction, Register};
|
||||
use std::hint::unlikely;
|
||||
use std::ops::AddAssign;
|
||||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, mpsc};
|
||||
use std::sync::mpsc::TryRecvError;
|
||||
use std::thread;
|
||||
use std::sync::{Arc, mpsc};
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
pub struct Emulator {
|
||||
@@ -53,7 +52,6 @@ impl DsaImplementation for Emulator {
|
||||
// do not change anything about this loop. it's fully optimised afaik.
|
||||
// Check for commands or hardware Interrupts every 32k cycles
|
||||
if unlikely(self.core.internal_state.clock & 0x7FFF == 0) {
|
||||
|
||||
// Responsibility: keep the UI thread up to date periodically
|
||||
// Update UI thread (roughly every 512k cycles targeting 60 UPS)
|
||||
if unlikely(self.core.internal_state.clock & 0x7FFFF == 0) {
|
||||
@@ -62,7 +60,9 @@ impl DsaImplementation for Emulator {
|
||||
self.share_state();
|
||||
|
||||
// Acknowledge update completed
|
||||
self.shared_state.update_requested.store(false, Ordering::Relaxed);
|
||||
self.shared_state
|
||||
.update_requested
|
||||
.store(false, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,12 +97,15 @@ impl DsaImplementation for Emulator {
|
||||
*self.core.mut_reg(Register::Pcx) = self.core.reg(Register::Pcx).wrapping_add(4);
|
||||
|
||||
match self.core.execute(Instruction(instruction)) {
|
||||
ExecutionResult::Continue => {},
|
||||
ExecutionResult::Continue => {}
|
||||
ExecutionResult::Halt => self.run_state_halted(Running),
|
||||
ExecutionResult::Interrupt(interrupt) => {
|
||||
if cfg!(debug_assertions) {
|
||||
println!("Interrupt: {:?}", interrupt);
|
||||
println!("Interrupt while at address {:04X}", self.core.reg(Register::Pcx));
|
||||
println!(
|
||||
"Interrupt while at address {:04X}",
|
||||
self.core.reg(Register::Pcx)
|
||||
);
|
||||
}
|
||||
|
||||
self.core.interrupt(interrupt);
|
||||
@@ -188,6 +191,10 @@ impl Emulator {
|
||||
// Transition: pause signal received
|
||||
if self.shared_state.pause_requested.load(Ordering::Relaxed) {
|
||||
self.run_state_paused(Halted);
|
||||
|
||||
if self.core.internal_state.running == Ready {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Responsibility: update UI when requested
|
||||
@@ -195,12 +202,15 @@ impl Emulator {
|
||||
self.share_state();
|
||||
|
||||
// Acknowledge update completed
|
||||
self.shared_state.update_requested.store(false, Ordering::Relaxed);
|
||||
self.shared_state
|
||||
.update_requested
|
||||
.store(false, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
// Responsibility: reset `private.time` on state exit
|
||||
self.time = Instant::now();
|
||||
|
||||
self.core.internal_state.running = prior;
|
||||
}
|
||||
|
||||
@@ -218,13 +228,19 @@ impl Emulator {
|
||||
self.share_state();
|
||||
|
||||
// Acknowledge update completed
|
||||
self.shared_state.update_requested.store(false, Ordering::Relaxed);
|
||||
self.shared_state
|
||||
.update_requested
|
||||
.store(false, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
// Responsibility: reset when requested by the UI
|
||||
if self.shared_state.reset_requested.load(Ordering::Relaxed) == true {
|
||||
self.reset();
|
||||
self.shared_state.reset_requested.store(false, Ordering::Relaxed);
|
||||
self.shared_state
|
||||
.reset_requested
|
||||
.store(false, Ordering::Relaxed);
|
||||
|
||||
self.core.internal_state.running = Ready;
|
||||
}
|
||||
|
||||
// Transition: run signal received
|
||||
@@ -238,6 +254,10 @@ impl Emulator {
|
||||
self.core.internal_state.time = Duration::new(0, 0);
|
||||
self.core.internal_state.clock = 0;
|
||||
|
||||
if self.core.internal_state.running == Ready {
|
||||
return;
|
||||
}
|
||||
|
||||
self.core.internal_state.running = prior;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::sync::{Arc, atomic::AtomicBool, mpsc};
|
||||
use std::sync::atomic::AtomicIsize;
|
||||
use std::time::Duration;
|
||||
use arc_swap::ArcSwap;
|
||||
use common::prelude::Register;
|
||||
use std::sync::{Arc, atomic::AtomicBool, mpsc};
|
||||
use std::time::Duration;
|
||||
|
||||
use super::interrupts::Interrupt;
|
||||
pub struct SharedState {
|
||||
@@ -32,6 +31,7 @@ pub enum RunningState {
|
||||
Paused,
|
||||
Halted,
|
||||
Running,
|
||||
Ready,
|
||||
Shutdown,
|
||||
Breakpoint(u32),
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ dsa_tasks = { path = "../../libraries/dsa_tasks" }
|
||||
|
||||
zxq5_egui = { path = "../../libraries/zxq5_egui" }
|
||||
assembler = { path = "../../tooling/assembler" }
|
||||
dsfl_compiler = { path = "../../tooling/dsfl_compiler" }
|
||||
dsa_emulator = { version = "0.3.0", path = "../dsa_emulator" }
|
||||
disassembler = { version = "0.3.0", path = "../../tooling/disassembler" }
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use crate::ui::ui_helpers::StateWrapper;
|
||||
use common::prelude::Register;
|
||||
use dsa_emulator::EmulatorHandle;
|
||||
use dsa_emulator::processor::RunningState;
|
||||
use dsa_emulator::processor::RunningState::Ready;
|
||||
use eframe::epaint::Color32;
|
||||
use zxq5_egui::buttons::PaddedWidget;
|
||||
use crate::ui::ui_helpers::StateWrapper;
|
||||
|
||||
pub struct Controller {
|
||||
emulator: EmulatorHandle,
|
||||
@@ -11,82 +12,91 @@ pub struct Controller {
|
||||
|
||||
impl Controller {
|
||||
pub fn new(state: EmulatorHandle) -> Self {
|
||||
Self {
|
||||
emulator: state,
|
||||
}
|
||||
Self { emulator: state }
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) {
|
||||
|
||||
self.emulator.request_update();
|
||||
|
||||
egui::Frame::new()
|
||||
.inner_margin(10.0)
|
||||
.show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
use RunningState::*;
|
||||
let status = self.emulator.status();
|
||||
egui::Frame::new().inner_margin(10.0).show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
use RunningState::*;
|
||||
let status = self.emulator.status();
|
||||
|
||||
match status {
|
||||
Paused | Breakpoint(_) =>
|
||||
if PaddedWidget::button("▶ Run").color(Color32::GREEN).ui(ui).clicked() {
|
||||
self.emulator.request_resume()
|
||||
}
|
||||
Running | Halted =>
|
||||
if PaddedWidget::button("⏸ Pause").color(Color32::YELLOW).ui(ui).clicked() {
|
||||
self.emulator.request_pause()
|
||||
}
|
||||
Shutdown => {
|
||||
ui.add_enabled_ui(false, |ui| {
|
||||
PaddedWidget::button("▶ Run").color(Color32::GREEN).ui(ui);
|
||||
});
|
||||
match status {
|
||||
Paused | Breakpoint(_) | Ready => {
|
||||
if PaddedWidget::button("▶ Run")
|
||||
.color(Color32::GREEN)
|
||||
.ui(ui)
|
||||
.clicked()
|
||||
{
|
||||
self.emulator.request_resume()
|
||||
}
|
||||
}
|
||||
|
||||
PaddedWidget::indicator(StateWrapper(status)).ui(ui);
|
||||
|
||||
if PaddedWidget::button("⟳ Reset All").color(Color32::ORANGE).ui(ui).clicked() {
|
||||
self.emulator.when_paused(|emu| emu.reset());
|
||||
Running | Halted => {
|
||||
if PaddedWidget::button("⏸ Pause")
|
||||
.color(Color32::YELLOW)
|
||||
.ui(ui)
|
||||
.clicked()
|
||||
{
|
||||
self.emulator.request_pause()
|
||||
}
|
||||
}
|
||||
Shutdown => {
|
||||
ui.add_enabled_ui(false, |ui| {
|
||||
PaddedWidget::button("▶ Run").color(Color32::GREEN).ui(ui);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Step
|
||||
// if ui.button("Step").clicked() {
|
||||
// state
|
||||
// .cmd_sender
|
||||
// .send(Command::Step(self.step_amount))
|
||||
// .unwrap_or_else(|_| {
|
||||
// state.error_log.push("Failed to send command".to_string());
|
||||
// });
|
||||
// }
|
||||
PaddedWidget::indicator(StateWrapper(status)).ui(ui);
|
||||
|
||||
// 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
|
||||
// }
|
||||
// }
|
||||
if PaddedWidget::button("⟳ Reset All")
|
||||
.color(Color32::ORANGE)
|
||||
.ui(ui)
|
||||
.clicked()
|
||||
{
|
||||
self.emulator.when_paused(|emu| emu.reset());
|
||||
}
|
||||
|
||||
ui.separator();
|
||||
// Step
|
||||
// if ui.button("Step").clicked() {
|
||||
// state
|
||||
// .cmd_sender
|
||||
// .send(Command::Step(self.step_amount))
|
||||
// .unwrap_or_else(|_| {
|
||||
// state.error_log.push("Failed to send command".to_string());
|
||||
// });
|
||||
// }
|
||||
|
||||
let clock = self.emulator.clock();
|
||||
PaddedWidget::label(format!("Clock: {clock}")).ui(ui);
|
||||
// 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
|
||||
// }
|
||||
// }
|
||||
|
||||
let pcx = self.emulator.get_register(Register::Pcx);
|
||||
PaddedWidget::label( format!("Pcx: 0x{pcx:08X}")).ui(ui);
|
||||
ui.separator();
|
||||
|
||||
let time = self.emulator.time().as_micros();
|
||||
PaddedWidget::label( format!("Elapsed: {} micros", time)).ui(ui);
|
||||
let clock = self.emulator.clock();
|
||||
PaddedWidget::label(format!("Clock: {clock}")).ui(ui);
|
||||
|
||||
let mips = (clock as u128).checked_div(time).unwrap_or(0);
|
||||
PaddedWidget::label(format!("Freq: {}MHz", mips)).ui(ui);
|
||||
});
|
||||
let pcx = self.emulator.get_register(Register::Pcx);
|
||||
PaddedWidget::label(format!("Pcx: 0x{pcx:08X}")).ui(ui);
|
||||
|
||||
let time = self.emulator.time().as_micros();
|
||||
PaddedWidget::label(format!("Elapsed: {} micros", time)).ui(ui);
|
||||
|
||||
let mips = (clock as u128).checked_div(time).unwrap_or(0);
|
||||
PaddedWidget::label(format!("Freq: {}MHz", mips)).ui(ui);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,13 +44,14 @@ impl ProcessHandle {
|
||||
id: usize,
|
||||
name: impl Into<String>,
|
||||
process: P,
|
||||
input: P::Input,
|
||||
on_complete: impl FnOnce(Result<P::Output, P::Error>) -> Action + Send + 'static,
|
||||
) -> Self {
|
||||
let (tx, rx) = mpsc::channel::<String>();
|
||||
let agent = ProcessAgent::new(tx);
|
||||
|
||||
let join_handle = std::thread::spawn(move || {
|
||||
let result = TraceableProcess::run(Box::new(process), agent);
|
||||
let result = TraceableProcess::run(Box::new(process), input, agent);
|
||||
on_complete(result)
|
||||
});
|
||||
|
||||
@@ -92,9 +93,10 @@ impl ProcessManager {
|
||||
&mut self,
|
||||
name: impl Into<String>,
|
||||
process: P,
|
||||
input: P::Input,
|
||||
on_complete: impl FnOnce(Result<P::Output, P::Error>) -> Action + Send + 'static,
|
||||
) {
|
||||
let handle = ProcessHandle::spawn(self.new_id(), name, process, on_complete);
|
||||
let handle = ProcessHandle::spawn(self.new_id(), name, process, input, on_complete);
|
||||
self.handles.push(handle);
|
||||
}
|
||||
|
||||
|
||||
@@ -67,12 +67,13 @@ impl Editor {
|
||||
&mut self.buffer
|
||||
}
|
||||
|
||||
pub fn get_build_command(filename: PathBuf) -> impl TraceableProcess {
|
||||
match filename.extension().unwrap().to_str().unwrap() {
|
||||
"dsa" => Assembler::new(filename),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
// pub fn get_build_command(file_path: PathBuf) -> impl TraceableProcess {
|
||||
// let filename = file_path.file_name().unwrap().to_str().unwrap();
|
||||
// match file_path.extension().unwrap().to_str().unwrap() {
|
||||
// "dsa" => Assembler::new(filename),
|
||||
// "dsfl" => DsflCompiler::new(filename),
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn create_build_action(
|
||||
&self,
|
||||
@@ -80,11 +81,16 @@ impl Editor {
|
||||
on_complete: impl FnOnce(DseExecutable) -> Action + Send + 'static,
|
||||
) -> Action {
|
||||
ProcessSpawner::new(move |pm| {
|
||||
let builder = Assembler::new(filename);
|
||||
pm.spawn(builder.label(), builder, move |result| match result {
|
||||
Ok(bin) => on_complete(bin),
|
||||
Err(e) => Action::ShowError(e.to_string()),
|
||||
});
|
||||
let builder = Assembler::new(filename.file_name().unwrap().to_str().unwrap());
|
||||
pm.spawn(
|
||||
builder.label(),
|
||||
builder,
|
||||
filename,
|
||||
move |result| match result {
|
||||
Ok(bin) => on_complete(bin),
|
||||
Err(e) => Action::ShowError(e.to_string()),
|
||||
},
|
||||
);
|
||||
})
|
||||
.into_action()
|
||||
}
|
||||
|
||||
@@ -76,23 +76,15 @@ impl Behavior<Pane> for TileBehavior {
|
||||
}
|
||||
|
||||
fn on_tab_close(&mut self, tiles: &mut Tiles<Pane>, tile_id: TileId) -> bool {
|
||||
println!("on_tab_close_1");
|
||||
|
||||
let Some(Tile::Pane(pane)) = tiles.get_mut(tile_id) else {
|
||||
println!("on_tab_close_ret1");
|
||||
return false;
|
||||
};
|
||||
|
||||
println!("on_tab_close_2");
|
||||
|
||||
if pane.close_requires_confirmation(tile_id) {
|
||||
println!("on_tab_close_ret2");
|
||||
self.pending_action = Some(RequestCloseTab(tile_id));
|
||||
return false;
|
||||
}
|
||||
|
||||
println!("on_tab_close_3");
|
||||
|
||||
tiles.remove(tile_id);
|
||||
true
|
||||
}
|
||||
@@ -220,20 +212,8 @@ impl CentralTiles {
|
||||
}
|
||||
|
||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<Action> {
|
||||
println!("centraltiles_ui_1");
|
||||
|
||||
// self.behavior.pending_action = None;
|
||||
self.tree.ui(&mut self.behavior, ui);
|
||||
|
||||
println!("centraltiles_ui_2");
|
||||
|
||||
let action = self.behavior.pending_action.take();
|
||||
|
||||
println!("centraltiles_ui_3 {action:?}");
|
||||
|
||||
action
|
||||
|
||||
// self.behavior.pending_action.take()
|
||||
self.behavior.pending_action.take()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ pub struct StateWrapper(pub RunningState);
|
||||
impl StatusIndicator for StateWrapper {
|
||||
fn color(&self) -> egui::Color32 {
|
||||
match self.0 {
|
||||
RunningState::Running => egui::Color32::GREEN,
|
||||
RunningState::Ready | RunningState::Running => egui::Color32::GREEN,
|
||||
RunningState::Paused => egui::Color32::YELLOW,
|
||||
RunningState::Halted => egui::Color32::ORANGE,
|
||||
RunningState::Breakpoint(_) => egui::Color32::RED,
|
||||
@@ -18,6 +18,7 @@ impl StatusIndicator for StateWrapper {
|
||||
|
||||
fn label(&self) -> String {
|
||||
match self.0 {
|
||||
RunningState::Ready => "Ready".to_string(),
|
||||
RunningState::Running => "Running".into(),
|
||||
RunningState::Paused => "Paused".into(),
|
||||
RunningState::Halted => "Halted".into(),
|
||||
@@ -26,4 +27,3 @@ impl StatusIndicator for StateWrapper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user