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} ;
66use crate :: ir:: * ;
77use crate :: scheduler:: TodoItem ;
88use 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
1113pub 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(
153177fn 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 ) ]
177371pub 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