use std::collections::BTreeSet;
use std::sync::Once;
use super::{Backend, BackendCircuit};
use crate::gate::Gate;
pub struct RsfqlibVerilog;
static WARN_ONCE: Once = Once::new();
fn warn_timing_ignored() {
WARN_ONCE.call_once(|| {
eprintln!("Warning: timing information is currently not supported and will be ignored.");
});
}
macro_rules! gate_string {
($c:ident, $name:ident, [$($arg:expr),*], $gate:expr) => {
format!("THmitll_{}_v3p0_extracted {} ({});", $gate, $name,
vec![ $($c.get_wire_name($arg), )*].join(", ")
)
};
}
impl Backend for RsfqlibVerilog {
fn generate(&self, circuit: &BackendCircuit<'_>) -> String {
let c = circuit.view();
warn_timing_ignored();
let mut res = Vec::new();
let in_ports: Vec<&str> = c.in_ports();
let out_ports: Vec<&str> = c.out_ports();
let ports: Vec<&str> = c.all_ports();
res.push(format!("module {} ({});", c.name(), ports.join(", ")));
if in_ports.len() > 0 {
res.push(format!("input {};", in_ports.join(", ")));
}
if out_ports.len() > 0 {
res.push(format!("output {};", out_ports.join(", ")));
}
let wires: Vec<&str> = c
.all_wire_names()
.into_iter()
.filter(|s| !ports.contains(s)) .collect::<BTreeSet<&str>>() .into_iter()
.collect();
if wires.len() > 0 {
res.push(format!("wire {};", wires.join(", ")));
}
for gate in c.gates().iter() {
let s = match &gate.value {
Gate::Jtl { name, a, q } => gate_string!(c, name, [*a, *q], "JTL"),
Gate::Split { name, a, q1, q2 } => gate_string!(c, name, [*a, *q1, *q2], "SPLIT"),
Gate::Merge { name, a, b, q } => gate_string!(c, name, [*a, *b, *q], "MERGE"),
Gate::And {
name, a, b, clk, q, ..
} => gate_string!(c, name, [a.id, b.id, clk.id, *q], "AND2"),
Gate::Or {
name, a, b, clk, q, ..
} => gate_string!(c, name, [a.id, b.id, clk.id, *q], "OR2"),
Gate::Xor {
name, a, b, clk, q, ..
} => gate_string!(c, name, [a.id, b.id, clk.id, *q], "XOR"),
Gate::Xnor {
name, a, b, clk, q, ..
} => gate_string!(c, name, [a.id, b.id, clk.id, *q], "XNOR"),
Gate::Not {
name, a, clk, q, ..
} => gate_string!(c, name, [a.id, clk.id, *q], "NOT"),
Gate::Dff {
name, a, clk, q, ..
} => gate_string!(c, name, [a.id, clk.id, *q], "DFF"),
Gate::Ndro {
name, a, b, clk, q, ..
} => gate_string!(c, name, [a.id, b.id, clk.id, *q], "NDRO"),
Gate::Buff { name, a, q } => gate_string!(c, name, [*a, *q], "BUFF"),
Gate::ZeroAsync { name, q } => format!(
"THmitll_ALWAYS0_ASYNC_NOA {} ({});",
name,
c.get_wire_name(*q)
),
Gate::Terminate { name: _, a: _ } => String::new(),
Gate::Subcircuit {
name,
inputs,
outputs,
circuit,
..
} => {
let ports: Vec<&str> = inputs
.iter()
.chain(outputs.iter())
.map(|wid| c.get_wire_name(*wid))
.collect();
format!("{} {} ({});", circuit, name, ports.join(", "))
}
_ => panic!("Unsupported Gate"),
};
res.push(s);
}
res.push("endmodule".to_string());
return res.join("\n");
}
}