diff --git a/verilog2logicworld/gates.v b/verilog2logicworld/gates.v index 2f73e0a..acee0b6 100644 --- a/verilog2logicworld/gates.v +++ b/verilog2logicworld/gates.v @@ -1,6 +1,6 @@ module gates( - input a,b,c,d, - output wire out, out2 + input [3:0] a,b,c,d, + output wire [3:0] out, out2 ); assign out = a & b | c; assign out2 = a & b ^ d; diff --git a/verilog2logicworld/src/router.rs b/verilog2logicworld/src/router.rs index f16f887..3dcdd5b 100644 --- a/verilog2logicworld/src/router.rs +++ b/verilog2logicworld/src/router.rs @@ -5,17 +5,28 @@ use vecmath::{vec3_add, Vector3}; use crate::verilog::{Cell, Error, Module}; +// https://yosyshq.readthedocs.io/projects/yosys/en/0.39/CHAPTER_CellLib.html + const SQUARE: lw::Int = 300; +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +struct Connection<'a> { + cell_index: usize, + port_name: &'a str, + bit_index: usize, +} + #[derive(Default, Debug)] struct Net<'a> { /// Index of cell that is outputting into this net (or None, if it's the module input) - connected_output: Option<(usize, &'a str)>, + connected_output: Option>, /// Indicies and names of ports of cells whose inputs are connected to this net - connected_inputs: Vec<(usize, &'a str)>, + connected_inputs: Vec>, } +type ConnectionMap<'a> = HashMap, lw::PegAddress>; + pub fn route(module: Module) -> Result<(Vec, Vec), Error> { let mut net_list: HashMap = HashMap::new(); @@ -37,22 +48,30 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro ); } } - for (i, cell) in module.cells.iter().enumerate() { + for (i_cell, cell) in module.cells.iter().enumerate() { for (key, bits) in &cell.inputs { - for bit in bits { + for (i_bit, bit) in bits.iter().enumerate() { net_list .entry(*bit) .or_insert(Net::default()) .connected_inputs - .push((i, key)); + .push(Connection { + cell_index: i_cell, + port_name: key, + bit_index: 0, + }); } } for (key, bits) in &cell.outputs { - for bit in bits { + for (i_bit, bit) in bits.iter().enumerate() { net_list .entry(*bit) .or_insert(Net::default()) - .connected_output = Some((i, key)); + .connected_output = Some(Connection { + cell_index: i_cell, + port_name: key, + bit_index: 0, + }); } } } @@ -69,7 +88,7 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro let mut input_ports: Vec = vec![]; let mut output_ports: Vec = vec![]; - let mut connection_map: HashMap<(usize, &str), lw::PegAddress> = HashMap::new(); + let mut connection_map: ConnectionMap = HashMap::new(); // the size of squares is 300 units // 150, 150, 150 is the middle of the first square @@ -89,9 +108,9 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro )); } // align back to middle - next_input_position[0] += SQUARE/2; + next_input_position[0] += SQUARE / 2; next_input_position[0] -= next_input_position[0] % SQUARE; - next_input_position[0] += SQUARE/2; + next_input_position[0] += SQUARE / 2; } let mut next_position = vec3_add(origin, [1 * SQUARE, 0, 3 * SQUARE]); @@ -149,9 +168,9 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro )); } // align back to middle - next_output_position[0] += SQUARE/2; + next_output_position[0] += SQUARE / 2; next_output_position[0] -= next_output_position[0] % SQUARE; - next_output_position[0] += SQUARE/2; + next_output_position[0] += SQUARE / 2; } let board = lw::Component { @@ -177,10 +196,14 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro components.extend(output_ports); for (id, net) in &net_list { - println!(); - println!("{}: {:?}", id, net); - println!("map; {:?}", connection_map.keys()); - let output_address = &connection_map[&net.connected_output.unwrap_or((*id, "input"))]; + // println!(); + // println!("{}: {:?}", id, net); + // println!("map; {:?}", connection_map.keys()); + let output_address = &connection_map[&net.connected_output.unwrap_or(Connection { + cell_index: *id, + port_name: "input", + bit_index: 0, // TODO: figure out + })]; for input in &net.connected_inputs { let input_address = &connection_map[input]; wires.push(lw::Wire { @@ -192,7 +215,11 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro } if net.connected_inputs.is_empty() { - let input_address = &connection_map[&(*id, "output")]; + let input_address = &connection_map[&Connection { + cell_index: *id, + port_name: "output", + bit_index: 0, // TODO: figure out + }]; wires.push(lw::Wire { first_point: output_address.clone(), second_point: input_address.clone(), @@ -211,9 +238,8 @@ fn input_port( parent_address: u32, next_address: &mut u32, next_position: &mut Vector3, - connection_map: &mut HashMap<(usize, &str), lw::PegAddress>, + connection_map: &mut ConnectionMap, ) -> Vec { - let label = lw::Component { address: *next_address, parent: parent_address, @@ -237,7 +263,14 @@ fn input_port( outputs: vec![], custom_data: vec![], }; - connection_map.insert((bit_id, "input"), lw::PegAddress::input(peg.address, 0)); + connection_map.insert( + Connection { + cell_index: bit_id, + port_name: "input", + bit_index: 0, + }, + lw::PegAddress::input(peg.address, 0), + ); *next_address += 1; next_position[0] += SQUARE / 3; // third of a square @@ -251,9 +284,8 @@ fn output_port( parent_address: u32, next_address: &mut u32, next_position: &mut Vector3, - connection_map: &mut HashMap<(usize, &str), lw::PegAddress>, + connection_map: &mut ConnectionMap, ) -> Vec { - let label = lw::Component { address: *next_address, parent: parent_address, @@ -277,7 +309,14 @@ fn output_port( outputs: vec![], custom_data: vec![], }; - connection_map.insert((bit_id, "output"), lw::PegAddress::input(peg.address, 0)); + connection_map.insert( + Connection { + cell_index: bit_id, + port_name: "output", + bit_index: 0, + }, + lw::PegAddress::input(peg.address, 0), + ); *next_address += 1; next_position[0] += SQUARE / 3; // third of a square @@ -291,39 +330,78 @@ fn binary_op( parent_address: u32, next_address: &mut u32, next_position: &mut Vector3, - connection_map: &mut HashMap<(usize, &str), lw::PegAddress>, + connection_map: &mut ConnectionMap, ) -> 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![], - }; + // All binary RTL cells have two input ports \A and \B and one output port \Y. They also have the following parameters: - connection_map.insert( - (cell.index, "A"), - lw::PegAddress::input(component.address, 0), - ); - connection_map.insert( - (cell.index, "B"), - lw::PegAddress::input(component.address, 1), - ); - connection_map.insert( - (cell.index, "Y"), - lw::PegAddress::output(component.address, 0), - ); + // 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"); + + // let mut next_parent = parent_address; + + let mut components = vec![]; + + for i in 0..a_width { + let input_a = lw::Input::new(cell.inputs["A"][i] as i32); + let input_b = lw::Input::new(cell.inputs["B"][i] as i32); + let output = lw::Output::new(cell.outputs["Y"][i] as i32); + let component = lw::Component { + address: *next_address, + parent: parent_address, + numeric_id: COMPONENT_MAP[text_id], + position: vec3_add(*next_position, [0, (i as lw::Int) * 2 * SQUARE, 0]), + 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: 0, + }, + lw::PegAddress::input(component.address, 0), + ); + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "B", + bit_index: 0, + }, + lw::PegAddress::input(component.address, 1), + ); + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "Y", + bit_index: 0, + }, + lw::PegAddress::output(component.address, 0), + ); + components.push(component); + } - *next_address += 1; next_position[2] += 3 * SQUARE; - return vec![component]; + return components; } fn unary_op( @@ -332,7 +410,7 @@ fn unary_op( parent_address: u32, next_address: &mut u32, next_position: &mut Vector3, - connection_map: &mut HashMap<(usize, &str), lw::PegAddress>, + 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); @@ -348,11 +426,19 @@ fn unary_op( }; connection_map.insert( - (cell.index, "A"), + Connection { + cell_index: cell.index, + port_name: "A", + bit_index: 0, + }, lw::PegAddress::input(component.address, 0), ); connection_map.insert( - (cell.index, "Y"), + Connection { + cell_index: cell.index, + port_name: "Y", + bit_index: 0, + }, lw::PegAddress::output(component.address, 0), ); @@ -368,7 +454,7 @@ fn or_gate( next_address: &mut u32, next_position: &mut Vector3, wires: &mut Vec, - connection_map: &mut HashMap<(usize, &str), lw::PegAddress>, + connection_map: &mut ConnectionMap, ) -> Vec { 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); @@ -409,14 +495,29 @@ fn or_gate( }; connection_map.insert( - (cell.index, "A"), + Connection { + cell_index: cell.index, + port_name: "A", + bit_index: 0, + }, lw::PegAddress::input(buffer_a.address, 0), ); connection_map.insert( - (cell.index, "B"), + Connection { + cell_index: cell.index, + port_name: "B", + bit_index: 0, + }, lw::PegAddress::input(buffer_b.address, 0), ); - connection_map.insert((cell.index, "Y"), lw::PegAddress::input(peg.address, 0)); + connection_map.insert( + Connection { + cell_index: cell.index, + port_name: "Y", + bit_index: 0, + }, + lw::PegAddress::input(peg.address, 0), + ); wires.push(lw::Wire { first_point: lw::PegAddress::output(buffer_a.address, 0),