From 3d983f0b5d2335b7dcc1e88d1209342982beba85 Mon Sep 17 00:00:00 2001 From: D4VID Date: Sat, 30 Aug 2025 17:41:21 +0200 Subject: [PATCH] Refactoring Separate gates into separate files Implement layer builder --- verilog2logicworld/src/cells/binary_op.rs | 270 ++++++++++++++++++++ verilog2logicworld/src/cells/mod.rs | 5 + verilog2logicworld/src/cells/unary_op.rs | 50 ++++ verilog2logicworld/src/main.rs | 1 + verilog2logicworld/src/router.rs | 285 +--------------------- 5 files changed, 335 insertions(+), 276 deletions(-) create mode 100644 verilog2logicworld/src/cells/binary_op.rs create mode 100644 verilog2logicworld/src/cells/mod.rs create mode 100644 verilog2logicworld/src/cells/unary_op.rs diff --git a/verilog2logicworld/src/cells/binary_op.rs b/verilog2logicworld/src/cells/binary_op.rs new file mode 100644 index 0000000..a094064 --- /dev/null +++ b/verilog2logicworld/src/cells/binary_op.rs @@ -0,0 +1,270 @@ +use std::cmp::max; + +use logicworld_subassembly::{lw, COMPONENT_MAP}; +use vecmath::{vec3_add, Vector3}; + +use crate::router::{Connection, ConnectionMap, SQUARE}; +use crate::verilog::Cell; + +pub fn binary_op( + cell: &Cell, + text_id: &str, + parent_address: u32, + next_address: &mut u32, + next_position: &mut Vector3, + wires: &mut Vec, + connection_map: &mut ConnectionMap, +) -> Vec { + // All binary RTL cells have two input ports \A and \B and one output port \Y. They also have the following parameters: + + // Set to a non-zero value if the input \A is signed and therefore should be sign-extended when needed. + let a_signed = cell.parameters["A_SIGNED"] > 0; + + // The width of the input port \A. + let a_width = cell.parameters["A_WIDTH"]; + + // Set to a non-zero value if the input \B is signed and therefore should be sign-extended when needed. + let b_signed = cell.parameters["B_SIGNED"] > 0; + + // The width of the input port \B. + let b_width = cell.parameters["B_WIDTH"]; + + // The width of the output port \Y. + let y_width = cell.parameters["Y_WIDTH"]; + + assert!(a_width == b_width, "Different widths not yet supported"); + assert!(!a_signed && !b_signed, "Signed not yet supported"); + assert!( + a_width == y_width, + "Different widths of input and output not yet supported" + ); + + let mut components = vec![]; + + let height = max(max(a_width, b_width), y_width); + + builder( + height, + parent_address, + next_address, + next_position, + &mut components, + wires, + connection_map, + |i_bit, next_address, parent, next_position_within, components, wires, connection_map| { + let input_a = lw::Input::new(cell.inputs["A"][i_bit] as i32); + let input_b = lw::Input::new(cell.inputs["B"][i_bit] as i32); + let output_state_id = cell.outputs["Y"][i_bit] as lw::Int; + let output = lw::Output::new(output_state_id); + if text_id == "Custom.OrGate" { + let input_a = lw::Input::new(cell.inputs["A"][0] as lw::Int); + let input_b = lw::Input::new(cell.inputs["B"][0] as lw::Int); + let output_a = lw::Output::new(output_state_id); + let output_b = lw::Output::new(output_state_id); + let peg = lw::Input::new(output_state_id); + let buffer_a = lw::Component { + address: *next_address, + parent, + numeric_id: COMPONENT_MAP["MHG.Buffer_WithOutput"], + position: *next_position_within, + rotation: quaternion::id(), + inputs: vec![input_a], + outputs: vec![output_a], + custom_data: vec![], + }; + let buffer_b = lw::Component { + address: *next_address + 1, + parent, + numeric_id: COMPONENT_MAP["MHG.Buffer_WithOutput"], + position: vec3_add(*next_position_within, [SQUARE, 0, 0]), + rotation: quaternion::id(), + inputs: vec![input_b], + outputs: vec![output_b], + custom_data: vec![], + }; + let peg = lw::Component { + address: *next_address + 2, + parent, + numeric_id: COMPONENT_MAP["MHG.Peg"], + position: vec3_add(*next_position_within, [0, 0, 2 * SQUARE]), + rotation: quaternion::id(), + inputs: vec![peg], + outputs: vec![], + custom_data: vec![], + }; + + *next_address += 3; + + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "A", + bit_index: i_bit, + }, + lw::PegAddress::input(buffer_a.address, 0), + ); + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "B", + bit_index: i_bit, + }, + lw::PegAddress::input(buffer_b.address, 0), + ); + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "Y", + bit_index: i_bit, + }, + lw::PegAddress::input(peg.address, 0), + ); + + wires.push(lw::Wire { + first_point: lw::PegAddress::output(buffer_a.address, 0), + second_point: lw::PegAddress::input(peg.address, 0), + circuit_state_id: output_state_id, + wire_rotation: 0.0, + }); + wires.push(lw::Wire { + first_point: lw::PegAddress::output(buffer_b.address, 0), + second_point: lw::PegAddress::input(peg.address, 0), + circuit_state_id: output_state_id, + wire_rotation: 0.0, + }); + + components.push(buffer_a); + components.push(buffer_b); + components.push(peg); + } else { + let component = lw::Component { + address: *next_address, + parent, + numeric_id: COMPONENT_MAP[text_id], + position: *next_position_within, + rotation: quaternion::id(), + inputs: vec![input_a, input_b], + outputs: vec![output], + custom_data: vec![], + }; + *next_address += 1; + + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "A", + bit_index: i_bit, + }, + lw::PegAddress::input(component.address, 0), + ); + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "B", + bit_index: i_bit, + }, + lw::PegAddress::input(component.address, 1), + ); + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "Y", + bit_index: i_bit, + }, + lw::PegAddress::output(component.address, 0), + ); + components.push(component); + } + }, + ); + + next_position[2] += 5 * SQUARE; + + return components; +} + +pub fn builder( + height: usize, + parent_address: u32, + next_address: &mut u32, + position: &Vector3, + components: &mut Vec, + wires: &mut Vec, + connection_map: &mut ConnectionMap, + layer_builder: impl Fn( + usize, + &mut u32, + u32, + &mut Vector3, + &mut Vec, + &mut Vec, + &mut ConnectionMap, + ), +) { + let mount = lw::Component { + address: *next_address, + parent: parent_address, + numeric_id: COMPONENT_MAP["MHG.Mount"], + position: *position, + rotation: quaternion::id(), + inputs: vec![], + outputs: vec![], + custom_data: lw::Mount::new(8).custom_data(), + }; + let next_board = lw::Component { + address: *next_address + 1, + parent: mount.address, + numeric_id: COMPONENT_MAP["MHG.CircuitBoard"], + position: [-SQUARE / 2, 3 * SQUARE - SQUARE / 3, -SQUARE / 2], + rotation: quaternion::id(), + inputs: vec![], + outputs: vec![], + custom_data: lw::CircuitBoard::default().with_size(3, 2).custom_data(), + }; + + *next_address += 2; + + let mut next_parent = next_board.address; + components.push(mount); + components.push(next_board); + + for i_bit in 0..height { + let mut next_position_within = [SQUARE / 2, SQUARE / 2, SQUARE / 2]; + let mount = lw::Component { + address: *next_address, + parent: next_parent, + numeric_id: COMPONENT_MAP["MHG.Mount"], + position: next_position_within, + rotation: quaternion::id(), + inputs: vec![], + outputs: vec![], + custom_data: lw::Mount::new(8).custom_data(), + }; + let next_board = lw::Component { + address: *next_address + 1, + parent: mount.address, + numeric_id: COMPONENT_MAP["MHG.CircuitBoard"], + position: [-SQUARE / 2, 3 * SQUARE - SQUARE / 3, -SQUARE / 2], + rotation: quaternion::id(), + inputs: vec![], + outputs: vec![], + custom_data: lw::CircuitBoard::default().with_size(3, 2).custom_data(), + }; + *next_address += 2; + next_position_within[0] += SQUARE; + + layer_builder( + i_bit, + next_address, + next_parent, + &mut next_position_within, + components, + wires, + connection_map, + ); + + next_parent = next_board.address; + components.push(mount); + components.push(next_board); + } +} diff --git a/verilog2logicworld/src/cells/mod.rs b/verilog2logicworld/src/cells/mod.rs new file mode 100644 index 0000000..a472f19 --- /dev/null +++ b/verilog2logicworld/src/cells/mod.rs @@ -0,0 +1,5 @@ +pub mod unary_op; +pub use unary_op::unary_op; + +pub mod binary_op; +pub use binary_op::binary_op; diff --git a/verilog2logicworld/src/cells/unary_op.rs b/verilog2logicworld/src/cells/unary_op.rs new file mode 100644 index 0000000..38e12f8 --- /dev/null +++ b/verilog2logicworld/src/cells/unary_op.rs @@ -0,0 +1,50 @@ +use logicworld_subassembly::{lw, COMPONENT_MAP}; +use vecmath::Vector3; + +use crate::verilog::Cell; +use crate::router::{Connection, ConnectionMap, SQUARE}; + +pub fn unary_op( + cell: &Cell, + text_id: &str, + parent_address: u32, + next_address: &mut u32, + next_position: &mut Vector3, + _wires: &mut Vec, + connection_map: &mut ConnectionMap, +) -> Vec { + let input = lw::Input::new(cell.inputs["A"][0] as i32); + let output = lw::Output::new(cell.outputs["Y"][0] as i32); + let component = lw::Component { + address: *next_address, + parent: parent_address, + numeric_id: COMPONENT_MAP[text_id], + position: *next_position, + rotation: quaternion::id(), + inputs: vec![input], + outputs: vec![output], + custom_data: vec![], + }; + + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "A", + bit_index: 0, + }, + lw::PegAddress::input(component.address, 0), + ); + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "Y", + bit_index: 0, + }, + lw::PegAddress::output(component.address, 0), + ); + + *next_address += 1; + next_position[2] += 3 * SQUARE; + + return vec![component]; +} diff --git a/verilog2logicworld/src/main.rs b/verilog2logicworld/src/main.rs index 5b4aba3..a51c289 100644 --- a/verilog2logicworld/src/main.rs +++ b/verilog2logicworld/src/main.rs @@ -1,5 +1,6 @@ mod router; mod verilog; +mod cells; use std::path::Path; diff --git a/verilog2logicworld/src/router.rs b/verilog2logicworld/src/router.rs index a498bf1..5ddd536 100644 --- a/verilog2logicworld/src/router.rs +++ b/verilog2logicworld/src/router.rs @@ -1,19 +1,20 @@ -use std::{cmp::max, collections::HashMap, f32::consts::PI, fmt::Debug}; +use std::{collections::HashMap, f32::consts::PI, fmt::Debug}; use logicworld_subassembly::{lw, COMPONENT_MAP}; use vecmath::{vec3_add, Vector3}; -use crate::verilog::{Cell, Error, Module}; +use crate::verilog::{Error, Module}; +use crate::cells::*; // https://yosyshq.readthedocs.io/projects/yosys/en/0.39/CHAPTER_CellLib.html -const SQUARE: lw::Int = 300; +pub const SQUARE: lw::Int = 300; #[derive(Clone, Copy, PartialEq, Eq, Hash)] -struct Connection<'a> { - cell_index: usize, - port_name: &'a str, - bit_index: usize, +pub struct Connection<'a> { + pub cell_index: usize, + pub port_name: &'a str, + pub bit_index: usize, } impl<'a> Debug for Connection<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -34,7 +35,7 @@ struct Net<'a> { connected_inputs: Vec>, } -type ConnectionMap<'a> = HashMap, lw::PegAddress>; +pub type ConnectionMap<'a> = HashMap, lw::PegAddress>; pub fn route(module: Module) -> Result<(Vec, Vec), Error> { let mut net_list: HashMap = HashMap::new(); @@ -337,271 +338,3 @@ fn output_port( return vec![peg, label]; } -fn binary_op( - cell: &Cell, - text_id: &str, - parent_address: u32, - next_address: &mut u32, - next_position: &mut Vector3, - wires: &mut Vec, - connection_map: &mut ConnectionMap, -) -> Vec { - // All binary RTL cells have two input ports \A and \B and one output port \Y. They also have the following parameters: - - // Set to a non-zero value if the input \A is signed and therefore should be sign-extended when needed. - let a_signed = cell.parameters["A_SIGNED"] > 0; - - // The width of the input port \A. - let a_width = cell.parameters["A_WIDTH"]; - - // Set to a non-zero value if the input \B is signed and therefore should be sign-extended when needed. - let b_signed = cell.parameters["B_SIGNED"] > 0; - - // The width of the input port \B. - let b_width = cell.parameters["B_WIDTH"]; - - // The width of the output port \Y. - let y_width = cell.parameters["Y_WIDTH"]; - - assert!(a_width == b_width, "Different widths not yet supported"); - assert!(!a_signed && !b_signed, "Signed not yet supported"); - assert!( - a_width == y_width, - "Different widths of input and output not yet supported" - ); - - let mut next_parent = parent_address; - - let mut components = vec![]; - - let height = max(max(a_width, b_width), y_width); - - let mount = lw::Component { - address: *next_address, - parent: next_parent, - numeric_id: COMPONENT_MAP["MHG.Mount"], - position: *next_position, - rotation: quaternion::id(), - inputs: vec![], - outputs: vec![], - custom_data: lw::Mount::new(8).custom_data(), - }; - let next_board = lw::Component { - address: *next_address + 1, - parent: mount.address, - numeric_id: COMPONENT_MAP["MHG.CircuitBoard"], - position: [-SQUARE / 2, 3 * SQUARE - SQUARE / 3, -SQUARE / 2], - rotation: quaternion::id(), - inputs: vec![], - outputs: vec![], - custom_data: lw::CircuitBoard::default().with_size(3, 2).custom_data(), - }; - - *next_address += 2; - - next_parent = next_board.address; - components.push(mount); - components.push(next_board); - - for i_bit in 0..height { - let mut next_position_within = [SQUARE / 2, SQUARE / 2, SQUARE / 2]; - let mount = lw::Component { - address: *next_address, - parent: next_parent, - numeric_id: COMPONENT_MAP["MHG.Mount"], - position: next_position_within, - rotation: quaternion::id(), - inputs: vec![], - outputs: vec![], - custom_data: lw::Mount::new(8).custom_data(), - }; - let next_board = lw::Component { - address: *next_address + 1, - parent: mount.address, - numeric_id: COMPONENT_MAP["MHG.CircuitBoard"], - position: [-SQUARE / 2, 3 * SQUARE - SQUARE / 3, -SQUARE / 2], - rotation: quaternion::id(), - inputs: vec![], - outputs: vec![], - custom_data: lw::CircuitBoard::default().with_size(3, 2).custom_data(), - }; - *next_address += 2; - next_position_within[0] += SQUARE; - - let input_a = lw::Input::new(cell.inputs["A"][i_bit] as i32); - let input_b = lw::Input::new(cell.inputs["B"][i_bit] as i32); - let output_state_id = cell.outputs["Y"][i_bit] as lw::Int; - let output = lw::Output::new(output_state_id); - if text_id == "Custom.OrGate" { - let input_a = lw::Input::new(cell.inputs["A"][0] as lw::Int); - let input_b = lw::Input::new(cell.inputs["B"][0] as lw::Int); - let output_a = lw::Output::new(output_state_id); - let output_b = lw::Output::new(output_state_id); - let peg = lw::Input::new(output_state_id); - let buffer_a = lw::Component { - address: *next_address, - parent: next_parent, - numeric_id: COMPONENT_MAP["MHG.Buffer_WithOutput"], - position: next_position_within, - rotation: quaternion::id(), - inputs: vec![input_a], - outputs: vec![output_a], - custom_data: vec![], - }; - let buffer_b = lw::Component { - address: *next_address + 1, - parent: next_parent, - numeric_id: COMPONENT_MAP["MHG.Buffer_WithOutput"], - position: vec3_add(next_position_within, [SQUARE, 0, 0]), - rotation: quaternion::id(), - inputs: vec![input_b], - outputs: vec![output_b], - custom_data: vec![], - }; - let peg = lw::Component { - address: *next_address + 2, - parent: next_parent, - numeric_id: COMPONENT_MAP["MHG.Peg"], - position: vec3_add(next_position_within, [0, 0, 2 * SQUARE]), - rotation: quaternion::id(), - inputs: vec![peg], - outputs: vec![], - custom_data: vec![], - }; - - connection_map.insert( - Connection { - cell_index: cell.index, - port_name: "A", - bit_index: i_bit, - }, - lw::PegAddress::input(buffer_a.address, 0), - ); - connection_map.insert( - Connection { - cell_index: cell.index, - port_name: "B", - bit_index: i_bit, - }, - lw::PegAddress::input(buffer_b.address, 0), - ); - connection_map.insert( - Connection { - cell_index: cell.index, - port_name: "Y", - bit_index: i_bit, - }, - lw::PegAddress::input(peg.address, 0), - ); - - wires.push(lw::Wire { - first_point: lw::PegAddress::output(buffer_a.address, 0), - second_point: lw::PegAddress::input(peg.address, 0), - circuit_state_id: output_state_id, - wire_rotation: 0.0, - }); - wires.push(lw::Wire { - first_point: lw::PegAddress::output(buffer_b.address, 0), - second_point: lw::PegAddress::input(peg.address, 0), - circuit_state_id: output_state_id, - wire_rotation: 0.0, - }); - - components.push(buffer_a); - components.push(buffer_b); - components.push(peg); - - *next_address += 3; - } else { - let component = lw::Component { - address: *next_address, - parent: next_parent, - numeric_id: COMPONENT_MAP[text_id], - position: next_position_within, - rotation: quaternion::id(), - inputs: vec![input_a, input_b], - outputs: vec![output], - custom_data: vec![], - }; - *next_address += 1; - - connection_map.insert( - Connection { - cell_index: cell.index, - port_name: "A", - bit_index: i_bit, - }, - lw::PegAddress::input(component.address, 0), - ); - connection_map.insert( - Connection { - cell_index: cell.index, - port_name: "B", - bit_index: i_bit, - }, - lw::PegAddress::input(component.address, 1), - ); - connection_map.insert( - Connection { - cell_index: cell.index, - port_name: "Y", - bit_index: i_bit, - }, - lw::PegAddress::output(component.address, 0), - ); - components.push(component); - } - next_parent = next_board.address; - components.push(mount); - components.push(next_board); - } - - next_position[2] += 5 * SQUARE; - - return components; -} - -fn unary_op( - cell: &Cell, - text_id: &str, - parent_address: u32, - next_address: &mut u32, - next_position: &mut Vector3, - wires: &mut Vec, - connection_map: &mut ConnectionMap, -) -> Vec { - let input = lw::Input::new(cell.inputs["A"][0] as i32); - let output = lw::Output::new(cell.outputs["Y"][0] as i32); - let component = lw::Component { - address: *next_address, - parent: parent_address, - numeric_id: COMPONENT_MAP[text_id], - position: *next_position, - rotation: quaternion::id(), - inputs: vec![input], - outputs: vec![output], - custom_data: vec![], - }; - - connection_map.insert( - Connection { - cell_index: cell.index, - port_name: "A", - bit_index: 0, - }, - lw::PegAddress::input(component.address, 0), - ); - connection_map.insert( - Connection { - cell_index: cell.index, - port_name: "Y", - bit_index: 0, - }, - lw::PegAddress::output(component.address, 0), - ); - - *next_address += 1; - next_position[2] += 3 * SQUARE; - - return vec![component]; -}