diff --git a/calyx-backend/src/verilog.rs b/calyx-backend/src/verilog.rs index dda26a31b4..ac42115ee3 100644 --- a/calyx-backend/src/verilog.rs +++ b/calyx-backend/src/verilog.rs @@ -329,7 +329,7 @@ fn emit_component( if let Some(check) = emit_guard_disjoint_check(dst, asgns, &pool, true) { - writeln!(f, "always_comb begin")?; + writeln!(f, "always_ff @(posedge clk) begin")?; writeln!(f, " {check}")?; writeln!(f, "end")?; } @@ -763,16 +763,17 @@ fn emit_guard( //========================================== /// Generates code of the form: /// ``` -/// string DATA; +/// `define STRINGIFY(x) `"x`" +/// string data = `STRINGIFY(`DATA); /// int CODE; /// initial begin -/// CODE = $value$plusargs("DATA=%s", DATA); -/// $display("DATA: %s", DATA); -/// $readmemh({DATA, "/.dat"}, .mem); +/// CODE = $value$plusargs("data=%s", data); +/// $display("data: %s", data); +/// $readmemh($sformatf("%s/.dat", data), .mem); /// ... /// end /// final begin -/// $writememh({DATA, "/.out"}, .mem); +/// $writememh($sformatf("%s/.out", data), .mem); /// end /// ``` fn memory_read_write(comp: &ir::Component) -> Vec { @@ -805,14 +806,17 @@ fn memory_read_write(comp: &ir::Component) -> Vec { } // Import futil helper library. - let data_decl = v::Stmt::new_rawstr("string DATA;".to_string()); + let stringify_decl = + v::Stmt::new_rawstr("`define STRINGIFY(x) `\"x`\"".to_string()); + let data_decl = + v::Stmt::new_rawstr("string data = `STRINGIFY(`DATA);".to_string()); let code_decl = v::Stmt::new_rawstr("int CODE;".to_string()); let plus_args = v::Sequential::new_blk_assign( v::Expr::Ref("CODE".to_string()), v::Expr::new_call( "$value$plusargs", - vec![v::Expr::new_str("DATA=%s"), v::Expr::new_ref("DATA")], + vec![v::Expr::new_str("data=%s"), v::Expr::new_ref("data")], ), ); @@ -824,8 +828,8 @@ fn memory_read_write(comp: &ir::Component) -> Vec { .add_seq(v::Sequential::new_seqexpr(v::Expr::new_call( "$display", vec![ - v::Expr::new_str("DATA (path to meminit files): %s"), - v::Expr::new_ref("DATA"), + v::Expr::new_str("data (path to meminit files): %s"), + v::Expr::new_ref("data"), ], ))); @@ -834,12 +838,19 @@ fn memory_read_write(comp: &ir::Component) -> Vec { initial_block.add_seq(v::Sequential::new_seqexpr(v::Expr::new_call( "$readmemh", vec![ - v::Expr::Concat(v::ExprConcat { - exprs: vec![ - v::Expr::new_str(&format!("/{}.dat", name)), - v::Expr::new_ref("DATA"), + // v::Expr::Concat(v::ExprConcat { + // exprs: vec![ + // v::Expr::new_str(&format!("/{}.dat", name)), + // v::Expr::new_ref("data"), + // ], + // }) + v::Expr::new_call( + "$sformatf", + vec![ + v::Expr::new_str(&format!("%s/{}.dat", name)), + v::Expr::new_ref("data"), ], - }), + ), v::Expr::new_ipath(&format!("{}.{}", name, mem_access_str)), ], ))); @@ -852,18 +863,26 @@ fn memory_read_write(comp: &ir::Component) -> Vec { final_block.add_seq(v::Sequential::new_seqexpr(v::Expr::new_call( "$writememh", vec![ - v::Expr::Concat(v::ExprConcat { - exprs: vec![ - v::Expr::new_str(&format!("/{}.out", name)), - v::Expr::new_ref("DATA"), + // v::Expr::Concat(v::ExprConcat { + // exprs: vec![ + // v::Expr::new_str(&format!("/{}.out", name)), + // v::Expr::new_ref("data"), + // ], + // }), + v::Expr::new_call( + "$sformatf", + vec![ + v::Expr::new_str(&format!("%s/{}.out", name)), + v::Expr::new_ref("data"), ], - }), + ), v::Expr::new_ipath(&format!("{}.{}", name, mem_access_str)), ], ))); }); vec![ + stringify_decl, data_decl, code_decl, v::Stmt::new_parallel(v::Parallel::new_process(initial_block)), diff --git a/fud2/rsrc/tb.sv b/fud2/rsrc/tb.sv index 79bdd99cd2..6113109e71 100644 --- a/fud2/rsrc/tb.sv +++ b/fud2/rsrc/tb.sv @@ -13,7 +13,7 @@ localparam RESET_CYCLES = 3; // Cycle counter. Make this signed to catch errors with cycle simulation // counts. -logic signed [63:0] cycle_count; +logic signed [63:0] cycle_count = 64'd0; always_ff @(posedge clk) begin cycle_count <= cycle_count + 1; @@ -35,15 +35,15 @@ string OUT; // Disable VCD tracing int NOTRACE; // Maximum number of cycles to simulate -longint CYCLE_LIMIT; +longint cycle_limit = `CYCLE_LIMIT; // Dummy variable to track value returned by $value$plusargs int CODE; initial begin CODE = $value$plusargs("OUT=%s", OUT); - CODE = $value$plusargs("CYCLE_LIMIT=%d", CYCLE_LIMIT); - if (CYCLE_LIMIT != 0) begin - $display("cycle limit set to %d", CYCLE_LIMIT); + CODE = $value$plusargs("cycle_limit=%d", cycle_limit); + if (cycle_limit != 0) begin + $display("cycle limit set to %d", cycle_limit); end CODE = $value$plusargs("NOTRACE=%d", NOTRACE); if (NOTRACE == 0) begin @@ -55,10 +55,7 @@ initial begin end // Initial values - go = 0; clk = 0; - reset = 1; - cycle_count = 0; forever begin #10 clk = ~clk; @@ -67,8 +64,8 @@ initial begin // cycle. $display("Simulated %d cycles", cycle_count - RESET_CYCLES - 1); $finish; - end else if (cycle_count != 0 && cycle_count == CYCLE_LIMIT + RESET_CYCLES) begin - $display("reached limit of %d cycles", CYCLE_LIMIT); + end else if (cycle_count != 0 && cycle_count == cycle_limit + RESET_CYCLES) begin + $display("reached limit of %d cycles", cycle_limit); $finish; end end diff --git a/fud2/rsrc/xsim.tcl b/fud2/rsrc/xsim.tcl new file mode 100644 index 0000000000..d4c85f0f75 --- /dev/null +++ b/fud2/rsrc/xsim.tcl @@ -0,0 +1,87 @@ +proc lshift listVar { + upvar 1 $listVar L + set r [lindex $L 0] + set L [lreplace $L [set L 0] 0] + return $r +} + +#------------------------------------------------------- +# Process command line arguments +#------------------------------------------------------- +set error 0 +set help 0 +set cycle_limit 50000 +set data "" +set verilog {} +set args $argv +# if {[llength $args] == 0} { incr help }; # Uncomment if necessary +while {[llength $args]} { + set flag [lshift args] + switch -exact -- $flag { + -i - + -ip-tcl { + set ip_script [lshift args] + } + -d - + -data { + set data [lshift args] + } + -c - + -cycle-limit { + set cycle_limit [lshift args] + } + -h - + -help { + incr help + } + default { + if {[string match "-*" $flag]} { + puts " ERROR - option '$flag' is not a valid option." + incr error + } else { + lappend verilog $flag + } + } + } +} + +if {$help} { + set callerflag [lindex [info level [expr [info level] -1]] 0] + # <-- HELP + puts [format { + Usage: %s + [-ports|-p ] + [-verbose|-v] + [-help|-h] + + Description: xxxxxxxxxxxxxxxxxxx. + xxxxxxxxxxxxxxxxxxx. + + Example: + %s -port xxxxxxxxxxxxxxx + + } $callerflag $callerflag ] + # HELP --> + return -code ok {} +} + +# Check validity of arguments. Increment $error to generate an error + +if {$error} { + return -code error {Oops, something is not correct} +} + +set dir [pwd] + +create_project -force prj1 +add_files $verilog +if {[info exists ip_script]} { + source $ip_script +} +set_property top toplevel [get_fileset sim_1] +set_property -name {xsim.simulate.runtime} -value {all} -objects [get_filesets sim_1] +puts $cycle_limit +set_property verilog_define [subst {CYCLE_LIMIT=$cycle_limit DATA=$dir/$data}] [get_filesets sim_1] +launch_simulation +close_project +return -code ok {} diff --git a/fud2/scripts/rtl_sim.rhai b/fud2/scripts/rtl_sim.rhai index 0882292d38..1ed93c3de2 100644 --- a/fud2/scripts/rtl_sim.rhai +++ b/fud2/scripts/rtl_sim.rhai @@ -30,7 +30,7 @@ fn sim_setup(e) { // Rule for simulation execution. e.rule( "sim-run", - "./$bin +DATA=$datadir +CYCLE_LIMIT=$cycle-limit $args > $out", + "./$bin $args > $out", ); // More shared configuration. diff --git a/fud2/scripts/verilator.rhai b/fud2/scripts/verilator.rhai index d41cff84ff..5458cd0809 100644 --- a/fud2/scripts/verilator.rhai +++ b/fud2/scripts/verilator.rhai @@ -8,11 +8,11 @@ fn verilator_setup(e) { e.config_var_or("cycle-limit", "sim.cycle_limit", "500000000"); e.rule( "verilator-compile-standalone-tb", - "$verilator $in tb.sv --trace --binary --top-module toplevel -fno-inline -Mdir $out-dir", + "$verilator $in tb.sv -DCYCLE_LIMIT=$cycle-limit -DDATA=$datadir --trace --binary --top-module toplevel -fno-inline -Mdir $out-dir", ); e.rule( "verilator-compile-custom-tb", - "$verilator $in tb.sv memories.sv --trace --binary --top-module toplevel -fno-inline -Mdir $out-dir", + "$verilator $in tb.sv memories.sv -DCYCLE_LIMIT=$cycle-limit -DDATA=$datadir --trace --binary --top-module toplevel -fno-inline -Mdir $out-dir", ); e.rule("cp", "cp $in $out"); } diff --git a/fud2/scripts/xilinx.rhai b/fud2/scripts/xilinx.rhai index 6d625fb2f8..6f005921f2 100644 --- a/fud2/scripts/xilinx.rhai +++ b/fud2/scripts/xilinx.rhai @@ -20,7 +20,7 @@ fn xilinx_setup(e) { ); e.arg("pool", "console"); // Lets Ninja stream the tool output "live." - // Compile an `.xo` file to an `.xclbin` file, which is where the actual EDA work occurs. + // Compile an `.xo` ile to an `.xclbin` file, which is where the actual EDA work occurs. e.config_var_or("xilinx-mode", "xilinx.mode", "hw_emu"); e.config_var_or("platform", "xilinx.device", "xilinx_u50_gen3x16_xdma_201920_3"); e.rule( diff --git a/fud2/scripts/xsim.rhai b/fud2/scripts/xsim.rhai new file mode 100644 index 0000000000..fd0db88c73 --- /dev/null +++ b/fud2/scripts/xsim.rhai @@ -0,0 +1,85 @@ +import "rtl_sim" as sim; +import "testbench" as tb; +import "calyx" as c; + +export const xsim_setup = xsim_setup; +fn xsim_setup(e) { + e.config_var("vivado-dir", "xilinx.vivado"); + e.config_var_or("cycle-limit", "sim.cycle_limit", "500000000"); + e.rsrc("xsim.tcl"); + let has_tcl = !e.config_or("xsim.ip_tcl", "").is_empty(); + if has_tcl { + let tcl_name = e.config_val("xsim.ip_tcl"); + let tcl_path = e.external_path(tcl_name); + e.var_("ip_tcl", tcl_path); + print(tcl_path); + e.rule( + "xsim-standalone-tb", + "$vivado-dir/bin/vivado -mode batch -source xsim.tcl -tclargs -c $cycle-limit -d $datadir -i $ip_tcl tb.sv verilog.sv > $out", + ); + e.rule( + "xsim-custom-tb", + "$vivado-dir/bin/vivado -mode batch -source xsim.tcl -tclargs -c $cycle-limit -d $datadir -i $ip_tcl tb.sv verilog.sv memories.sv > $out", + ); + } else { + e.rule( + "xsim-standalone-tb", + "$vivado-dir/bin/vivado -mode batch -source xsim.tcl -tclargs -c $cycle-limit -d $datadir tb.sv verilog.sv > $out", + ); + e.rule( + "xsim-custom-tb", + "$vivado-dir/bin/vivado -mode batch -source xsim.tcl -tclargs -c $cycle-limit -d $datadir tb.sv verilog.sv memories.sv > $out", + ); + } +} + +export const xsim_build = xsim_build; +fn xsim_build(e, input, output, datadir, standalone_tb) { + if standalone_tb { + e.build_cmd( + [output], + "xsim-standalone-tb", + [input], + ["tb.sv", "xsim.tcl", datadir], + ); + } else { + e.build_cmd( + [output], + "xsim-custom-tb", + [input], + ["tb.sv", "memories.sv", "xsim.tcl", datadir], + ); + } +} + +op( + "xsim", + [sim::sim_setup, tb::standalone_setup, xsim_setup], + c::verilog_state, + sim::dat, + |e, input, output| { + xsim_build(e, input, "sim.log", "$datadir", true); + e.build_cmd( + [output], + "json-data", + ["$datadir", "sim.log"], + ["json-dat.py"], + ); + }, +); + +op( + "xsim-refmem", + [sim::sim_setup, tb::custom_setup, xsim_setup], + tb::verilog_refmem, + sim::dat, + |e, input, output| { + xsim_build(e, input, "sim.log", "$datadir", false); + e.build_cmd( + [output], + "json-data", + ["$datadir", "sim.log"], + ["json-dat.py"], + ); + } +);