Restructure project

master
D4VID 1 month ago
parent 1579b5d82c
commit 84c3197fac

3
.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "logicworld-subassembly"]
path = logicworld-subassembly
url = git@gitea.d4vid.xyz:D4VID/logicworld-subassembly.git

@ -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"

@ -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"] }

@ -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<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
#(#field_writes)*
return Ok(());
}
}
};
TokenStream::from(expanded)
}

@ -0,0 +1 @@
Subproject commit 3ff75d8d16e7e676160da21889cce2992ee912b3

@ -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",

@ -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"

@ -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<W: Write>(&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<int>,
pub rotation: Quaternion<float>,
pub inputs: Vec<Input>,
pub outputs: Vec<Output>,
pub custom_data: Vec<u8>,
}
#[derive(BinarySerializable)]
pub struct Wire {
first_point: PegAddress,
second_point: PegAddress,
circuit_state_id: int,
wire_rotation: float,
}
impl<T: BinarySerializable> BinarySerializable for Vec<T> {
fn write_to<W: Write>(&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<u8> {
fn write_to<W: Write>(&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<W: Write>(&self, writer: &mut W) -> io::Result<()> {
writer.write_all(&[*self as u8])
}
}
impl BinarySerializable for String {
fn write_to<W: Write>(&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<int> {
fn write_to<W: Write>(&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<float> {
fn write_to<W: Write>(&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<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
writer.write_all(&self.to_le_bytes())
}
})*
};
}
impl_binary_num!(i16, u16, i32, u32, f32);

@ -1,104 +1,57 @@
use std::{
fs::File,
io::{self, Read},
process::{Command, Stdio},
};
mod verilog;
use subassembly::{
write_meta_file, write_placements_file, write_placing_info_file, write_subassembly_file,
};
use tempfile::tempdir;
mod lw;
mod subassembly;
use std::io;
use std::path::Path;
#[derive(Debug)]
enum Error {
ExitCode(i32),
Terminated,
TempDir,
NoOutput,
Execute,
IO(io::Error),
InvalidJson,
}
impl From<io::Error> 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);
}
use logicworld_subassembly::create_subassembly;
use logicworld_subassembly::lw;
use logicworld_subassembly::COMPONENT_MAP;
use verilog::run_yosys;
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 {
fn write_subassembly() -> io::Result<()> {
let components = vec![
lw::Component {
address: 1,
parent: 0,
numeric_id: 15,
numeric_id: COMPONENT_MAP["MHG.CircuitBoard"],
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],
}];
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);

@ -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(),
)
}

@ -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<io::Error> 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(());
}
Loading…
Cancel
Save