diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7f374dc --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "logicworld-subassembly"] + path = logicworld-subassembly + url = git@gitea.d4vid.xyz:D4VID/logicworld-subassembly.git diff --git a/binary_serialize_derive/Cargo.lock b/binary_serialize_derive/Cargo.lock deleted file mode 100644 index 682123d..0000000 --- a/binary_serialize_derive/Cargo.lock +++ /dev/null @@ -1,47 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "binary_serialize_derive" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "proc-macro2" -version = "1.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "syn" -version = "2.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" diff --git a/binary_serialize_derive/Cargo.toml b/binary_serialize_derive/Cargo.toml deleted file mode 100644 index 80d024e..0000000 --- a/binary_serialize_derive/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "binary_serialize_derive" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0.101" -quote = "1.0.40" -syn = { version = "2.0.106", features = ["full"] } diff --git a/binary_serialize_derive/src/lib.rs b/binary_serialize_derive/src/lib.rs deleted file mode 100644 index 57aeadf..0000000 --- a/binary_serialize_derive/src/lib.rs +++ /dev/null @@ -1,36 +0,0 @@ -extern crate proc_macro; - -use proc_macro::TokenStream; -use quote::quote; -use syn::{parse_macro_input, DeriveInput}; - -#[proc_macro_derive(BinarySerializable)] -pub fn derive_binary_serializable(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - - let name = input.ident; - - let fields = match input.data { - syn::Data::Struct(s) => s.fields, - _ => panic!("#[derive(BinarySerializable)] only works on structs"), - }; - - let field_writes = fields.iter().map(|f| { - let ident = f.ident.as_ref().unwrap(); - quote! { - BinarySerializable::write_to(&self.#ident, writer)?; - } - }); - - let expanded = quote! { - impl BinarySerializable for #name { - fn write_to(&self, writer: &mut W) -> std::io::Result<()> { - #(#field_writes)* - return Ok(()); - } - } - }; - - TokenStream::from(expanded) -} - diff --git a/logicworld-subassembly b/logicworld-subassembly new file mode 160000 index 0000000..3ff75d8 --- /dev/null +++ b/logicworld-subassembly @@ -0,0 +1 @@ +Subproject commit 3ff75d8d16e7e676160da21889cce2992ee912b3 diff --git a/verilog2logicworld/Cargo.lock b/verilog2logicworld/Cargo.lock index ddeb0db..8d6a2bf 100644 --- a/verilog2logicworld/Cargo.lock +++ b/verilog2logicworld/Cargo.lock @@ -3,7 +3,7 @@ version = 4 [[package]] -name = "binary_serialize_derive" +name = "binary-serialize-derive" version = "0.1.0" dependencies = [ "proc-macro2", @@ -57,6 +57,12 @@ version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + [[package]] name = "libc" version = "0.2.175" @@ -69,6 +75,16 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +[[package]] +name = "logicworld-subassembly" +version = "0.1.0" +dependencies = [ + "binary-serialize-derive", + "lazy_static", + "quaternion", + "vecmath", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -170,8 +186,8 @@ dependencies = [ name = "verilog2logicworld" version = "0.1.0" dependencies = [ - "binary_serialize_derive", "json", + "logicworld-subassembly", "quaternion", "tempfile", "vecmath", diff --git a/verilog2logicworld/Cargo.toml b/verilog2logicworld/Cargo.toml index 448f44f..afdcd39 100644 --- a/verilog2logicworld/Cargo.toml +++ b/verilog2logicworld/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -binary_serialize_derive = { path = "../binary_serialize_derive" } +logicworld-subassembly = { path = "../logicworld-subassembly/logicworld-subassembly" } json = "0.12.4" quaternion = "2.0.0" tempfile = "3.20.0" diff --git a/verilog2logicworld/src/lw.rs b/verilog2logicworld/src/lw.rs deleted file mode 100644 index 4cec668..0000000 --- a/verilog2logicworld/src/lw.rs +++ /dev/null @@ -1,149 +0,0 @@ -use std::io::{self, Write}; - -use binary_serialize_derive::BinarySerializable; -use quaternion::Quaternion; -use vecmath::Vector3; - -pub trait BinarySerializable { - fn write_to(&self, writer: &mut W) -> io::Result<()>; -} - -#[repr(u8)] -#[derive(Copy, Clone)] -enum PegType { - Input = 1, - Output = 2, -} - -pub type int = i32; -pub type float = f32; -pub type ComponentAddress = u32; - -#[derive(BinarySerializable)] -pub struct Version { - pub major: int, - pub minor: int, - pub build: int, - pub revision: int, -} -impl Version { - pub fn new(major: int, minor: int, build: int, revision: int) -> Self { - Self { - major, - minor, - build, - revision, - } - } -} - -#[derive(BinarySerializable)] -pub struct ModVersion { - pub id: String, - pub version: Version, -} - -#[derive(BinarySerializable)] -pub struct Input { - circuit_state_id: int, -} -#[derive(BinarySerializable)] -pub struct Output { - circuit_state_id: int, -} - -#[derive(BinarySerializable)] -pub struct ComponentIdMap { - pub numeric_id: i16, - pub text_id: String, -} - -#[derive(BinarySerializable)] -pub struct PegAddress { - peg_type: PegType, - component_address: ComponentAddress, - index: int, -} - -#[derive(BinarySerializable)] -pub struct Component { - pub address: ComponentAddress, - pub parent: ComponentAddress, - pub numeric_id: u16, - pub position: Vector3, - pub rotation: Quaternion, - pub inputs: Vec, - pub outputs: Vec, - pub custom_data: Vec, -} - -#[derive(BinarySerializable)] -pub struct Wire { - first_point: PegAddress, - second_point: PegAddress, - circuit_state_id: int, - wire_rotation: float, -} - -impl BinarySerializable for Vec { - fn write_to(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&(self.len() as int).to_le_bytes())?; - for value in self { - value.write_to(writer)?; - } - return Ok(()); - } -} - -impl BinarySerializable for Vec { - fn write_to(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&(self.len() as int).to_le_bytes())?; - writer.write_all(&self)?; - return Ok(()); - } -} - -impl BinarySerializable for PegType { - fn write_to(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&[*self as u8]) - } -} - -impl BinarySerializable for String { - fn write_to(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&(self.len() as int).to_le_bytes())?; - writer.write_all(self.as_bytes())?; - return Ok(()); - } -} - -impl BinarySerializable for Vector3 { - fn write_to(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&self[0].to_le_bytes())?; // x - writer.write_all(&self[1].to_le_bytes())?; // y - writer.write_all(&self[2].to_le_bytes())?; // z - return Ok(()); - } -} - -impl BinarySerializable for Quaternion { - fn write_to(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&self.1[0].to_le_bytes())?; // x - writer.write_all(&self.1[1].to_le_bytes())?; // y - writer.write_all(&self.1[2].to_le_bytes())?; // z - writer.write_all(&self.0.to_le_bytes())?; // w - return Ok(()); - } -} - -macro_rules! impl_binary_num { - ($($t:ty),*) => { - $(impl BinarySerializable for $t { - fn write_to(&self, writer: &mut W) -> std::io::Result<()> { - writer.write_all(&self.to_le_bytes()) - } - })* - }; -} - -impl_binary_num!(i16, u16, i32, u32, f32); diff --git a/verilog2logicworld/src/main.rs b/verilog2logicworld/src/main.rs index 0e75cc4..5969934 100644 --- a/verilog2logicworld/src/main.rs +++ b/verilog2logicworld/src/main.rs @@ -1,104 +1,57 @@ -use std::{ - fs::File, - io::{self, Read}, - process::{Command, Stdio}, -}; - -use subassembly::{ - write_meta_file, write_placements_file, write_placing_info_file, write_subassembly_file, -}; -use tempfile::tempdir; -mod lw; -mod subassembly; - -#[derive(Debug)] -enum Error { - ExitCode(i32), - Terminated, - TempDir, - NoOutput, - Execute, - IO(io::Error), - InvalidJson, -} - -impl From for Error { - fn from(value: io::Error) -> Self { - Self::IO(value) - } -} - -fn run_yosys(yosys_command: &str, module: Option<&str>, files: &[&str]) -> Result<(), Error> { - let tmp = tempdir().map_err(|_| Error::TempDir)?; - let tmp_file_path = tmp.path().join("modules.json"); - - let mut command = Command::new("yosys"); - command.args(["-o", tmp_file_path.to_str().unwrap(), "-p", yosys_command]); - command.args(files); - - if let Some(module) = module { - command.args(["-r", module]); - } - - let result = command - .stdout(Stdio::null()) - .status() - .map_err(|_| Error::Execute)?; - - if let Some(code) = result.code() { - if code != 0 { - return Err(Error::ExitCode(code)); - } - } else { - return Err(Error::Terminated); - } - - let mut file = File::open(tmp_file_path).map_err(|_| Error::NoOutput)?; - let mut file_contents = String::new(); - file.read_to_string(&mut file_contents)?; - - println!("{}", file_contents); - - let object = json::parse(&file_contents).map_err(|_| Error::InvalidJson)?; - - println!("{:?}", object["modules"]); - - return Ok(()); -} - -fn write_subassembly() -> Result<(), Error> { - let mut file = File::create("output/data.partialworld")?; - let components = vec![lw::Component { - address: 1, - parent: 0, - numeric_id: 15, - position: [0, 0, 0], - rotation: quaternion::id(), - inputs: vec![], - outputs: vec![], - custom_data: vec![0x80, 0x00, 0x00, 5, 0, 0, 0, 10, 0, 0, 0], - }]; +mod verilog; + +use std::io; +use std::path::Path; + +use logicworld_subassembly::create_subassembly; +use logicworld_subassembly::lw; +use logicworld_subassembly::COMPONENT_MAP; +use verilog::run_yosys; + +fn write_subassembly() -> io::Result<()> { + let components = vec![ + lw::Component { + address: 1, + parent: 0, + numeric_id: COMPONENT_MAP["MHG.CircuitBoard"], + position: [0, 0, 0], + rotation: quaternion::id(), + inputs: vec![], + outputs: vec![], + custom_data: lw::CircuitBoard::default() + .with_color(0, 100, 50) + .with_size(10, 10) + .custom_data(), + }, + lw::Component { + address: 2, + parent: 1, + numeric_id: COMPONENT_MAP["MHG.AndGate"], + position: [800, 150, 750], + rotation: (0.1, [0.2, 0.4, 0.5]), + inputs: vec![lw::Input::new(1), lw::Input::new(2), lw::Input::new(3)], + outputs: vec![lw::Output::new(4)], + custom_data: vec![], + }, + ]; let wires = vec![]; - write_subassembly_file(&mut file, &components, &wires)?; - - let mut placing_info_file = File::create("output/LastMainPlacingInfo.jecs")?; - write_placing_info_file(&mut placing_info_file)?; - - let mut placements_file = File::create("output/placements.jecs")?; - write_placements_file(&mut placements_file)?; - let mut meta_file = File::create("output/meta.jecs")?; - write_meta_file(&mut meta_file, &"output")?; + create_subassembly( + "test".to_owned(), + &Path::new("output/"), + &components, + &wires, + )?; return Ok(()); } fn main() { - // let result = run_yosys("proc;", None, &["gates.v"]); - // println!("{:?}", result); + let result = run_yosys("proc;", None, &["gates.v"]); + println!("{:?}", result); - // let result = run_yosys("proc; flatten; wreduce; opt; fsm; opt; memory -nomap -nordff; opt; muxpack; peepopt; async2sync; wreduce; opt -mux_bool", Some("$abstract\\gates"), &["gates.v"]); - // println!("{:?}", result); + let result = run_yosys("proc; flatten; wreduce; opt; fsm; opt; memory -nomap -nordff; opt; muxpack; peepopt; async2sync; wreduce; opt -mux_bool", Some("$abstract\\gates"), &["gates.v"]); + println!("{:?}", result); let result = write_subassembly(); println!("{:?}", result); diff --git a/verilog2logicworld/src/subassembly.rs b/verilog2logicworld/src/subassembly.rs deleted file mode 100644 index 080e1e8..0000000 --- a/verilog2logicworld/src/subassembly.rs +++ /dev/null @@ -1,102 +0,0 @@ -use std::{ - i32, - io::{self, Write}, -}; - -use crate::lw::{self, BinarySerializable, ComponentIdMap, ModVersion, Version}; - -enum SaveType { - World = 1, - Subassembly = 2, -} - -pub fn write_subassembly_file( - file: &mut impl Write, - components: &[lw::Component], - wires: &[lw::Wire], -) -> io::Result<()> { - // Header: - file.write_all(b"Logic World save")?; // Magic bytes - file.write_all(&[7 as u8])?; // Version 7 - Version::new(0, 92, 0, 455).write_to(file)?; // Game Version - file.write_all(&[SaveType::Subassembly as u8])?; - - (components.len() as i32).write_to(file)?; - (wires.len() as i32).write_to(file)?; - - // Body: - let mods = vec![ModVersion { - id: "MHG".to_owned(), - version: Version::new(0, 91, 4, -1), - }]; - mods.write_to(file)?; - - let component_id_map = vec![ComponentIdMap { - numeric_id: 15, - text_id: "MHG.CircuitBoard".to_owned(), - }]; - component_id_map.write_to(file)?; - - for component in components { - component.write_to(file)?; - } - - for wire in wires { - wire.write_to(file)?; - } - - 0i32.write_to(file)?; // We don't have any turned on nets - - file.write_all(b"redstone sux lol")?; // Footer - - return Ok(()); -} - -pub fn write_placing_info_file(file: &mut impl Write) -> io::Result<()> { - file.write_all( - b"PlacingInfo: - RaiseOnChangedEvents: true - Flipped: false - RotationAboutUpVector: 180 - Offset: - x: 0 - y: 0 - BoardIsFlat: true - BoardRotationState: 0 -", - ) -} -pub fn write_placements_file(file: &mut impl Write) -> io::Result<()> { - file.write_all( - b"Placements: - - - CornerMidpointPositionBeforeFlipping: - x: 0 - y: 0 - z: 0 - RotationBeforeFlipping: - x: 0 - y: 0 - z: 0 - w: 1 - PlacementType: OnTerrain - Flipped: false - BoardRotationState: 0 - Type: Standard -data_format_version: 1 -", - ) -} - -pub fn write_meta_file(file: &mut impl Write, title: &str) -> io::Result<()> { - file.write_all( - format!( - "Title: {} -Column: null -Category: null -", - title - ) - .as_bytes(), - ) -} diff --git a/verilog2logicworld/src/verilog.rs b/verilog2logicworld/src/verilog.rs new file mode 100644 index 0000000..bf2126a --- /dev/null +++ b/verilog2logicworld/src/verilog.rs @@ -0,0 +1,60 @@ +use std::{ + fs::File, io::{self, Read}, process::{Command, Stdio} +}; + +use tempfile::tempdir; + +#[derive(Debug)] +pub enum Error { + ExitCode(i32), + Terminated, + TempDir, + NoOutput, + Execute, + IO(io::Error), + InvalidJson, +} + +impl From for Error { + fn from(value: io::Error) -> Self { + Self::IO(value) + } +} + +pub fn run_yosys(yosys_command: &str, module: Option<&str>, files: &[&str]) -> Result<(), Error> { + let tmp = tempdir().map_err(|_| Error::TempDir)?; + let tmp_file_path = tmp.path().join("modules.json"); + + let mut command = Command::new("yosys"); + command.args(["-o", tmp_file_path.to_str().unwrap(), "-p", yosys_command]); + command.args(files); + + if let Some(module) = module { + command.args(["-r", module]); + } + + let result = command + .stdout(Stdio::null()) + .status() + .map_err(|_| Error::Execute)?; + + if let Some(code) = result.code() { + if code != 0 { + return Err(Error::ExitCode(code)); + } + } else { + return Err(Error::Terminated); + } + + let mut file = File::open(tmp_file_path).map_err(|_| Error::NoOutput)?; + let mut file_contents = String::new(); + file.read_to_string(&mut file_contents)?; + + println!("{}", file_contents); + + let object = json::parse(&file_contents).map_err(|_| Error::InvalidJson)?; + + println!("{:?}", object["modules"]); + + return Ok(()); +}