diff --git a/riscv/examples/empty.rs b/riscv/examples/empty.rs index 753e14cc..ef2ef06c 100644 --- a/riscv/examples/empty.rs +++ b/riscv/examples/empty.rs @@ -1,6 +1,6 @@ use clap::Parser; use riscv::components::*; -use std::{collections::BTreeMap, path::PathBuf, rc::Rc}; +use std::{cell::RefCell, collections::BTreeMap, path::PathBuf, rc::Rc}; use syncrim::common::{ComponentStore, Input}; #[derive(Parser, Debug)] @@ -53,6 +53,41 @@ fn main() { ctrl: dummy.clone(), enable: dummy.clone(), }), + Rc::new(Decoder { + width: DECODER_WIDTH, + height: DECODER_HEIGHT, + id: "dummy_decoder".to_string(), + pos: (0.0, 0.0), + instruction: dummy.clone(), + }), + Rc::new(LSBZero { + height: LSB_ZERO_HEIGHT, + width: LSB_ZERO_WIDTH, + id: "dummy_lsbzero".to_string(), + pos: (0.0, 0.0), + data_i: dummy.clone(), + }), + Rc::new(RegFile { + id: "dummy_reg_file".into(), + pos: (0.0, 0.0), + width: REG_FILE_WIDTH, + height: REG_FILE_HEIGHT, + read_addr1: dummy.clone(), + read_addr2: dummy.clone(), + write_data: dummy.clone(), + write_addr: dummy.clone(), + write_enable: dummy.clone(), + registers: RegStore::new(Rc::new(RefCell::new([0; 32]))), + history: RegHistory::new(), + }), + Rc::new(SZExt { + height: SIGN_ZERO_EXT_HEIGHT, + width: SIGN_ZERO_EXT_WIDTH, + id: "dummy_szext".to_string(), + pos: (0.0, 0.0), + data_i: dummy.clone(), + sel_i: dummy.clone(), + }), ], }; let library = syncrim::gui_egui::editor::Library(lib.store); diff --git a/riscv/examples/riscv.rs b/riscv/examples/riscv.rs index 08635046..df59811c 100644 --- a/riscv/examples/riscv.rs +++ b/riscv/examples/riscv.rs @@ -89,8 +89,8 @@ fn main() { Input::new("jalr_se", "out"), ), Rc::new(BranchLogic { - width: 60.0, - height: 60.0, + width: BRANCH_LOGIC_WIDTH, + height: BRANCH_LOGIC_HEIGHT, id: "branch_logic".to_string(), pos: (725.0, 300.0), rs1: Input::new("reg_file", "reg_a"), @@ -99,6 +99,8 @@ fn main() { enable: Input::new("decoder", "branch_logic_enable"), }), Rc::new(LSBZero { + height: LSB_ZERO_HEIGHT, + width: LSB_ZERO_WIDTH, id: "jalr_stripper".to_string(), pos: (600.0, 1000.0), data_i: Input::new("jalr_adder", "out"), @@ -140,14 +142,16 @@ fn main() { 32, ), Rc::new(InstrMem { - width: 200.0, - height: 100.0, + width: INSTR_MEM_WIDTH, + height: INSTR_MEM_HEIGHT, id: "instr_mem".to_string(), pos: (180.0, 400.0), pc: Input::new("reg", "out"), bytes: instr_mem, }), Rc::new(Decoder { + width: DECODER_WIDTH, + height: DECODER_HEIGHT, id: "decoder".to_string(), pos: (300.0, 150.0), instruction: Input::new("instr_mem", "instruction"), diff --git a/riscv/src/components/decoder.rs b/riscv/src/components/decoder.rs index 68822467..61bbd160 100644 --- a/riscv/src/components/decoder.rs +++ b/riscv/src/components/decoder.rs @@ -1,7 +1,11 @@ use log::trace; use serde::{Deserialize, Serialize}; +#[cfg(feature = "gui-egui")] +use std::rc::Rc; +#[cfg(feature = "gui-egui")] +use syncrim::common::EguiComponent; use syncrim::common::{ - Component, Condition, Input, InputPort, OutputType, Ports, SignalValue, Simulator, + Component, Condition, Id, Input, InputPort, OutputType, Ports, SignalValue, Simulator, }; use syncrim::components::MemCtrl; @@ -30,8 +34,13 @@ pub const DECODER_BRANCH_LOGIC_CTL_ID: &str = "branch_logic_ctl"; pub const DECODER_BRANCH_LOGIC_ENABLE_ID: &str = "branch_logic_enable"; pub const DECODER_JALR_IMM_ID: &str = "jalr_imm"; +pub const DECODER_HEIGHT: f32 = 200.0; +pub const DECODER_WIDTH: f32 = 30.0; + #[derive(Serialize, Deserialize)] pub struct Decoder { + pub width: f32, + pub height: f32, pub id: String, pub pos: (f32, f32), @@ -43,6 +52,23 @@ impl Component for Decoder { fn to_(&self) { println!("Decoder"); } + #[cfg(feature = "gui-egui")] + fn dummy(&self, id: &str, pos: (f32, f32)) -> Box> { + let dummy_input = Input::new("dummy", "out"); + Box::new(Rc::new(Decoder { + width: DECODER_WIDTH, + height: DECODER_HEIGHT, + id: id.to_string(), + pos: (pos.0, pos.1), + instruction: dummy_input, + })) + } + fn set_id_port(&mut self, target_port_id: Id, new_input: Input) { + match target_port_id.as_str() { + DECODER_INSTRUCTION_ID => self.instruction = new_input, + _ => (), + } + } fn get_id_ports(&self) -> (String, Ports) { ( self.id.clone(), @@ -487,6 +513,8 @@ mod test { store: vec![ Rc::new(ProbeOut::new("instruction")), Rc::new(Decoder { + width: 0.0, + height: 0.0, id: "decoder".to_string(), pos: (0.0, 0.0), instruction: Input::new("instruction", "out"), @@ -1083,6 +1111,8 @@ mod test { store: vec![ Rc::new(ProbeOut::new("instruction")), Rc::new(Decoder { + width: 0.0, + height: 0.0, id: "decoder".to_string(), pos: (0.0, 0.0), instruction: Input::new("instruction", "out"), @@ -1602,6 +1632,8 @@ mod test { store: vec![ Rc::new(ProbeOut::new("instruction")), Rc::new(Decoder { + width: 0.0, + height: 0.0, id: "decoder".to_string(), pos: (0.0, 0.0), instruction: Input::new("instruction", "out"), @@ -2145,6 +2177,8 @@ mod test { store: vec![ Rc::new(ProbeOut::new("instruction")), Rc::new(Decoder { + width: 0.0, + height: 0.0, id: "decoder".to_string(), pos: (0.0, 0.0), instruction: Input::new("instruction", "out"), diff --git a/riscv/src/components/lsb_zero.rs b/riscv/src/components/lsb_zero.rs index 3b9746a1..2c53c595 100644 --- a/riscv/src/components/lsb_zero.rs +++ b/riscv/src/components/lsb_zero.rs @@ -1,15 +1,23 @@ use serde::{Deserialize, Serialize}; +#[cfg(feature = "gui-egui")] +use std::rc::Rc; +#[cfg(feature = "gui-egui")] +use syncrim::common::EguiComponent; use syncrim::{ - common::{Component, Condition, Input, InputPort, OutputType, Ports, Simulator}, + common::{Component, Condition, Id, Input, InputPort, OutputType, Ports, Simulator}, signal::SignalValue, }; - pub const LSB_ZERO_DATA_I_ID: &str = "data_i"; pub const LSB_ZERO_OUT_ID: &str = "out"; +pub const LSB_ZERO_HEIGHT: f32 = 10.0; +pub const LSB_ZERO_WIDTH: f32 = 10.0; + #[derive(Serialize, Deserialize)] pub struct LSBZero { + pub height: f32, + pub width: f32, pub id: String, pub pos: (f32, f32), @@ -21,6 +29,23 @@ impl Component for LSBZero { fn to_(&self) { println!("LSBZero"); } + #[cfg(feature = "gui-egui")] + fn dummy(&self, id: &str, pos: (f32, f32)) -> Box> { + let dummy = Input::new("dummy", "out"); + Box::new(Rc::new(LSBZero { + height: LSB_ZERO_HEIGHT, + width: LSB_ZERO_WIDTH, + id: id.to_string(), + pos: (pos.0, pos.1), + data_i: dummy.clone(), + })) + } + fn set_id_port(&mut self, target_port_id: Id, new_input: Input) { + match target_port_id.as_str() { + LSB_ZERO_DATA_I_ID => self.data_i = new_input, + _ => (), + } + } fn get_id_ports(&self) -> (String, Ports) { ( self.id.clone(), @@ -63,6 +88,8 @@ mod test { store: vec![ Rc::new(ProbeOut::new("input")), Rc::new(LSBZero { + height: 0.0, + width: 0.0, id: "lzero".to_string(), pos: (0.0, 0.0), data_i: Input::new("input", "out"), diff --git a/riscv/src/components/reg_file.rs b/riscv/src/components/reg_file.rs index 095ace2e..3a23391d 100644 --- a/riscv/src/components/reg_file.rs +++ b/riscv/src/components/reg_file.rs @@ -3,11 +3,12 @@ use num_enum::TryFromPrimitive; use serde::{Deserialize, Serialize}; use std::ops::{Deref, Range}; use std::{cell::RefCell, rc::Rc}; +#[cfg(feature = "gui-egui")] +use syncrim::common::EguiComponent; use syncrim::common::{ - Component, Condition, Input, InputPort, OutputType, Ports, SignalUnsigned, Simulator, + Component, Condition, Id, Input, InputPort, OutputType, Ports, SignalUnsigned, Simulator, }; use syncrim::signal::SignalValue; - #[allow(non_camel_case_types)] #[rustfmt::skip] #[derive(Copy, Clone, Debug, TryFromPrimitive)] @@ -56,6 +57,9 @@ pub const REG_FILE_WRITE_ENABLE_ID: &str = "write_enable"; pub const REG_FILE_REG_A_OUT: &str = "reg_a"; pub const REG_FILE_REG_B_OUT: &str = "reg_b"; +pub const REG_FILE_WIDTH: f32 = 250.0; +pub const REG_FILE_HEIGHT: f32 = 500.0; + #[derive(Serialize, Deserialize, Clone)] pub struct RegFile { pub id: String, @@ -188,7 +192,33 @@ impl Component for RegFile { }, ) } - + #[cfg(feature = "gui-egui")] + fn dummy(&self, id: &str, pos: (f32, f32)) -> Box> { + let dummy_input = Input::new("dummy", "out"); + Box::new(Rc::new(RegFile { + width: REG_FILE_WIDTH, + height: REG_FILE_HEIGHT, + id: id.to_string(), + pos: (pos.0, pos.1), + registers: RegStore::new(Rc::new(RefCell::new([0; 32]))), + history: RegHistory::new(), + read_addr1: dummy_input.clone(), + read_addr2: dummy_input.clone(), + write_data: dummy_input.clone(), + write_addr: dummy_input.clone(), + write_enable: dummy_input.clone(), + })) + } + fn set_id_port(&mut self, target_port_id: Id, new_input: Input) { + match target_port_id.as_str() { + REG_FILE_READ_ADDR1_ID => self.read_addr1 = new_input, + REG_FILE_READ_ADDR2_ID => self.read_addr2 = new_input, + REG_FILE_WRITE_DATA_ID => self.write_data = new_input, + REG_FILE_WRITE_ADDR_ID => self.write_addr = new_input, + REG_FILE_WRITE_ENABLE_ID => self.write_enable = new_input, + _ => (), + } + } fn clock(&self, simulator: &mut Simulator) -> Result<(), Condition> { if simulator.get_input_value(&self.write_enable) == (true as SignalUnsigned).into() { let data = simulator.get_input_value(&self.write_data); diff --git a/riscv/src/components/sign_zero_ext.rs b/riscv/src/components/sign_zero_ext.rs index ae9470ee..bb3d6f29 100644 --- a/riscv/src/components/sign_zero_ext.rs +++ b/riscv/src/components/sign_zero_ext.rs @@ -1,16 +1,24 @@ use log::trace; use serde::{Deserialize, Serialize}; +#[cfg(feature = "gui-egui")] +use std::rc::Rc; +#[cfg(feature = "gui-egui")] +use syncrim::common::EguiComponent; use syncrim::common::{ - Component, Condition, Input, InputPort, OutputType, Ports, SignalValue, Simulator, + Component, Condition, Id, Input, InputPort, OutputType, Ports, SignalValue, Simulator, }; - pub const SIGN_ZERO_EXT_DATA_I_ID: &str = "data_i"; pub const SIGN_ZERO_EXT_SEL_I_ID: &str = "sel_i"; pub const SIGN_ZERO_EXT_OUT_ID: &str = "out"; +pub const SIGN_ZERO_EXT_HEIGHT: f32 = 30.0; +pub const SIGN_ZERO_EXT_WIDTH: f32 = 60.0; + #[derive(Serialize, Deserialize)] pub struct SZExt { + pub height: f32, + pub width: f32, pub id: String, pub pos: (f32, f32), @@ -23,6 +31,25 @@ impl Component for SZExt { fn to_(&self) { println!("s_z_ext"); } + #[cfg(feature = "gui-egui")] + fn dummy(&self, id: &str, pos: (f32, f32)) -> Box> { + let dummy = Input::new("dummy", "out"); + Box::new(Rc::new(SZExt { + height: SIGN_ZERO_EXT_HEIGHT, + width: SIGN_ZERO_EXT_WIDTH, + id: id.to_string(), + pos: (pos.0, pos.1), + data_i: dummy.clone(), + sel_i: dummy.clone(), + })) + } + fn set_id_port(&mut self, target_port_id: Id, new_input: Input) { + match target_port_id.as_str() { + SIGN_ZERO_EXT_DATA_I_ID => self.data_i = new_input, + SIGN_ZERO_EXT_SEL_I_ID => self.sel_i = new_input, + _ => (), + } + } fn get_id_ports(&self) -> (String, Ports) { ( self.id.clone(), diff --git a/riscv/src/gui_egui/components/branch_logic.rs b/riscv/src/gui_egui/components/branch_logic.rs index 8951c5a5..030d6358 100644 --- a/riscv/src/gui_egui/components/branch_logic.rs +++ b/riscv/src/gui_egui/components/branch_logic.rs @@ -167,7 +167,7 @@ impl EguiComponent for BranchLogic { } fn top_padding(&self) -> f32 { - 20f32 + self.height / 2f32 } fn set_pos(&mut self, pos: (f32, f32)) { diff --git a/riscv/src/gui_egui/components/decoder.rs b/riscv/src/gui_egui/components/decoder.rs new file mode 100644 index 00000000..c58f82d0 --- /dev/null +++ b/riscv/src/gui_egui/components/decoder.rs @@ -0,0 +1,277 @@ +use crate::components::Decoder; +use egui::{Color32, Pos2, Rect, Response, Rounding, Shape, Stroke, Ui, Vec2}; +use syncrim::common::{EguiComponent, Ports, Simulator}; +use syncrim::gui_egui::component_ui::{ + drag_logic, input_change_id, input_selector, pos_drag_value, properties_window, + rect_with_hover, visualize_ports, +}; +use syncrim::gui_egui::editor::{EditorMode, EditorRenderReturn, GridOptions}; +use syncrim::gui_egui::gui::EguiExtra; +use syncrim::gui_egui::helper::offset_helper; + +#[typetag::serde] +impl EguiComponent for Decoder { + fn render( + &self, + ui: &mut Ui, + _context: &mut EguiExtra, + _simulator: Option<&mut Simulator>, + offset: Vec2, + scale: f32, + clip_rect: Rect, + editor_mode: EditorMode, + ) -> Option> { + // 21x41 + // middle: 11x 21y (0 0) + let oh: fn((f32, f32), f32, Vec2) -> Pos2 = offset_helper; + let offset_old = offset; + let mut offset = offset; + offset.x += self.pos.0 * scale; + offset.y += self.pos.1 * scale; + let s = scale; + let o = offset; + + // The shape + let rect = Rect { + min: oh((-self.width / 2f32, -self.height / 2f32), s, o), + max: oh((self.width / 2f32, self.height / 2f32), s, o), + }; + ui.painter().add(Shape::rect_stroke( + rect, + Rounding::none(), + Stroke { + width: scale, + color: Color32::BLACK, + }, + )); + + let r = rect_with_hover(rect, clip_rect, editor_mode, ui, self.id.clone(), |ui| { + ui.label(format!("Id: {}", self.id.clone())); + ui.label("Decoder"); + }); + match editor_mode { + EditorMode::Simulator => (), + _ => visualize_ports(ui, self.ports_location(), offset_old, scale, clip_rect), + } + Some(vec![r]) + } + + fn render_editor( + &mut self, + ui: &mut Ui, + context: &mut EguiExtra, + simulator: Option<&mut Simulator>, + offset: Vec2, + scale: f32, + clip_rect: Rect, + id_ports: &[(syncrim::common::Id, Ports)], + grid: &GridOptions, + editor_mode: EditorMode, + ) -> EditorRenderReturn { + let r_vec = Decoder::render( + self, + ui, + context, + simulator, + offset, + scale, + clip_rect, + editor_mode, + ) + .unwrap(); + let resp = &r_vec[0]; + let delete = drag_logic( + ui.ctx(), + resp, + &mut self.pos, + &mut context.pos_tmp, + scale, + offset, + grid, + ); + + properties_window( + ui, + self.id.clone(), + resp, + &mut context.properties_window, + |ui| { + let mut clicked_dropdown = false; + input_change_id(ui, &mut context.id_tmp, &mut self.id, id_ports); + pos_drag_value(ui, &mut self.pos); + clicked_dropdown |= input_selector( + ui, + &mut self.instruction, + crate::components::DECODER_INSTRUCTION_ID.to_string(), + id_ports, + self.id.clone(), + ); + clicked_dropdown + }, + ); + + EditorRenderReturn { + delete, + resp: Some(r_vec), + } + } + + fn ports_location(&self) -> Vec<(syncrim::common::Id, Pos2)> { + let own_pos = Vec2::new(self.pos.0, self.pos.1); + vec![ + ( + crate::components::DECODER_WB_MUX_ID.to_string(), + Pos2::new(self.width / 2f32, -self.height / 2f32 + self.height / 20f32) + own_pos, + ), + ( + crate::components::DECODER_ALU_OPERAND_A_SEL_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 2f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_ALU_OPERAND_B_SEL_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 3f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_ALU_OPERATOR_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 4f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_REGFILE_RD_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 5f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_REGFILE_RS1_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 6f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_REGFILE_RS2_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 7f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_REGFILE_WE_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 8f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_SIGN_ZERO_EXT_SEL_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 9f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_SIGN_ZERO_EXT_DATA_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 10f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_IMM_A_MUX_DATA_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 11f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_DATA_MEM_SIZE_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 12f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_DATA_SE_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 13f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_DATA_MEM_CTRL_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 14f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_PC_IMM_SEL_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 15f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_BIG_IMM_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 16f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_BRANCH_IMM_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 17f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_BRANCH_LOGIC_CTL_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 18f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_BRANCH_LOGIC_ENABLE_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 19f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_JALR_IMM_ID.to_string(), + Pos2::new( + self.width / 2f32, + -self.height / 2f32 + 20f32 * self.height / 20f32, + ) + own_pos, + ), + ( + crate::components::DECODER_INSTRUCTION_ID.to_string(), + Pos2::new(0.0, self.height / 2f32) + own_pos, + ), + ] + } + + fn top_padding(&self) -> f32 { + self.height / 2f32 + } + + fn set_pos(&mut self, pos: (f32, f32)) { + self.pos = pos; + } + + fn get_pos(&self) -> (f32, f32) { + self.pos + } +} diff --git a/riscv/src/gui_egui/components/instr_mem.rs b/riscv/src/gui_egui/components/instr_mem.rs index 6647b3bf..99396004 100644 --- a/riscv/src/gui_egui/components/instr_mem.rs +++ b/riscv/src/gui_egui/components/instr_mem.rs @@ -137,7 +137,7 @@ impl EguiComponent for InstrMem { } fn top_padding(&self) -> f32 { - 20f32 + self.height / 2f32 } fn set_pos(&mut self, pos: (f32, f32)) { diff --git a/riscv/src/gui_egui/components/lsb_zero.rs b/riscv/src/gui_egui/components/lsb_zero.rs new file mode 100644 index 00000000..827501cf --- /dev/null +++ b/riscv/src/gui_egui/components/lsb_zero.rs @@ -0,0 +1,144 @@ +use crate::components::LSBZero; +use egui::{Color32, Pos2, Rect, Response, Rounding, Shape, Stroke, Ui, Vec2}; +use syncrim::common::{EguiComponent, Ports, Simulator}; +use syncrim::gui_egui::component_ui::{ + drag_logic, input_change_id, input_selector, pos_drag_value, properties_window, + rect_with_hover, visualize_ports, +}; +use syncrim::gui_egui::editor::{EditorMode, EditorRenderReturn, GridOptions}; +use syncrim::gui_egui::gui::EguiExtra; +use syncrim::gui_egui::helper::offset_helper; + +#[typetag::serde] +impl EguiComponent for LSBZero { + fn render( + &self, + ui: &mut Ui, + _context: &mut EguiExtra, + _simulator: Option<&mut Simulator>, + offset: Vec2, + scale: f32, + clip_rect: Rect, + editor_mode: EditorMode, + ) -> Option> { + // 21x41 + // middle: 11x 21y (0 0) + let oh: fn((f32, f32), f32, Vec2) -> Pos2 = offset_helper; + let offset_old = offset; + let mut offset = offset; + offset.x += self.pos.0 * scale; + offset.y += self.pos.1 * scale; + let s = scale; + let o = offset; + + // The shape + let rect = Rect { + min: oh((-self.width / 2f32, -self.height / 2f32), s, o), + max: oh((self.width / 2f32, self.height / 2f32), s, o), + }; + ui.painter().add(Shape::rect_stroke( + rect, + Rounding::none(), + Stroke { + width: scale, + color: Color32::BLACK, + }, + )); + + let r = rect_with_hover(rect, clip_rect, editor_mode, ui, self.id.clone(), |ui| { + ui.label(format!("Id: {}", self.id.clone())); + ui.label("LSBZero"); + }); + match editor_mode { + EditorMode::Simulator => (), + _ => visualize_ports(ui, self.ports_location(), offset_old, scale, clip_rect), + } + Some(vec![r]) + } + + fn render_editor( + &mut self, + ui: &mut Ui, + context: &mut EguiExtra, + simulator: Option<&mut Simulator>, + offset: Vec2, + scale: f32, + clip_rect: Rect, + id_ports: &[(syncrim::common::Id, Ports)], + grid: &GridOptions, + editor_mode: EditorMode, + ) -> EditorRenderReturn { + let r_vec = LSBZero::render( + self, + ui, + context, + simulator, + offset, + scale, + clip_rect, + editor_mode, + ) + .unwrap(); + let resp = &r_vec[0]; + let delete = drag_logic( + ui.ctx(), + resp, + &mut self.pos, + &mut context.pos_tmp, + scale, + offset, + grid, + ); + + properties_window( + ui, + self.id.clone(), + resp, + &mut context.properties_window, + |ui| { + let mut clicked_dropdown = false; + input_change_id(ui, &mut context.id_tmp, &mut self.id, id_ports); + pos_drag_value(ui, &mut self.pos); + clicked_dropdown |= input_selector( + ui, + &mut self.data_i, + crate::components::LSB_ZERO_DATA_I_ID.to_string(), + id_ports, + self.id.clone(), + ); + clicked_dropdown + }, + ); + + EditorRenderReturn { + delete, + resp: Some(r_vec), + } + } + + fn ports_location(&self) -> Vec<(syncrim::common::Id, Pos2)> { + let own_pos = Vec2::new(self.pos.0, self.pos.1); + vec![ + ( + crate::components::LSB_ZERO_DATA_I_ID.to_string(), + Pos2::new(-self.width / 2f32, 0.0) + own_pos, + ), + ( + crate::components::LSB_ZERO_OUT_ID.to_string(), + Pos2::new(self.width / 2f32, 0.0) + own_pos, + ), + ] + } + + fn top_padding(&self) -> f32 { + self.height / 2f32 + } + + fn set_pos(&mut self, pos: (f32, f32)) { + self.pos = pos; + } + + fn get_pos(&self) -> (f32, f32) { + self.pos + } +} diff --git a/riscv/src/gui_egui/components/mod.rs b/riscv/src/gui_egui/components/mod.rs index 27387dd5..f2314f5e 100644 --- a/riscv/src/gui_egui/components/mod.rs +++ b/riscv/src/gui_egui/components/mod.rs @@ -1,4 +1,7 @@ pub mod alu; pub mod branch_logic; +pub mod decoder; pub mod instr_mem; +pub mod lsb_zero; pub mod reg_file; +pub mod sign_zero_ext; diff --git a/riscv/src/gui_egui/components/reg_file.rs b/riscv/src/gui_egui/components/reg_file.rs index 65486a76..b8bf3918 100644 --- a/riscv/src/gui_egui/components/reg_file.rs +++ b/riscv/src/gui_egui/components/reg_file.rs @@ -1,5 +1,192 @@ use crate::components::RegFile; -use syncrim::common::EguiComponent; +use egui::{Color32, Pos2, Rect, Response, Rounding, Shape, Stroke, Ui, Vec2}; +use syncrim::common::{EguiComponent, Ports, Simulator}; +use syncrim::gui_egui::component_ui::{ + drag_logic, input_change_id, input_selector, pos_drag_value, properties_window, + rect_with_hover, visualize_ports, +}; +use syncrim::gui_egui::editor::{EditorMode, EditorRenderReturn, GridOptions}; +use syncrim::gui_egui::gui::EguiExtra; +use syncrim::gui_egui::helper::offset_helper; #[typetag::serde] -impl EguiComponent for RegFile {} +impl EguiComponent for RegFile { + fn render( + &self, + ui: &mut Ui, + _context: &mut EguiExtra, + _simulator: Option<&mut Simulator>, + offset: Vec2, + scale: f32, + clip_rect: Rect, + editor_mode: EditorMode, + ) -> Option> { + // 21x41 + // middle: 11x 21y (0 0) + let oh: fn((f32, f32), f32, Vec2) -> Pos2 = offset_helper; + let offset_old = offset; + let mut offset = offset; + offset.x += self.pos.0 * scale; + offset.y += self.pos.1 * scale; + let s = scale; + let o = offset; + + // The shape + let rect = Rect { + min: oh((-self.width / 2f32, -self.height / 2f32), s, o), + max: oh((self.width / 2f32, self.height / 2f32), s, o), + }; + ui.painter().add(Shape::rect_stroke( + rect, + Rounding::none(), + Stroke { + width: scale, + color: Color32::BLACK, + }, + )); + + let r = rect_with_hover(rect, clip_rect, editor_mode, ui, self.id.clone(), |ui| { + ui.label(format!("Id: {}", self.id.clone())); + ui.label("RegFile"); + }); + match editor_mode { + EditorMode::Simulator => (), + _ => visualize_ports(ui, self.ports_location(), offset_old, scale, clip_rect), + } + Some(vec![r]) + } + + fn render_editor( + &mut self, + ui: &mut Ui, + context: &mut EguiExtra, + simulator: Option<&mut Simulator>, + offset: Vec2, + scale: f32, + clip_rect: Rect, + id_ports: &[(syncrim::common::Id, Ports)], + grid: &GridOptions, + editor_mode: EditorMode, + ) -> EditorRenderReturn { + let r_vec = RegFile::render( + self, + ui, + context, + simulator, + offset, + scale, + clip_rect, + editor_mode, + ) + .unwrap(); + let resp = &r_vec[0]; + let delete = drag_logic( + ui.ctx(), + resp, + &mut self.pos, + &mut context.pos_tmp, + scale, + offset, + grid, + ); + + properties_window( + ui, + self.id.clone(), + resp, + &mut context.properties_window, + |ui| { + let mut clicked_dropdown = false; + input_change_id(ui, &mut context.id_tmp, &mut self.id, id_ports); + pos_drag_value(ui, &mut self.pos); + clicked_dropdown |= input_selector( + ui, + &mut self.read_addr1, + crate::components::REG_FILE_READ_ADDR1_ID.to_string(), + id_ports, + self.id.clone(), + ); + clicked_dropdown |= input_selector( + ui, + &mut self.read_addr2, + crate::components::REG_FILE_READ_ADDR2_ID.to_string(), + id_ports, + self.id.clone(), + ); + clicked_dropdown |= input_selector( + ui, + &mut self.write_data, + crate::components::REG_FILE_WRITE_DATA_ID.to_string(), + id_ports, + self.id.clone(), + ); + clicked_dropdown |= input_selector( + ui, + &mut self.write_addr, + crate::components::REG_FILE_WRITE_ADDR_ID.to_string(), + id_ports, + self.id.clone(), + ); + clicked_dropdown |= input_selector( + ui, + &mut self.write_enable, + crate::components::REG_FILE_WRITE_ENABLE_ID.to_string(), + id_ports, + self.id.clone(), + ); + clicked_dropdown + }, + ); + + EditorRenderReturn { + delete, + resp: Some(r_vec), + } + } + + fn ports_location(&self) -> Vec<(syncrim::common::Id, Pos2)> { + let own_pos = Vec2::new(self.pos.0, self.pos.1); + vec![ + ( + crate::components::REG_FILE_READ_ADDR1_ID.to_string(), + Pos2::new(-self.width / 2f32, -self.height / 5f32) + own_pos, + ), + ( + crate::components::REG_FILE_READ_ADDR2_ID.to_string(), + Pos2::new(-self.width / 2f32, self.height / 5f32) + own_pos, + ), + ( + crate::components::REG_FILE_WRITE_ADDR_ID.to_string(), + Pos2::new(-self.width / 2f32, 0f32) + own_pos, + ), + ( + crate::components::REG_FILE_WRITE_DATA_ID.to_string(), + Pos2::new(-self.width / 3f32, -self.height / 2f32) + own_pos, + ), + ( + crate::components::REG_FILE_WRITE_ENABLE_ID.to_string(), + Pos2::new(self.width / 3f32, -self.height / 2f32) + own_pos, + ), + ( + crate::components::REG_FILE_REG_A_OUT.to_string(), + Pos2::new(self.width / 2f32, -self.height / 3f32) + own_pos, + ), + ( + crate::components::REG_FILE_REG_B_OUT.to_string(), + Pos2::new(self.width / 2f32, self.height / 3f32) + own_pos, + ), + ] + } + + fn top_padding(&self) -> f32 { + self.height / 2f32 + } + + fn set_pos(&mut self, pos: (f32, f32)) { + self.pos = pos; + } + + fn get_pos(&self) -> (f32, f32) { + self.pos + } +} diff --git a/riscv/src/gui_egui/components/sign_zero_ext.rs b/riscv/src/gui_egui/components/sign_zero_ext.rs new file mode 100644 index 00000000..ee374617 --- /dev/null +++ b/riscv/src/gui_egui/components/sign_zero_ext.rs @@ -0,0 +1,156 @@ +use crate::components::SZExt; +use egui::{Color32, Pos2, Rect, Response, Rounding, Shape, Stroke, Ui, Vec2}; +use syncrim::common::{EguiComponent, Ports, Simulator}; +use syncrim::gui_egui::component_ui::{ + drag_logic, input_change_id, input_selector, pos_drag_value, properties_window, + rect_with_hover, visualize_ports, +}; +use syncrim::gui_egui::editor::{EditorMode, EditorRenderReturn, GridOptions}; +use syncrim::gui_egui::gui::EguiExtra; +use syncrim::gui_egui::helper::offset_helper; + +#[typetag::serde] +impl EguiComponent for SZExt { + fn render( + &self, + ui: &mut Ui, + _context: &mut EguiExtra, + _simulator: Option<&mut Simulator>, + offset: Vec2, + scale: f32, + clip_rect: Rect, + editor_mode: EditorMode, + ) -> Option> { + // 21x41 + // middle: 11x 21y (0 0) + let oh: fn((f32, f32), f32, Vec2) -> Pos2 = offset_helper; + let offset_old = offset; + let mut offset = offset; + offset.x += self.pos.0 * scale; + offset.y += self.pos.1 * scale; + let s = scale; + let o = offset; + + // The shape + let rect = Rect { + min: oh((-self.width / 2f32, -self.height / 2f32), s, o), + max: oh((self.width / 2f32, self.height / 2f32), s, o), + }; + ui.painter().add(Shape::rect_stroke( + rect, + Rounding::none(), + Stroke { + width: scale, + color: Color32::BLACK, + }, + )); + + let r = rect_with_hover(rect, clip_rect, editor_mode, ui, self.id.clone(), |ui| { + ui.label(format!("Id: {}", self.id.clone())); + ui.label("SZExt"); + }); + match editor_mode { + EditorMode::Simulator => (), + _ => visualize_ports(ui, self.ports_location(), offset_old, scale, clip_rect), + } + Some(vec![r]) + } + + fn render_editor( + &mut self, + ui: &mut Ui, + context: &mut EguiExtra, + simulator: Option<&mut Simulator>, + offset: Vec2, + scale: f32, + clip_rect: Rect, + id_ports: &[(syncrim::common::Id, Ports)], + grid: &GridOptions, + editor_mode: EditorMode, + ) -> EditorRenderReturn { + let r_vec = SZExt::render( + self, + ui, + context, + simulator, + offset, + scale, + clip_rect, + editor_mode, + ) + .unwrap(); + let resp = &r_vec[0]; + let delete = drag_logic( + ui.ctx(), + resp, + &mut self.pos, + &mut context.pos_tmp, + scale, + offset, + grid, + ); + + properties_window( + ui, + self.id.clone(), + resp, + &mut context.properties_window, + |ui| { + let mut clicked_dropdown = false; + input_change_id(ui, &mut context.id_tmp, &mut self.id, id_ports); + pos_drag_value(ui, &mut self.pos); + clicked_dropdown |= input_selector( + ui, + &mut self.data_i, + crate::components::SIGN_ZERO_EXT_DATA_I_ID.to_string(), + id_ports, + self.id.clone(), + ); + clicked_dropdown |= input_selector( + ui, + &mut self.data_i, + crate::components::SIGN_ZERO_EXT_SEL_I_ID.to_string(), + id_ports, + self.id.clone(), + ); + + clicked_dropdown + }, + ); + + EditorRenderReturn { + delete, + resp: Some(r_vec), + } + } + + fn ports_location(&self) -> Vec<(syncrim::common::Id, Pos2)> { + let own_pos = Vec2::new(self.pos.0, self.pos.1); + vec![ + ( + crate::components::SIGN_ZERO_EXT_DATA_I_ID.to_string(), + Pos2::new(self.width / 2f32, 0.0) + own_pos, + ), + ( + crate::components::SIGN_ZERO_EXT_SEL_I_ID.to_string(), + Pos2::new(0.0, -self.height / 2f32) + own_pos, + ), + ( + crate::components::SIGN_ZERO_EXT_OUT_ID.to_string(), + Pos2::new(-self.width / 2f32, 0.0) + own_pos, + ), + ] + } + + fn top_padding(&self) -> f32 { + self.height / 2f32 + } + + fn set_pos(&mut self, pos: (f32, f32)) { + self.pos = pos; + } + + fn get_pos(&self) -> (f32, f32) { + self.pos + } +}