|
|
@ -1,7 +1,11 @@
|
|
|
|
use std::{
|
|
|
|
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;
|
|
|
|
use tempfile::tempdir;
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Debug)]
|
|
|
@ -13,6 +17,26 @@ pub enum Error {
|
|
|
|
Execute,
|
|
|
|
Execute,
|
|
|
|
IO(io::Error),
|
|
|
|
IO(io::Error),
|
|
|
|
InvalidJson,
|
|
|
|
InvalidJson,
|
|
|
|
|
|
|
|
BadJson,
|
|
|
|
|
|
|
|
UnsupportedCell,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub struct Port {
|
|
|
|
|
|
|
|
pub name: String,
|
|
|
|
|
|
|
|
pub bits: Vec<usize>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Default)]
|
|
|
|
|
|
|
|
pub struct Module {
|
|
|
|
|
|
|
|
inputs: Vec<Port>,
|
|
|
|
|
|
|
|
outputs: Vec<Port>,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
|
|
|
pub struct Cell<'a> {
|
|
|
|
|
|
|
|
pub cell_type: String,
|
|
|
|
|
|
|
|
pub parameters: HashMap<&'a str, usize>,
|
|
|
|
|
|
|
|
pub connections: HashMap<&'a str, Vec<usize>>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl From<io::Error> for Error {
|
|
|
|
impl From<io::Error> for Error {
|
|
|
@ -21,18 +45,106 @@ impl From<io::Error> for Error {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pub fn run_yosys(yosys_command: &str, module: Option<&str>, files: &[&str]) -> Result<(), Error> {
|
|
|
|
pub fn get_modules(files: &[&str]) -> Result<Vec<String>, 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::<Result<_, _>>()?,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
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<Cell, Error> {
|
|
|
|
|
|
|
|
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<usize>> = HashMap::new();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (key, bits) in json_connections.entries() {
|
|
|
|
|
|
|
|
let JsonValue::Array(arr) = bits else {
|
|
|
|
|
|
|
|
return Err(Error::BadJson);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
let connection_bits: Vec<usize> = arr
|
|
|
|
|
|
|
|
.iter()
|
|
|
|
|
|
|
|
.map(|x| x.as_usize().ok_or(Error::BadJson))
|
|
|
|
|
|
|
|
.collect::<Result<_, _>>()?;
|
|
|
|
|
|
|
|
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<JsonValue, Error> {
|
|
|
|
let tmp = tempdir().map_err(|_| Error::TempDir)?;
|
|
|
|
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");
|
|
|
|
let mut command = Command::new("yosys");
|
|
|
|
command.args(["-o", tmp_file_path.to_str().unwrap(), "-p", yosys_command]);
|
|
|
|
command.args(["-o", tmp_file_path.to_str().unwrap(), "-p", yosys_command]);
|
|
|
|
command.args(files);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if let Some(module) = module {
|
|
|
|
if let Some(module) = module {
|
|
|
|
command.args(["-r", module]);
|
|
|
|
command.args(["-r", module]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
command.args(files);
|
|
|
|
|
|
|
|
|
|
|
|
let result = command
|
|
|
|
let result = command
|
|
|
|
.stdout(Stdio::null())
|
|
|
|
.stdout(Stdio::null())
|
|
|
|
.status()
|
|
|
|
.status()
|
|
|
@ -52,9 +164,7 @@ pub fn run_yosys(yosys_command: &str, module: Option<&str>, files: &[&str]) -> R
|
|
|
|
|
|
|
|
|
|
|
|
println!("{}", file_contents);
|
|
|
|
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(root);
|
|
|
|
|
|
|
|
|
|
|
|
return Ok(());
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|