diff --git a/.vscode/settings.json b/.vscode/settings.json index d9cac2ae..ebbdb44c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -30,6 +30,7 @@ "rgbf", "rustfmt", "serde", + "stim", "struct", "stylesheet", "syncrim", diff --git a/CHANGELOG.md b/CHANGELOG.md index 548d5487..0b5d8517 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ Tracking changes per date: +## 230725 + +- Refactored, `clock` as `cycle` and put it in the `Simulator` (thanks to Fredrik for suggesting this a while back). Now the Simulator holds the complete state, which is better. + +- Implemented the `ProbeStim` component, to provide a set sequence of outputs. + ## 230721 - Added rudimentary support for a structured `Signal` type, inspired by HDLs. diff --git a/mips/src/components/reg_file.rs b/mips/src/components/reg_file.rs index 9fafa91f..7899ce14 100644 --- a/mips/src/components/reg_file.rs +++ b/mips/src/components/reg_file.rs @@ -215,10 +215,10 @@ mod test { }), ], }; - let mut clock = 0; - let mut simulator = Simulator::new(&cs, &mut clock); - assert_eq!(clock, 1); + let mut simulator = Simulator::new(&cs); + + assert_eq!(simulator.cycle, 1); // outputs let out_reg_1 = &Input::new("reg_file", "reg_a"); @@ -238,9 +238,9 @@ mod test { // test write and read to reg # 1 in same cycle println!("sim_state {:?}", simulator.sim_state); println!(""); - simulator.clock(&mut clock); + simulator.clock(); println!("sim_state {:?}", simulator.sim_state); - assert_eq!(clock, 2); + assert_eq!(simulator.cycle, 2); assert_eq!(simulator.get_input_val(out_reg_1), 0.into()); assert_eq!(simulator.get_input_val(out_reg_2), 1337.into()); @@ -252,9 +252,9 @@ mod test { simulator.set_out_val("write_addr", "out", 0); simulator.set_out_val("write_enable", "out", true as SignalUnsigned); println!(""); - simulator.clock(&mut clock); + simulator.clock(); println!("sim_state {:?}", simulator.sim_state); - assert_eq!(clock, 3); + assert_eq!(simulator.cycle, 3); assert_eq!(simulator.get_input_val(out_reg_1), 0.into()); assert_eq!(simulator.get_input_val(out_reg_2), 1337.into()); } diff --git a/src/common.rs b/src/common.rs index 3881c4eb..2687f957 100644 --- a/src/common.rs +++ b/src/common.rs @@ -59,6 +59,7 @@ type Components = Vec>; #[cfg_attr(feature = "gui-vizia", derive(Lens))] #[derive(Clone)] pub struct Simulator { + pub cycle: usize, pub id_start_index: IdStartIndex, // Components stored in topological evaluation order diff --git a/src/components/add.rs b/src/components/add.rs index 9b5d6a4e..bcb78cff 100644 --- a/src/components/add.rs +++ b/src/components/add.rs @@ -85,10 +85,9 @@ mod test { }), ], }; - let mut clock = 0; - let mut simulator = Simulator::new(&cs, &mut clock); + let mut simulator = Simulator::new(&cs); - assert_eq!(clock, 1); + assert_eq!(simulator.cycle, 1); // outputs let add_val = &Input::new("add", "out"); @@ -106,9 +105,10 @@ mod test { simulator.set_out_val("po2", "out", 1337); println!("sim_state {:?}", simulator.sim_state); println!(""); - simulator.clock(&mut clock); + simulator.clock(); + println!("sim_state {:?}", simulator.sim_state); - assert_eq!(clock, 2); + assert_eq!(simulator.cycle, 2); assert_eq!(simulator.get_input_val(add_val), (42 + 1337).into()); assert_eq!( simulator.get_input_val(add_overflow), @@ -121,9 +121,9 @@ mod test { simulator.set_out_val("po2", "out", 1); println!("sim_state {:?}", simulator.sim_state); println!(""); - simulator.clock(&mut clock); + simulator.clock(); println!("sim_state {:?}", simulator.sim_state); - assert_eq!(clock, 3); + assert_eq!(simulator.cycle, 3); assert_eq!( simulator.get_input_val(add_val), (SignalUnsigned::MAX / 2 + 1).into() diff --git a/src/components/mem.rs b/src/components/mem.rs index 3615c8d9..0bcea32c 100644 --- a/src/components/mem.rs +++ b/src/components/mem.rs @@ -274,10 +274,9 @@ mod test { ], }; - let mut clock = 0; - let mut simulator = Simulator::new(&cs, &mut clock); + let mut simulator = Simulator::new(&cs); - assert_eq!(clock, 1); + assert_eq!(simulator.cycle, 1); // outputs let out = &Input::new("mem", "data"); @@ -299,10 +298,10 @@ mod test { println!("sim_state {:?}", simulator.sim_state); println!(""); - simulator.clock(&mut clock); + simulator.clock(); println!("sim_state {:?}", simulator.sim_state); - assert_eq!(clock, 2); + assert_eq!(simulator.cycle, 2); assert_eq!(simulator.get_input_val(out), 0.into()); assert_eq!( simulator.get_input_val(err), @@ -314,9 +313,9 @@ mod test { simulator.set_out_val("ctrl", "out", MemCtrl::Read as SignalUnsigned); simulator.set_out_val("size", "out", 1); - simulator.clock(&mut clock); + simulator.clock(); - assert_eq!(clock, 3); + assert_eq!(simulator.cycle, 3); assert_eq!(simulator.get_input_val(out), 0xf0.into()); assert_eq!( simulator.get_input_val(err), @@ -327,8 +326,8 @@ mod test { simulator.set_out_val("size", "out", 1); simulator.set_out_val("sign", "out", true); - simulator.clock(&mut clock); - assert_eq!(clock, 4); + simulator.clock(); + assert_eq!(simulator.cycle, 4); assert_eq!(simulator.get_input_val(out), 0xffff_fff0.into()); assert_eq!( simulator.get_input_val(err), @@ -339,8 +338,8 @@ mod test { simulator.set_out_val("size", "out", 2); simulator.set_out_val("sign", "out", true as SignalUnsigned); - simulator.clock(&mut clock); - assert_eq!(clock, 5); + simulator.clock(); + assert_eq!(simulator.cycle, 5); assert_eq!(simulator.get_input_val(out), 0xffff_f000.into()); assert_eq!( simulator.get_input_val(err), @@ -351,72 +350,72 @@ mod test { simulator.set_out_val("size", "out", 4); simulator.set_out_val("sign", "out", true); - simulator.clock(&mut clock); - assert_eq!(clock, 6); + simulator.clock(); + assert_eq!(simulator.cycle, 6); assert_eq!(simulator.get_input_val(out), 0xf000_0000.into()); assert_eq!(simulator.get_input_val(err), false.into()); println!(""); simulator.set_out_val("addr", "out", 5); - simulator.clock(&mut clock); - assert_eq!(clock, 7); + simulator.clock(); + assert_eq!(simulator.cycle, 7); assert_eq!(simulator.get_input_val(err), true.into()); println!(""); simulator.set_out_val("addr", "out", 6); - simulator.clock(&mut clock); - assert_eq!(clock, 8); + simulator.clock(); + assert_eq!(simulator.cycle, 8); assert_eq!(simulator.get_input_val(err), true.into()); println!(""); simulator.set_out_val("addr", "out", 7); - simulator.clock(&mut clock); - assert_eq!(clock, 9); + simulator.clock(); + assert_eq!(simulator.cycle, 9); assert_eq!(simulator.get_input_val(err), true.into()); println!(""); simulator.set_out_val("addr", "out", 8); - simulator.clock(&mut clock); - assert_eq!(clock, 10); + simulator.clock(); + assert_eq!(simulator.cycle, 10); assert_eq!(simulator.get_input_val(err), false.into()); println!(""); simulator.set_out_val("addr", "out", 9); simulator.set_out_val("size", "out", 2); - simulator.clock(&mut clock); - assert_eq!(clock, 11); + simulator.clock(); + assert_eq!(simulator.cycle, 11); assert_eq!(simulator.get_input_val(err), true.into()); println!(""); simulator.set_out_val("addr", "out", 10); - simulator.clock(&mut clock); - assert_eq!(clock, 12); + simulator.clock(); + assert_eq!(simulator.cycle, 12); assert_eq!(simulator.get_input_val(err), false.into()); println!(""); simulator.set_out_val("addr", "out", 10); simulator.set_out_val("data", "out", 0x1234); simulator.set_out_val("ctrl", "out", MemCtrl::Write as SignalUnsigned); - simulator.clock(&mut clock); - assert_eq!(clock, 13); + simulator.clock(); + assert_eq!(simulator.cycle, 13); assert_eq!(simulator.get_input_val(err), false.into()); println!(""); simulator.set_out_val("ctrl", "out", MemCtrl::Read as SignalUnsigned); simulator.set_out_val("size", "out", 1); - simulator.clock(&mut clock); - assert_eq!(clock, 14); + simulator.clock(); + assert_eq!(simulator.cycle, 14); assert_eq!(simulator.get_input_val(out), 0x12.into()); println!(""); simulator.set_out_val("addr", "out", 11); - simulator.clock(&mut clock); - assert_eq!(clock, 15); + simulator.clock(); + assert_eq!(simulator.cycle, 15); assert_eq!(simulator.get_input_val(out), 0x34.into()); println!("test done") @@ -456,10 +455,9 @@ mod test { ], }; - let mut clock = 0; - let mut simulator = Simulator::new(&cs, &mut clock); + let mut simulator = Simulator::new(&cs); - assert_eq!(clock, 1); + assert_eq!(simulator.cycle, 1); // outputs let out = &Input::new("mem", "data"); @@ -479,10 +477,10 @@ mod test { println!("sim_state {:?}", simulator.sim_state); println!(""); - simulator.clock(&mut clock); + simulator.clock(); println!("sim_state {:?}", simulator.sim_state); - assert_eq!(clock, 2); + assert_eq!(simulator.cycle, 2); assert_eq!(simulator.get_input_val(out), 0.into()); assert_eq!(simulator.get_input_val(err), false.into()); @@ -491,9 +489,9 @@ mod test { simulator.set_out_val("ctrl", "out", MemCtrl::Read as SignalUnsigned); simulator.set_out_val("size", "out", 1); - simulator.clock(&mut clock); + simulator.clock(); - assert_eq!(clock, 3); + assert_eq!(simulator.cycle, 3); assert_eq!(simulator.get_input_val(out), 0xf0.into()); assert_eq!(simulator.get_input_val(err), false.into()); @@ -501,8 +499,8 @@ mod test { simulator.set_out_val("size", "out", 1); simulator.set_out_val("sign", "out", true); - simulator.clock(&mut clock); - assert_eq!(clock, 4); + simulator.clock(); + assert_eq!(simulator.cycle, 4); assert_eq!(simulator.get_input_val(out), 0xffff_fff0.into()); assert_eq!(simulator.get_input_val(err), false.into()); @@ -510,16 +508,16 @@ mod test { simulator.set_out_val("size", "out", 2); simulator.set_out_val("sign", "out", true); - simulator.clock(&mut clock); - assert_eq!(clock, 5); + simulator.clock(); + assert_eq!(simulator.cycle, 5); assert_eq!(simulator.get_input_val(out), 0x0000_00f0.into()); assert_eq!(simulator.get_input_val(err), false.into()); println!(""); simulator.set_out_val("size", "out", 4); simulator.set_out_val("sign", "out", true); - simulator.clock(&mut clock); - assert_eq!(clock, 6); + simulator.clock(); + assert_eq!(simulator.cycle, 6); assert_eq!(simulator.get_input_val(out), 0x0000_00f0.into()); assert_eq!(simulator.get_input_val(err), false.into()); @@ -529,21 +527,21 @@ mod test { simulator.set_out_val("ctrl", "out", MemCtrl::Write as SignalUnsigned); simulator.set_out_val("size", "out", 2); - simulator.clock(&mut clock); - assert_eq!(clock, 7); + simulator.clock(); + assert_eq!(simulator.cycle, 7); assert_eq!(simulator.get_input_val(err), false.into()); println!(""); simulator.set_out_val("ctrl", "out", MemCtrl::Read as SignalUnsigned); simulator.set_out_val("size", "out", 1); - simulator.clock(&mut clock); - assert_eq!(clock, 8); + simulator.clock(); + assert_eq!(simulator.cycle, 8); assert_eq!(simulator.get_input_val(out), 0x34.into()); println!(""); simulator.set_out_val("addr", "out", 11); - simulator.clock(&mut clock); - assert_eq!(clock, 9); + simulator.clock(); + assert_eq!(simulator.cycle, 9); assert_eq!(simulator.get_input_val(out), 0x12.into()); } } diff --git a/src/components/mod.rs b/src/components/mod.rs index 4c35a88b..951775fd 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -5,6 +5,7 @@ mod mux; mod probe; mod probe_edit; mod probe_out; +mod probe_stim; mod register; mod sext; mod wire; @@ -16,6 +17,7 @@ pub use mux::*; pub use probe::*; pub use probe_edit::*; pub use probe_out::*; +pub use probe_stim::*; pub use register::*; pub use sext::*; pub use wire::*; diff --git a/src/components/probe.rs b/src/components/probe.rs index 1d5436ca..ac3bf45d 100644 --- a/src/components/probe.rs +++ b/src/components/probe.rs @@ -1,6 +1,7 @@ use crate::common::{Component, Id, Input, OutputType, Ports}; use log::*; use serde::{Deserialize, Serialize}; +use std::rc::Rc; #[derive(Serialize, Deserialize)] pub struct Probe { pub id: Id, @@ -27,3 +28,17 @@ impl Component for Probe { ) } } + +impl Probe { + pub fn new(id: &str, pos: (f32, f32), input: Input) -> Self { + Probe { + id: id.to_string(), + pos, + input, + } + } + + pub fn rc_new(id: &str, pos: (f32, f32), input: Input) -> Rc { + Rc::new(Probe::new(id, pos, input)) + } +} diff --git a/src/components/probe_stim.rs b/src/components/probe_stim.rs new file mode 100644 index 00000000..a49d0ee6 --- /dev/null +++ b/src/components/probe_stim.rs @@ -0,0 +1,122 @@ +use crate::common::{Component, Id, OutputType, Ports, Signal, Simulator}; +use log::*; +use serde::{Deserialize, Serialize}; +use std::rc::Rc; + +#[derive(Serialize, Deserialize)] +pub struct ProbeStim { + pub id: Id, + pub pos: (f32, f32), + pub values: Vec, +} + +#[typetag::serde] +impl Component for ProbeStim { + fn to_(&self) { + trace!("constant {:?}", self.values); + } + + fn get_id_ports(&self) -> (Id, Ports) { + ( + self.id.clone(), + Ports::new( + // ProbeStim do not take any inputs + vec![], + OutputType::Combinatorial, + vec!["out"], + ), + ) + } + + fn clock(&self, simulator: &mut Simulator) { + trace!("-- cycle {} --", simulator.cycle); + simulator.set_out_val(&self.id, "out", self.values[simulator.cycle]); + } + + // notice we don't implement `un_clock` since the state is already kept in history +} + +impl ProbeStim { + pub fn new(id: &str, pos: (f32, f32), values: Vec>) -> Self { + ProbeStim { + id: id.to_string(), + pos, + values: values.into_iter().map(|v| v.into()).collect(), + } + } + + pub fn rc_new(id: &str, pos: (f32, f32), values: Vec>) -> Rc { + Rc::new(ProbeStim::new(id, pos, values)) + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::common::{ComponentStore, Input}; + + #[test] + fn test_probe_stim() { + let cs = ComponentStore { + store: vec![ProbeStim::rc_new("stim", (0.0, 0.0), vec![0, 1, 2, 3])], + }; + + let mut simulator = Simulator::new(&cs); + // output + let out = &Input::new("stim", "out"); + + // reset + println!(""); + println!("sim_state {:?}", simulator.sim_state); + assert_eq!(simulator.cycle, 1); + assert_eq!(simulator.get_input_val(out), 0.into()); + + println!(""); + simulator.clock(); + println!("sim_state {:?}", simulator.sim_state); + assert_eq!(simulator.cycle, 2); + assert_eq!(simulator.get_input_val(out), 1.into()); + + println!(""); + simulator.clock(); + println!("sim_state {:?}", simulator.sim_state); + assert_eq!(simulator.cycle, 3); + assert_eq!(simulator.get_input_val(out), 2.into()); + + println!(""); + simulator.un_clock(); + println!("sim_state {:?}", simulator.sim_state); + assert_eq!(simulator.cycle, 2); + assert_eq!(simulator.get_input_val(out), 1.into()); + + println!(""); + simulator.un_clock(); + println!("sim_state {:?}", simulator.sim_state); + assert_eq!(simulator.cycle, 1); + assert_eq!(simulator.get_input_val(out), 0.into()); + + println!(""); + simulator.un_clock(); + println!("sim_state {:?}", simulator.sim_state); + assert_eq!(simulator.cycle, 1); + assert_eq!(simulator.get_input_val(out), 0.into()); + + println!(""); + simulator.clock(); + println!("sim_state {:?}", simulator.sim_state); + assert_eq!(simulator.cycle, 2); + assert_eq!(simulator.get_input_val(out), 1.into()); + + println!(""); + simulator.clock(); + println!("sim_state {:?}", simulator.sim_state); + assert_eq!(simulator.cycle, 3); + assert_eq!(simulator.get_input_val(out), 2.into()); + + println!(""); + simulator.reset(); + println!("sim_state {:?}", simulator.sim_state); + assert_eq!(simulator.cycle, 1); + assert_eq!(simulator.get_input_val(out), 0.into()); + } +} diff --git a/src/components/sext.rs b/src/components/sext.rs index 362886be..2b6599a7 100644 --- a/src/components/sext.rs +++ b/src/components/sext.rs @@ -81,10 +81,10 @@ mod test { }), ], }; - let mut clock = 0; - let mut simulator = Simulator::new(&cs, &mut clock); - assert_eq!(clock, 1); + let mut simulator = Simulator::new(&cs); + + assert_eq!(simulator.cycle, 1); // outputs let sext32_out = &Input::new("sext32", "out"); @@ -99,9 +99,9 @@ mod test { simulator.set_out_val("po", "out", 0b1111); println!("sim_state {:?}", simulator.sim_state); println!(""); - simulator.clock(&mut clock); + simulator.clock(); println!("sim_state {:?}", simulator.sim_state); - assert_eq!(clock, 2); + assert_eq!(simulator.cycle, 2); assert_eq!(simulator.get_input_val(sext32_out), 0xFFFFFFFF.into()); assert_eq!(simulator.get_input_val(sext16_out), 0xFFFF.into()); @@ -110,9 +110,9 @@ mod test { simulator.set_out_val("po", "out", 0b111); println!("sim_state {:?}", simulator.sim_state); println!(""); - simulator.clock(&mut clock); + simulator.clock(); println!("sim_state {:?}", simulator.sim_state); - assert_eq!(clock, 3); + assert_eq!(simulator.cycle, 3); assert_eq!(simulator.get_input_val(sext32_out), 0b111.into()); assert_eq!(simulator.get_input_val(sext16_out), 0b111.into()); @@ -121,9 +121,9 @@ mod test { simulator.set_out_val("po", "out", 0b10111); println!("sim_state {:?}", simulator.sim_state); println!(""); - simulator.clock(&mut clock); + simulator.clock(); println!("sim_state {:?}", simulator.sim_state); - assert_eq!(clock, 4); + assert_eq!(simulator.cycle, 4); assert_eq!(simulator.get_input_val(sext32_out), 0b111.into()); assert_eq!(simulator.get_input_val(sext16_out), 0b111.into()); } diff --git a/src/gui_egui/components/constant.rs b/src/gui_egui/components/constant.rs index 0ac134ad..b645ecd9 100644 --- a/src/gui_egui/components/constant.rs +++ b/src/gui_egui/components/constant.rs @@ -1,4 +1,4 @@ -use crate::common::{EguiComponent, Signal, SignalUnsigned, Simulator}; +use crate::common::{EguiComponent, SignalUnsigned, Simulator}; use crate::components::Constant; use egui::{Align2, Area, Color32, Order, Rect, RichText}; diff --git a/src/gui_egui/components/wire.rs b/src/gui_egui/components/wire.rs index 76a977d5..66da17a0 100644 --- a/src/gui_egui/components/wire.rs +++ b/src/gui_egui/components/wire.rs @@ -1,7 +1,6 @@ use crate::common::{EguiComponent, Simulator}; use crate::components::Wire; use crate::gui_egui::helper::offset_helper; -use egui::Pos2; #[typetag::serde] impl EguiComponent for Wire { diff --git a/src/gui_egui/gui.rs b/src/gui_egui/gui.rs index 1d723238..0d5e95e6 100644 --- a/src/gui_egui/gui.rs +++ b/src/gui_egui/gui.rs @@ -9,7 +9,6 @@ pub struct Gui { // History, acts like a stack pub history: Vec>, pub scale: f32, - pub clock: usize, // When the ui elements change size pub ui_change: bool, pub offset: egui::Vec2, @@ -20,13 +19,11 @@ pub struct Gui { } pub fn gui(cs: &ComponentStore, path: &PathBuf) -> Result<(), eframe::Error> { - let mut clock = 0; - let simulator = Simulator::new(cs, &mut clock); + let simulator = Simulator::new(cs); let options = eframe::NativeOptions::default(); let path = path.to_owned(); simulator.save_dot(&path); let gui = Gui { - clock, path, simulator, history: vec![], diff --git a/src/gui_egui/keymap.rs b/src/gui_egui/keymap.rs index 7d8e3c6e..24956bac 100644 --- a/src/gui_egui/keymap.rs +++ b/src/gui_egui/keymap.rs @@ -229,12 +229,12 @@ pub fn control_pause(gui: &mut crate::gui_egui::gui::Gui) { gui.pause = true; } pub fn control_reset(gui: &mut crate::gui_egui::gui::Gui) { - gui.simulator.reset(&mut gui.clock); + gui.simulator.reset(); gui.pause = true; } pub fn control_step_forward(gui: &mut crate::gui_egui::gui::Gui) { - gui.simulator.clock(&mut gui.clock); + gui.simulator.clock(); } pub fn control_step_back(gui: &mut crate::gui_egui::gui::Gui) { - gui.simulator.un_clock(&mut gui.clock); + gui.simulator.un_clock(); } diff --git a/src/gui_egui/menu.rs b/src/gui_egui/menu.rs index ec03623c..7f8f1945 100644 --- a/src/gui_egui/menu.rs +++ b/src/gui_egui/menu.rs @@ -109,7 +109,7 @@ impl Menu { if ui.button("⏸").clicked() { crate::gui_egui::keymap::control_pause(gui); } - ui.label(format!("Clock #{}", gui.clock)); + ui.label(format!("Cycle #{}", gui.simulator.cycle)); }); } } diff --git a/src/gui_vizia/components/mod.rs b/src/gui_vizia/components/mod.rs index 0cc21c5a..46760aa5 100644 --- a/src/gui_vizia/components/mod.rs +++ b/src/gui_vizia/components/mod.rs @@ -8,3 +8,4 @@ mod probe_out; mod register; mod sext; mod wire; +mod probe_stim; diff --git a/src/gui_vizia/components/probe.rs b/src/gui_vizia/components/probe.rs index d48efc89..04d854cc 100644 --- a/src/gui_vizia/components/probe.rs +++ b/src/gui_vizia/components/probe.rs @@ -1,5 +1,5 @@ use crate::{ - common::{Component, ViziaComponent}, + common::{Component, Simulator, ViziaComponent}, components::Probe, gui_vizia::{popup::NewPopup, tooltip::new_component_tooltip, GuiData}, }; @@ -19,13 +19,17 @@ impl ViziaComponent for Probe { View::build(ProbeView {}, cx, |cx| { let input = self.input.clone(); - Binding::new(cx, crate::gui_vizia::GuiData::clock, move |cx, _| { - Label::new(cx, { - let simulator = GuiData::simulator.get(cx); - &format!(" {:?}", simulator.get_input_val(&input)) - }) - .hoverable(false); - }); + Binding::new( + cx, + crate::gui_vizia::GuiData::simulator.then(Simulator::cycle), + move |cx, _| { + Label::new(cx, { + let simulator = GuiData::simulator.get(cx); + &format!(" {:?}", simulator.get_input_val(&input)) + }) + .hoverable(false); + }, + ); NewPopup::new(cx, self.get_id_ports()).position_type(PositionType::SelfDirected); }) .position_type(PositionType::SelfDirected) diff --git a/src/gui_vizia/components/probe_edit.rs b/src/gui_vizia/components/probe_edit.rs index 0ef1fe60..99e0dd10 100644 --- a/src/gui_vizia/components/probe_edit.rs +++ b/src/gui_vizia/components/probe_edit.rs @@ -1,6 +1,6 @@ use crate::gui_vizia::GuiData; use crate::{ - common::{Signal, SignalSigned, SignalUnsigned, ViziaComponent}, + common::{Signal, SignalSigned, SignalUnsigned, Simulator, ViziaComponent}, components::{ProbeEdit, TextSignal}, }; // use anyhow::{anyhow, Result}; @@ -21,13 +21,16 @@ impl ViziaComponent for ProbeEdit { let history_submit = self.history.clone(); Textbox::new(cx, ProbeEditView::editable_text) - .bind(GuiData::clock, move |mut handle, clock| { - let cx = handle.context(); - trace!("bind: clock --- {}", clock.get(cx)); - let text = history_bind.read().unwrap().last().unwrap().text.clone(); - trace!("last text: {:?}", text); - cx.emit(ProbeEditViewSetter::EditableText(text)); - }) + .bind( + GuiData::simulator.then(Simulator::cycle), + move |mut handle, clock| { + let cx = handle.context(); + trace!("bind: clock --- {}", clock.get(cx)); + let text = history_bind.read().unwrap().last().unwrap().text.clone(); + trace!("last text: {:?}", text); + cx.emit(ProbeEditViewSetter::EditableText(text)); + }, + ) .on_submit(move |ex, text, enter| { trace!("submit: text {} enter {}", text, enter); ex.emit(ProbeEditViewSetter::EditableText(text)); diff --git a/src/gui_vizia/components/probe_stim.rs b/src/gui_vizia/components/probe_stim.rs new file mode 100644 index 00000000..f702d66c --- /dev/null +++ b/src/gui_vizia/components/probe_stim.rs @@ -0,0 +1,56 @@ +use crate::{ + common::{Component, ViziaComponent}, + components::ProbeStim, + gui_vizia::{popup::NewPopup, tooltip::new_component_tooltip}, +}; + +use vizia::{ + prelude::*, + vg::{Paint, Path}, +}; + +use log::*; + +#[typetag::serde] +impl ViziaComponent for ProbeStim { + // create view + fn view(&self, cx: &mut Context) { + trace!("---- Create ProbeStim View"); + View::build(ProbeStimView {}, cx, |cx| { + // Label::new(cx, &format!("{:?}", self.value)).hoverable(false); + NewPopup::new(cx, self.get_id_ports()).position_type(PositionType::SelfDirected); + }) + .position_type(PositionType::SelfDirected) + .left(Pixels(self.pos.0 - 10.0)) + .top(Pixels(self.pos.1 - 10.0)) + .width(Pixels(20.0)) + .height(Pixels(20.0)) + // TODO: do we want/need tooltip/popup for constants + .on_press(|ex| ex.emit(PopupEvent::Switch)) + .tooltip(|cx| new_component_tooltip(cx, self)); + } +} +pub struct ProbeStimView {} + +impl View for ProbeStimView { + fn element(&self) -> Option<&'static str> { + Some("ProbeStim") + } + + fn draw(&self, cx: &mut DrawContext<'_>, canvas: &mut Canvas) { + let bounds = cx.bounds(); + // trace!("Constant draw {:?}", bounds); + + let mut path = Path::new(); + let mut paint = Paint::color(vizia::vg::Color::rgbf(0.0, 1.0, 0.0)); + paint.set_line_width(cx.logical_to_physical(1.0)); + + path.move_to(bounds.left() + 0.5, bounds.top() + 0.5); + path.line_to(bounds.right() + 0.5, bounds.top() + 0.5); + path.line_to(bounds.right() + 0.5, bounds.bottom() + 0.5); + path.line_to(bounds.left() + 0.5, bounds.bottom() + 0.5); + path.line_to(bounds.left() + 0.5, bounds.top() + 0.5); + + canvas.fill_path(&path, &paint); + } +} diff --git a/src/gui_vizia/gui.rs b/src/gui_vizia/gui.rs index 6c39671e..60941532 100644 --- a/src/gui_vizia/gui.rs +++ b/src/gui_vizia/gui.rs @@ -1,5 +1,7 @@ -use crate::common::{ComponentStore, Simulator}; -use crate::gui_vizia::{grid::Grid, keymap::init_keymap, menu::Menu, transport::Transport}; +use crate::{ + common::{ComponentStore, Simulator}, + gui_vizia::{grid::Grid, keymap::init_keymap, menu::Menu, transport::Transport}, +}; use rfd::FileDialog; use std::collections::HashSet; use std::path::PathBuf; @@ -10,7 +12,6 @@ use log::*; #[derive(Lens, Clone)] pub struct GuiData { pub path: PathBuf, - pub clock: usize, pub simulator: Simulator, pub pause: bool, pub is_saved: bool, @@ -64,10 +65,10 @@ impl Model for GuiData { } } GuiEvent::ReOpen => self.open(), - GuiEvent::Clock => self.simulator.clock(&mut self.clock), - GuiEvent::UnClock => self.simulator.un_clock(&mut self.clock), + GuiEvent::Clock => self.simulator.clock(), + GuiEvent::UnClock => self.simulator.un_clock(), GuiEvent::Reset => { - self.simulator.reset(&mut self.clock); + self.simulator.reset(); self.pause = true; } GuiEvent::Play => self.pause = false, @@ -103,7 +104,7 @@ impl GuiData { // Re-Open model trace!("open path {:?}", self.path); let cs = Box::new(ComponentStore::load_file(&self.path)); - let simulator = Simulator::new(&cs, &mut self.clock); + let simulator = Simulator::new(&cs); self.simulator = simulator; @@ -112,8 +113,7 @@ impl GuiData { } pub fn gui(cs: &ComponentStore, path: &PathBuf) { - let mut clock = 0; - let simulator = Simulator::new(cs, &mut clock); + let simulator = Simulator::new(cs); let path = path.to_owned(); simulator.save_dot(&path); @@ -126,7 +126,6 @@ pub fn gui(cs: &ComponentStore, path: &PathBuf) { GuiData { path, - clock, simulator, pause: true, is_saved: false, @@ -142,10 +141,13 @@ pub fn gui(cs: &ComponentStore, path: &PathBuf) { Menu::new(cx, |cx| { HStack::new(cx, |cx| { Transport::new(cx).size(Auto); - Label::new(cx, GuiData::clock.map(|clock| format!("Clock #{}", clock))) - .top(Stretch(1.0)) - .bottom(Stretch(1.0)) - .height(Auto); + Label::new( + cx, + GuiData::simulator.map(|simulator| format!("Cycle #{:?}", simulator.cycle)), + ) + .top(Stretch(1.0)) + .bottom(Stretch(1.0)) + .height(Auto); }) .col_between(Pixels(10.0)) .top(Stretch(1.0)) diff --git a/src/gui_vizia/popup.rs b/src/gui_vizia/popup.rs index 97952a64..892b1f25 100644 --- a/src/gui_vizia/popup.rs +++ b/src/gui_vizia/popup.rs @@ -1,5 +1,5 @@ use crate::{ - common::{Id, Ports}, + common::{Id, Ports, Simulator}, gui_vizia::GuiData, }; use vizia::prelude::*; @@ -20,16 +20,20 @@ impl NewPopup { for input in ports.inputs { HStack::new(cx, |cx| { Label::new(cx, &input.id); - Binding::new(cx, GuiData::clock, move |cx, _| { - Label::new( - cx, - &format!( - "{:?}", - GuiData::simulator.get(cx).get_input_val(&input) - ), - ) - .class("tt_shortcut"); - }) + Binding::new( + cx, + GuiData::simulator.then(Simulator::cycle), + move |cx, _| { + Label::new( + cx, + &format!( + "{:?}", + GuiData::simulator.get(cx).get_input_val(&input) + ), + ) + .class("tt_shortcut"); + }, + ) }) .size(Auto); } @@ -37,21 +41,25 @@ impl NewPopup { let id_clone = id.clone(); HStack::new(cx, move |cx| { Label::new(cx, &format!("out {}", output)); - Binding::new(cx, GuiData::clock, move |cx, _| { - Label::new( - cx, - &format!( - "{:?}", - GuiData::simulator.get(cx).get( - GuiData::simulator - .get(cx) - .get_id_start_index(&id_clone) - + output - ) - ), - ) - .class("tt_shortcut"); - }); + Binding::new( + cx, + GuiData::simulator.then(Simulator::cycle), + move |cx, _| { + Label::new( + cx, + &format!( + "{:?}", + GuiData::simulator.get(cx).get( + GuiData::simulator + .get(cx) + .get_id_start_index(&id_clone) + + output + ) + ), + ) + .class("tt_shortcut"); + }, + ); }) .size(Auto); } @@ -70,51 +78,3 @@ impl NewPopup { impl View for NewPopup {} -// pub fn new_popup(cx: &mut Context, id_ports: (Id, Ports)) { -// PopupData::default().build(cx); -// Popup::new(cx, PopupData::is_open, true, move |cx| { -// VStack::new(cx, |cx| { -// let (id, ports) = id_ports.clone(); -// Label::new(cx, id); - -// for input in ports.inputs { -// HStack::new(cx, |cx| { -// Label::new(cx, input.id); -// Binding::new(cx, GuiData::clock, move |cx, _| { -// Label::new( -// cx, -// &format!("{:?}", GuiData::simulator.get(cx).get_input_val(&input)), -// ) -// .class("tt_shortcut"); -// }) -// }) -// .size(Auto); -// } -// for output in 0..ports.outputs.len() { -// let id_clone = id.clone(); -// HStack::new(cx, move |cx| { -// Label::new(cx, &format!("out {}", output)); -// Binding::new(cx, GuiData::clock, move |cx, _| { -// Label::new( -// cx, -// &format!( -// "{:?}", -// GuiData::simulator.get(cx).get( -// GuiData::simulator.get(cx).get_id_start_index(&id_clone) -// + output -// ) -// ), -// ) -// .class("tt_shortcut"); -// }); -// }) -// .size(Auto); -// } -// }) -// .size(Auto); -// }) -// .on_blur(|cx| cx.emit(PopupEvent::Close)) -// //.size(Auto) -// .background_color(Color::red()) -// .position_type(PositionType::SelfDirected); -// } diff --git a/src/gui_vizia/tooltip.rs b/src/gui_vizia/tooltip.rs index 235dec44..70c92696 100644 --- a/src/gui_vizia/tooltip.rs +++ b/src/gui_vizia/tooltip.rs @@ -1,4 +1,7 @@ -use crate::{common::Component, gui_vizia::GuiData}; +use crate::{ + common::{Component, Simulator}, + gui_vizia::GuiData, +}; use vizia::prelude::*; pub fn new_component_tooltip(cx: &mut Context, component: &dyn Component) { @@ -9,13 +12,17 @@ pub fn new_component_tooltip(cx: &mut Context, component: &dyn Component) { for input in ports.inputs { HStack::new(cx, |cx| { Label::new(cx, &input.id); - Binding::new(cx, GuiData::clock, move |cx, _| { - Label::new( - cx, - &format!("{:?}", GuiData::simulator.get(cx).get_input_val(&input)), - ) - .class("tt_shortcut"); - }) + Binding::new( + cx, + GuiData::simulator.then(Simulator::cycle), + move |cx, _| { + Label::new( + cx, + &format!("{:?}", GuiData::simulator.get(cx).get_input_val(&input)), + ) + .class("tt_shortcut"); + }, + ) }) .size(Auto); } @@ -23,18 +30,23 @@ pub fn new_component_tooltip(cx: &mut Context, component: &dyn Component) { let id_clone = id.clone(); HStack::new(cx, move |cx| { Label::new(cx, &format!("out {}", output)); - Binding::new(cx, GuiData::clock, move |cx, _| { - Label::new( - cx, - &format!( - "{:?}", - GuiData::simulator.get(cx).get( - GuiData::simulator.get(cx).get_id_start_index(&id_clone) + output - ) - ), - ) - .class("tt_shortcut"); - }); + Binding::new( + cx, + GuiData::simulator.then(Simulator::cycle), + move |cx, _| { + Label::new( + cx, + &format!( + "{:?}", + GuiData::simulator.get(cx).get( + GuiData::simulator.get(cx).get_id_start_index(&id_clone) + + output + ) + ), + ) + .class("tt_shortcut"); + }, + ); // Label::new(cx, v).class("tt_shortcut"); }) .size(Auto); diff --git a/src/simulator.rs b/src/simulator.rs index 8aab50fa..83a55d7d 100644 --- a/src/simulator.rs +++ b/src/simulator.rs @@ -19,7 +19,7 @@ pub struct IdComponent(pub HashMap>); // A solution is to evaluate register updates separately from other components // ... but not currently implemented ... impl Simulator { - pub fn new(component_store: &ComponentStore, clock: &mut usize) -> Self { + pub fn new(component_store: &ComponentStore) -> Self { let mut lens_values = vec![]; let mut id_start_index = HashMap::new(); @@ -121,6 +121,7 @@ impl Simulator { .collect(); let mut simulator = Simulator { + cycle: 0, id_start_index, ordered_components, id_nr_outputs, @@ -133,7 +134,7 @@ impl Simulator { trace!("sim_state {:?}", simulator.sim_state); - simulator.clock(clock); + simulator.clock(); simulator } @@ -186,37 +187,37 @@ impl Simulator { } /// iterate over the evaluators and increase clock by one - pub fn clock(&mut self, clock: &mut usize) { + pub fn clock(&mut self) { // push current state self.history.push(self.sim_state.clone()); - let ordered_components = self.ordered_components.clone(); - for component in ordered_components { + for component in self.ordered_components.clone() { component.clock(self); } - *clock = self.history.len(); + self.cycle = self.history.len(); } /// reverse simulation using history if clock > 1 - pub fn un_clock(&mut self, clock: &mut usize) { - if *clock > 1 { + pub fn un_clock(&mut self) { + if self.cycle > 1 { let state = self.history.pop().unwrap(); // set old state self.sim_state = state; - let ordered_components = self.ordered_components.clone(); + // to ensure that history length and cycle count complies + self.cycle = self.history.len(); - for component in ordered_components { + for component in self.ordered_components.clone() { component.un_clock(); } } - *clock = self.history.len(); } /// reset simulator - pub fn reset(&mut self, clock: &mut usize) { + pub fn reset(&mut self) { self.history = vec![]; + self.cycle = 0; self.sim_state.iter_mut().for_each(|val| *val = 0.into()); - self.clock(clock); + self.clock(); } /// save as `dot` file with `.gv` extension @@ -244,10 +245,9 @@ mod test { store: vec![Rc::new(ProbeOut::new("po1"))], }; - let mut clock = 0; - let _simulator = Simulator::new(&cs, &mut clock); + let simulator = Simulator::new(&cs); - assert_eq!(clock, 1); + assert_eq!(simulator.cycle, 1); } #[test] @@ -257,10 +257,9 @@ mod test { store: vec![Rc::new(ProbeOut::new("po1")), Rc::new(ProbeOut::new("po1"))], }; - let mut clock = 0; - let _simulator = Simulator::new(&cs, &mut clock); + let simulator = Simulator::new(&cs); - assert_eq!(clock, 1); + assert_eq!(simulator.cycle, 1); } #[test] @@ -269,10 +268,9 @@ mod test { store: vec![Rc::new(ProbeOut::new("po1"))], }; - let mut clock = 0; - let simulator = Simulator::new(&cs, &mut clock); + let simulator = Simulator::new(&cs); - assert_eq!(clock, 1); + assert_eq!(simulator.cycle, 1); let _ = simulator.get_input_val(&Input::new("po1", "out")); } @@ -283,10 +281,9 @@ mod test { store: vec![Rc::new(ProbeOut::new("po1"))], }; - let mut clock = 0; - let simulator = Simulator::new(&cs, &mut clock); + let simulator = Simulator::new(&cs); - assert_eq!(clock, 1); + assert_eq!(simulator.cycle, 1); let _ = simulator.get_input_val(&Input::new("po1", "missing")); } }