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