Compare commits

...

3 Commits

Author SHA1 Message Date
D4VID d66e60c888 Improve inputs and outputs
1 month ago
D4VID af7f1fe19a More outputs
1 month ago
D4VID 0561673fc2 Connecting components
1 month ago

@ -1 +1 @@
Subproject commit 5c4ba463240312b81d43ed3e284aabf560d38520 Subproject commit 77ff0310b431872b4255dc73c53ecddace57b611

@ -1,3 +1,7 @@
module gates(input a, input b, input c, output wire out); module gates(
input a,b,c,d,
output wire out, out2
);
assign out = a & b | c; assign out = a & b | c;
assign out2 = a & b ^ d;
endmodule endmodule

@ -39,7 +39,7 @@ fn main() {
let result = create_subassembly( let result = create_subassembly(
module_name, module_name,
&Path::new("output/"), &Path::new("/mnt/SSD_DATA/Steam/steamapps/common/Logic World/subassemblies"),
&components, &components,
&wires, &wires,
); );

@ -5,13 +5,15 @@ use vecmath::{vec3_add, Vector3};
use crate::verilog::{Cell, Error, Module}; use crate::verilog::{Cell, Error, Module};
const SQUARE: lw::Int = 300;
#[derive(Default, Debug)] #[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) /// 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 /// 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<lw::Component>, Vec<lw::Wire>), Error> { pub fn route(module: Module) -> Result<(Vec<lw::Component>, Vec<lw::Wire>), Error> {
@ -36,17 +38,13 @@ pub fn route(module: Module) -> Result<(Vec<lw::Component>, Vec<lw::Wire>), Erro
} }
} }
for (i, cell) in module.cells.iter().enumerate() { 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 (key, bits) in &cell.inputs {
for bit in bits { for bit in bits {
net_list net_list
.entry(*bit) .entry(*bit)
.or_insert(Net::default()) .or_insert(Net::default())
.connected_inputs .connected_inputs
.push((i, key.to_owned())); .push((i, key));
} }
} }
for (key, bits) in &cell.outputs { for (key, bits) in &cell.outputs {
@ -54,7 +52,7 @@ pub fn route(module: Module) -> Result<(Vec<lw::Component>, Vec<lw::Wire>), Erro
net_list net_list
.entry(*bit) .entry(*bit)
.or_insert(Net::default()) .or_insert(Net::default())
.connected_output = Some((i, key.to_owned())); .connected_output = Some((i, key));
} }
} }
} }
@ -63,8 +61,93 @@ pub fn route(module: Module) -> Result<(Vec<lw::Component>, Vec<lw::Wire>), Erro
println!("Net {}: {:?}", key, value); println!("Net {}: {:?}", key, value);
} }
let board_address = 1;
let mut next_address = board_address + 1;
let mut wires: Vec<lw::Wire> = vec![];
let mut cells: Vec<lw::Component> = vec![];
let mut input_ports: Vec<lw::Component> = vec![];
let mut output_ports: Vec<lw::Component> = 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,
));
}
// align back to middle
next_input_position[0] += SQUARE/2;
next_input_position[0] -= next_input_position[0] % SQUARE;
next_input_position[0] += SQUARE/2;
}
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,
));
}
// align back to middle
next_output_position[0] += SQUARE/2;
next_output_position[0] -= next_output_position[0] % SQUARE;
next_output_position[0] += SQUARE/2;
}
let board = lw::Component { let board = lw::Component {
address: 1, address: board_address,
parent: 0, parent: 0,
numeric_id: COMPONENT_MAP["MHG.CircuitBoard"], numeric_id: COMPONENT_MAP["MHG.CircuitBoard"],
position: [0, 0, 0], position: [0, 0, 0],
@ -72,60 +155,126 @@ pub fn route(module: Module) -> Result<(Vec<lw::Component>, Vec<lw::Wire>), Erro
inputs: vec![], inputs: vec![],
outputs: vec![], outputs: vec![],
custom_data: lw::CircuitBoard::default() 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) .with_color(100, 25, 25)
.custom_data(), .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<lw::Wire> = vec![]; fn input_port(
bit_id: usize,
port_name: &str,
parent_address: u32,
next_address: &mut u32,
next_position: &mut Vector3<lw::Int>,
connection_map: &mut HashMap<(usize, &str), lw::PegAddress>,
) -> Vec<lw::Component> {
let mut components = vec![board]; let label = lw::Component {
components.extend( address: *next_address,
module parent: parent_address,
.cells numeric_id: COMPONENT_MAP["MHG.PanelLabel"],
.iter() position: *next_position,
.map(|cell| { rotation: quaternion::euler_angles(0.0, -PI / 2.0, 0.0),
println!("{:?}", cell); inputs: vec![],
let component = match cell.cell_type.as_str() { outputs: vec![],
"$and" => Ok(basic_gate( custom_data: lw::Label::new(port_name).with_size(2.0).custom_data(),
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::<Result<Vec<Vec<lw::Component>>, Error>>()?
.into_iter()
.flatten()
.collect::<Vec<_>>(),
);
return Ok((components, wires)); *next_address += 1;
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, "input"), lw::PegAddress::input(peg.address, 0));
*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<lw::Int>,
connection_map: &mut HashMap<(usize, &str), lw::PegAddress>,
) -> Vec<lw::Component> {
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;
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, "output"), lw::PegAddress::input(peg.address, 0));
*next_address += 1;
next_position[0] += SQUARE / 3; // third of a square
return vec![peg, label];
} }
fn basic_gate( fn basic_gate(
@ -134,6 +283,7 @@ fn basic_gate(
parent_address: u32, parent_address: u32,
next_address: &mut u32, next_address: &mut u32,
next_position: &mut Vector3<i32>, next_position: &mut Vector3<i32>,
connection_map: &mut HashMap<(usize, &str), lw::PegAddress>,
) -> Vec<lw::Component> { ) -> Vec<lw::Component> {
let input_a = lw::Input::new(cell.inputs["A"][0] as i32); 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 input_b = lw::Input::new(cell.inputs["B"][0] as i32);
@ -149,8 +299,21 @@ fn basic_gate(
custom_data: vec![], 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_address += 1;
next_position[2] += 3 * 300; next_position[2] += 3 * SQUARE;
return vec![component]; return vec![component];
} }
@ -159,12 +322,13 @@ fn or_gate(
cell: &Cell, cell: &Cell,
parent_address: u32, parent_address: u32,
next_address: &mut u32, next_address: &mut u32,
next_position: &mut Vector3<i32>, next_position: &mut Vector3<lw::Int>,
wires: &mut Vec<lw::Wire>, wires: &mut Vec<lw::Wire>,
connection_map: &mut HashMap<(usize, &str), lw::PegAddress>,
) -> Vec<lw::Component> { ) -> Vec<lw::Component> {
let input_a = lw::Input::new(cell.inputs["A"][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 i32); let input_b = lw::Input::new(cell.inputs["B"][0] as lw::Int);
let output_state_id = cell.outputs["Y"][0] as i32; let output_state_id = cell.outputs["Y"][0] as lw::Int;
let output_a = lw::Output::new(output_state_id); let output_a = lw::Output::new(output_state_id);
let output_b = lw::Output::new(output_state_id); let output_b = lw::Output::new(output_state_id);
let peg = lw::Input::new(output_state_id); let peg = lw::Input::new(output_state_id);
@ -183,7 +347,7 @@ fn or_gate(
address: *next_address + 1, address: *next_address + 1,
parent: parent_address, parent: parent_address,
numeric_id: COMPONENT_MAP["MHG.Buffer_WithOutput"], 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(), rotation: quaternion::id(),
inputs: vec![input_b], inputs: vec![input_b],
outputs: vec![output_b], outputs: vec![output_b],
@ -193,13 +357,23 @@ fn or_gate(
address: *next_address + 2, address: *next_address + 2,
parent: parent_address, parent: parent_address,
numeric_id: COMPONENT_MAP["MHG.Peg"], 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(), rotation: quaternion::id(),
inputs: vec![peg], inputs: vec![peg],
outputs: vec![], outputs: vec![],
custom_data: 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 { wires.push(lw::Wire {
first_point: lw::PegAddress::output(buffer_a.address, 0), first_point: lw::PegAddress::output(buffer_a.address, 0),
second_point: lw::PegAddress::input(peg.address, 0), second_point: lw::PegAddress::input(peg.address, 0),
@ -214,7 +388,7 @@ fn or_gate(
}); });
*next_address += 3; *next_address += 3;
next_position[2] += 5 * 300; next_position[2] += 5 * SQUARE;
return vec![buffer_a, buffer_b, peg]; return vec![buffer_a, buffer_b, peg];
} }

@ -35,6 +35,7 @@ pub struct Module {
#[derive(Debug)] #[derive(Debug)]
pub struct Cell { pub struct Cell {
pub index: usize,
pub cell_type: String, pub cell_type: String,
pub parameters: HashMap<String, usize>, pub parameters: HashMap<String, usize>,
pub inputs: HashMap<String, Vec<usize>>, pub inputs: HashMap<String, Vec<usize>>,
@ -87,13 +88,14 @@ pub fn compile_module(module_name: &str, files: &[&str]) -> Result<Module, Error
module.cells = compiled_module["cells"] module.cells = compiled_module["cells"]
.entries() .entries()
.map(|(_, cell)| resolve_cell(cell)) .enumerate()
.map(|(i, (_, cell))| resolve_cell(i, cell))
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
return Ok(module); return Ok(module);
} }
pub fn resolve_cell(cell: &JsonValue) -> Result<Cell, Error> { pub fn resolve_cell(index: usize, cell: &JsonValue) -> Result<Cell, Error> {
let json_parameters = &cell["parameters"]; let json_parameters = &cell["parameters"];
let mut parameters: HashMap<String, usize> = HashMap::new(); let mut parameters: HashMap<String, usize> = HashMap::new();
@ -133,6 +135,7 @@ pub fn resolve_cell(cell: &JsonValue) -> Result<Cell, Error> {
let cell_type = cell["type"].as_str().ok_or(Error::BadJson)?.to_owned(); let cell_type = cell["type"].as_str().ok_or(Error::BadJson)?.to_owned();
return Ok(Cell { return Ok(Cell {
index,
cell_type, cell_type,
parameters, parameters,
inputs, inputs,

Loading…
Cancel
Save