From 6f173533db8f53b821e3634c5d28fa99c3ae8041 Mon Sep 17 00:00:00 2001 From: D4VID Date: Tue, 19 Aug 2025 16:37:18 +0200 Subject: [PATCH] Placing basic components --- verilog2logicworld/src/main.rs | 34 ++++- verilog2logicworld/src/router.rs | 220 ++++++++++++++++++++++++++++++ verilog2logicworld/src/verilog.rs | 35 +++-- 3 files changed, 274 insertions(+), 15 deletions(-) create mode 100644 verilog2logicworld/src/router.rs diff --git a/verilog2logicworld/src/main.rs b/verilog2logicworld/src/main.rs index 0396139..32be719 100644 --- a/verilog2logicworld/src/main.rs +++ b/verilog2logicworld/src/main.rs @@ -1,3 +1,4 @@ +mod router; mod verilog; use std::f32::consts::PI; @@ -89,11 +90,32 @@ fn main() { return; }; - for module in modules { - let result = compile_module(&module, &files); - println!("{}: {:?}", module, result); - } + for module_name in modules { + let result = compile_module(&module_name, &files); + + let module = match result { + Ok(module) => module, + Err(err) => { + println!("Error while compiling module {}: {:?}", module_name, err); + return; + } + }; - // let result = write_subassembly(); - // println!("{:?}", result); + let result = router::route(module); + let (components, wires) = match result { + Ok(pair) => pair, + Err(err) => { + println!("Error while routing module {}: {:?}", module_name, err); + return; + } + }; + + let result = create_subassembly( + module_name, + &Path::new("output/"), + &components, + &wires, + ); + println!("{:?}", result); + } } diff --git a/verilog2logicworld/src/router.rs b/verilog2logicworld/src/router.rs new file mode 100644 index 0000000..574b6e4 --- /dev/null +++ b/verilog2logicworld/src/router.rs @@ -0,0 +1,220 @@ +use std::{collections::HashMap, f32::consts::PI}; + +use logicworld_subassembly::{lw, COMPONENT_MAP}; +use vecmath::{vec3_add, Vector3}; + +use crate::verilog::{Cell, Error, Module}; + +#[derive(Default, Debug)] +struct Net { + /// Index of cell that is outputting into this net (or None, if it's the module input) + connected_output: Option<(usize, String)>, + + /// Indicies and names of ports of cells whose inputs are connected to this net + connected_inputs: Vec<(usize, String)>, +} + +pub fn route(module: Module) -> Result<(Vec, Vec), Error> { + let mut net_list: HashMap = HashMap::new(); + + for input in &module.inputs { + println!("Input {}: {:?} ", input.name, input.bits); + for bit in &input.bits { + net_list.insert(*bit, Net::default()); + } + } + for output in &module.outputs { + println!("Output {}: {:?} ", output.name, output.bits); + for bit in &output.bits { + net_list.insert( + *bit, + Net { + connected_output: None, + connected_inputs: Vec::with_capacity(0), + }, + ); + } + } + for (i, cell) in module.cells.iter().enumerate() { + // println!( + // "Cell {} - {}: in={:?} out={:?}", + // i, cell.cell_type, cell.inputs, cell.outputs + // ); + for (key, bits) in &cell.inputs { + for bit in bits { + net_list + .entry(*bit) + .or_insert(Net::default()) + .connected_inputs + .push((i, key.to_owned())); + } + } + for (key, bits) in &cell.outputs { + for bit in bits { + net_list + .entry(*bit) + .or_insert(Net::default()) + .connected_output = Some((i, key.to_owned())); + } + } + } + + for (key, value) in &net_list { + println!("Net {}: {:?}", key, value); + } + + let board = lw::Component { + address: 1, + parent: 0, + numeric_id: COMPONENT_MAP["MHG.CircuitBoard"], + position: [0, 0, 0], + rotation: quaternion::euler_angles(0.0, -PI / 2.0, 0.0), + inputs: vec![], + outputs: vec![], + custom_data: lw::CircuitBoard::default() + .with_size(5, 10) + .with_color(100, 25, 25) + .custom_data(), + }; + + let board_address = board.address; + + let mut next_address = board_address + 1; + + let mut next_position = [150 + 1 * 300, 150, 150 + 1 * 300]; + + let mut wires: Vec = vec![]; + + let mut components = vec![board]; + components.extend( + module + .cells + .iter() + .map(|cell| { + println!("{:?}", cell); + let component = match cell.cell_type.as_str() { + "$and" => Ok(basic_gate( + cell, + "MHG.AndGate", + board_address, + &mut next_address, + &mut next_position, + )), + "$xor" => Ok(basic_gate( + cell, + "MHG.XorGate", + board_address, + &mut next_address, + &mut next_position, + )), + "$or" => Ok(or_gate( + cell, + board_address, + &mut next_address, + &mut next_position, + &mut wires, + )), + _ => Err(Error::UnsupportedCell), + }; + + return component; + }) + .collect::>, Error>>()? + .into_iter() + .flatten() + .collect::>(), + ); + + return Ok((components, wires)); +} + +fn basic_gate( + cell: &Cell, + text_id: &str, + parent_address: u32, + next_address: &mut u32, + next_position: &mut Vector3, +) -> Vec { + let input_a = lw::Input::new(cell.inputs["A"][0] as i32); + let input_b = lw::Input::new(cell.inputs["B"][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_a, input_b], + outputs: vec![output], + custom_data: vec![], + }; + + *next_address += 1; + next_position[2] += 3 * 300; + + return vec![component]; +} + +fn or_gate( + cell: &Cell, + parent_address: u32, + next_address: &mut u32, + next_position: &mut Vector3, + wires: &mut Vec, +) -> Vec { + let input_a = lw::Input::new(cell.inputs["A"][0] as i32); + let input_b = lw::Input::new(cell.inputs["B"][0] as i32); + let output_state_id = cell.outputs["Y"][0] as i32; + 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: parent_address, + numeric_id: COMPONENT_MAP["MHG.Buffer_WithOutput"], + position: *next_position, + rotation: quaternion::id(), + inputs: vec![input_a], + outputs: vec![output_a], + custom_data: vec![], + }; + let buffer_b = lw::Component { + address: *next_address + 1, + parent: parent_address, + numeric_id: COMPONENT_MAP["MHG.Buffer_WithOutput"], + position: vec3_add(*next_position, [300, 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: parent_address, + numeric_id: COMPONENT_MAP["MHG.Peg"], + position: vec3_add(*next_position, [0, 0, 2 * 300]), + rotation: quaternion::id(), + inputs: vec![peg], + outputs: vec![], + custom_data: vec![], + }; + + 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, + }); + + *next_address += 3; + next_position[2] += 5 * 300; + + return vec![buffer_a, buffer_b, peg]; +} diff --git a/verilog2logicworld/src/verilog.rs b/verilog2logicworld/src/verilog.rs index 7f5d6a9..269bd21 100644 --- a/verilog2logicworld/src/verilog.rs +++ b/verilog2logicworld/src/verilog.rs @@ -28,15 +28,17 @@ pub struct Port { #[derive(Default)] pub struct Module { - inputs: Vec, - outputs: Vec, + pub inputs: Vec, + pub outputs: Vec, + pub cells: Vec, } #[derive(Debug)] pub struct Cell { pub cell_type: String, pub parameters: HashMap, - pub connections: HashMap>, + pub inputs: HashMap>, + pub outputs: HashMap>, } impl From for Error { @@ -55,7 +57,7 @@ pub fn get_modules(files: &[&str]) -> Result, Error> { return Ok(module_names); } -pub fn compile_module(module_name: &str, files: &[&str]) -> Result, Error> { +pub fn compile_module(module_name: &str, files: &[&str]) -> Result { let json = run_yosys("proc; flatten; wreduce; opt; fsm; opt; memory -nomap -nordff; opt; muxpack; peepopt; async2sync; wreduce; opt -mux_bool", Some(module_name), files)?; let compiled_module = &json["modules"][module_name]; let ports_json = &compiled_module["ports"]; @@ -83,9 +85,12 @@ pub fn compile_module(module_name: &str, files: &[&str]) -> Result, Er } } - let cells = &compiled_module["cells"]; + module.cells = compiled_module["cells"] + .entries() + .map(|(_, cell)| resolve_cell(cell)) + .collect::>()?; - return cells.entries().map(|(_, cell)| resolve_cell(cell)).collect::>(); + return Ok(module); } pub fn resolve_cell(cell: &JsonValue) -> Result { @@ -101,17 +106,28 @@ pub fn resolve_cell(cell: &JsonValue) -> Result { } let json_connections = &cell["connections"]; - let mut connections: HashMap> = HashMap::new(); + let json_port_directions = &cell["port_directions"]; + let mut inputs: HashMap> = HashMap::new(); + let mut outputs: HashMap> = HashMap::new(); for (key, bits) in json_connections.entries() { let JsonValue::Array(arr) = bits else { return Err(Error::BadJson); }; + let direction = json_port_directions[key].as_str().ok_or(Error::BadJson)?; let connection_bits: Vec = arr .iter() .map(|x| x.as_usize().ok_or(Error::BadJson)) .collect::>()?; - connections.insert(key.to_owned(), connection_bits); + match direction { + "input" => { + inputs.insert(key.to_owned(), connection_bits); + } + "output" => { + outputs.insert(key.to_owned(), connection_bits); + } + _ => return Err(Error::BadJson), + } } let cell_type = cell["type"].as_str().ok_or(Error::BadJson)?.to_owned(); @@ -119,7 +135,8 @@ pub fn resolve_cell(cell: &JsonValue) -> Result { return Ok(Cell { cell_type, parameters, - connections, + inputs, + outputs, }); }