use crate::ast::*;
pub struct Emitter { pub output: String }
impl Emitter {
pub fn new() -> Self { Self { output: String::new() } }
pub fn emit_file(&mut self, file: &File) {
self.output.push_str("`timescale 1ns / 1ps\n\n");
for stmt in &file.statements {
match stmt {
Statement::Block(b) => self.emit_block(b),
Statement::Testbench(t) => self.emit_testbench(t),
Statement::Testgroup(g) => self.emit_testgroup(g),
Statement::Piece(p) => self.emit_piece(p),
Statement::Known(_, _) => {},
}
}
}
fn emit_block(&mut self, b: &BlockDef) {
self.output.push_str(&format!("module {}();\n", b.name));
for stmt in &b.body {
match stmt {
BlockStmt::RetAssign(r) => {
let w = r.width.as_ref().map(|x| format!("[{}:{}]", x.msb, x.lsb)).unwrap_or_default();
self.output.push_str(&format!(" assign {} {} = {};\n", w, r.target, r.expr));
}
BlockStmt::PassParams(p) => {
self.output.push_str(&format!(" {} {}({});\n", p.block_type, p.inst_name, p.params.join(", ")));
}
_ => {}
}
}
self.output.push_str("endmodule\n");
}
fn emit_testbench(&mut self, t: &TestbenchDef) {
self.output.push_str(&format!("module tb_{}();\n", t.name));
self.output.push_str(&format!(" {} dut();\n", t.target));
self.output.push_str(" initial begin\n");
for cmd in &t.body {
self.emit_verif_cmd(cmd);
}
self.output.push_str(" end\nendmodule\n");
}
fn emit_verif_cmd(&mut self, cmd: &VerifCmd) {
match cmd {
VerifCmd::Expect { time, lhs, rhs } =>
self.output.push_str(&format!(" #{} assert({} == {});\n", time, lhs, rhs)),
VerifCmd::Pulse { len, gap } =>
self.output.push_str(&format!(" {} = 1; #{} {} = 0; #{} {} = 0;\n", len, len, len, gap, gap)),
VerifCmd::Watchfor { lhs, rhs, time_b, out, .. } => {
let out_sv = match out { OutTarget::Variable(v) => v.clone(), OutTarget::Literal(s) => s.clone() };
self.output.push_str(&format!(" wait({} == {}); #{} ({});\n", lhs, rhs, time_b, out_sv));
}
VerifCmd::Write(w) => self.output.push_str(&format!(" {} = {};\n", w.target, w.val)),
VerifCmd::Put(p) => self.emit_put(p),
VerifCmd::Out { time, target } => {
let t_str = match target { OutTarget::Variable(v) => v.clone(), OutTarget::Literal(s) => s.clone() };
self.output.push_str(&format!(" #{} $display({});\n", time, t_str));
},
VerifCmd::WriteFile { file, .. } => {
self.output.push_str(&format!(" $dumpfile(\"{}\"); $dumpvars;\n", file));
}
}
}
fn emit_put(&mut self, p: &PutStmt) {
self.output.push_str(&format!(" {} {} {};\n", p.target, p.op, p.expr));
}
fn emit_testgroup(&mut self, g: &TestGroupDef) {
self.output.push_str(&format!("module tg_{}();\n", g.name));
self.output.push_str("endmodule\n");
}
fn emit_piece(&mut self, _p: &PieceDef) { }
}