diff --git a/verilog2logicworld/src/main.rs b/verilog2logicworld/src/main.rs index 855861e..326680c 100644 --- a/verilog2logicworld/src/main.rs +++ b/verilog2logicworld/src/main.rs @@ -7,7 +7,8 @@ use logicworld_subassembly::create_subassembly; use logicworld_subassembly::lw; use logicworld_subassembly::lw::PegAddress; use logicworld_subassembly::COMPONENT_MAP; -use verilog::run_yosys; +use verilog::compile_module; +use verilog::get_modules; fn write_subassembly() -> io::Result<()> { let components = vec![ @@ -63,12 +64,20 @@ fn write_subassembly() -> io::Result<()> { } fn main() { - let result = run_yosys("proc;", None, &["gates.v"]); + let files = ["gates.v"]; + let result = get_modules(&files); 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 Ok(modules) = result else { + println!("Error while getting modules: {:?}", result); + return; + }; - let result = write_subassembly(); - println!("{:?}", result); + for module in modules { + let result = compile_module(&module, &files); + println!("{}: {:?}", module, result); + } + + // let result = write_subassembly(); + // println!("{:?}", result); } diff --git a/verilog2logicworld/src/verilog.rs b/verilog2logicworld/src/verilog.rs index bf2126a..4f899af 100644 --- a/verilog2logicworld/src/verilog.rs +++ b/verilog2logicworld/src/verilog.rs @@ -1,7 +1,11 @@ use std::{ - fs::File, io::{self, Read}, process::{Command, Stdio} + collections::HashMap, + fs::File, + io::{self, Read}, + process::{Command, Stdio}, }; +use json::JsonValue; use tempfile::tempdir; #[derive(Debug)] @@ -13,6 +17,26 @@ pub enum Error { Execute, IO(io::Error), InvalidJson, + BadJson, + UnsupportedCell, +} + +pub struct Port { + pub name: String, + pub bits: Vec, +} + +#[derive(Default)] +pub struct Module { + inputs: Vec, + outputs: Vec, +} + +#[derive(Debug)] +pub struct Cell<'a> { + pub cell_type: String, + pub parameters: HashMap<&'a str, usize>, + pub connections: HashMap<&'a str, Vec>, } impl From for Error { @@ -21,18 +45,106 @@ impl From for Error { } } -pub fn run_yosys(yosys_command: &str, module: Option<&str>, files: &[&str]) -> Result<(), Error> { +pub fn get_modules(files: &[&str]) -> Result, Error> { + let json = run_yosys("proc;", None, files)?; + // module names in this step have a "$abstract\" prefix + let module_names = json["modules"] + .entries() + .map(|(key, _)| key[10..].to_string()) + .collect(); + return Ok(module_names); +} + +pub fn compile_module(module_name: &str, files: &[&str]) -> Result<(), Error> { + let json = run_yosys("proc; flatten; wreduce; opt; fsm; opt; memory -nomap -nordff; opt; muxpack; peepopt; async2sync; wreduce; opt -mux_bool", Some(module_name), files)?; + let compiled_module = &json["modules"][module_name]; + let ports_json = &compiled_module["ports"]; + + let mut module = Module::default(); + for (name, value) in ports_json.entries() { + let JsonValue::Array(arr) = &value["bits"] else { + return Err(Error::BadJson); + }; + let port = Port { + name: name.to_owned(), + bits: arr + .iter() + .map(|x| x.as_usize().ok_or(Error::BadJson)) + .collect::>()?, + }; + match value["direction"].as_str() { + Some("input") => { + module.inputs.push(port); + } + Some("output") => { + module.outputs.push(port); + } + _ => return Err(Error::BadJson), + } + } + + let cells = &compiled_module["cells"]; + + for (_, cell) in cells.entries() { + let cell = resolve_cell(cell)?; + println!("{:?}", cell); + } + + return Ok(()); +} + +pub fn resolve_cell(cell: &JsonValue) -> Result { + let json_parameters = &cell["parameters"]; + let mut parameters: HashMap<&str, usize> = HashMap::new(); + + for (key, value) in json_parameters.entries() { + parameters.insert( + key, + usize::from_str_radix(value.as_str().ok_or(Error::BadJson)?, 2) + .map_err(|_| Error::BadJson)?, + ); + } + + let json_connections = &cell["connections"]; + let mut connections: HashMap<&str, Vec> = HashMap::new(); + + for (key, bits) in json_connections.entries() { + let JsonValue::Array(arr) = bits else { + return Err(Error::BadJson); + }; + let connection_bits: Vec = arr + .iter() + .map(|x| x.as_usize().ok_or(Error::BadJson)) + .collect::>()?; + connections.insert(key, connection_bits); + } + + let cell_type = cell["type"].as_str().ok_or(Error::BadJson)?.to_owned(); + + return Ok(Cell { + cell_type, + parameters, + connections, + }); +} + +fn run_yosys( + yosys_command: &str, + module: Option<&str>, + files: &[&str], +) -> Result { let tmp = tempdir().map_err(|_| Error::TempDir)?; - let tmp_file_path = tmp.path().join("modules.json"); + let tmp_file_path = tmp.path().join("yosys-output.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]); } + command.args(files); + let result = command .stdout(Stdio::null()) .status() @@ -52,9 +164,7 @@ pub fn run_yosys(yosys_command: &str, module: Option<&str>, files: &[&str]) -> R println!("{}", file_contents); - let object = json::parse(&file_contents).map_err(|_| Error::InvalidJson)?; + let root = json::parse(&file_contents).map_err(|_| Error::InvalidJson)?; - println!("{:?}", object["modules"]); - - return Ok(()); + return Ok(root); }