Skip to content

Commit 39ff04b

Browse files
committed
verilog: simple testbench works
1 parent 61b6d78 commit 39ff04b

File tree

1 file changed

+208
-14
lines changed

1 file changed

+208
-14
lines changed

protocols/src/backends/verilog.rs

Lines changed: 208 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22
// released under MIT License
33
// author: Kevin Laeufer <laeufer@cornell.edu>
44

5-
use crate::design::find_designs;
5+
use crate::design::{Design, find_designs};
66
use crate::ir::*;
77
use crate::scheduler::TodoItem;
88
use baa::{BitVecOps, BitVecValue};
9+
use patronus::smt::Error::Parser;
10+
use rustc_hash::FxHashMap;
911

1012
// todo: add `interface` and `module` to protocol language and remove pin argument
1113
pub fn to_verilog(
@@ -23,9 +25,6 @@ pub fn to_verilog(
2325
"Currently we only handle a single modules."
2426
);
2527
let (_, module) = modules.into_iter().next().unwrap();
26-
if !pins.is_empty() {
27-
todo!("deal with extra pins");
28-
}
2928

3029
// derive the instance name from the first protocol
3130
let first_proto_id = *module.transaction_ids.first().unwrap();
@@ -86,23 +85,47 @@ pub fn to_verilog(
8685
)?,
8786
}
8887
}
88+
// extra pins
89+
for (name, anno) in pins {
90+
match anno {
91+
PinAnnotation::Clock => {
92+
writeln!(out, " wire {}_{}; // Clock input", instance_name, name)?;
93+
writeln!(out, " assign {}_{} = clk;", instance_name, name)?;
94+
}
95+
PinAnnotation::Const(value) => {
96+
writeln!(
97+
out,
98+
" wire [{}:0] {}_{}; // Constant input",
99+
value.width() - 1,
100+
instance_name,
101+
name
102+
)?;
103+
writeln!(
104+
out,
105+
" assign {}_{} = 'h{};",
106+
instance_name,
107+
name,
108+
value.to_hex_str()
109+
)?;
110+
}
111+
}
112+
}
89113
writeln!(out, "")?;
90114

91115
// instance
92116
writeln!(out, " // instance of the design under test")?;
93117
writeln!(out, " {} {}(", module.name, instance_name)?;
94-
for (ii, (_, field)) in module.pins.iter().enumerate() {
118+
let pin_names = module
119+
.pins
120+
.iter()
121+
.map(|(_, f)| f.name())
122+
.chain(pins.iter().map(|(n, _)| n.as_str()));
123+
for (ii, name) in pin_names.enumerate() {
95124
let is_first = ii == 0;
96125
if !is_first {
97126
writeln!(out, ",")?;
98127
}
99-
write!(
100-
out,
101-
" .{}({}_{})",
102-
field.name(),
103-
instance_name,
104-
field.name()
105-
)?;
128+
write!(out, " .{}({}_{})", name, instance_name, name)?;
106129
}
107130
writeln!(out, "")?;
108131
writeln!(out, " );")?;
@@ -111,7 +134,8 @@ pub fn to_verilog(
111134
// one task for each protocol
112135
for &proto_id in module.transaction_ids.iter() {
113136
let (proto, st) = &protos[proto_id];
114-
proto_to_verilog(st, proto, out)?;
137+
let sym_verilog = gen_sym_to_verilog_map(st, proto, &module, &instance_name);
138+
proto_to_verilog(st, proto, &sym_verilog, out)?;
115139
}
116140

117141
// the test program
@@ -153,6 +177,7 @@ pub fn to_verilog(
153177
fn proto_to_verilog(
154178
st: &SymbolTable,
155179
proto: &Transaction,
180+
sym_verilog: &FxHashMap<SymbolId, String>,
156181
out: &mut impl std::io::Write,
157182
) -> std::io::Result<()> {
158183
writeln!(out, " // protocol: {}", proto.name)?;
@@ -168,11 +193,180 @@ fn proto_to_verilog(
168193
}
169194
writeln!(out, ");")?;
170195

196+
stmt_to_verilog(st, proto, " ", sym_verilog, out, proto.body)?;
197+
171198
writeln!(out, " endtask; // {}", proto.name)?;
172199
writeln!(out, "")?;
173200
Ok(())
174201
}
175202

203+
fn gen_sym_to_verilog_map(
204+
st: &SymbolTable,
205+
proto: &Transaction,
206+
m: &Design,
207+
instance_name: &str,
208+
) -> FxHashMap<SymbolId, String> {
209+
let mut out = FxHashMap::default();
210+
211+
// transaction arguments are just flat identifiers with no prefixing
212+
for arg in proto.args.iter() {
213+
out.insert(arg.symbol(), st[arg.symbol()].name().to_string());
214+
}
215+
216+
// dut ports get a prefix
217+
for (sym, field) in m.pins.iter() {
218+
out.insert(*sym, format!("{instance_name}_{}", field.name()));
219+
}
220+
221+
out
222+
}
223+
224+
fn stmt_to_verilog(
225+
st: &SymbolTable,
226+
proto: &Transaction,
227+
indent: &str,
228+
sym_verilog: &FxHashMap<SymbolId, String>,
229+
out: &mut impl std::io::Write,
230+
stmt: StmtId,
231+
) -> std::io::Result<()> {
232+
match &proto[stmt] {
233+
Stmt::Block(stmts) => {
234+
for s in stmts {
235+
stmt_to_verilog(st, proto, indent, sym_verilog, out, *s)?;
236+
}
237+
}
238+
Stmt::Assign(lhs, rhs) => {
239+
write!(out, "{indent}")?;
240+
sym_to_verilog(st, sym_verilog, out, lhs)?;
241+
write!(out, " = ")?;
242+
expr_to_verilog(st, proto, sym_verilog, out, *rhs)?;
243+
writeln!(out, ";")?;
244+
}
245+
Stmt::Step => {
246+
writeln!(out, "{indent}#2; // step()")?;
247+
}
248+
Stmt::Fork => {
249+
writeln!(out, "{indent}do_fork = 1; // fork()")?;
250+
}
251+
Stmt::While(_, _) => {
252+
todo!("while loop")
253+
}
254+
Stmt::BoundedLoop(_, _) => {
255+
todo!("repeat loop")
256+
}
257+
Stmt::IfElse(_, _, _) => {
258+
todo!("if/else")
259+
}
260+
Stmt::AssertEq(a, b) => {
261+
assert_eq_to_verilog(st, proto, indent, sym_verilog, out, *a, *b)?;
262+
}
263+
}
264+
Ok(())
265+
}
266+
267+
fn assert_eq_to_verilog(
268+
st: &SymbolTable,
269+
proto: &Transaction,
270+
indent: &str,
271+
sym_verilog: &FxHashMap<SymbolId, String>,
272+
out: &mut impl std::io::Write,
273+
a: ExprId,
274+
b: ExprId,
275+
) -> std::io::Result<()> {
276+
// print out error
277+
write!(out, "{indent}if (")?;
278+
expr_to_verilog(st, proto, sym_verilog, out, a)?;
279+
write!(out, " != ")?;
280+
expr_to_verilog(st, proto, sym_verilog, out, b)?;
281+
writeln!(out, ")")?;
282+
write!(out, "{indent} $display (\"[%0t] {}(", proto.name)?;
283+
for ii in 0..proto.args.len() {
284+
let is_first = ii == 0;
285+
if !is_first {
286+
write!(out, ", 0x%0h")?;
287+
} else {
288+
write!(out, "0x%0h")?;
289+
}
290+
}
291+
write!(out, "): ")?;
292+
expr_to_verilog(st, proto, sym_verilog, out, a)?;
293+
write!(out, "=0x%0h ")?;
294+
expr_to_verilog(st, proto, sym_verilog, out, b)?;
295+
write!(out, "=0x%0h\", $time, ")?;
296+
for arg in proto.args.iter() {
297+
let arg_name = st[arg.symbol()].name();
298+
write!(out, "{arg_name}, ")?;
299+
}
300+
expr_to_verilog(st, proto, sym_verilog, out, a)?;
301+
write!(out, ", ")?;
302+
expr_to_verilog(st, proto, sym_verilog, out, b)?;
303+
writeln!(out, ");")?;
304+
305+
// actual assert
306+
write!(out, "{indent}assert(")?;
307+
expr_to_verilog(st, proto, sym_verilog, out, a)?;
308+
write!(out, " == ")?;
309+
expr_to_verilog(st, proto, sym_verilog, out, b)?;
310+
writeln!(out, ");")?;
311+
312+
Ok(())
313+
}
314+
315+
fn expr_to_verilog(
316+
st: &SymbolTable,
317+
proto: &Transaction,
318+
sym_verilog: &FxHashMap<SymbolId, String>,
319+
out: &mut impl std::io::Write,
320+
e: ExprId,
321+
) -> std::io::Result<()> {
322+
match &proto[e] {
323+
Expr::Const(value) => write!(out, "'h{}", value.to_hex_str()),
324+
Expr::Sym(s) => sym_to_verilog(st, sym_verilog, out, s),
325+
Expr::DontCare => write!(out, "$random"),
326+
Expr::Binary(BinOp::Equal, a, b) => {
327+
write!(out, "(")?;
328+
expr_to_verilog(st, proto, sym_verilog, out, *a)?;
329+
write!(out, " == ")?;
330+
expr_to_verilog(st, proto, sym_verilog, out, *b)?;
331+
write!(out, ")")
332+
}
333+
Expr::Binary(BinOp::Concat, a, b) => {
334+
write!(out, "{{")?;
335+
expr_to_verilog(st, proto, sym_verilog, out, *a)?;
336+
write!(out, ", ")?;
337+
expr_to_verilog(st, proto, sym_verilog, out, *b)?;
338+
write!(out, "}}")
339+
}
340+
Expr::Unary(UnaryOp::Not, e) => {
341+
write!(out, "~")?;
342+
expr_to_verilog(st, proto, sym_verilog, out, *e)
343+
}
344+
Expr::Slice(e, msb, lsb) => {
345+
write!(out, "(")?;
346+
expr_to_verilog(st, proto, sym_verilog, out, *e)?;
347+
if msb == lsb {
348+
write!(out, ")[{msb}]")
349+
} else {
350+
write!(out, ")[{msb}:{lsb}]")
351+
}
352+
}
353+
}
354+
}
355+
356+
fn sym_to_verilog(
357+
st: &SymbolTable,
358+
sym_verilog: &FxHashMap<SymbolId, String>,
359+
out: &mut impl std::io::Write,
360+
s: &SymbolId,
361+
) -> std::io::Result<()> {
362+
debug_assert!(
363+
sym_verilog.contains_key(s),
364+
"Unknown symbol: {} ({s:?})",
365+
st[s].full_name(st)
366+
);
367+
write!(out, "{}", sym_verilog[s])
368+
}
369+
176370
#[derive(Debug, Clone, PartialOrd, PartialEq)]
177371
pub enum PinAnnotation {
178372
Clock,
@@ -224,7 +418,7 @@ pub mod tests {
224418
BitVecValue::from_i64(7, 32),
225419
],
226420
)];
227-
let verilog = backend(&protos, &[], &tx);
421+
let verilog = backend(&protos, &[("clk".to_string(), PinAnnotation::Clock)], &tx);
228422
println!("{verilog}");
229423
todo!("actually assert something!")
230424
}

0 commit comments

Comments
 (0)