diff --git a/logicworld-subassembly b/logicworld-subassembly index 5c4ba46..77ff031 160000 --- a/logicworld-subassembly +++ b/logicworld-subassembly @@ -1 +1 @@ -Subproject commit 5c4ba463240312b81d43ed3e284aabf560d38520 +Subproject commit 77ff0310b431872b4255dc73c53ecddace57b611 diff --git a/verilog2logicworld/src/router.rs b/verilog2logicworld/src/router.rs index 574b6e4..7a186ae 100644 --- a/verilog2logicworld/src/router.rs +++ b/verilog2logicworld/src/router.rs @@ -5,13 +5,15 @@ use vecmath::{vec3_add, Vector3}; use crate::verilog::{Cell, Error, Module}; +const SQUARE: lw::Int = 300; + #[derive(Default, Debug)] -struct Net { +struct Net<'a> { /// Index of cell that is outputting into this net (or None, if it's the module input) - connected_output: Option<(usize, String)>, + connected_output: Option<(usize, &'a str)>, /// Indicies and names of ports of cells whose inputs are connected to this net - connected_inputs: Vec<(usize, String)>, + connected_inputs: Vec<(usize, &'a str)>, } pub fn route(module: Module) -> Result<(Vec, Vec), Error> { @@ -36,17 +38,13 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro } } 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())); + .push((i, key)); } } for (key, bits) in &cell.outputs { @@ -54,7 +52,7 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro net_list .entry(*bit) .or_insert(Net::default()) - .connected_output = Some((i, key.to_owned())); + .connected_output = Some((i, key)); } } } @@ -63,8 +61,87 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro println!("Net {}: {:?}", key, value); } + let board_address = 1; + let mut next_address = board_address + 1; + + let mut wires: Vec = vec![]; + let mut cells: Vec = vec![]; + let mut input_ports: Vec = vec![]; + let mut output_ports: Vec = vec![]; + + let mut connection_map: HashMap<(usize, &str), lw::PegAddress> = HashMap::new(); + + // the size of squares is 300 units + // 150, 150, 150 is the middle of the first square + // first coordinate is down, second up, third to the right + let origin = [SQUARE / 2, SQUARE / 2, SQUARE / 2]; + + let mut next_input_position = origin.clone(); + for input in &module.inputs { + for bit in &input.bits { + input_ports.extend(input_port( + *bit, + &input.name, + board_address, + &mut next_address, + &mut next_input_position, + &mut connection_map, + )); + } + next_input_position[0] += SQUARE; + } + + let mut next_position = vec3_add(origin, [1 * SQUARE, 0, 3 * SQUARE]); + + for (i, cell) in module.cells.iter().enumerate() { + println!("{}: {:?}", i, cell); + let components = match cell.cell_type.as_str() { + "$and" => basic_gate( + cell, + "MHG.AndGate", + board_address, + &mut next_address, + &mut next_position, + &mut connection_map, + ), + "$xor" => basic_gate( + cell, + "MHG.XorGate", + board_address, + &mut next_address, + &mut next_position, + &mut connection_map, + ), + "$or" => or_gate( + cell, + board_address, + &mut next_address, + &mut next_position, + &mut wires, + &mut connection_map, + ), + _ => return Err(Error::UnsupportedCell), + }; + cells.extend(components); + } + + let mut next_output_position = next_position.clone(); + for output in &module.outputs { + for bit in &output.bits { + output_ports.extend(output_port( + *bit, + &output.name, + board_address, + &mut next_address, + &mut next_output_position, + &mut connection_map, + )); + } + next_output_position[0] += SQUARE; + } + let board = lw::Component { - address: 1, + address: board_address, parent: 0, numeric_id: COMPONENT_MAP["MHG.CircuitBoard"], position: [0, 0, 0], @@ -72,60 +149,127 @@ pub fn route(module: Module) -> Result<(Vec, Vec), Erro inputs: vec![], outputs: vec![], custom_data: lw::CircuitBoard::default() - .with_size(5, 10) + .with_size( + next_output_position[0] / SQUARE + 2, + next_output_position[2] / SQUARE + 2, + ) .with_color(100, 25, 25) .custom_data(), }; - let board_address = board.address; + let mut components = vec![board]; + components.extend(input_ports); + components.extend(cells); + 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"))]; + for input in &net.connected_inputs { + let input_address = &connection_map[input]; + wires.push(lw::Wire { + first_point: output_address.clone(), + second_point: input_address.clone(), + circuit_state_id: *id as lw::Int, + wire_rotation: 0.0, + }); + } - let mut next_address = board_address + 1; + if net.connected_inputs.is_empty() { + let input_address = &connection_map[&(*id, "output")]; + wires.push(lw::Wire { + first_point: output_address.clone(), + second_point: input_address.clone(), + circuit_state_id: *id as lw::Int, + wire_rotation: 0.0, + }); + } + } - let mut next_position = [150 + 1 * 300, 150, 150 + 1 * 300]; + return Ok((components, wires)); +} - let mut wires: Vec = vec![]; +fn input_port( + bit_id: usize, + port_name: &str, + parent_address: u32, + next_address: &mut u32, + next_position: &mut Vector3, + connection_map: &mut HashMap<(usize, &str), lw::PegAddress>, +) -> Vec { + let peg = lw::Component { + address: *next_address, + parent: parent_address, + numeric_id: COMPONENT_MAP["MHG.Peg"], + position: *next_position, + rotation: quaternion::id(), + inputs: vec![lw::Input::new(bit_id as lw::Int)], + outputs: vec![], + custom_data: vec![], + }; + connection_map.insert((bit_id, "input"), lw::PegAddress::input(peg.address, 0)); - 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::>(), - ); + *next_address += 1; - return Ok((components, wires)); + let label = lw::Component { + address: *next_address, + parent: parent_address, + numeric_id: COMPONENT_MAP["MHG.PanelLabel"], + position: vec3_add(*next_position, [0, 0, SQUARE]), + rotation: quaternion::euler_angles(0.0, -PI / 2.0, 0.0), + inputs: vec![], + outputs: vec![], + custom_data: lw::Label::new(port_name).with_size(2.0).custom_data(), + }; + + *next_address += 1; + + next_position[0] += SQUARE / 3; // third of a square + + return vec![peg, label]; +} + +fn output_port( + bit_id: usize, + port_name: &str, + parent_address: u32, + next_address: &mut u32, + next_position: &mut Vector3, + connection_map: &mut HashMap<(usize, &str), lw::PegAddress>, +) -> Vec { + let peg = lw::Component { + address: *next_address, + parent: parent_address, + numeric_id: COMPONENT_MAP["MHG.Peg"], + position: vec3_add(*next_position, [0, 0, SQUARE]), + rotation: quaternion::id(), + inputs: vec![lw::Input::new(bit_id as lw::Int)], + outputs: vec![], + custom_data: vec![], + }; + + connection_map.insert((bit_id, "output"), lw::PegAddress::input(peg.address, 0)); + + *next_address += 1; + + let label = lw::Component { + address: *next_address, + parent: parent_address, + numeric_id: COMPONENT_MAP["MHG.PanelLabel"], + position: *next_position, + rotation: quaternion::euler_angles(0.0, -PI / 2.0, 0.0), + inputs: vec![], + outputs: vec![], + custom_data: lw::Label::new(port_name).with_size(2.0).custom_data(), + }; + + *next_address += 1; + + next_position[0] += SQUARE / 3; // third of a square + + return vec![peg, label]; } fn basic_gate( @@ -134,6 +278,7 @@ fn basic_gate( parent_address: u32, next_address: &mut u32, next_position: &mut Vector3, + connection_map: &mut HashMap<(usize, &str), lw::PegAddress>, ) -> 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); @@ -149,8 +294,21 @@ fn basic_gate( custom_data: vec![], }; + 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), + ); + *next_address += 1; - next_position[2] += 3 * 300; + next_position[2] += 3 * SQUARE; return vec![component]; } @@ -159,12 +317,13 @@ fn or_gate( cell: &Cell, parent_address: u32, next_address: &mut u32, - next_position: &mut Vector3, + next_position: &mut Vector3, wires: &mut Vec, + connection_map: &mut HashMap<(usize, &str), lw::PegAddress>, ) -> 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 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_state_id = cell.outputs["Y"][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); @@ -183,7 +342,7 @@ fn or_gate( address: *next_address + 1, parent: parent_address, numeric_id: COMPONENT_MAP["MHG.Buffer_WithOutput"], - position: vec3_add(*next_position, [300, 0, 0]), + position: vec3_add(*next_position, [SQUARE, 0, 0]), rotation: quaternion::id(), inputs: vec![input_b], outputs: vec![output_b], @@ -193,13 +352,23 @@ fn or_gate( address: *next_address + 2, parent: parent_address, numeric_id: COMPONENT_MAP["MHG.Peg"], - position: vec3_add(*next_position, [0, 0, 2 * 300]), + position: vec3_add(*next_position, [0, 0, 2 * SQUARE]), rotation: quaternion::id(), inputs: vec![peg], outputs: vec![], custom_data: vec![], }; + connection_map.insert( + (cell.index, "A"), + lw::PegAddress::input(buffer_a.address, 0), + ); + connection_map.insert( + (cell.index, "B"), + lw::PegAddress::input(buffer_b.address, 0), + ); + connection_map.insert((cell.index, "Y"), 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), @@ -214,7 +383,7 @@ fn or_gate( }); *next_address += 3; - next_position[2] += 5 * 300; + next_position[2] += 5 * SQUARE; return vec![buffer_a, buffer_b, peg]; } diff --git a/verilog2logicworld/src/verilog.rs b/verilog2logicworld/src/verilog.rs index 269bd21..bab3479 100644 --- a/verilog2logicworld/src/verilog.rs +++ b/verilog2logicworld/src/verilog.rs @@ -35,6 +35,7 @@ pub struct Module { #[derive(Debug)] pub struct Cell { + pub index: usize, pub cell_type: String, pub parameters: HashMap, pub inputs: HashMap>, @@ -87,13 +88,14 @@ pub fn compile_module(module_name: &str, files: &[&str]) -> Result>()?; return Ok(module); } -pub fn resolve_cell(cell: &JsonValue) -> Result { +pub fn resolve_cell(index: usize, cell: &JsonValue) -> Result { let json_parameters = &cell["parameters"]; let mut parameters: HashMap = HashMap::new(); @@ -133,6 +135,7 @@ pub fn resolve_cell(cell: &JsonValue) -> Result { let cell_type = cell["type"].as_str().ok_or(Error::BadJson)?.to_owned(); return Ok(Cell { + index, cell_type, parameters, inputs,