From 868b27ea282d58c1b276310116039106ac7a3ac3 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Mon, 27 Oct 2025 18:05:37 -0400 Subject: [PATCH 1/8] Fixed Guard True branch --- calyx/backend/src/firrtl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/calyx/backend/src/firrtl.rs b/calyx/backend/src/firrtl.rs index dbdcd7f620..d37404dd37 100644 --- a/calyx/backend/src/firrtl.rs +++ b/calyx/backend/src/firrtl.rs @@ -262,7 +262,7 @@ fn get_guard_string(guard: &ir::Guard) -> String { let g_str = get_guard_string(g); format!("not({g_str})") } - ir::Guard::True => String::from(""), + ir::Guard::True => String::from("UInt<1>(1)"), ir::Guard::CompOp(op, l, r) => { let l_str = get_port_string(&l.borrow(), false); let r_str = get_port_string(&r.borrow(), false); From 5bf510729f0e9ed5c68bbfa9a04c438e8dd55eed Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 29 Oct 2025 13:07:43 -0400 Subject: [PATCH 2/8] Added iterate example test --- tests/backend/firrtl/iterate-tutorial.expect | 273 +++++++++++++++++++ tests/backend/firrtl/iterate-tutorial.futil | 84 ++++++ 2 files changed, 357 insertions(+) create mode 100644 tests/backend/firrtl/iterate-tutorial.expect create mode 100644 tests/backend/firrtl/iterate-tutorial.futil diff --git a/tests/backend/firrtl/iterate-tutorial.expect b/tests/backend/firrtl/iterate-tutorial.expect new file mode 100644 index 0000000000..1616f682bb --- /dev/null +++ b/tests/backend/firrtl/iterate-tutorial.expect @@ -0,0 +1,273 @@ +circuit main: + module main: + input go: UInt<1> + input clk: Clock + input reset: UInt<1> + output done: UInt<1> + output mem_addr0: UInt<1> + output mem_write_data: UInt<32> + output mem_write_en: UInt<1> + input mem_read_data: UInt<32> + input mem_done: UInt<1> + done is invalid ; default initialization + done <= UInt(0) + mem_addr0 is invalid ; default initialization + mem_addr0 <= UInt(0) + mem_write_data is invalid ; default initialization + mem_write_data <= UInt(0) + mem_write_en is invalid ; default initialization + mem_write_en <= UInt(0) + ; COMPONENT START: main + inst val of std_reg_32 + inst add of std_add_32 + inst counter of std_reg_32 + inst add2 of std_add_32 + inst lt of std_lt_32 + inst comb_reg of std_reg_1 + inst fsm of std_reg_2 + inst adder of std_add_2 + inst ud0 of undef_1 + inst ud1 of undef_1 + inst signal_reg of std_reg_1 + inst pd of std_reg_1 + inst fsm0 of std_reg_2 + inst pd0 of std_reg_1 + inst fsm1 of std_reg_3 + inst write_go of std_wire_1 + inst write_done of std_wire_1 + inst invoke0_go of std_wire_1 + inst invoke0_done of std_wire_1 + inst invoke2_go of std_wire_1 + inst invoke2_done of std_wire_1 + inst early_reset_static_seq_go of std_wire_1 + inst early_reset_static_seq_done of std_wire_1 + inst early_reset_cond00_go of std_wire_1 + inst early_reset_cond00_done of std_wire_1 + inst wrapper_early_reset_cond00_go of std_wire_1 + inst wrapper_early_reset_cond00_done of std_wire_1 + inst wrapper_early_reset_static_seq_go of std_wire_1 + inst wrapper_early_reset_static_seq_done of std_wire_1 + inst par0_go of std_wire_1 + inst par0_done of std_wire_1 + inst tdcc_go of std_wire_1 + inst tdcc_done of std_wire_1 + inst tdcc0_go of std_wire_1 + inst tdcc0_done of std_wire_1 + early_reset_cond00_go.in is invalid ; default initialization + early_reset_cond00_go.in <= UInt(0) + when wrapper_early_reset_cond00_go.out: + early_reset_cond00_go.in <= UInt(1) + when tdcc0_done.out: + done <= UInt(1) + when or(write_go.out, and(eq(fsm.out, UInt(0)), early_reset_static_seq_go.out)): + mem_addr0 <= UInt(0) + when write_go.out: + mem_write_en <= UInt(1) + when write_go.out: + mem_write_data <= val.out + fsm.write_en is invalid ; default initialization + fsm.write_en <= UInt(0) + when or(and(neq(fsm.out, UInt(1)), early_reset_static_seq_go.out), and(eq(fsm.out, UInt(1)), early_reset_static_seq_go.out)): + fsm.write_en <= UInt(1) + fsm.clk <= clk + fsm.reset <= reset + fsm.in is invalid ; default initialization + fsm.in <= UInt(0) + when and(neq(fsm.out, UInt(1)), early_reset_static_seq_go.out): + fsm.in <= adder.out + when and(eq(fsm.out, UInt(1)), early_reset_static_seq_go.out): + fsm.in <= UInt(0) + adder.left is invalid ; default initialization + adder.left <= UInt(0) + when early_reset_static_seq_go.out: + adder.left <= fsm.out + adder.right is invalid ; default initialization + adder.right <= UInt(0) + when early_reset_static_seq_go.out: + adder.right <= UInt(1) + invoke2_go.in is invalid ; default initialization + invoke2_go.in <= UInt(0) + when and(not(or(pd.out, invoke2_done.out)), par0_go.out): + invoke2_go.in <= UInt(1) + tdcc0_done.in is invalid ; default initialization + tdcc0_done.in <= UInt(0) + when eq(fsm1.out, UInt(4)): + tdcc0_done.in <= UInt(1) + add2.left is invalid ; default initialization + add2.left <= UInt(0) + when invoke2_go.out: + add2.left <= counter.out + add2.right is invalid ; default initialization + add2.right <= UInt(0) + when invoke2_go.out: + add2.right <= UInt(1) + comb_reg.write_en is invalid ; default initialization + comb_reg.write_en <= UInt(0) + when early_reset_cond00_go.out: + comb_reg.write_en <= UInt(1) + comb_reg.clk <= clk + comb_reg.reset <= reset + comb_reg.in is invalid ; default initialization + comb_reg.in <= UInt(0) + when early_reset_cond00_go.out: + comb_reg.in <= lt.out + write_go.in is invalid ; default initialization + write_go.in <= UInt(0) + when and(and(not(write_done.out), eq(fsm0.out, UInt(1))), tdcc_go.out): + write_go.in <= UInt(1) + early_reset_cond00_done.in <= ud1.out + val.write_en is invalid ; default initialization + val.write_en <= UInt(0) + when and(or(eq(fsm.out, UInt(0)), eq(fsm.out, UInt(1))), early_reset_static_seq_go.out): + val.write_en <= UInt(1) + val.clk <= clk + val.reset <= reset + val.in is invalid ; default initialization + val.in <= UInt(0) + when and(eq(fsm.out, UInt(0)), early_reset_static_seq_go.out): + val.in <= mem_read_data + when and(eq(fsm.out, UInt(1)), early_reset_static_seq_go.out): + val.in <= add.out + fsm1.write_en is invalid ; default initialization + fsm1.write_en <= UInt(0) + when or(or(or(or(or(or(eq(fsm1.out, UInt(4)), and(and(eq(fsm1.out, UInt(0)), invoke0_done.out), tdcc0_go.out)), and(and(eq(fsm1.out, UInt(1)), and(wrapper_early_reset_cond00_done.out, comb_reg.out)), tdcc0_go.out)), and(and(eq(fsm1.out, UInt(3)), and(wrapper_early_reset_cond00_done.out, comb_reg.out)), tdcc0_go.out)), and(and(eq(fsm1.out, UInt(2)), par0_done.out), tdcc0_go.out)), and(and(eq(fsm1.out, UInt(1)), and(wrapper_early_reset_cond00_done.out, not(comb_reg.out))), tdcc0_go.out)), and(and(eq(fsm1.out, UInt(3)), and(wrapper_early_reset_cond00_done.out, not(comb_reg.out))), tdcc0_go.out)): + fsm1.write_en <= UInt(1) + fsm1.clk <= clk + fsm1.reset <= reset + fsm1.in is invalid ; default initialization + fsm1.in <= UInt(0) + when or(and(and(eq(fsm1.out, UInt(1)), and(wrapper_early_reset_cond00_done.out, comb_reg.out)), tdcc0_go.out), and(and(eq(fsm1.out, UInt(3)), and(wrapper_early_reset_cond00_done.out, comb_reg.out)), tdcc0_go.out)): + fsm1.in <= UInt(2) + when or(and(and(eq(fsm1.out, UInt(1)), and(wrapper_early_reset_cond00_done.out, not(comb_reg.out))), tdcc0_go.out), and(and(eq(fsm1.out, UInt(3)), and(wrapper_early_reset_cond00_done.out, not(comb_reg.out))), tdcc0_go.out)): + fsm1.in <= UInt(4) + when eq(fsm1.out, UInt(4)): + fsm1.in <= UInt(0) + when and(and(eq(fsm1.out, UInt(0)), invoke0_done.out), tdcc0_go.out): + fsm1.in <= UInt(1) + when and(and(eq(fsm1.out, UInt(2)), par0_done.out), tdcc0_go.out): + fsm1.in <= UInt(3) + counter.write_en is invalid ; default initialization + counter.write_en <= UInt(0) + when or(invoke0_go.out, invoke2_go.out): + counter.write_en <= UInt(1) + counter.clk <= clk + counter.reset <= reset + counter.in is invalid ; default initialization + counter.in <= UInt(0) + when invoke0_go.out: + counter.in <= UInt(0) + when invoke2_go.out: + counter.in <= add2.out + invoke0_go.in is invalid ; default initialization + invoke0_go.in <= UInt(0) + when and(and(not(invoke0_done.out), eq(fsm1.out, UInt(0))), tdcc0_go.out): + invoke0_go.in <= UInt(1) + tdcc_go.in is invalid ; default initialization + tdcc_go.in <= UInt(0) + when and(not(or(pd0.out, tdcc_done.out)), par0_go.out): + tdcc_go.in <= UInt(1) + fsm0.write_en is invalid ; default initialization + fsm0.write_en <= UInt(0) + when or(or(eq(fsm0.out, UInt(2)), and(and(eq(fsm0.out, UInt(0)), wrapper_early_reset_static_seq_done.out), tdcc_go.out)), and(and(eq(fsm0.out, UInt(1)), write_done.out), tdcc_go.out)): + fsm0.write_en <= UInt(1) + fsm0.clk <= clk + fsm0.reset <= reset + fsm0.in is invalid ; default initialization + fsm0.in <= UInt(0) + when and(and(eq(fsm0.out, UInt(0)), wrapper_early_reset_static_seq_done.out), tdcc_go.out): + fsm0.in <= UInt(1) + when eq(fsm0.out, UInt(2)): + fsm0.in <= UInt(0) + when and(and(eq(fsm0.out, UInt(1)), write_done.out), tdcc_go.out): + fsm0.in <= UInt(2) + tdcc0_go.in <= go + write_done.in <= mem_done + wrapper_early_reset_static_seq_done.in is invalid ; default initialization + wrapper_early_reset_static_seq_done.in <= UInt(0) + when signal_reg.out: + wrapper_early_reset_static_seq_done.in <= UInt(1) + par0_done.in is invalid ; default initialization + par0_done.in <= UInt(0) + when and(pd.out, pd0.out): + par0_done.in <= UInt(1) + invoke0_done.in <= counter.done + early_reset_static_seq_go.in is invalid ; default initialization + early_reset_static_seq_go.in <= UInt(0) + when wrapper_early_reset_static_seq_go.out: + early_reset_static_seq_go.in <= UInt(1) + signal_reg.write_en is invalid ; default initialization + signal_reg.write_en <= UInt(0) + when or(or(signal_reg.out, and(and(and(UInt<1>(1), UInt<1>(1)), not(signal_reg.out)), wrapper_early_reset_cond00_go.out)), and(and(and(eq(fsm.out, UInt(1)), UInt<1>(1)), not(signal_reg.out)), wrapper_early_reset_static_seq_go.out)): + signal_reg.write_en <= UInt(1) + signal_reg.clk <= clk + signal_reg.reset <= reset + signal_reg.in is invalid ; default initialization + signal_reg.in <= UInt(0) + when or(and(and(and(UInt<1>(1), UInt<1>(1)), not(signal_reg.out)), wrapper_early_reset_cond00_go.out), and(and(and(eq(fsm.out, UInt(1)), UInt<1>(1)), not(signal_reg.out)), wrapper_early_reset_static_seq_go.out)): + signal_reg.in <= UInt(1) + when signal_reg.out: + signal_reg.in <= UInt(0) + invoke2_done.in <= counter.done + add.left is invalid ; default initialization + add.left <= UInt(0) + when and(eq(fsm.out, UInt(1)), early_reset_static_seq_go.out): + add.left <= val.out + add.right is invalid ; default initialization + add.right <= UInt(0) + when and(eq(fsm.out, UInt(1)), early_reset_static_seq_go.out): + add.right <= UInt(4) + pd.write_en is invalid ; default initialization + pd.write_en <= UInt(0) + when or(and(pd.out, pd0.out), and(invoke2_done.out, par0_go.out)): + pd.write_en <= UInt(1) + pd.clk <= clk + pd.reset <= reset + pd.in is invalid ; default initialization + pd.in <= UInt(0) + when and(invoke2_done.out, par0_go.out): + pd.in <= UInt(1) + when and(pd.out, pd0.out): + pd.in <= UInt(0) + pd0.write_en is invalid ; default initialization + pd0.write_en <= UInt(0) + when or(and(pd.out, pd0.out), and(tdcc_done.out, par0_go.out)): + pd0.write_en <= UInt(1) + pd0.clk <= clk + pd0.reset <= reset + pd0.in is invalid ; default initialization + pd0.in <= UInt(0) + when and(tdcc_done.out, par0_go.out): + pd0.in <= UInt(1) + when and(pd.out, pd0.out): + pd0.in <= UInt(0) + wrapper_early_reset_cond00_go.in is invalid ; default initialization + wrapper_early_reset_cond00_go.in <= UInt(0) + when or(and(and(not(wrapper_early_reset_cond00_done.out), eq(fsm1.out, UInt(1))), tdcc0_go.out), and(and(not(wrapper_early_reset_cond00_done.out), eq(fsm1.out, UInt(3))), tdcc0_go.out)): + wrapper_early_reset_cond00_go.in <= UInt(1) + wrapper_early_reset_cond00_done.in is invalid ; default initialization + wrapper_early_reset_cond00_done.in <= UInt(0) + when signal_reg.out: + wrapper_early_reset_cond00_done.in <= UInt(1) + early_reset_static_seq_done.in <= ud0.out + tdcc_done.in is invalid ; default initialization + tdcc_done.in <= UInt(0) + when eq(fsm0.out, UInt(2)): + tdcc_done.in <= UInt(1) + lt.left is invalid ; default initialization + lt.left <= UInt(0) + when early_reset_cond00_go.out: + lt.left <= counter.out + lt.right is invalid ; default initialization + lt.right <= UInt(0) + when early_reset_cond00_go.out: + lt.right <= UInt(8) + wrapper_early_reset_static_seq_go.in is invalid ; default initialization + wrapper_early_reset_static_seq_go.in <= UInt(0) + when and(and(not(wrapper_early_reset_static_seq_done.out), eq(fsm0.out, UInt(0))), tdcc_go.out): + wrapper_early_reset_static_seq_go.in <= UInt(1) + par0_go.in is invalid ; default initialization + par0_go.in <= UInt(0) + when and(and(not(par0_done.out), eq(fsm1.out, UInt(2))), tdcc0_go.out): + par0_go.in <= UInt(1) + ; COMPONENT END: main + diff --git a/tests/backend/firrtl/iterate-tutorial.futil b/tests/backend/firrtl/iterate-tutorial.futil new file mode 100644 index 0000000000..43d259e7cf --- /dev/null +++ b/tests/backend/firrtl/iterate-tutorial.futil @@ -0,0 +1,84 @@ +// -b firrtl -p external-to-ref -p all +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; + +component main() -> () { + cells { + @external(1) mem = comb_mem_d1(32, 1, 1); + val = std_reg(32); + add = std_add(32); + + // ANCHOR: new_cells + counter = std_reg(32); + add2 = std_add(32); + lt = std_lt(32); + // ANCHOR_END: new_cells + } + + wires { + group read { + mem.addr0 = 1'b0; + val.in = mem.read_data; + val.write_en = 1'b1; + read[done] = val.done; + } + + group upd { + add.left = val.out; + add.right = 32'd4; + val.in = add.out; + val.write_en = 1'b1; + upd[done] = val.done; + } + + group write { + mem.addr0 = 1'b0; + mem.write_en = 1'b1; + mem.write_data = val.out; + write[done] = mem.done; + } + + // ANCHOR: init + group init { + counter.in = 32'd0; + counter.write_en = 1'b1; + init[done] = counter.done; + } + // ANCHOR_END: init + + // ANCHOR: incr + group incr { + add2.left = counter.out; + add2.right = 32'd1; + counter.in = add2.out; + counter.write_en = 1'b1; + incr[done] = counter.done; + } + // ANCHOR_END: incr + + // ANCHOR: cond + comb group cond { + lt.left = counter.out; + lt.right = 32'd8; + } + // ANCHOR_END: cond + } + + // ANCHOR: control + control { + seq { + init; + while lt.out with cond { + par { + seq { + read; + upd; + write; + } + incr; + } + } + } + } + // ANCHOR_END: control +} From ce705351d97b280bb4e084399bb66321a71bb489 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 12 Nov 2025 13:30:40 -0500 Subject: [PATCH 3/8] Added more firrtl tests --- fud2/rsrc/primitives-for-firrtl.sv | 114 ++++++++++++++++++ runt.toml | 7 ++ tests/backend/firrtl/firrtl/adder.expect | 8 ++ tests/backend/firrtl/firrtl/adder.futil | 44 +++++++ tests/backend/firrtl/firrtl/data.json | 10 ++ .../firrtl/language-tutorial-compute.expect | 8 ++ .../firrtl/language-tutorial-compute.futil | 50 ++++++++ .../firrtl/language-tutorial-control.expect | 8 ++ .../firrtl/language-tutorial-control.futil | 25 ++++ .../firrtl/language-tutorial-iterate.expect | 8 ++ .../firrtl/language-tutorial-iterate.futil | 83 +++++++++++++ .../firrtl/language-tutorial-mem.expect | 8 ++ .../firrtl/firrtl/language-tutorial-mem.futil | 19 +++ tests/backend/firrtl/firrtl/multiply.expect | 8 ++ tests/backend/firrtl/firrtl/multiply.futil | 51 ++++++++ 15 files changed, 451 insertions(+) create mode 100644 tests/backend/firrtl/firrtl/adder.expect create mode 100644 tests/backend/firrtl/firrtl/adder.futil create mode 100644 tests/backend/firrtl/firrtl/data.json create mode 100644 tests/backend/firrtl/firrtl/language-tutorial-compute.expect create mode 100644 tests/backend/firrtl/firrtl/language-tutorial-compute.futil create mode 100644 tests/backend/firrtl/firrtl/language-tutorial-control.expect create mode 100644 tests/backend/firrtl/firrtl/language-tutorial-control.futil create mode 100644 tests/backend/firrtl/firrtl/language-tutorial-iterate.expect create mode 100644 tests/backend/firrtl/firrtl/language-tutorial-iterate.futil create mode 100644 tests/backend/firrtl/firrtl/language-tutorial-mem.expect create mode 100644 tests/backend/firrtl/firrtl/language-tutorial-mem.futil create mode 100644 tests/backend/firrtl/firrtl/multiply.expect create mode 100644 tests/backend/firrtl/firrtl/multiply.futil diff --git a/fud2/rsrc/primitives-for-firrtl.sv b/fud2/rsrc/primitives-for-firrtl.sv index 66b296c6c9..94b05c1f96 100644 --- a/fud2/rsrc/primitives-for-firrtl.sv +++ b/fud2/rsrc/primitives-for-firrtl.sv @@ -275,3 +275,117 @@ always_ff @(posedge clk) begin end else done <= 1'd0; end endmodule + +module std_fp_mult_pipe #( + parameter WIDTH = 32, + parameter INT_WIDTH = 16, + parameter FRAC_WIDTH = 16, + parameter SIGNED = 0 +) ( + input logic [WIDTH-1:0] left, + input logic [WIDTH-1:0] right, + input logic go, + input logic clk, + input logic reset, + output logic [WIDTH-1:0] out, + output logic done +); + logic [WIDTH-1:0] rtmp; + logic [WIDTH-1:0] ltmp; + logic [(WIDTH << 1) - 1:0] out_tmp; + // Buffer used to walk through the 3 cycles of the pipeline. + logic done_buf[1:0]; + + assign done = done_buf[1]; + + assign out = out_tmp[(WIDTH << 1) - INT_WIDTH - 1 : WIDTH - INT_WIDTH]; + + // If the done buffer is completely empty and go is high then execution + // just started. + logic start; + assign start = go; + + // Start sending the done signal. + always_ff @(posedge clk) begin + if (start) + done_buf[0] <= 1; + else + done_buf[0] <= 0; + end + + // Push the done signal through the pipeline. + always_ff @(posedge clk) begin + if (go) begin + done_buf[1] <= done_buf[0]; + end else begin + done_buf[1] <= 0; + end + end + + // Register the inputs + always_ff @(posedge clk) begin + if (reset) begin + rtmp <= 0; + ltmp <= 0; + end else if (go) begin + if (SIGNED) begin + rtmp <= $signed(right); + ltmp <= $signed(left); + end else begin + rtmp <= right; + ltmp <= left; + end + end else begin + rtmp <= 0; + ltmp <= 0; + end + + end + + // Compute the output and save it into out_tmp + always_ff @(posedge clk) begin + if (reset) begin + out_tmp <= 0; + end else if (go) begin + if (SIGNED) begin + // In the first cycle, this performs an invalid computation because + // ltmp and rtmp only get their actual values in cycle 1 + out_tmp <= $signed( + { {WIDTH{ltmp[WIDTH-1]}}, ltmp} * + { {WIDTH{rtmp[WIDTH-1]}}, rtmp} + ); + end else begin + out_tmp <= ltmp * rtmp; + end + end else begin + out_tmp <= out_tmp; + end + end +endmodule + +module std_mult_pipe #( + parameter WIDTH = 32 +) ( + input logic [WIDTH-1:0] left, + input logic [WIDTH-1:0] right, + input logic reset, + input logic go, + input logic clk, + output logic [WIDTH-1:0] out, + output logic done +); + std_fp_mult_pipe #( + .WIDTH(WIDTH), + .INT_WIDTH(WIDTH), + .FRAC_WIDTH(0), + .SIGNED(0) + ) comp ( + .reset(reset), + .clk(clk), + .done(done), + .go(go), + .left(left), + .right(right), + .out(out) + ); +endmodule \ No newline at end of file diff --git a/runt.toml b/runt.toml index 0a5c537b63..94cfadba68 100644 --- a/runt.toml +++ b/runt.toml @@ -73,6 +73,13 @@ cmd = """ fud2 {} --from calyx --to yxi """ +[[tests]] +name = "Firrtl Correctness Tests" +paths = ["tests/backend/firrtl/firrtl/*.futil"] +cmd = """ + fud2 {} -q --to dat -s sim.data=tests/backend/firrtl/firrtl/data.json --through firrtl +""" + ##### Frontend Tests ##### [[tests]] name = "[frontend] dahlia" diff --git a/tests/backend/firrtl/firrtl/adder.expect b/tests/backend/firrtl/firrtl/adder.expect new file mode 100644 index 0000000000..682a693cb0 --- /dev/null +++ b/tests/backend/firrtl/firrtl/adder.expect @@ -0,0 +1,8 @@ +{ + "cycles": 4, + "memories": { + "mem": [ + 45 + ] + } +} diff --git a/tests/backend/firrtl/firrtl/adder.futil b/tests/backend/firrtl/firrtl/adder.futil new file mode 100644 index 0000000000..439b15d73c --- /dev/null +++ b/tests/backend/firrtl/firrtl/adder.futil @@ -0,0 +1,44 @@ +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; + +component main(@go go: 1) -> (@done done: 1) { + cells { + @external(1) mem = comb_mem_d1(32, 1, 1); + add_a = std_add(32); + add_b = std_add(32); + result_a = std_reg(32); + result_b = std_reg(32); + } + + wires { + group add_group { + // First adder: 10 + 20 = 30 + add_a.left = 32'd10; + add_a.right = 32'd20; + result_a.in = add_a.out; + result_a.write_en = 1'b1; + + // Second adder: 30 + 15 = 45 + add_b.left = add_a.out; + add_b.right = 32'd15; + result_b.in = add_b.out; + result_b.write_en = 1'b1; + + add_group[done] = result_b.done; + } + + group write { + mem.addr0 = 1'b0; + mem.write_en = 1'b1; + mem.write_data = result_b.out; + write[done] = mem.done; + } + } + + control { + seq { + add_group; + write; + } + } +} diff --git a/tests/backend/firrtl/firrtl/data.json b/tests/backend/firrtl/firrtl/data.json new file mode 100644 index 0000000000..da9bbb4231 --- /dev/null +++ b/tests/backend/firrtl/firrtl/data.json @@ -0,0 +1,10 @@ +{ + "mem": { + "data": [10], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-compute.expect b/tests/backend/firrtl/firrtl/language-tutorial-compute.expect new file mode 100644 index 0000000000..4fefb8b2ff --- /dev/null +++ b/tests/backend/firrtl/firrtl/language-tutorial-compute.expect @@ -0,0 +1,8 @@ +{ + "cycles": 5, + "memories": { + "mem": [ + 14 + ] + } +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-compute.futil b/tests/backend/firrtl/firrtl/language-tutorial-compute.futil new file mode 100644 index 0000000000..b6e12b4740 --- /dev/null +++ b/tests/backend/firrtl/firrtl/language-tutorial-compute.futil @@ -0,0 +1,50 @@ +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; + +component main(@go go: 1) -> (@done done: 1) { + // ANCHOR: cells + cells { + @external(1) mem = comb_mem_d1(32, 1, 1); + val = std_reg(32); + add = std_add(32); + } + // ANCHOR_END: cells + // ANCHOR: wires + wires { + // ANCHOR: write + group write { + mem.addr0 = 1'b0; + mem.write_en = 1'b1; + mem.write_data = val.out; + write[done] = mem.done; + } + // ANCHOR_END: write + // ANCHOR: read + group read { + mem.addr0 = 1'b0; + val.in = mem.read_data; + val.write_en = 1'b1; + read[done] = val.done; + } + // ANCHOR_END: read + // ANCHOR: upd + group upd { + add.left = val.out; + add.right = 32'd4; + val.in = add.out; + val.write_en = 1'b1; + upd[done] = val.done; + } + // ANCHOR_END: upd + } + // ANCHOR_END: wires + // ANCHOR: control + control { + seq { + read; + upd; + write; + } + } + // ANCHOR_END: control +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-control.expect b/tests/backend/firrtl/firrtl/language-tutorial-control.expect new file mode 100644 index 0000000000..d87cad1b8e --- /dev/null +++ b/tests/backend/firrtl/firrtl/language-tutorial-control.expect @@ -0,0 +1,8 @@ +{ + "cycles": 1, + "memories": { + "mem": [ + 42 + ] + } +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-control.futil b/tests/backend/firrtl/firrtl/language-tutorial-control.futil new file mode 100644 index 0000000000..106ebd4c46 --- /dev/null +++ b/tests/backend/firrtl/firrtl/language-tutorial-control.futil @@ -0,0 +1,25 @@ +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; + +component main(@go go: 1) -> (@done done: 1) { + // ANCHOR: cells + cells { + @external(1) mem = comb_mem_d1(32, 1, 1); + } + // ANCHOR_END: cells + // ANCHOR: wires + wires { + group the_answer { + mem.addr0 = 1'b0; + mem.write_data = 32'd42; + mem.write_en = 1'b1; + the_answer[done] = mem.done; + } + } + // ANCHOR_END: wires + // ANCHOR: control + control { + the_answer; + } + // ANCHOR_END: control +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-iterate.expect b/tests/backend/firrtl/firrtl/language-tutorial-iterate.expect new file mode 100644 index 0000000000..6129e85abb --- /dev/null +++ b/tests/backend/firrtl/firrtl/language-tutorial-iterate.expect @@ -0,0 +1,8 @@ +{ + "cycles": 76, + "memories": { + "mem": [ + 42 + ] + } +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-iterate.futil b/tests/backend/firrtl/firrtl/language-tutorial-iterate.futil new file mode 100644 index 0000000000..878bd1473f --- /dev/null +++ b/tests/backend/firrtl/firrtl/language-tutorial-iterate.futil @@ -0,0 +1,83 @@ +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; + +component main() -> () { + cells { + @external(1) mem = comb_mem_d1(32, 1, 1); + val = std_reg(32); + add = std_add(32); + + // ANCHOR: new_cells + counter = std_reg(32); + add2 = std_add(32); + lt = std_lt(32); + // ANCHOR_END: new_cells + } + + wires { + group read { + mem.addr0 = 1'b0; + val.in = mem.read_data; + val.write_en = 1'b1; + read[done] = val.done; + } + + group upd { + add.left = val.out; + add.right = 32'd4; + val.in = add.out; + val.write_en = 1'b1; + upd[done] = val.done; + } + + group write { + mem.addr0 = 1'b0; + mem.write_en = 1'b1; + mem.write_data = val.out; + write[done] = mem.done; + } + + // ANCHOR: init + group init { + counter.in = 32'd0; + counter.write_en = 1'b1; + init[done] = counter.done; + } + // ANCHOR_END: init + + // ANCHOR: incr + group incr { + add2.left = counter.out; + add2.right = 32'd1; + counter.in = add2.out; + counter.write_en = 1'b1; + incr[done] = counter.done; + } + // ANCHOR_END: incr + + // ANCHOR: cond + comb group cond { + lt.left = counter.out; + lt.right = 32'd8; + } + // ANCHOR_END: cond + } + + // ANCHOR: control + control { + seq { + init; + while lt.out with cond { + par { + seq { + read; + upd; + write; + } + incr; + } + } + } + } + // ANCHOR_END: control +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-mem.expect b/tests/backend/firrtl/firrtl/language-tutorial-mem.expect new file mode 100644 index 0000000000..d87cad1b8e --- /dev/null +++ b/tests/backend/firrtl/firrtl/language-tutorial-mem.expect @@ -0,0 +1,8 @@ +{ + "cycles": 1, + "memories": { + "mem": [ + 42 + ] + } +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-mem.futil b/tests/backend/firrtl/firrtl/language-tutorial-mem.futil new file mode 100644 index 0000000000..615ab15d2e --- /dev/null +++ b/tests/backend/firrtl/firrtl/language-tutorial-mem.futil @@ -0,0 +1,19 @@ +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; + +component main(@go go: 1) -> (@done done: 1) { + // ANCHOR: cells + cells { + @external mem = comb_mem_d1(32, 1, 1); + } + // ANCHOR_END: cells + // ANCHOR: wires + wires { + mem.addr0 = 1'b0; + mem.write_data = 32'd42; + mem.write_en = 1'b1; + done = mem.done; + } + // ANCHOR_END: wires + control {} +} diff --git a/tests/backend/firrtl/firrtl/multiply.expect b/tests/backend/firrtl/firrtl/multiply.expect new file mode 100644 index 0000000000..0d5fc3f1bf --- /dev/null +++ b/tests/backend/firrtl/firrtl/multiply.expect @@ -0,0 +1,8 @@ +{ + "cycles": 11, + "memories": { + "mem": [ + 3000 + ] + } +} diff --git a/tests/backend/firrtl/firrtl/multiply.futil b/tests/backend/firrtl/firrtl/multiply.futil new file mode 100644 index 0000000000..f62621fefb --- /dev/null +++ b/tests/backend/firrtl/firrtl/multiply.futil @@ -0,0 +1,51 @@ +import "primitives/core.futil"; +import "primitives/memories/comb.futil"; +import "primitives/binary_operators.futil"; + +component main(@go go: 1) -> (@done done: 1) { + cells { + @external(1) mem = comb_mem_d1(32, 1, 1); + mult_a = std_mult_pipe(32); + mult_b = std_mult_pipe(32); + result_a = std_reg(32); + result_b = std_reg(32); + } + + wires { + group mult_1 { + // First multiply: 10 * 20 = 200 + mult_a.left = 32'd10; + mult_a.right = 32'd20; + mult_a.go = 1'b1; + result_a.in = mult_a.out; + result_a.write_en = mult_a.done; + mult_1[done] = result_a.done; + } + + group mult_2 { + // Second multiply: 200 * 15 = 3000 + mult_b.left = mult_a.out; + mult_b.right = 32'd15; + mult_b.go = 1'b1; + result_b.in = mult_b.out; + result_b.write_en = mult_b.done; + + mult_2[done] = result_b.done; + } + + group write { + mem.addr0 = 1'b0; + mem.write_en = 1'b1; + mem.write_data = result_b.out; + write[done] = mem.done; + } + } + + control { + seq { + mult_1; + mult_2; + write; + } + } +} \ No newline at end of file From 5002216720e3ab8a28117dc6a424a14acc445b95 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Sun, 16 Nov 2025 23:18:23 -0500 Subject: [PATCH 4/8] Work in progress: matrix_multiply program integrated where test suite is currently failing --- runt.toml | 4 +- .../{backend/firrtl => }/firrtl/adder.expect | 0 tests/{backend/firrtl => }/firrtl/adder.futil | 0 .../data.json => firrtl/adder.futil.data} | 0 .../firrtl/language-tutorial-compute.expect | 0 .../firrtl/language-tutorial-compute.futil | 0 .../language-tutorial-compute.futil.data | 10 + .../firrtl/language-tutorial-control.expect | 0 .../firrtl/language-tutorial-control.futil | 0 .../language-tutorial-control.futil.data | 10 + .../firrtl/language-tutorial-iterate.expect | 0 .../firrtl/language-tutorial-iterate.futil | 0 .../language-tutorial-iterate.futil.data | 10 + .../firrtl/language-tutorial-mem.expect | 0 .../firrtl/language-tutorial-mem.futil | 0 tests/firrtl/language-tutorial-mem.futil.data | 10 + tests/firrtl/matrix_multiply.expect | 83 +++++++ tests/firrtl/matrix_multiply.futil | 218 ++++++++++++++++++ tests/firrtl/matrix_multiply.futil.data | 26 +++ .../firrtl => }/firrtl/multiply.expect | 0 .../firrtl => }/firrtl/multiply.futil | 0 tests/firrtl/multiply.futil.data | 10 + 22 files changed, 379 insertions(+), 2 deletions(-) rename tests/{backend/firrtl => }/firrtl/adder.expect (100%) rename tests/{backend/firrtl => }/firrtl/adder.futil (100%) rename tests/{backend/firrtl/firrtl/data.json => firrtl/adder.futil.data} (100%) rename tests/{backend/firrtl => }/firrtl/language-tutorial-compute.expect (100%) rename tests/{backend/firrtl => }/firrtl/language-tutorial-compute.futil (100%) create mode 100644 tests/firrtl/language-tutorial-compute.futil.data rename tests/{backend/firrtl => }/firrtl/language-tutorial-control.expect (100%) rename tests/{backend/firrtl => }/firrtl/language-tutorial-control.futil (100%) create mode 100644 tests/firrtl/language-tutorial-control.futil.data rename tests/{backend/firrtl => }/firrtl/language-tutorial-iterate.expect (100%) rename tests/{backend/firrtl => }/firrtl/language-tutorial-iterate.futil (100%) create mode 100644 tests/firrtl/language-tutorial-iterate.futil.data rename tests/{backend/firrtl => }/firrtl/language-tutorial-mem.expect (100%) rename tests/{backend/firrtl => }/firrtl/language-tutorial-mem.futil (100%) create mode 100644 tests/firrtl/language-tutorial-mem.futil.data create mode 100644 tests/firrtl/matrix_multiply.expect create mode 100644 tests/firrtl/matrix_multiply.futil create mode 100644 tests/firrtl/matrix_multiply.futil.data rename tests/{backend/firrtl => }/firrtl/multiply.expect (100%) rename tests/{backend/firrtl => }/firrtl/multiply.futil (100%) create mode 100644 tests/firrtl/multiply.futil.data diff --git a/runt.toml b/runt.toml index 94cfadba68..38a65b78ff 100644 --- a/runt.toml +++ b/runt.toml @@ -75,9 +75,9 @@ fud2 {} --from calyx --to yxi [[tests]] name = "Firrtl Correctness Tests" -paths = ["tests/backend/firrtl/firrtl/*.futil"] +paths = ["tests/firrtl/*.futil"] cmd = """ - fud2 {} -q --to dat -s sim.data=tests/backend/firrtl/firrtl/data.json --through firrtl + fud2 {} -q --to dat -s sim.data={}.data --through firrtl """ ##### Frontend Tests ##### diff --git a/tests/backend/firrtl/firrtl/adder.expect b/tests/firrtl/adder.expect similarity index 100% rename from tests/backend/firrtl/firrtl/adder.expect rename to tests/firrtl/adder.expect diff --git a/tests/backend/firrtl/firrtl/adder.futil b/tests/firrtl/adder.futil similarity index 100% rename from tests/backend/firrtl/firrtl/adder.futil rename to tests/firrtl/adder.futil diff --git a/tests/backend/firrtl/firrtl/data.json b/tests/firrtl/adder.futil.data similarity index 100% rename from tests/backend/firrtl/firrtl/data.json rename to tests/firrtl/adder.futil.data diff --git a/tests/backend/firrtl/firrtl/language-tutorial-compute.expect b/tests/firrtl/language-tutorial-compute.expect similarity index 100% rename from tests/backend/firrtl/firrtl/language-tutorial-compute.expect rename to tests/firrtl/language-tutorial-compute.expect diff --git a/tests/backend/firrtl/firrtl/language-tutorial-compute.futil b/tests/firrtl/language-tutorial-compute.futil similarity index 100% rename from tests/backend/firrtl/firrtl/language-tutorial-compute.futil rename to tests/firrtl/language-tutorial-compute.futil diff --git a/tests/firrtl/language-tutorial-compute.futil.data b/tests/firrtl/language-tutorial-compute.futil.data new file mode 100644 index 0000000000..da9bbb4231 --- /dev/null +++ b/tests/firrtl/language-tutorial-compute.futil.data @@ -0,0 +1,10 @@ +{ + "mem": { + "data": [10], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-control.expect b/tests/firrtl/language-tutorial-control.expect similarity index 100% rename from tests/backend/firrtl/firrtl/language-tutorial-control.expect rename to tests/firrtl/language-tutorial-control.expect diff --git a/tests/backend/firrtl/firrtl/language-tutorial-control.futil b/tests/firrtl/language-tutorial-control.futil similarity index 100% rename from tests/backend/firrtl/firrtl/language-tutorial-control.futil rename to tests/firrtl/language-tutorial-control.futil diff --git a/tests/firrtl/language-tutorial-control.futil.data b/tests/firrtl/language-tutorial-control.futil.data new file mode 100644 index 0000000000..da9bbb4231 --- /dev/null +++ b/tests/firrtl/language-tutorial-control.futil.data @@ -0,0 +1,10 @@ +{ + "mem": { + "data": [10], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-iterate.expect b/tests/firrtl/language-tutorial-iterate.expect similarity index 100% rename from tests/backend/firrtl/firrtl/language-tutorial-iterate.expect rename to tests/firrtl/language-tutorial-iterate.expect diff --git a/tests/backend/firrtl/firrtl/language-tutorial-iterate.futil b/tests/firrtl/language-tutorial-iterate.futil similarity index 100% rename from tests/backend/firrtl/firrtl/language-tutorial-iterate.futil rename to tests/firrtl/language-tutorial-iterate.futil diff --git a/tests/firrtl/language-tutorial-iterate.futil.data b/tests/firrtl/language-tutorial-iterate.futil.data new file mode 100644 index 0000000000..da9bbb4231 --- /dev/null +++ b/tests/firrtl/language-tutorial-iterate.futil.data @@ -0,0 +1,10 @@ +{ + "mem": { + "data": [10], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} diff --git a/tests/backend/firrtl/firrtl/language-tutorial-mem.expect b/tests/firrtl/language-tutorial-mem.expect similarity index 100% rename from tests/backend/firrtl/firrtl/language-tutorial-mem.expect rename to tests/firrtl/language-tutorial-mem.expect diff --git a/tests/backend/firrtl/firrtl/language-tutorial-mem.futil b/tests/firrtl/language-tutorial-mem.futil similarity index 100% rename from tests/backend/firrtl/firrtl/language-tutorial-mem.futil rename to tests/firrtl/language-tutorial-mem.futil diff --git a/tests/firrtl/language-tutorial-mem.futil.data b/tests/firrtl/language-tutorial-mem.futil.data new file mode 100644 index 0000000000..da9bbb4231 --- /dev/null +++ b/tests/firrtl/language-tutorial-mem.futil.data @@ -0,0 +1,10 @@ +{ + "mem": { + "data": [10], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} diff --git a/tests/firrtl/matrix_multiply.expect b/tests/firrtl/matrix_multiply.expect new file mode 100644 index 0000000000..524baa10f5 --- /dev/null +++ b/tests/firrtl/matrix_multiply.expect @@ -0,0 +1,83 @@ +{ + "cycles": 1141, + "memories": { + "arr_1": [ + [ + 5, + 3, + 2, + 6 + ], + [ + 4, + 9, + 2, + 1 + ], + [ + 3, + 7, + 2, + 6 + ], + [ + 6, + 1, + 4, + 2 + ] + ], + "arr_2": [ + [ + 8, + 3, + 7, + 2 + ], + [ + 9, + 8, + 4, + 5 + ], + [ + 3, + 6, + 1, + 2 + ], + [ + 5, + 6, + 9, + 2 + ] + ], + "mem_output": [ + [ + 103, + 87, + 103, + 41 + ], + [ + 124, + 102, + 75, + 59 + ], + [ + 123, + 113, + 105, + 57 + ], + [ + 79, + 62, + 68, + 29 + ] + ] + } +} \ No newline at end of file diff --git a/tests/firrtl/matrix_multiply.futil b/tests/firrtl/matrix_multiply.futil new file mode 100644 index 0000000000..d7955df877 --- /dev/null +++ b/tests/firrtl/matrix_multiply.futil @@ -0,0 +1,218 @@ +import "primitives/core.futil"; +import "primitives/memories/seq.futil"; +import "primitives/binary_operators.futil"; + +// Modified from pass-in-register.futil +component multiply_and_add() -> () { + cells { + ref acc = std_reg(32); + ref loaded_val_a = std_reg(32); + ref loaded_val_b = std_reg(32); + add = std_add(32); + mult = std_mult_pipe(32); + result = std_reg(32); + } + wires { + group do_mul { + mult.left = loaded_val_a.out; + mult.right = loaded_val_b.out; + mult.go = 1'd1; + result.in = mult.out; + result.write_en = mult.done; + do_mul[done] = result.done; + } + + group do_add { + acc.write_en = 1'd1; + + add.left = acc.out; + add.right = result.out; + acc.in = add.out; + do_add[done] = acc.done; + } + } + control { + seq { + do_mul; + do_add; + } + } +} + +component main() -> () { + cells { + // 4×4 matrix memories + @external arr_1 = seq_mem_d2(32, 4, 4, 4, 4); + @external arr_2 = seq_mem_d2(32, 4, 4, 4, 4); + @external mem_output = seq_mem_d2(32, 4, 4, 4, 4); + + // Constants + const0 = std_const(32,3); + const1 = std_const(32,0); + const2 = std_const(32,1); + + // Registers + i = std_reg(32); + j = std_reg(32); + k = std_reg(32); + acc = std_reg(32); + val_a = std_reg(32); + val_b = std_reg(32); + + // Multiply-and-accumulate unit + mul_add = multiply_and_add(); + + // Comparators + le0 = std_le(32); + le1 = std_le(32); + le2 = std_le(32); + + // Adder + add = std_add(32); + + // Bit Slicer + slice0 = std_slice(32, 4); + slice1 = std_slice(32, 4); + slice2 = std_slice(32, 4); + } + + wires { + // Loop Conditions + comb group cond0 { + le0.left = i.out; + le0.right = const0.out; + } + comb group cond1 { + le1.left = j.out; + le1.right = const0.out; + } + comb group cond2 { + le2.left = k.out; + le2.right = const0.out; + } + + // Loop Initialization + group let0<"promotable"=1> { + i.in = const1.out; + i.write_en = 1'd1; + let0[done] = i.done; + } + group let1<"promotable"=1> { + j.in = const1.out; + j.write_en = 1'd1; + let1[done] = j.done; + } + group let2<"promotable"=1> { + k.in = const1.out; + k.write_en = 1'd1; + let2[done] = k.done; + } + + // Accumulator Reset + group begin_acc { + acc.in = const1.out; + acc.write_en = 1'd1; + begin_acc[done] = acc.done; + } + + group read_data { + slice0.in = i.out; + slice1.in = k.out; + slice2.in = j.out; + arr_1.addr0 = slice0.out; + arr_1.addr1 = slice1.out; + arr_1.content_en = 1'd1; + + arr_2.addr0 = slice1.out; + arr_2.addr1 = slice2.out; + arr_2.content_en = 1'd1; + + val_a.in = arr_1.read_data; + val_a.write_en = arr_1.done ? 1'd1; + val_b.in = arr_2.read_data; + val_b.write_en = arr_2.done ? 1'd1; + read_data[done] = val_b.done; + } + + // Writing results + group write_result { + slice0.in = i.out; + slice1.in = j.out; + mem_output.addr0 = slice0.out; + mem_output.addr1 = slice1.out; + mem_output.content_en = 1'd1; + mem_output.write_data = acc.out; + mem_output.write_en = 1'd1; + write_result[done] = mem_output.done; + } + + // Loop Increment + group upd_i<"promotable"=1> { + add.left = i.out; + add.right = const2.out; + i.in = add.out; + i.write_en = 1'd1; + upd_i[done] = i.done; + } + group upd_j<"promotable"=1> { + add.left = j.out; + add.right = const2.out; + j.in = add.out; + j.write_en = 1'd1; + upd_j[done] = j.done; + } + group upd_k<"promotable"=1> { + add.left = k.out; + add.right = const2.out; + k.in = add.out; + k.write_en = 1'd1; + upd_k[done] = k.done; + } + group reset_i { + i.in = const1.out; + i.write_en = 1'd1; + reset_i[done] = i.done; + } + group reset_j { + j.in = const1.out; + j.write_en = 1'd1; + reset_j[done] = j.done; + } + group reset_k { + k.in = const1.out; + k.write_en = 1'd1; + reset_k[done] = k.done; + } + } + + control { + seq { + // i, j, k initialization + let0; + let1; + let2; + reset_i; + while le0.out with cond0 { + seq { + reset_j; + while le1.out with cond1 { + seq { + reset_k; + begin_acc; + while le2.out with cond2 { + seq { + read_data; + invoke mul_add[acc=acc, loaded_val_a=val_a, loaded_val_b=val_b]()(); + upd_k; + } + } + write_result; + upd_j; + } + } + upd_i; + } + } + } + } +} \ No newline at end of file diff --git a/tests/firrtl/matrix_multiply.futil.data b/tests/firrtl/matrix_multiply.futil.data new file mode 100644 index 0000000000..0599fee1f4 --- /dev/null +++ b/tests/firrtl/matrix_multiply.futil.data @@ -0,0 +1,26 @@ +{ + "arr_1": { + "data": [ [5, 3, 2, 6], [4, 9, 2, 1], [3, 7, 2, 6], [6, 1, 4, 2] ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + }, + "arr_2": { + "data": [ [8, 3, 7, 2], [9, 8, 4, 5], [3, 6, 1, 2], [5, 6, 9, 2] ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + }, + "mem_output": { + "data": [ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0] ], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} \ No newline at end of file diff --git a/tests/backend/firrtl/firrtl/multiply.expect b/tests/firrtl/multiply.expect similarity index 100% rename from tests/backend/firrtl/firrtl/multiply.expect rename to tests/firrtl/multiply.expect diff --git a/tests/backend/firrtl/firrtl/multiply.futil b/tests/firrtl/multiply.futil similarity index 100% rename from tests/backend/firrtl/firrtl/multiply.futil rename to tests/firrtl/multiply.futil diff --git a/tests/firrtl/multiply.futil.data b/tests/firrtl/multiply.futil.data new file mode 100644 index 0000000000..da9bbb4231 --- /dev/null +++ b/tests/firrtl/multiply.futil.data @@ -0,0 +1,10 @@ +{ + "mem": { + "data": [10], + "format": { + "numeric_type": "bitnum", + "is_signed": false, + "width": 32 + } + } +} From b7050bcea1de7d2d8529d04c205b908ffd6e5be9 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 19 Nov 2025 13:35:30 -0500 Subject: [PATCH 5/8] Debugged testbench bug --- fud2/rsrc/memories.sv | 260 +++++++++++++++++++++++----- tests/firrtl/matrix_multiply.expect | 4 +- tests/firrtl/matrix_multiply.futil | 10 +- tools/firrtl/generate-testbench.py | 23 +-- 4 files changed, 232 insertions(+), 65 deletions(-) diff --git a/fud2/rsrc/memories.sv b/fud2/rsrc/memories.sv index e9257ae494..4d38062243 100644 --- a/fud2/rsrc/memories.sv +++ b/fud2/rsrc/memories.sv @@ -5,14 +5,14 @@ module comb_mem_d1 #( ) ( input wire logic [IDX_SIZE-1:0] addr0, input wire logic [ WIDTH-1:0] write_data, - output logic [ WIDTH-1:0] read_data, input wire logic write_en, input wire logic clk, input wire logic reset, + output logic [ WIDTH-1:0] read_data, output logic done ); - logic [WIDTH-1:0] mem[SIZE-1:0]; + logic [WIDTH-1:0] mem[SIZE-1:0]; /* verilator lint_off WIDTH */ assign read_data = mem[addr0]; @@ -235,15 +235,22 @@ module comb_mem_d4 #( end `endif endmodule - /** Implements a memory with sequential reads and writes. -- Both reads and writes take one cycle to perform. +- Both reads and writes are not guaranteed to have a given latency. - Attempting to read and write at the same time is an error. - The out signal is registered to the last value requested by the read_en signal. - The out signal is undefined once write_en is asserted. + +NOTE(nate): In practice we expect this implementation to be single cycle, +but should not be relied on as such. +In particular we probably eventually want to have `dyn_mems` exist as "virtual operators." +Which have a flexible latency, where the compiler can decide upon actual latency. + +See #2111 (PR introducing this: https://github.com/calyxir/calyx/pull/2111) +and a more in depth discussion #1151 (https://github.com/calyxir/calyx/issues/1151) */ -module seq_mem_d1 #( +module dyn_mem_d1 #( parameter WIDTH = 32, parameter SIZE = 16, parameter IDX_SIZE = 4 @@ -252,19 +259,18 @@ module seq_mem_d1 #( input wire logic clk, input wire logic reset, input wire logic [IDX_SIZE-1:0] addr0, + input wire logic content_en, + output logic done, // Read signal - input wire logic read_en, output logic [ WIDTH-1:0] read_data, - output logic read_done, // Write signals input wire logic [ WIDTH-1:0] write_data, - input wire logic write_en, - output logic write_done + input wire logic write_en ); // Internal memory - (* ram_style = "ultra" *) logic [WIDTH-1:0] mem[SIZE-1:0]; + logic [WIDTH-1:0] mem[SIZE-1:0]; // Register for the read output logic [WIDTH-1:0] read_out; @@ -274,10 +280,10 @@ module seq_mem_d1 #( always_ff @(posedge clk) begin if (reset) begin read_out <= '0; - end else if (read_en) begin + end else if (content_en && !write_en) begin /* verilator lint_off WIDTH */ read_out <= mem[addr0]; - end else if (write_en) begin + end else if (content_en && write_en) begin // Explicitly clobber the read output when a write is performed read_out <= 'x; end else begin @@ -285,38 +291,207 @@ module seq_mem_d1 #( end end - // Propagate the read_done signal + // Propagate the done signal always_ff @(posedge clk) begin if (reset) begin - read_done <= '0; - end else if (read_en) begin - read_done <= '1; + done <= '0; + end else if (content_en) begin + done <= '1; end else begin - read_done <= '0; + done <= '0; end end // Write value to the memory always_ff @(posedge clk) begin - if (!reset && write_en) + if (!reset && content_en && write_en) mem[addr0] <= write_data; end - // Propagate the write_done signal + // Check for out of bounds access + `ifdef VERILATOR + always_comb begin + if (content_en && !write_en) + if (addr0 >= SIZE) + $error( + "comb_mem_d1: Out of bounds access\n", + "addr0: %0d\n", addr0, + "SIZE: %0d", SIZE + ); + end + `endif +endmodule + +module dyn_mem_d2 #( + parameter WIDTH = 32, + parameter D0_SIZE = 16, + parameter D1_SIZE = 16, + parameter D0_IDX_SIZE = 4, + parameter D1_IDX_SIZE = 4 +) ( + // Common signals + input wire logic clk, + input wire logic reset, + input wire logic [D0_IDX_SIZE-1:0] addr0, + input wire logic [D1_IDX_SIZE-1:0] addr1, + input wire logic content_en, + output logic done, + + // Read signal + output logic [WIDTH-1:0] read_data, + + // Write signals + input wire logic write_en, + input wire logic [ WIDTH-1:0] write_data +); + wire [D0_IDX_SIZE+D1_IDX_SIZE-1:0] addr; + assign addr = addr0 * D1_SIZE + addr1; + + dyn_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE)) mem + (.clk(clk), .reset(reset), .addr0(addr), + .content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en), + .done(done)); +endmodule + +module dyn_mem_d3 #( + parameter WIDTH = 32, + parameter D0_SIZE = 16, + parameter D1_SIZE = 16, + parameter D2_SIZE = 16, + parameter D0_IDX_SIZE = 4, + parameter D1_IDX_SIZE = 4, + parameter D2_IDX_SIZE = 4 +) ( + // Common signals + input wire logic clk, + input wire logic reset, + input wire logic [D0_IDX_SIZE-1:0] addr0, + input wire logic [D1_IDX_SIZE-1:0] addr1, + input wire logic [D2_IDX_SIZE-1:0] addr2, + input wire logic content_en, + output logic done, + + // Read signal + output logic [WIDTH-1:0] read_data, + + // Write signals + input wire logic write_en, + input wire logic [ WIDTH-1:0] write_data +); + wire [D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE-1:0] addr; + assign addr = addr0 * (D1_SIZE * D2_SIZE) + addr1 * (D2_SIZE) + addr2; + + dyn_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE * D2_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE)) mem + (.clk(clk), .reset(reset), .addr0(addr), + .content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en), + .done(done)); +endmodule + +module dyn_mem_d4 #( + parameter WIDTH = 32, + parameter D0_SIZE = 16, + parameter D1_SIZE = 16, + parameter D2_SIZE = 16, + parameter D3_SIZE = 16, + parameter D0_IDX_SIZE = 4, + parameter D1_IDX_SIZE = 4, + parameter D2_IDX_SIZE = 4, + parameter D3_IDX_SIZE = 4 +) ( + // Common signals + input wire logic clk, + input wire logic reset, + input wire logic [D0_IDX_SIZE-1:0] addr0, + input wire logic [D1_IDX_SIZE-1:0] addr1, + input wire logic [D2_IDX_SIZE-1:0] addr2, + input wire logic [D3_IDX_SIZE-1:0] addr3, + input wire logic content_en, + output logic done, + + // Read signal + output logic [WIDTH-1:0] read_data, + + // Write signals + input wire logic write_en, + input wire logic [ WIDTH-1:0] write_data +); + wire [D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE+D3_IDX_SIZE-1:0] addr; + assign addr = addr0 * (D1_SIZE * D2_SIZE * D3_SIZE) + addr1 * (D2_SIZE * D3_SIZE) + addr2 * (D3_SIZE) + addr3; + + dyn_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE * D2_SIZE * D3_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE+D3_IDX_SIZE)) mem + (.clk(clk), .reset(reset), .addr0(addr), + .content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en), + .done(done)); +endmodule +/** +Implements a memory with sequential reads and writes. +- Both reads and writes take one cycle to perform. +- Attempting to read and write at the same time is an error. +- The out signal is registered to the last value requested by the read_en signal. +- The out signal is undefined once write_en is asserted. +*/ +module seq_mem_d1 #( + parameter WIDTH = 32, + parameter SIZE = 16, + parameter IDX_SIZE = 4 +) ( + // Common signals + input wire logic clk, + input wire logic reset, + input wire logic [IDX_SIZE-1:0] addr0, + input wire logic content_en, + output logic done, + + // Read signal + output logic [ WIDTH-1:0] read_data, + + // Write signals + input wire logic [ WIDTH-1:0] write_data, + input wire logic write_en +); + // Internal memory + logic [WIDTH-1:0] mem[SIZE-1:0]; + + // Register for the read output + logic [WIDTH-1:0] read_out; + assign read_data = read_out; + + // Read value from the memory + always_ff @(posedge clk) begin + if (reset) begin + read_out <= '0; + end else if (content_en && !write_en) begin + /* verilator lint_off WIDTH */ + read_out <= mem[addr0]; + end else if (content_en && write_en) begin + // Explicitly clobber the read output when a write is performed + read_out <= 'x; + end else begin + read_out <= read_out; + end + end + + // Propagate the done signal always_ff @(posedge clk) begin if (reset) begin - write_done <= '0; - end else if (write_en) begin - write_done <= 1'd1; + done <= '0; + end else if (content_en) begin + done <= '1; end else begin - write_done <= '0; + done <= '0; end end + // Write value to the memory + always_ff @(posedge clk) begin + if (!reset && content_en && write_en) + mem[addr0] <= write_data; + end + // Check for out of bounds access `ifdef VERILATOR always_comb begin - if (read_en) + if (content_en && !write_en) if (addr0 >= SIZE) $error( "comb_mem_d1: Out of bounds access\n", @@ -324,10 +499,6 @@ module seq_mem_d1 #( "SIZE: %0d", SIZE ); end - always_comb begin - if (read_en && write_en) - $error("Simultaneous read and write attempted\n"); - end `endif endmodule @@ -343,24 +514,23 @@ module seq_mem_d2 #( input wire logic reset, input wire logic [D0_IDX_SIZE-1:0] addr0, input wire logic [D1_IDX_SIZE-1:0] addr1, + input wire logic content_en, + output logic done, // Read signal - input wire logic read_en, output logic [WIDTH-1:0] read_data, - output logic read_done, // Write signals input wire logic write_en, - input wire logic [ WIDTH-1:0] write_data, - output logic write_done + input wire logic [ WIDTH-1:0] write_data ); wire [D0_IDX_SIZE+D1_IDX_SIZE-1:0] addr; assign addr = addr0 * D1_SIZE + addr1; seq_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE)) mem (.clk(clk), .reset(reset), .addr0(addr), - .read_en(read_en), .read_data(read_data), .read_done(read_done), .write_data(write_data), .write_en(write_en), - .write_done(write_done)); + .content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en), + .done(done)); endmodule module seq_mem_d3 #( @@ -378,24 +548,23 @@ module seq_mem_d3 #( input wire logic [D0_IDX_SIZE-1:0] addr0, input wire logic [D1_IDX_SIZE-1:0] addr1, input wire logic [D2_IDX_SIZE-1:0] addr2, + input wire logic content_en, + output logic done, // Read signal - input wire logic read_en, output logic [WIDTH-1:0] read_data, - output logic read_done, // Write signals input wire logic write_en, - input wire logic [ WIDTH-1:0] write_data, - output logic write_done + input wire logic [ WIDTH-1:0] write_data ); wire [D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE-1:0] addr; assign addr = addr0 * (D1_SIZE * D2_SIZE) + addr1 * (D2_SIZE) + addr2; seq_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE * D2_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE)) mem (.clk(clk), .reset(reset), .addr0(addr), - .read_en(read_en), .read_data(read_data), .read_done(read_done), .write_data(write_data), .write_en(write_en), - .write_done(write_done)); + .content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en), + .done(done)); endmodule module seq_mem_d4 #( @@ -416,22 +585,21 @@ module seq_mem_d4 #( input wire logic [D1_IDX_SIZE-1:0] addr1, input wire logic [D2_IDX_SIZE-1:0] addr2, input wire logic [D3_IDX_SIZE-1:0] addr3, + input wire logic content_en, + output logic done, // Read signal - input wire logic read_en, output logic [WIDTH-1:0] read_data, - output logic read_done, // Write signals input wire logic write_en, - input wire logic [ WIDTH-1:0] write_data, - output logic write_done + input wire logic [ WIDTH-1:0] write_data ); wire [D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE+D3_IDX_SIZE-1:0] addr; assign addr = addr0 * (D1_SIZE * D2_SIZE * D3_SIZE) + addr1 * (D2_SIZE * D3_SIZE) + addr2 * (D3_SIZE) + addr3; seq_mem_d1 #(.WIDTH(WIDTH), .SIZE(D0_SIZE * D1_SIZE * D2_SIZE * D3_SIZE), .IDX_SIZE(D0_IDX_SIZE+D1_IDX_SIZE+D2_IDX_SIZE+D3_IDX_SIZE)) mem (.clk(clk), .reset(reset), .addr0(addr), - .read_en(read_en), .read_data(read_data), .read_done(read_done), .write_data(write_data), .write_en(write_en), - .write_done(write_done)); + .content_en(content_en), .read_data(read_data), .write_data(write_data), .write_en(write_en), + .done(done)); endmodule diff --git a/tests/firrtl/matrix_multiply.expect b/tests/firrtl/matrix_multiply.expect index 524baa10f5..e2aa8ef950 100644 --- a/tests/firrtl/matrix_multiply.expect +++ b/tests/firrtl/matrix_multiply.expect @@ -1,5 +1,5 @@ { - "cycles": 1141, + "cycles": 1157, "memories": { "arr_1": [ [ @@ -80,4 +80,4 @@ ] ] } -} \ No newline at end of file +} diff --git a/tests/firrtl/matrix_multiply.futil b/tests/firrtl/matrix_multiply.futil index d7955df877..1767fc2d4c 100644 --- a/tests/firrtl/matrix_multiply.futil +++ b/tests/firrtl/matrix_multiply.futil @@ -3,19 +3,17 @@ import "primitives/memories/seq.futil"; import "primitives/binary_operators.futil"; // Modified from pass-in-register.futil -component multiply_and_add() -> () { +component multiply_and_add(loaded_val_a: 32, loaded_val_b: 32) -> () { cells { ref acc = std_reg(32); - ref loaded_val_a = std_reg(32); - ref loaded_val_b = std_reg(32); add = std_add(32); mult = std_mult_pipe(32); result = std_reg(32); } wires { group do_mul { - mult.left = loaded_val_a.out; - mult.right = loaded_val_b.out; + mult.left = loaded_val_a; + mult.right = loaded_val_b; mult.go = 1'd1; result.in = mult.out; result.write_en = mult.done; @@ -202,7 +200,7 @@ component main() -> () { while le2.out with cond2 { seq { read_data; - invoke mul_add[acc=acc, loaded_val_a=val_a, loaded_val_b=val_b]()(); + invoke mul_add[acc=acc](loaded_val_a = val_a.out, loaded_val_b = val_b.out)(); upd_k; } } diff --git a/tools/firrtl/generate-testbench.py b/tools/firrtl/generate-testbench.py index 8e26217263..83798f9cc8 100644 --- a/tools/firrtl/generate-testbench.py +++ b/tools/firrtl/generate-testbench.py @@ -1,5 +1,6 @@ # Writes a custom testbench to stdout based on memories used in the Calyx program. -# Input: YXI_JSON - JSON generated by the YXI backend containing information about memories used +# Input: YXI_JSON - JSON generated by the YXI backend containing information +# about memories used import json import os @@ -33,9 +34,10 @@ def generate_fields(memory_cell_dicts): if "comb" in module_name: out_str += f"wire {name}_done;\n\n" else: # seq has more ports. - out_str += f"""wire {name}_read_en; + out_str += f"""wire {name}_content_en; + wire {name}_write_done; -wire {name}_read_done;\n\n""" +wire {name}_done;\n\n""" return out_str @@ -69,9 +71,8 @@ def generate_memory_dec(memory_cell_dicts): if "comb" in module_name: out_str += f" .done({name}_done)\n" else: - out_str += f""" .read_en({name}_read_en), - .read_done({name}_read_done), - .write_done({name}_write_done) + out_str += f""" .content_en({name}_content_en), + .done({name}_done) """ out_str += ");\n\n" return out_str @@ -83,8 +84,9 @@ def generate_main_decl(memory_cell_dicts): .clk(clk), .reset(reset), .done(done)""" - # Documentation: Need to connect to the wires we initialized above (ex. {name}_addr0) - # and not the ports of the memory (ex. {name},addr0) because verilator would error + # Documentation: Need to connect to the wires we initialized above + # (ex. {name}_addr0) and not the ports of the memory + # (ex. {name},addr0) because verilator would error # out due to some of the memory ports being input ports. for memory_cell_dict in memory_cell_dicts: name = memory_cell_dict["cell-name"] @@ -100,9 +102,8 @@ def generate_main_decl(memory_cell_dicts): if "comb" in module_name: out_str += f" .{name}_done({name}_done)" else: - out_str += f""" .{name}_read_en({name}_read_en), - .{name}_write_done({name}_write_done), - .{name}_read_done({name}_read_done)""" + out_str += f""" .{name}_content_en({name}_content_en), + .{name}_done({name}_done)""" out_str += "\n);" return out_str From c354310c893db12d4fff363937bf2846b73f2914 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Wed, 3 Dec 2025 00:45:33 -0500 Subject: [PATCH 6/8] Adding firtool to docker file --- Dockerfile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index fcf9d644f0..f7f52e1927 100644 --- a/Dockerfile +++ b/Dockerfile @@ -60,7 +60,7 @@ RUN uv pip install antlr4-python3-runtime==4.7.2 . # Install Dahlia WORKDIR /home -RUN git clone https://github.com/cucapra/dahlia.git +RUN git clone https://github.com/cucapra/dahlia.git WORKDIR /home/dahlia ## Checkout specific version. Fetch before checkout because clone might be cached. RUN git fetch --all && git checkout 9ec9a58 @@ -104,5 +104,11 @@ RUN uv pip install ./frontends/mrxl # stacktrace-walking magic that dictates source position generation. RUN uv pip install ./calyx-py +# Install Firtool +WORKDIR /home +RUN curl -L https://github.com/llvm/circt/releases/download/firtool-1.75.0/firrtl-bin-linux-x64.tar.gz | tar -xz \ + && chmod +x /home/firtool-1.75.0/bin/firtool \ + && printf "[firrtl]\nfirtool = \"/home/firtool-1.75.0/bin/firtool\"\n" >> ~/.config/fud2.toml + # Used to make runt cocotb tests happy ENV LANG=C.UTF-8 From 84b317eb230c5f1d4dddc787a56f21bccf72118a Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Sun, 7 Dec 2025 14:40:32 -0500 Subject: [PATCH 7/8] Removed redundant tests --- tests/firrtl/language-tutorial-compute.expect | 8 --- tests/firrtl/language-tutorial-compute.futil | 50 ------------------- .../language-tutorial-compute.futil.data | 10 ---- tests/firrtl/language-tutorial-control.expect | 8 --- tests/firrtl/language-tutorial-control.futil | 25 ---------- .../language-tutorial-control.futil.data | 10 ---- tests/firrtl/language-tutorial-mem.expect | 8 --- tests/firrtl/language-tutorial-mem.futil | 19 ------- tests/firrtl/language-tutorial-mem.futil.data | 10 ---- 9 files changed, 148 deletions(-) delete mode 100644 tests/firrtl/language-tutorial-compute.expect delete mode 100644 tests/firrtl/language-tutorial-compute.futil delete mode 100644 tests/firrtl/language-tutorial-compute.futil.data delete mode 100644 tests/firrtl/language-tutorial-control.expect delete mode 100644 tests/firrtl/language-tutorial-control.futil delete mode 100644 tests/firrtl/language-tutorial-control.futil.data delete mode 100644 tests/firrtl/language-tutorial-mem.expect delete mode 100644 tests/firrtl/language-tutorial-mem.futil delete mode 100644 tests/firrtl/language-tutorial-mem.futil.data diff --git a/tests/firrtl/language-tutorial-compute.expect b/tests/firrtl/language-tutorial-compute.expect deleted file mode 100644 index 4fefb8b2ff..0000000000 --- a/tests/firrtl/language-tutorial-compute.expect +++ /dev/null @@ -1,8 +0,0 @@ -{ - "cycles": 5, - "memories": { - "mem": [ - 14 - ] - } -} diff --git a/tests/firrtl/language-tutorial-compute.futil b/tests/firrtl/language-tutorial-compute.futil deleted file mode 100644 index b6e12b4740..0000000000 --- a/tests/firrtl/language-tutorial-compute.futil +++ /dev/null @@ -1,50 +0,0 @@ -import "primitives/core.futil"; -import "primitives/memories/comb.futil"; - -component main(@go go: 1) -> (@done done: 1) { - // ANCHOR: cells - cells { - @external(1) mem = comb_mem_d1(32, 1, 1); - val = std_reg(32); - add = std_add(32); - } - // ANCHOR_END: cells - // ANCHOR: wires - wires { - // ANCHOR: write - group write { - mem.addr0 = 1'b0; - mem.write_en = 1'b1; - mem.write_data = val.out; - write[done] = mem.done; - } - // ANCHOR_END: write - // ANCHOR: read - group read { - mem.addr0 = 1'b0; - val.in = mem.read_data; - val.write_en = 1'b1; - read[done] = val.done; - } - // ANCHOR_END: read - // ANCHOR: upd - group upd { - add.left = val.out; - add.right = 32'd4; - val.in = add.out; - val.write_en = 1'b1; - upd[done] = val.done; - } - // ANCHOR_END: upd - } - // ANCHOR_END: wires - // ANCHOR: control - control { - seq { - read; - upd; - write; - } - } - // ANCHOR_END: control -} diff --git a/tests/firrtl/language-tutorial-compute.futil.data b/tests/firrtl/language-tutorial-compute.futil.data deleted file mode 100644 index da9bbb4231..0000000000 --- a/tests/firrtl/language-tutorial-compute.futil.data +++ /dev/null @@ -1,10 +0,0 @@ -{ - "mem": { - "data": [10], - "format": { - "numeric_type": "bitnum", - "is_signed": false, - "width": 32 - } - } -} diff --git a/tests/firrtl/language-tutorial-control.expect b/tests/firrtl/language-tutorial-control.expect deleted file mode 100644 index d87cad1b8e..0000000000 --- a/tests/firrtl/language-tutorial-control.expect +++ /dev/null @@ -1,8 +0,0 @@ -{ - "cycles": 1, - "memories": { - "mem": [ - 42 - ] - } -} diff --git a/tests/firrtl/language-tutorial-control.futil b/tests/firrtl/language-tutorial-control.futil deleted file mode 100644 index 106ebd4c46..0000000000 --- a/tests/firrtl/language-tutorial-control.futil +++ /dev/null @@ -1,25 +0,0 @@ -import "primitives/core.futil"; -import "primitives/memories/comb.futil"; - -component main(@go go: 1) -> (@done done: 1) { - // ANCHOR: cells - cells { - @external(1) mem = comb_mem_d1(32, 1, 1); - } - // ANCHOR_END: cells - // ANCHOR: wires - wires { - group the_answer { - mem.addr0 = 1'b0; - mem.write_data = 32'd42; - mem.write_en = 1'b1; - the_answer[done] = mem.done; - } - } - // ANCHOR_END: wires - // ANCHOR: control - control { - the_answer; - } - // ANCHOR_END: control -} diff --git a/tests/firrtl/language-tutorial-control.futil.data b/tests/firrtl/language-tutorial-control.futil.data deleted file mode 100644 index da9bbb4231..0000000000 --- a/tests/firrtl/language-tutorial-control.futil.data +++ /dev/null @@ -1,10 +0,0 @@ -{ - "mem": { - "data": [10], - "format": { - "numeric_type": "bitnum", - "is_signed": false, - "width": 32 - } - } -} diff --git a/tests/firrtl/language-tutorial-mem.expect b/tests/firrtl/language-tutorial-mem.expect deleted file mode 100644 index d87cad1b8e..0000000000 --- a/tests/firrtl/language-tutorial-mem.expect +++ /dev/null @@ -1,8 +0,0 @@ -{ - "cycles": 1, - "memories": { - "mem": [ - 42 - ] - } -} diff --git a/tests/firrtl/language-tutorial-mem.futil b/tests/firrtl/language-tutorial-mem.futil deleted file mode 100644 index 615ab15d2e..0000000000 --- a/tests/firrtl/language-tutorial-mem.futil +++ /dev/null @@ -1,19 +0,0 @@ -import "primitives/core.futil"; -import "primitives/memories/comb.futil"; - -component main(@go go: 1) -> (@done done: 1) { - // ANCHOR: cells - cells { - @external mem = comb_mem_d1(32, 1, 1); - } - // ANCHOR_END: cells - // ANCHOR: wires - wires { - mem.addr0 = 1'b0; - mem.write_data = 32'd42; - mem.write_en = 1'b1; - done = mem.done; - } - // ANCHOR_END: wires - control {} -} diff --git a/tests/firrtl/language-tutorial-mem.futil.data b/tests/firrtl/language-tutorial-mem.futil.data deleted file mode 100644 index da9bbb4231..0000000000 --- a/tests/firrtl/language-tutorial-mem.futil.data +++ /dev/null @@ -1,10 +0,0 @@ -{ - "mem": { - "data": [10], - "format": { - "numeric_type": "bitnum", - "is_signed": false, - "width": 32 - } - } -} From 272d8476e926dfb9b84c5b6d2ab31deb3c73bd08 Mon Sep 17 00:00:00 2001 From: Ryan Fu Date: Sun, 7 Dec 2025 15:35:50 -0500 Subject: [PATCH 8/8] Added Firrtl-With-Primitives Tests - Changed std_slice template to allow Firrtl Tests to properly compile, and changed from head to tail to properly drop correct bits. --- runt.toml | 7 +++++++ tools/firrtl/templates/std_slice.fir | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/runt.toml b/runt.toml index 38a65b78ff..cc542c0c26 100644 --- a/runt.toml +++ b/runt.toml @@ -80,6 +80,13 @@ cmd = """ fud2 {} -q --to dat -s sim.data={}.data --through firrtl """ +[[tests]] +name = "Firrtl-With-Primitives Tests" +paths = ["tests/firrtl/*.futil"] +cmd = """ + fud2 {} -q --to dat -s sim.data={}.data --through firrtl-with-primitives +""" + ##### Frontend Tests ##### [[tests]] name = "[frontend] dahlia" diff --git a/tools/firrtl/templates/std_slice.fir b/tools/firrtl/templates/std_slice.fir index a5bd50943c..049be0a235 100644 --- a/tools/firrtl/templates/std_slice.fir +++ b/tools/firrtl/templates/std_slice.fir @@ -2,4 +2,4 @@ input in : UInt output out : UInt - out <= head(in, UInt(DIFF)) ; DIFF should be IN_WIDTH - OUT_WIDTH + out <= tail(in, DIFF) ; DIFF should be IN_WIDTH - OUT_WIDTH