diff --git a/calyx-py/calyx/py_ast.py b/calyx-py/calyx/py_ast.py index 5456f26737..0dbc212937 100644 --- a/calyx-py/calyx/py_ast.py +++ b/calyx-py/calyx/py_ast.py @@ -89,7 +89,7 @@ def doc(self) -> str: ins = ", ".join([s.doc() for s in self.inputs]) outs = ", ".join([s.doc() for s in self.outputs]) latency_annotation = ( - f"static<{self.latency}> " if self.latency is not None else "" + f"static<{self.latency}> " if self.latency is not None else "" ) attribute_annotation = f"<{', '.join([f'{a.doc()}' for a in self.attributes])}>" if self.attributes else "" signature = f"{latency_annotation}component {self.name}{attribute_annotation}({ins}) -> ({outs})" diff --git a/runt.toml b/runt.toml index 3d2fbc5666..96bebca7e1 100644 --- a/runt.toml +++ b/runt.toml @@ -481,6 +481,13 @@ fud e {} -s verilog.cycle_limit 500 \ --to dat -q """ +[[tests]] +name = "calyx-py AXI wrapper generation" +paths = ["yxi/axi-calyx/axi-generator.py"] +cmd = """ +python3 {} +""" + ##### Xilinx Tests ###### [[tests]] name = "AXI wrapper generation" diff --git a/yxi/axi-calyx/axi-generator.expect b/yxi/axi-calyx/axi-generator.expect new file mode 100644 index 0000000000..ab5b60ba87 --- /dev/null +++ b/yxi/axi-calyx/axi-generator.expect @@ -0,0 +1,393 @@ +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +import "primitives/memories/seq.futil"; +component m_ar_channel(ARESETn: 1, ARREADY: 1) -> (ARVALID: 1, ARADDR: 64, ARSIZE: 3, ARLEN: 8, ARBURST: 2, ARPROT: 3) { + cells { + arvalid = std_reg(1); + ar_handshake_occurred = std_reg(1); + ref curr_addr_axi = std_reg(64); + arlen = std_reg(8); + txn_n = std_const(32, 1); + txn_count = std_reg(32); + txn_adder = std_add(32); + bt_reg = std_reg(1); + perform_reads = std_neq(32); + } + wires { + ARVALID = arvalid.out; + group do_ar_transfer { + arvalid.in = (!(arvalid.out & ARREADY) & !ar_handshake_occurred.out) ? 1'd1; + arvalid.in = ((arvalid.out & ARREADY) | ar_handshake_occurred.out) ? 1'd0; + arvalid.write_en = 1'd1; + ar_handshake_occurred.in = (arvalid.out & ARREADY) ? 1'd1; + ar_handshake_occurred.write_en = !ar_handshake_occurred.out ? 1'd1; + ARADDR = curr_addr_axi.out; + ARSIZE = 3'd2; + ARLEN = arlen.out; + ARBURST = 2'd1; + ARPROT = 3'd6; + bt_reg.in = (ARREADY & arvalid.out) ? 1'd1; + bt_reg.in = !(ARREADY & arvalid.out) ? 1'd0; + bt_reg.write_en = 1'd1; + do_ar_transfer[done] = bt_reg.out; + } + group incr_txn_count { + txn_adder.left = txn_count.out; + txn_adder.right = 32'd1; + txn_count.in = txn_adder.out; + txn_count.write_en = 1'd1; + incr_txn_count[done] = txn_count.done; + } + comb group perform_reads_group { + perform_reads.left = txn_count.out; + perform_reads.right = txn_n.out; + } + } + control { + seq { + invoke txn_count(in=32'd0)(); + invoke arlen(in=8'd7)(); + while perform_reads.out with perform_reads_group { + seq { + par { + invoke bt_reg(in=1'd0)(); + invoke ar_handshake_occurred(in=1'd0)(); + } + do_ar_transfer; + invoke arvalid(in=1'd0)(); + incr_txn_count; + } + } + } + } +} +component m_aw_channel(ARESETn: 1, AWREADY: 1) -> (AWVALID: 1, AWADDR: 64, AWSIZE: 3, AWLEN: 8, AWBURST: 2, AWPROT: 3) { + cells { + awvalid = std_reg(1); + aw_handshake_occurred = std_reg(1); + ref curr_addr_axi = std_reg(64); + awlen = std_reg(8); + txn_n = std_const(32, 1); + txn_count = std_reg(32); + txn_adder = std_add(32); + bt_reg = std_reg(1); + perform_writes = std_neq(32); + ref max_transfers = std_reg(8); + } + wires { + AWVALID = awvalid.out; + group do_aw_transfer { + awvalid.in = (!(awvalid.out & AWREADY) & !aw_handshake_occurred.out) ? 1'd1; + awvalid.in = ((awvalid.out & AWREADY) | aw_handshake_occurred.out) ? 1'd0; + awvalid.write_en = 1'd1; + aw_handshake_occurred.in = (awvalid.out & AWREADY) ? 1'd1; + aw_handshake_occurred.write_en = !aw_handshake_occurred.out ? 1'd1; + AWADDR = curr_addr_axi.out; + AWSIZE = 3'd2; + AWLEN = awlen.out; + AWBURST = 2'd1; + AWPROT = 3'd6; + bt_reg.in = (AWREADY & awvalid.out) ? 1'd1; + bt_reg.in = !(AWREADY & awvalid.out) ? 1'd0; + bt_reg.write_en = 1'd1; + do_aw_transfer[done] = bt_reg.out; + max_transfers.in = 8'd7; + max_transfers.write_en = 1'd1; + } + group incr_txn_count { + txn_adder.left = txn_count.out; + txn_adder.right = 32'd1; + txn_count.in = txn_adder.out; + txn_count.write_en = 1'd1; + incr_txn_count[done] = txn_count.done; + } + comb group perform_writes_group { + perform_writes.left = txn_count.out; + perform_writes.right = txn_n.out; + } + } + control { + seq { + invoke txn_count(in=32'd0)(); + invoke awlen(in=8'd7)(); + while perform_writes.out with perform_writes_group { + seq { + par { + invoke bt_reg(in=1'd0)(); + invoke aw_handshake_occurred(in=1'd0)(); + } + do_aw_transfer; + invoke awvalid(in=1'd0)(); + incr_txn_count; + } + } + } + } +} +component m_read_channel(ARESETn: 1, RVALID: 1, RLAST: 1, RDATA: 32, RRESP: 2) -> (RREADY: 1) { + cells { + ref mem_ref = seq_mem_d1(32, 8, 3); + rready = std_reg(1); + ref curr_addr_internal_mem = std_reg(3); + ref curr_addr_axi = std_reg(64); + n_RLAST = std_reg(1); + read_data_reg = std_reg(32); + bt_reg = std_reg(1); + curr_addr_internal_mem_incr = std_add(3); + curr_addr_axi_incr = std_add(64); + } + wires { + RREADY = rready.out; + mem_ref.content_en = 1'd0; + group block_transfer { + rready.in = !(rready.out & RVALID) ? 1'd1; + rready.in = (rready.out & RVALID) ? 1'd0; + rready.write_en = 1'd1; + read_data_reg.in = RDATA; + read_data_reg.write_en = (rready.out & RVALID) ? 1'd1; + read_data_reg.write_en = !(rready.out & RVALID) ? 1'd0; + n_RLAST.in = RLAST ? 1'd0; + n_RLAST.in = !RLAST ? 1'd1; + n_RLAST.write_en = 1'd1; + bt_reg.in = (rready.out & RVALID) ? 1'd1; + bt_reg.in = !(rready.out & RVALID) ? 1'd0; + bt_reg.write_en = 1'd1; + block_transfer[done] = bt_reg.out; + } + group service_read_transfer { + rready.in = 1'd0; + rready.write_en = 1'd1; + mem_ref.addr0 = curr_addr_internal_mem.out; + mem_ref.write_data = read_data_reg.out; + mem_ref.write_en = 1'd1; + service_read_transfer[done] = mem_ref.write_done; + } + group curr_addr_internal_mem_incr_group { + curr_addr_internal_mem_incr.left = curr_addr_internal_mem.out; + curr_addr_internal_mem_incr.right = 3'd1; + curr_addr_internal_mem.write_en = 1'd1; + curr_addr_internal_mem.in = curr_addr_internal_mem_incr.out; + curr_addr_internal_mem_incr_group[done] = curr_addr_internal_mem.done; + } + group curr_addr_axi_incr_group { + curr_addr_axi_incr.left = curr_addr_axi.out; + curr_addr_axi_incr.right = 64'd4; + curr_addr_axi.write_en = 1'd1; + curr_addr_axi.in = curr_addr_axi_incr.out; + curr_addr_axi_incr_group[done] = curr_addr_axi.done; + } + } + control { + seq { + invoke n_RLAST(in=1'd1)(); + while n_RLAST.out { + seq { + invoke bt_reg(in=1'd0)(); + block_transfer; + service_read_transfer; + par { + curr_addr_internal_mem_incr_group; + curr_addr_axi_incr_group; + } + } + } + } + } +} +component m_write_channel(ARESETn: 1, WREADY: 1) -> (WVALID: 1, WLAST: 1, WDATA: 32) { + cells { + ref mem_ref = seq_mem_d1(32, 8, 3); + wvalid = std_reg(1); + w_handshake_occurred = std_reg(1); + ref curr_addr_internal_mem = std_reg(3); + ref curr_addr_axi = std_reg(64); + curr_trsnfr_count = std_reg(8); + ref max_transfers = std_reg(8); + n_finished_last_trnsfr = std_reg(1); + bt_reg = std_reg(1); + curr_addr_internal_mem_incr = std_add(3); + curr_addr_axi_incr = std_add(64); + curr_trsnfr_count_incr = std_add(8); + } + wires { + WVALID = wvalid.out; + group service_write_transfer { + wvalid.in = (!(wvalid.out & WREADY) & !w_handshake_occurred.out) ? 1'd1; + wvalid.in = ((wvalid.out & WREADY) | w_handshake_occurred.out) ? 1'd0; + wvalid.write_en = 1'd1; + w_handshake_occurred.in = (wvalid.out & WREADY) ? 1'd1; + w_handshake_occurred.write_en = !w_handshake_occurred.out ? 1'd1; + mem_ref.addr0 = curr_addr_internal_mem.out; + mem_ref.content_en = 1'd1; + WDATA = mem_ref.read_data; + WLAST = (max_transfers.out == curr_trsnfr_count.out) ? 1'd1; + WLAST = (max_transfers.out != curr_trsnfr_count.out) ? 1'd0; + n_finished_last_trnsfr.in = ((max_transfers.out == curr_trsnfr_count.out) & (wvalid.out & WREADY)) ? 1'd0; + n_finished_last_trnsfr.write_en = ((max_transfers.out == curr_trsnfr_count.out) & (wvalid.out & WREADY)) ? 1'd1; + bt_reg.in = (wvalid.out & WREADY) ? 1'd1; + bt_reg.in = !(wvalid.out & WREADY) ? 1'd0; + bt_reg.write_en = 1'd1; + service_write_transfer[done] = bt_reg.out; + } + group curr_addr_internal_mem_incr_group { + curr_addr_internal_mem_incr.left = curr_addr_internal_mem.out; + curr_addr_internal_mem_incr.right = 3'd1; + curr_addr_internal_mem.write_en = 1'd1; + curr_addr_internal_mem.in = curr_addr_internal_mem_incr.out; + curr_addr_internal_mem_incr_group[done] = curr_addr_internal_mem.done; + } + group curr_addr_axi_incr_group { + curr_addr_axi_incr.left = curr_addr_axi.out; + curr_addr_axi_incr.right = 64'd4; + curr_addr_axi.write_en = 1'd1; + curr_addr_axi.in = curr_addr_axi_incr.out; + curr_addr_axi_incr_group[done] = curr_addr_axi.done; + } + group curr_trsnfr_count_incr_group { + curr_trsnfr_count_incr.left = curr_trsnfr_count.out; + curr_trsnfr_count_incr.right = 8'd1; + curr_trsnfr_count.write_en = 1'd1; + curr_trsnfr_count.in = curr_trsnfr_count_incr.out; + curr_trsnfr_count_incr_group[done] = curr_trsnfr_count.done; + } + } + control { + seq { + invoke curr_addr_internal_mem(in=3'd0)(); + invoke n_finished_last_trnsfr(in=1'd1)(); + while n_finished_last_trnsfr.out { + seq { + invoke bt_reg(in=1'd0)(); + service_write_transfer; + par { + curr_addr_internal_mem_incr_group; + curr_trsnfr_count_incr_group; + curr_addr_axi_incr_group; + invoke w_handshake_occurred(in=1'd0)(); + } + } + } + } + } +} +component m_bresp_channel(ARESETn: 1, BVALID: 1) -> (BREADY: 1) { + cells { + bready = std_reg(1); + bt_reg = std_reg(1); + } + wires { + BREADY = bready.out; + group block_transfer { + bready.in = !(bready.out & BVALID) ? 1'd1; + bready.in = (bready.out & BVALID) ? 1'd0; + bready.write_en = 1'd1; + bt_reg.in = (bready.out & BVALID) ? 1'd1; + bt_reg.in = !(bready.out & BVALID) ? 1'd0; + bt_reg.write_en = 1'd1; + block_transfer[done] = bt_reg.out; + } + } + control { + seq { + invoke bt_reg(in=1'd0)(); + block_transfer; + } + } +} +component wrapper<"toplevel"=1>(A0_ARESETn: 1, A0_ARREADY: 1, A0_RVALID: 1, A0_RLAST: 1, A0_RDATA: 32, A0_RRESP: 2, A0_AWREADY: 1, A0_WRESP: 2, A0_WREADY: 1, A0_BVALID: 1, A0_BRESP: 2, A0_RID: 1, B0_ARESETn: 1, B0_ARREADY: 1, B0_RVALID: 1, B0_RLAST: 1, B0_RDATA: 32, B0_RRESP: 2, B0_AWREADY: 1, B0_WRESP: 2, B0_WREADY: 1, B0_BVALID: 1, B0_BRESP: 2, B0_RID: 1, Sum0_ARESETn: 1, Sum0_ARREADY: 1, Sum0_RVALID: 1, Sum0_RLAST: 1, Sum0_RDATA: 32, Sum0_RRESP: 2, Sum0_AWREADY: 1, Sum0_WRESP: 2, Sum0_WREADY: 1, Sum0_BVALID: 1, Sum0_BRESP: 2, Sum0_RID: 1) -> (A0_ARVALID: 1, A0_ARADDR: 64, A0_ARSIZE: 3, A0_ARLEN: 8, A0_ARBURST: 2, A0_RREADY: 1, A0_AWVALID: 1, A0_AWADDR: 64, A0_AWSIZE: 3, A0_AWLEN: 8, A0_AWBURST: 2, A0_AWPROT: 3, A0_WVALID: 1, A0_WLAST: 1, A0_WDATA: 32, A0_BREADY: 1, A0_ARID: 1, A0_AWID: 1, A0_WID: 1, A0_BID: 1, B0_ARVALID: 1, B0_ARADDR: 64, B0_ARSIZE: 3, B0_ARLEN: 8, B0_ARBURST: 2, B0_RREADY: 1, B0_AWVALID: 1, B0_AWADDR: 64, B0_AWSIZE: 3, B0_AWLEN: 8, B0_AWBURST: 2, B0_AWPROT: 3, B0_WVALID: 1, B0_WLAST: 1, B0_WDATA: 32, B0_BREADY: 1, B0_ARID: 1, B0_AWID: 1, B0_WID: 1, B0_BID: 1, Sum0_ARVALID: 1, Sum0_ARADDR: 64, Sum0_ARSIZE: 3, Sum0_ARLEN: 8, Sum0_ARBURST: 2, Sum0_RREADY: 1, Sum0_AWVALID: 1, Sum0_AWADDR: 64, Sum0_AWSIZE: 3, Sum0_AWLEN: 8, Sum0_AWBURST: 2, Sum0_AWPROT: 3, Sum0_WVALID: 1, Sum0_WLAST: 1, Sum0_WDATA: 32, Sum0_BREADY: 1, Sum0_ARID: 1, Sum0_AWID: 1, Sum0_WID: 1, Sum0_BID: 1) { + cells { + main_compute = main(); + curr_addr_internal_mem_A0 = std_reg(3); + curr_addr_axi_A0 = std_reg(64); + ar_channel_A0 = m_ar_channel(); + read_channel_A0 = m_read_channel(); + internal_mem_A0 = seq_mem_d1(32, 8, 3); + max_transfers_A0 = std_reg(8); + aw_channel_A0 = m_aw_channel(); + write_channel_A0 = m_write_channel(); + bresp_channel_A0 = m_bresp_channel(); + curr_addr_internal_mem_B0 = std_reg(3); + curr_addr_axi_B0 = std_reg(64); + ar_channel_B0 = m_ar_channel(); + read_channel_B0 = m_read_channel(); + internal_mem_B0 = seq_mem_d1(32, 8, 3); + max_transfers_B0 = std_reg(8); + aw_channel_B0 = m_aw_channel(); + write_channel_B0 = m_write_channel(); + bresp_channel_B0 = m_bresp_channel(); + curr_addr_internal_mem_Sum0 = std_reg(3); + curr_addr_axi_Sum0 = std_reg(64); + ar_channel_Sum0 = m_ar_channel(); + read_channel_Sum0 = m_read_channel(); + internal_mem_Sum0 = seq_mem_d1(32, 8, 3); + max_transfers_Sum0 = std_reg(8); + aw_channel_Sum0 = m_aw_channel(); + write_channel_Sum0 = m_write_channel(); + bresp_channel_Sum0 = m_bresp_channel(); + } + wires { + A0_ARID = 1'd0; + A0_AWID = 1'd0; + A0_WID = 1'd0; + A0_BID = 1'd0; + B0_ARID = 1'd0; + B0_AWID = 1'd0; + B0_WID = 1'd0; + B0_BID = 1'd0; + Sum0_ARID = 1'd0; + Sum0_AWID = 1'd0; + Sum0_WID = 1'd0; + Sum0_BID = 1'd0; + } + control { + seq { + par { + invoke curr_addr_axi_A0(in=64'd4096)(); + invoke curr_addr_axi_B0(in=64'd4096)(); + invoke curr_addr_axi_Sum0(in=64'd4096)(); + } + par { + invoke curr_addr_internal_mem_A0(in=3'd0)(); + invoke curr_addr_internal_mem_B0(in=3'd0)(); + invoke curr_addr_internal_mem_Sum0(in=3'd0)(); + } + par { + seq { + invoke ar_channel_A0[curr_addr_axi=curr_addr_axi_A0](ARESETn=A0_ARESETn, ARREADY=A0_ARREADY)(ARVALID=A0_ARVALID, ARADDR=A0_ARADDR, ARSIZE=A0_ARSIZE, ARLEN=A0_ARLEN, ARBURST=A0_ARBURST); + invoke read_channel_A0[mem_ref=internal_mem_A0, curr_addr_internal_mem=curr_addr_internal_mem_A0, curr_addr_axi=curr_addr_axi_A0](ARESETn=A0_ARESETn, RVALID=A0_RVALID, RLAST=A0_RLAST, RDATA=A0_RDATA, RRESP=A0_RRESP)(RREADY=A0_RREADY); + } + seq { + invoke ar_channel_B0[curr_addr_axi=curr_addr_axi_B0](ARESETn=B0_ARESETn, ARREADY=B0_ARREADY)(ARVALID=B0_ARVALID, ARADDR=B0_ARADDR, ARSIZE=B0_ARSIZE, ARLEN=B0_ARLEN, ARBURST=B0_ARBURST); + invoke read_channel_B0[mem_ref=internal_mem_B0, curr_addr_internal_mem=curr_addr_internal_mem_B0, curr_addr_axi=curr_addr_axi_B0](ARESETn=B0_ARESETn, RVALID=B0_RVALID, RLAST=B0_RLAST, RDATA=B0_RDATA, RRESP=B0_RRESP)(RREADY=B0_RREADY); + } + seq { + invoke ar_channel_Sum0[curr_addr_axi=curr_addr_axi_Sum0](ARESETn=Sum0_ARESETn, ARREADY=Sum0_ARREADY)(ARVALID=Sum0_ARVALID, ARADDR=Sum0_ARADDR, ARSIZE=Sum0_ARSIZE, ARLEN=Sum0_ARLEN, ARBURST=Sum0_ARBURST); + invoke read_channel_Sum0[mem_ref=internal_mem_Sum0, curr_addr_internal_mem=curr_addr_internal_mem_Sum0, curr_addr_axi=curr_addr_axi_Sum0](ARESETn=Sum0_ARESETn, RVALID=Sum0_RVALID, RLAST=Sum0_RLAST, RDATA=Sum0_RDATA, RRESP=Sum0_RRESP)(RREADY=Sum0_RREADY); + } + } + invoke main_compute[A0=internal_mem_A0, B0=internal_mem_B0, Sum0=internal_mem_Sum0]()(); + par { + invoke curr_addr_axi_A0(in=64'd4096)(); + invoke curr_addr_axi_B0(in=64'd4096)(); + invoke curr_addr_axi_Sum0(in=64'd4096)(); + } + par { + seq { + invoke aw_channel_A0[curr_addr_axi=curr_addr_axi_A0, max_transfers=max_transfers_A0](ARESETn=A0_ARESETn, AWREADY=A0_AWREADY)(AWVALID=A0_AWVALID, AWADDR=A0_AWADDR, AWSIZE=A0_AWSIZE, AWLEN=A0_AWLEN, AWBURST=A0_AWBURST, AWPROT=A0_AWPROT); + invoke write_channel_A0[mem_ref=internal_mem_A0, curr_addr_internal_mem=curr_addr_internal_mem_A0, curr_addr_axi=curr_addr_axi_A0, max_transfers=max_transfers_A0](ARESETn=A0_ARESETn, WREADY=A0_WREADY)(WVALID=A0_WVALID, WLAST=A0_WLAST, WDATA=A0_WDATA); + invoke bresp_channel_A0(BVALID=A0_BVALID)(BREADY=A0_BREADY); + } + seq { + invoke aw_channel_B0[curr_addr_axi=curr_addr_axi_B0, max_transfers=max_transfers_B0](ARESETn=B0_ARESETn, AWREADY=B0_AWREADY)(AWVALID=B0_AWVALID, AWADDR=B0_AWADDR, AWSIZE=B0_AWSIZE, AWLEN=B0_AWLEN, AWBURST=B0_AWBURST, AWPROT=B0_AWPROT); + invoke write_channel_B0[mem_ref=internal_mem_B0, curr_addr_internal_mem=curr_addr_internal_mem_B0, curr_addr_axi=curr_addr_axi_B0, max_transfers=max_transfers_B0](ARESETn=B0_ARESETn, WREADY=B0_WREADY)(WVALID=B0_WVALID, WLAST=B0_WLAST, WDATA=B0_WDATA); + invoke bresp_channel_B0(BVALID=B0_BVALID)(BREADY=B0_BREADY); + } + seq { + invoke aw_channel_Sum0[curr_addr_axi=curr_addr_axi_Sum0, max_transfers=max_transfers_Sum0](ARESETn=Sum0_ARESETn, AWREADY=Sum0_AWREADY)(AWVALID=Sum0_AWVALID, AWADDR=Sum0_AWADDR, AWSIZE=Sum0_AWSIZE, AWLEN=Sum0_AWLEN, AWBURST=Sum0_AWBURST, AWPROT=Sum0_AWPROT); + invoke write_channel_Sum0[mem_ref=internal_mem_Sum0, curr_addr_internal_mem=curr_addr_internal_mem_Sum0, curr_addr_axi=curr_addr_axi_Sum0, max_transfers=max_transfers_Sum0](ARESETn=Sum0_ARESETn, WREADY=Sum0_WREADY)(WVALID=Sum0_WVALID, WLAST=Sum0_WLAST, WDATA=Sum0_WDATA); + invoke bresp_channel_Sum0(BVALID=Sum0_BVALID)(BREADY=Sum0_BREADY); + } + } + } + } +} diff --git a/yxi/axi-calyx/axi-generator.py b/yxi/axi-calyx/axi-generator.py index 21e61eade1..22702345f1 100644 --- a/yxi/axi-calyx/axi-generator.py +++ b/yxi/axi-calyx/axi-generator.py @@ -27,9 +27,9 @@ "size": 8 }, { - "name": "v0", + "name": "Sum0", "width": 32, - "size": 1 + "size": 8 } ] } @@ -44,15 +44,15 @@ def add_arread_channel(prog, mem): def add_awwrite_channel(prog, mem): - awwrite_channel = _add_m_to_s_address_channel(prog, mem, "AW") - max_transfers = awwrite_channel.reg("max_transfers", 8, is_ref=True) + aw_channel = _add_m_to_s_address_channel(prog, mem, "AW") + max_transfers = aw_channel.reg("max_transfers", 8, is_ref=True) # TODO(nathanielnrn): We eventually want to move beyond # the implicit 1 transaction that is the size of the memory # How should we store this? # Recall this goes to write channel as number of transfers it expectes to do before # setting WLAST high - with awwrite_channel.get_group("do_aw_transfer"): + with aw_channel.get_group("do_aw_transfer"): max_transfers.in_ = mem["size"] - 1 max_transfers.write_en = 1 @@ -117,7 +117,7 @@ def _add_m_to_s_address_channel(prog, mem, prefix: Literal["AW", "AR"]): xvalid.write_en = 1 xhandshake_occurred.in_ = (xvalid.out & xREADY) @ 1 - xhandshake_occurred.write_en = (~xhandshake_occurred.out) @ 1 + xhandshake_occurred.write_en = (~xhandshake_occurred.out) @ 1 # Drive output signals for transfer m_to_s_address_channel.this()[f"{x}ADDR"] = curr_addr_axi.out @@ -203,7 +203,9 @@ def add_read_channel(prog, mem): # according to zipcpu, rready should be registered rready = read_channel.reg("rready", 1) - curr_addr_internal_mem = read_channel.reg("curr_addr_internal_mem", clog2(mem["size"]), is_ref=True) + curr_addr_internal_mem = read_channel.reg( + "curr_addr_internal_mem", clog2(mem["size"]), is_ref=True + ) curr_addr_axi = read_channel.reg("curr_addr_axi", 64, is_ref=True) # Registed because RLAST is high with laster transfer, not after # before this we were terminating immediately with @@ -218,7 +220,7 @@ def add_read_channel(prog, mem): with read_channel.continuous: read_channel.this()["RREADY"] = rready.out # Tie this low as we are only ever writing to seq_mem - mem_ref.read_en = 0 + mem_ref.content_en = 0 # Wait for handshake. Ensure that when this is done we are ready to write # (i.e., read_data_reg.write_en = is_rdy.out) @@ -266,7 +268,7 @@ def add_read_channel(prog, mem): mem_ref.addr0 = curr_addr_internal_mem.out mem_ref.write_data = read_data_reg.out mem_ref.write_en = 1 - service_read_transfer.done = mem_ref.done + service_read_transfer.done = mem_ref.write_done # creates group that increments curr_addr_internal_mem by 1. Creates adder and wires up correctly curr_addr_internal_mem_incr = read_channel.incr(curr_addr_internal_mem, 1) @@ -320,13 +322,15 @@ def add_write_channel(prog, mem): wvalid = write_channel.reg("wvalid", 1) w_handshake_occurred = write_channel.reg("w_handshake_occurred", 1) # internal calyx memory indexing - curr_addr_internal_mem = write_channel.reg("curr_addr_internal_mem", clog2(mem["size"]), is_ref=True) + curr_addr_internal_mem = write_channel.reg( + "curr_addr_internal_mem", clog2(mem["size"]), is_ref=True + ) # host indexing, must be 64 bits curr_addr_axi = write_channel.reg("curr_addr_axi", 64, is_ref=True) curr_trsnfr_count = write_channel.reg("curr_trsnfr_count", 8) # Number of transfers we want to do in current txn - max_trnsfrs = write_channel.reg("max_trnsfrs", 8, is_ref=True) + max_transfers = write_channel.reg("max_transfers", 8, is_ref=True) # Register because w last is high with last transfer. Before this # We were terminating immediately with last transfer and not servicing it. @@ -354,22 +358,18 @@ def add_write_channel(prog, mem): # Set data output based on intermal memory output mem_ref.addr0 = curr_addr_internal_mem.out - mem_ref.read_en = 1 + mem_ref.content_en = 1 write_channel.this()["WDATA"] = mem_ref.read_data - write_channel.this()["WLAST"] = ( - max_trnsfrs.out == curr_trsnfr_count.out - ) @ 1 - write_channel.this()["WLAST"] = ( - max_trnsfrs.out != curr_trsnfr_count.out - ) @ 0 + write_channel.this()["WLAST"] = (max_transfers.out == curr_trsnfr_count.out) @ 1 + write_channel.this()["WLAST"] = (max_transfers.out != curr_trsnfr_count.out) @ 0 # set high when WLAST is high and a handshake occurs n_finished_last_trnsfr.in_ = ( - (max_trnsfrs.out == curr_trsnfr_count.out) & (wvalid.out & WREADY) + (max_transfers.out == curr_trsnfr_count.out) & (wvalid.out & WREADY) ) @ 0 n_finished_last_trnsfr.write_en = ( - (max_trnsfrs.out == curr_trsnfr_count.out) & (wvalid.out & WREADY) + (max_transfers.out == curr_trsnfr_count.out) & (wvalid.out & WREADY) ) @ 1 # done after handshake @@ -393,7 +393,12 @@ def add_write_channel(prog, mem): while_n_finished_last_trnsfr_body = [ invoke(bt_reg, in_in=0), service_write_transfer, - par(curr_addr_internal_mem_incr, curr_trsnfr_count_incr, curr_addr_axi_incr, invoke(w_handshake_occurred, in_in=0)), + par( + curr_addr_internal_mem_incr, + curr_trsnfr_count_incr, + curr_addr_axi_incr, + invoke(w_handshake_occurred, in_in=0), + ), ] while_n_finished_last_trnsfr = while_( n_finished_last_trnsfr.out, while_n_finished_last_trnsfr_body @@ -442,6 +447,213 @@ def add_bresp_channel(prog, mem): bresp_channel.control += [invoke(bt_reg, in_in=0), block_transfer] +# NOTE: Unlike the channel functions, this can expect multiple mems +def add_main_comp(prog, mems): + wrapper_comp = prog.component("wrapper") + wrapper_comp.attribute("toplevel",1) + # Get handles to be used later + read_channel = prog.get_component("m_read_channel") + write_channel = prog.get_component("m_write_channel") + ar_channel = prog.get_component("m_ar_channel") + aw_channel = prog.get_component("m_aw_channel") + bresp_channel = prog.get_component("m_bresp_channel") + + curr_addr_axi_par = [] + curr_addr_internal_par = [] + reads_par = [] + writes_par = [] + ref_mem_kwargs = {} + + #Create single main cell + main_compute = wrapper_comp.comp_instance("main_compute", "main", check_undeclared=False) + + + for mem in mems: + mem_name = mem["name"] + # Inputs/Outputs + wrapper_inputs = [ + (f"{mem_name}_ARESETn", 1), + (f"{mem_name}_ARREADY", 1), + (f"{mem_name}_RVALID", 1), + (f"{mem_name}_RLAST", 1), + (f"{mem_name}_RDATA", mem["width"]), + (f"{mem_name}_RRESP", 2), + (f"{mem_name}_AWREADY", 1), + (f"{mem_name}_WRESP", 2), + (f"{mem_name}_WREADY", 1), + (f"{mem_name}_BVALID", 1), + # Only used for waveform tracing, not sent anywhere + (f"{mem_name}_BRESP", 2), + # Only needed for coctb compatability, tied low + (f"{mem_name}_RID", 1), + ] + + wrapper_outputs = [ + (f"{mem_name}_ARVALID", 1), + (f"{mem_name}_ARADDR", 64), + (f"{mem_name}_ARSIZE", 3), + (f"{mem_name}_ARLEN", 8), + (f"{mem_name}_ARBURST", 2), + (f"{mem_name}_RREADY", 1), + (f"{mem_name}_AWVALID", 1), + (f"{mem_name}_AWADDR", 64), + (f"{mem_name}_AWSIZE", 3), + (f"{mem_name}_AWLEN", 8), + (f"{mem_name}_AWBURST", 2), + (f"{mem_name}_AWPROT", 3), + (f"{mem_name}_WVALID", 1), + (f"{mem_name}_WLAST", 1), + (f"{mem_name}_WDATA", mem["width"]), + (f"{mem_name}_BREADY", 1), + # ID signals are needed for coco compatability, tied low + (f"{mem_name}_ARID", 1), + (f"{mem_name}_AWID", 1), + (f"{mem_name}_WID", 1), + (f"{mem_name}_BID", 1), + ] + + + add_comp_params(wrapper_comp, wrapper_inputs, wrapper_outputs) + + # Cells + # Read stuff + curr_addr_internal_mem = wrapper_comp.reg( + f"curr_addr_internal_mem_{mem_name}", clog2(mem["size"]) + ) + curr_addr_axi = wrapper_comp.reg(f"curr_addr_axi_{mem_name}", 64) + + wrapper_comp.cell(f"ar_channel_{mem_name}", ar_channel) + wrapper_comp.cell(f"read_channel_{mem_name}", read_channel) + + # TODO: Don't think these need to be marked external, but we + # we need to raise them at some point form original calyx program + internal_mem = wrapper_comp.seq_mem_d1( + name=f"internal_mem_{mem_name}", + bitwidth=mem["width"], + len=mem["size"], + idx_size=clog2(mem["size"]), + ) + + + # Write stuff + max_transfers = wrapper_comp.reg(f"max_transfers_{mem_name}", 8) + wrapper_comp.cell(f"aw_channel_{mem_name}", aw_channel) + wrapper_comp.cell(f"write_channel_{mem_name}", write_channel) + wrapper_comp.cell(f"bresp_channel_{mem_name}", bresp_channel) + + # Wires + + # Tie IDs low, needed for cocotb compatability. Not used anywhere + with wrapper_comp.continuous: + wrapper_comp.this()[f"{mem_name}_ARID"] = 0 + wrapper_comp.this()[f"{mem_name}_AWID"] = 0 + wrapper_comp.this()[f"{mem_name}_WID"] = 0 + wrapper_comp.this()[f"{mem_name}_BID"] = 0 + + # No groups needed! + + # set up internal control blocks + #TODO: turn these into parts of a par block + this_component = wrapper_comp.this() + + ar_channel_invoke = invoke( + # main_comp.get_cell(f"ar_channel_{mem_name}"), + wrapper_comp.get_cell(f"ar_channel_{mem_name}"), + ref_curr_addr_axi=curr_addr_axi, + in_ARESETn=this_component[f"{mem_name}_ARESETn"], + in_ARREADY=this_component[f"{mem_name}_ARREADY"], + out_ARVALID=this_component[f"{mem_name}_ARVALID"], + out_ARADDR=this_component[f"{mem_name}_ARADDR"], + out_ARSIZE=this_component[f"{mem_name}_ARSIZE"], + out_ARLEN=this_component[f"{mem_name}_ARLEN"], + out_ARBURST=this_component[f"{mem_name}_ARBURST"] + ) + + read_channel_invoke = invoke( + wrapper_comp.get_cell(f"read_channel_{mem_name}"), + ref_mem_ref = internal_mem, + ref_curr_addr_internal_mem = curr_addr_internal_mem, + ref_curr_addr_axi = curr_addr_axi, + in_ARESETn = this_component[f"{mem_name}_ARESETn"], + in_RVALID = this_component[f"{mem_name}_RVALID"], + in_RLAST = this_component[f"{mem_name}_RLAST"], + in_RDATA = this_component[f"{mem_name}_RDATA"], + #TODO: Do we need this? Don't think this goes anywhere + in_RRESP = this_component[f"{mem_name}_RRESP"], + out_RREADY = this_component[f"{mem_name}_RREADY"] + ) + + aw_channel_invoke = invoke( + wrapper_comp.get_cell(f"aw_channel_{mem_name}"), + ref_curr_addr_axi = curr_addr_axi, + ref_max_transfers = max_transfers, + in_ARESETn = this_component[f"{mem_name}_ARESETn"], + in_AWREADY = this_component[f"{mem_name}_AWREADY"], + out_AWVALID = this_component[f"{mem_name}_AWVALID"], + out_AWADDR = this_component[f"{mem_name}_AWADDR"], + out_AWSIZE = this_component[f"{mem_name}_AWSIZE"], + out_AWLEN = this_component[f"{mem_name}_AWLEN"], + out_AWBURST = this_component[f"{mem_name}_AWBURST"], + out_AWPROT = this_component[f"{mem_name}_AWPROT"] + ) + + write_channel_invoke = invoke( + wrapper_comp.get_cell(f"write_channel_{mem_name}"), + ref_mem_ref = internal_mem, + ref_curr_addr_internal_mem = curr_addr_internal_mem, + ref_curr_addr_axi = curr_addr_axi, + ref_max_transfers = max_transfers, + in_ARESETn = this_component[f"{mem_name}_ARESETn"], + in_WREADY = this_component[f"{mem_name}_WREADY"], + out_WVALID = this_component[f"{mem_name}_WVALID"], + out_WLAST = this_component[f"{mem_name}_WLAST"], + out_WDATA = this_component[f"{mem_name}_WDATA"], + ) + + bresp_channel_invoke = invoke( + wrapper_comp.get_cell(f"bresp_channel_{mem_name}"), + in_BVALID = this_component[f"{mem_name}_BVALID"], + out_BREADY = this_component[f"{mem_name}_BREADY"] + ) + + curr_addr_axi_invoke = invoke( + curr_addr_axi, in_in=0x1000 + ) + curr_addr_internal_invoke = invoke( + curr_addr_internal_mem, in_in=0x0000 + ) + + curr_addr_axi_par.append(curr_addr_axi_invoke) + curr_addr_internal_par.append(curr_addr_internal_invoke) + reads_par.append([ar_channel_invoke, read_channel_invoke]) + writes_par.append([aw_channel_invoke, write_channel_invoke, bresp_channel_invoke]) + #Creates ` = internal_mem_` as refs in invocation of `main_compute` + ref_mem_kwargs[f"ref_{mem_name}"] = internal_mem + + + #Compute invoke + #Assumes refs should be of form ` = internal_mem_` + main_compute_invoke = invoke( + wrapper_comp.get_cell("main_compute"), + **ref_mem_kwargs + ) + + + #Compiler should reschedule these 2 seqs to be in parallel right? + wrapper_comp.control += par(*curr_addr_axi_par) + wrapper_comp.control += par(*curr_addr_internal_par) + + wrapper_comp.control += par(*reads_par) + wrapper_comp.control += main_compute_invoke + # Reset axi adress to 0 + wrapper_comp.control += par(*curr_addr_axi_par) + wrapper_comp.control += par(*writes_par) + + + + + + # Helper functions def width_in_bytes(width: int): assert width % 8 == 0, "Width must be a multiple of 8." @@ -469,14 +681,21 @@ def build(): add_read_channel(prog, mems[0]) add_write_channel(prog, mems[0]) add_bresp_channel(prog, mems[0]) + add_main_comp(prog, mems) return prog.program + def check_mems_welformed(mems): """Checks if memories from yxi are well formed. Returns true if they are, false otherwise.""" for mem in mems: - assert mem["width"] % 8 == 0, "Width must be a multiple of 8 to alow byte addressing to host" - assert log2(mem["width"]).is_integer(), "Width must be a power of 2 to be correctly described by xSIZE" + assert ( + mem["width"] % 8 == 0 + ), "Width must be a multiple of 8 to alow byte addressing to host" + assert log2( + mem["width"] + ).is_integer(), "Width must be a power of 2 to be correctly described by xSIZE" assert mem["size"] > 0, "Memory size must be greater than 0" + if __name__ == "__main__": build().emit() diff --git a/yxi/axi-calyx/axi-reads-calyx.futil b/yxi/axi-calyx/axi-reads-calyx.futil deleted file mode 100644 index 8bd5d6f349..0000000000 --- a/yxi/axi-calyx/axi-reads-calyx.futil +++ /dev/null @@ -1,374 +0,0 @@ -// ### -// This file contains the components needed to perform read transacitons via AXI. -// Current goal is to create a cocotb testbench that tests correctness of this. -// See https://github.com/cucapra/calyx/issues/1733 for more information. -// -// This wrapper assumes it is part of a dot product computation with vectors of -// length 16 -// It assumes a bus data width of 32 -// This is largely a work in progress and as of Nov 20 2023 is not intended to -// actually be used for anything -// ### - -import "primitives/core.futil"; -import "primitives/memories/comb.futil"; -import "primitives/compile.futil"; -import "primitives/math.futil"; -import "primitives/memories/seq.futil"; - - -//this goes m->s unlike read channel -component m_arread_channel( - ARESET: 1, - ARREADY: 1 -) -> ( - ARVALID: 1, - // This needs to be 64, see link below `m_axi` section. - ARADDR: 64, - // 2^ARSIZE is bytes used in transfer. For memory-mapped AXI (which is what we - // are doing I believe), should match width of data bus (to shell?, so 32 wide? This - // is 3'b010) - // see https://docs.xilinx.com/r/en-US/ug1393-vitis-application-acceleration/Kernel-Interface-Requirements - // for restrictions - ARSIZE: 3, - // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. - ARLEN : 8, - // 00 for fixed, 01 for incrementing, 2 for wrap, - // needs to be incr for RTL kernels (can't use wrapped of fixed - ARBURST : 2, - // required by spec. We hardwire this to priviliged access, non secure, data access. - ARPROT : 3) { - cells{ - is_arvalid = std_reg(1); - - // gets set high with ARVALID and remains high - arvalid_was_high = std_reg(1); - // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` - // but for now will live here. - ref base_addr = std_reg(64); - - // number of trasfers in a transaction. This is sent to subordinate - txn_len = std_reg(8); - - // number of txns we want to occur before entire m_arread_channel is done - // this is internal to the channel (unlike txn_len) - txn_n = std_const(32,1); - txn_count = std_reg(32); - perform_reads = std_neq(32); - txn_adder = std_add(32); - - //"block_transfer" register. need to put into a reg to avoid combinational loops - bt_reg = std_reg(1); - - - } - - wires{ - - ARVALID = is_arvalid.out; - - group deassert_val { - is_arvalid.in = 1'b0; - is_arvalid.write_en = 1'b1; - deassert_val[done] = is_arvalid.done; - } - - group reset_bt { - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt[done] = bt_reg.done; - } - - // this asserts valid and defines all inputs correctly - // because valid should not be deasserted until handshake occurs - // this all needs to be one group - // this contains blocking logic previously in its own group - group do_ar_transfer { - //assert ARVALID - is_arvalid.in = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; - - // TODO(nathanielnrn): in theory should be able to get rid of arvalid_was_high - // but for now we will be explicit and reduce this in generation maybe. Not sure - // it even matters. - // This makes ARVALID go low after a single cycle. Without it it stays high for 2. - is_arvalid.in = is_arvalid.out & ARREADY & arvalid_was_high.out ? 1'b0; - is_arvalid.write_en = 1'b1; - - arvalid_was_high.in = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; - arvalid_was_high.write_en = !(is_arvalid.out & ARREADY) & !arvalid_was_high.out ? 1'b1; - - - // drive output signals for transfer - ARADDR = base_addr.out; - // see link above, needs to match data width to host. - // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. - ARSIZE = 3'b010; - // For now this can be taken from .yxi, as size of mem, because we are assuming - // data_bus width that matches size of memory cells - // If we want to use bigger mems need to be able to update base addr - ARLEN = txn_len.out; - ARBURST = 2'b01; //incr - // privileged, non-secure, instruction access - ARPROT = 3'b110; - - - //done when one cycle after handshake (handshake happens for a single cycle) - bt_reg.in = ARREADY & is_arvalid.out ? 1'b1; - bt_reg.in = !(ARREADY & is_arvalid.out) ? 1'b0; - bt_reg.write_en = 1'b1; - do_ar_transfer[done] = bt_reg.out; - } - - - //txn bookkeeping. - //We are done performing reads when txn_count == txn_n - group txn_count_init { - txn_count.in = 32'b0; - txn_count.write_en = 1'b1; - txn_count_init[done] = txn_count.done; - - } - - group txn_len_init { - //TODO(nathanielnrn): 15 is good for word wide data bus. We'd - //expect 16 transfers. Number of transfers that occur is ARLEN + 1 - txn_len.in = 8'd15; - txn_len.write_en = 1'b1; - txn_len_init[done] = txn_len.done; - } - - group txn_incr { - txn_adder.left = txn_count.out; - txn_adder.right = 32'b1; - txn_count.in = txn_adder.out; - txn_count.write_en = 1'b1; - txn_incr[done] = txn_count.done; - - } - - comb group check_reads_done { - perform_reads.left = txn_count.out; - perform_reads.right = txn_n.out; - } - } - - control{ - //XXX(nathanielnrn): What is best way to offer more flexiblity beyond just a counter? - seq{ - txn_count_init; - txn_len_init; - while perform_reads.out with check_reads_done{ - seq{ - reset_bt; - do_ar_transfer; - deassert_val; - txn_incr; - } - } - } - } -} - - - - -component m_read_channel( - ARESET : 1, - RVALID : 1, - RLAST : 1, - RDATA : 32, - RRESP : 2, // Note: This is generated in subordinate! had this backwards in earlier version -) -> ( - // NOTE: In general, according to ZipCPU we want xREADY signals to be registered - // because (IIRC) it helps avoid combinational loops between READY and VALID. - RREADY : 1, -) { - cells { - // 16 is due to dot-product vector length assumption - // For this manual implementation we are just writing into this data based - // on the data we read from cocotb - ref data_received = seq_mem_d1(32, 16, 64); - is_rdy = std_reg(1); - ref curr_addr = std_reg(64); - - // registered because RLAST is high with last transfer, not after - // before this was registered we were terminating immediately with - // last transfer and not servicing it - n_RLAST = std_reg(1); - - // TODO: get this width from yxi - read_data_reg = std_reg(32); - - //address of seq_d1_mem we are writing to - curr_addr_adder = std_add(64); - - // block_transfer reg to avoid combinational loops - bt_reg = std_reg(1); - - } - wires{ - - RREADY = is_rdy.out; - data_received.content_en = 1'b0; - - group init_n_RLAST { - n_RLAST.in = 1'b1; - n_RLAST.write_en = 1'b1; - init_n_RLAST[done] = n_RLAST.done; - } - - // Used to block any servicing until handshake occurs. - group reset_bt { - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt[done] = bt_reg.done; - } - - // NOTE: xVALID signals must be high until xREADY is high as well, so this works - // because if xREADY is high (is_rdy.out) then RVALID being high makes 1 flip - // and group will be done by bt_reg.out - group block_transfer { - // set RREADY high - // TODO (nathanielnrn): technically we can make RREADY depend on on RVALID (but not vice versa). - // Could we simplify this we just making things ready when we are in - // block_transfer && RVALID? - - //NOTE: is_rdy.in = 1'b1; does not work, it leaves RREADY high for 2 cycles - // this both asserts and deasserts one cycle later - // TODO(nathanielnrn): Spec recommends defaulting xREADY high as it - // can get rid of extra cycle. Maybe doing so here would be useful? - // as opposed to waiting for RVALID - is_rdy.in = !(RVALID & is_rdy.out) ? 1'b1; - is_rdy.in = RVALID & is_rdy.out ? 1'b0; - is_rdy.write_en = 1'b1; - - - //store the data we want to write - read_data_reg.in = RDATA; - read_data_reg.write_en = is_rdy.out; - - //update n_RLAST reg - n_RLAST.in = RLAST ? 1'b0; - n_RLAST.in = !RLAST ? 1'b1; - n_RLAST.write_en = 1'b1; - - - // we are done after handshake - bt_reg.in = is_rdy.out & RVALID ? 1'b1; - bt_reg.in = !(is_rdy.out & RVALID) ? 1'b0; - bt_reg.write_en = 1'b1; - block_transfer[done] = bt_reg.out; - } - - group receive_r_transfer{ - // keep RREADY low; - is_rdy.in = 1'b0; - is_rdy.write_en = 1'b1; - - //write the data we received during transfer to seq_d1_mem - data_received.addr0 = curr_addr.out; - data_received.write_en = 1'b1; - data_received.write_data = read_data_reg.out; - receive_r_transfer[done] = data_received.done; - - } - - group incr_curr_addr{ - curr_addr_adder.left = 64'd1 ; - curr_addr_adder.right = curr_addr.out; - curr_addr.in = curr_addr_adder.out; - curr_addr.write_en = 1'b1; - incr_curr_addr[done] = curr_addr.done; - } - } - control{ - init_n_RLAST; - while n_RLAST.out{ - seq{ - reset_bt; - block_transfer; - receive_r_transfer; - incr_curr_addr; - } - } - } -} - -//TODO(nathanielnrn): this is axi_wrapper, prefer to use @toplevel attribute but its not working -// See individual channel components for explanations of signals -component main( - m_ARESET : 1, - m_ARREADY : 1, - - m_RVALID : 1, - m_RLAST : 1, - m_RDATA : 32, - m_RRESP : 2, - //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. - m_RID : 1, -) -> ( - m_ARVALID : 1, - m_ARADDR: 64, - m_ARSIZE: 3, - m_ARLEN : 8, - m_ARBURST : 2, - - m_RREADY : 1, - //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. - m_ARID : 1 -) { - cells{ - vec1_data = seq_mem_d1(32,16,64); - output_data = seq_mem_d1(32,1,0); - - curr_addr = std_reg(64); - base_addr = std_reg(64); - - read_channel = m_read_channel(); - arread_channel = m_arread_channel(); - - } - - wires{ - - m_ARID = 1'b0; - - group set_curr_to_base_addr{ - curr_addr.in = base_addr.out; - curr_addr.write_en = 1'b1; - set_curr_to_base_addr[done] = curr_addr.done; - } - } - control{ - seq{ - invoke arread_channel[base_addr = base_addr] - ( - ARESET = m_ARESET, - ARREADY = m_ARREADY - ) - ( - ARVALID = m_ARVALID, - ARADDR = m_ARADDR, - ARSIZE = m_ARSIZE, - ARLEN = m_ARLEN, - ARBURST = m_ARBURST - ); - - set_curr_to_base_addr; - - invoke read_channel[data_received = vec1_data, curr_addr = curr_addr] - ( - ARESET = m_ARESET, - RVALID = m_RVALID, - RLAST = m_RLAST, - RDATA = m_RDATA, - RRESP = m_RRESP - ) - ( - RREADY = m_RREADY - ); - } - } - - -} diff --git a/yxi/axi-calyx/axi-writes-calyx.futil b/yxi/axi-calyx/axi-writes-calyx.futil deleted file mode 100644 index 150cc9be9c..0000000000 --- a/yxi/axi-calyx/axi-writes-calyx.futil +++ /dev/null @@ -1,522 +0,0 @@ -// ### -// This file contains the components needed to perform write transacitons via AXI. -// Current goal is to create a cocotb testbench that tests correctness of this. -// See https://github.com/cucapra/calyx/issues/1733 for more information. -// -// This wrapper assumes it is part of a dot product computation with vectors of -// length 16 -// It assumes a bus data width of 32 -// This is largely a work in progress and as of Nov 20 2023 is not intended to -// actually be used for anything -// ### - -import "primitives/core.futil"; -import "primitives/memories/comb.futil"; -import "primitives/compile.futil"; -import "primitives/math.futil"; -import "primitives/memories/seq.futil"; - - -//this goes m->s -component m_awwrite_channel( - ARESET: 1, - AWREADY: 1 -) -> ( - AWVALID: 1, - // This needs to be 64, see link below `m_axi` section. - AWADDR: 64, - // 2^AWSIZE is bytes used in transfer. For memory-mapped AXI (which is what we - // are doing I believe), should match width of data bus (to shell?, so 32 wide? This - // is 3'b010) - // see https://docs.xilinx.com/r/en-US/ug1393-vitis-application-acceleration/Kernel-Interface-Requirements - // for restrictions - AWSIZE: 3, - // in AXI4 this is 8 bits, 1-256 transfers in requested transaction. - AWLEN : 8, - // 00 for fixed, 01 for incrementing, 2 for wrap, - // needs to be incr for RTL kernels (can't use wrapped or fixed) - AWBURST : 2, - // required according to spec. We hardcode this - AWPROT : 3) { - cells{ - is_awvalid = std_reg(1); - - // gets set high with AWVALID and remains high - awvalid_was_high = std_reg(1); - // TODO(nathanielnrn): should arguably eventually live in `s_axi_control` - // but for now will live here. - ref base_addr = std_reg(64); - - //we write to this here and read from it in m_write_channel - ref max_trnsfrs = std_reg(8); - - // number of trasfers in a transaction. This is sent to subordinate - txn_len = std_reg(8); - - // number of txns we want to occur before entire m_awwrite_channel is done - // this is internal to the channel (unlike txn_len) - txn_n = std_const(32,1); - txn_count = std_reg(32); - perform_write_txns = std_neq(32); - txn_adder = std_add(32); - - //"block_transfer" register. need to put into a reg to avoid combinational loops - bt_reg = std_reg(1); - - - } - - wires{ - - AWVALID = is_awvalid.out; - - group deassert_val { - is_awvalid.in = 1'b0; - is_awvalid.write_en = 1'b1; - deassert_val[done] = is_awvalid.done; - } - - group reset_bt { - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt[done] = bt_reg.done; - } - - // this asserts valid and defines all inputs correctly - // because valid should not be deasserted until handshake occurs - // this all needs to be one group - // this contains blocking logic previously in its own group - group do_aw_transfer { - //assert AWVALID - is_awvalid.in = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; - - // TODO(nathanielnrn): in theory should be able to get rid of awvalid_was_high - // but for now we will be explicit and reduce this in generation maybe. Not sure - // it even matters. - // This makes AWVALID go low after a single cycle. Without it it stays high for 2. - is_awvalid.in = is_awvalid.out & AWREADY & awvalid_was_high.out ? 1'b0; - is_awvalid.write_en = 1'b1; - - awvalid_was_high.in = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; - awvalid_was_high.write_en = !(is_awvalid.out & AWREADY) & !awvalid_was_high.out ? 1'b1; - - - // drive output signals for transfer - AWADDR = base_addr.out; - // see link above, needs to match data width to host. - // In this case 2^2 = 4 bytes = 32 bits = width of our data_bus. - AWSIZE = 3'b010; - // For now this can be taken from .yxi, as size of mem, because we are assuming - // data_bus width that matches size of memory cells - // If we want to use bigger mems need to be able to update base addr - AWLEN = txn_len.out; - AWBURST = 2'b01; //incr - // 3'b110 is [privileged access] [Non-secure access] [Data access]] - AWPROT = 3'b110; - - - // TODO(nathanielnrn): This is used to tell write_channel how many transfers to do - // we eventually want this to correspond to AWLEN - // (need a case statement or mux or something) - // for now hardcoding to 15 for 16 transfers - max_trnsfrs.in = 8'd15; - max_trnsfrs.write_en = 1'b1; - - //done when one cycle after handshake (handshake happens for a single cycle) - bt_reg.in = AWREADY & is_awvalid.out ? 1'b1; - bt_reg.in = !(AWREADY & is_awvalid.out) ? 1'b0; - bt_reg.write_en = 1'b1; - do_aw_transfer[done] = bt_reg.out; - } - - - //txn bookkeeping. - //We are done performing reads when txn_count == txn_n - group txn_count_init { - txn_count.in = 32'b0; - txn_count.write_en = 1'b1; - txn_count_init[done] = txn_count.done; - - } - - group txn_len_init { - //TODO(nathanielnrn): 15 is good for word wide data bus. We'd - //expect 16 transfers. Number of transfers that occur is AWLEN + 1 - txn_len.in = 8'd15; - txn_len.write_en = 1'b1; - txn_len_init[done] = txn_len.done; - } - - group txn_incr { - txn_adder.left = txn_count.out; - txn_adder.right = 32'b1; - txn_count.in = txn_adder.out; - txn_count.write_en = 1'b1; - txn_incr[done] = txn_count.done; - - } - - comb group check_writes_done { - perform_write_txns.left = txn_count.out; - perform_write_txns.right = txn_n.out; - } - } - - control{ - //XXX(nathanielnrn): What is best way to offer more flexiblity beyond just a counter? - seq{ - txn_count_init; - txn_len_init; - while perform_write_txns.out with check_writes_done{ - seq{ - reset_bt; - do_aw_transfer; - deassert_val; - txn_incr; - } - } - } - } -} - - - - -component m_write_channel( - ARESET : 1, - WREADY : 1, -) -> ( - WVALID : 1, - WLAST : 1, - WDATA : 32, -) { - cells { - // 16 is due to dot-product vector length assumption - // For this manual implementation we are just writing into this data based - // on the data we read from cocotb - ref internal_mem = seq_mem_d1(32, 16, 64); - wvalid = std_reg(1); - wvalid_was_high = std_reg(1); - // used internally to access our seq_mem_d1 - ref curr_addr = std_reg(64); - - //this increments - curr_trnsfr_count = std_reg(8); //between 0 and 255, add +1 for transfer count - //this is number of transfer we want to do - ref max_trnsfrs = std_reg(8); - - // registered because wlast is high with last transfer, not after - // before this was registered we were terminating immediately with - // last transfer and not servicing it. This is for while loop in control group - n_finished_last_trnsfr = std_reg(1); - - // TODO: get this width from yxi - //read_data_reg = std_reg(32); - - //used for address of seq_d1_mem we are reading from - curr_addr_adder = std_add(64); - curr_trnsfr_count_adder = std_add(8); - - - // block_transfer reg to avoid combinational loops - bt_reg = std_reg(1); - - - - //write init stuff TODO: delete this - n_init_done = std_reg(1); - curr_addr_slice = std_slice(64,32); - - } - wires{ - - WVALID = wvalid.out; - //internal_mem.write_en = 1'b0; - - - - //stuff for initialization - group reset_curr_addr{ - curr_addr.in = 64'b0; - curr_addr.write_en = 1'b1; - reset_curr_addr[done] = curr_addr.done; - } - - group write_to_internal{ - internal_mem.content_en = 1'b0; - internal_mem.write_en = 1'b1; - internal_mem.addr0 = curr_addr.out; - - curr_addr_slice.in = curr_addr.out; - internal_mem.write_data = curr_addr_slice.out; - write_to_internal[done] = internal_mem.done; - } - - group check_if_writes_done{ - n_init_done.in = curr_addr.out == 64'd16 ? 1'b0; - n_init_done.in = !(curr_addr.out == 64'd16) ? 1'b1; - n_init_done.write_en = 1'b1; - check_if_writes_done[done] = n_init_done.done; - } - - group init_done{ - n_init_done.in = 1'b1; - n_init_done.write_en = 1'b1; - init_done[done] = n_init_done.done; - } - //end stuff for initialization - - - group init_n_finished_last_trnsfr { - n_finished_last_trnsfr.in = 1'b1; - n_finished_last_trnsfr.write_en = 1'b1; - init_n_finished_last_trnsfr[done] = n_finished_last_trnsfr.done; - } - - //Used to block any servicing until handshake occurs. - group reset_bt { - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt[done] = bt_reg.done; - } - - //NOTE: xVALID signals must be high until xREADY is high as well, so this works - //because if xREADY is high (is_rdy.out) then RVALID being high makes 1 flip - //and group will be done by bt_reg.out - group do_write_transfer { - //set RREADY high - //TODO (nathanielnrn): technically we can make RREADY depend on on RVALID (but not vice versa). - //Could we simplify this we just making things ready when we are in - //block_transfer && RVALID? - - //NOTE: is_rdy.in = 1'b1; does not work, it leaves RREADY high for 2 cycles - // this both asserts and deasserts one cycle later - wvalid.in = !(wvalid.out & WREADY & wvalid_was_high.out) ? 1'b1; - // TODO(nathanielnrn): Can prob get rid of wvalid_was_high - wvalid.in = wvalid.out & WREADY & wvalid_was_high.out ? 1'b0; - wvalid.write_en = 1'b1; - - //set to 1 after valid has been high even once - wvalid_was_high.in = 1'b1; - wvalid_was_high.write_en = !(wvalid.out & WREADY) & !wvalid_was_high.out ? 1'b1; - - - // set data output based on curr_addr register - internal_mem.addr0 = curr_addr.out; - internal_mem.content_en = 1'b1; - WDATA = internal_mem.read_data; - - //set wlast - WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; - WLAST = max_trnsfrs.out == curr_trnsfr_count.out ? 1'b1; - - //set high only when WLAST is high and a handshake occurs. - n_finished_last_trnsfr.in = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b0; - n_finished_last_trnsfr.write_en = (max_trnsfrs.out == curr_trnsfr_count.out) & wvalid.out & WREADY ? 1'b1; - - - - // we are done after handshake - bt_reg.in = wvalid.out & WREADY ? 1'b1; - bt_reg.in = !(wvalid.out & WREADY) ? 1'b0; - bt_reg.write_en = 1'b1; - do_write_transfer[done] = bt_reg.out; - } - - group incr_curr_addr{ - curr_addr_adder.left = 64'd1 ; - curr_addr_adder.right = curr_addr.out; - curr_addr.in = curr_addr_adder.out; - curr_addr.write_en = 1'b1; - incr_curr_addr[done] = curr_addr.done; - } - - group incr_curr_trnsfr_count { - curr_trnsfr_count_adder.left = 8'd1; - curr_trnsfr_count_adder.right = curr_trnsfr_count.out; - curr_trnsfr_count.in = curr_trnsfr_count_adder.out; - curr_trnsfr_count.write_en = 1'b1; - incr_curr_trnsfr_count[done] = curr_trnsfr_count.done; - } - - } - control{ - seq{ - - //done for writing to internal mem - init_done; - reset_curr_addr; - while n_init_done.out { - seq{ - write_to_internal; - incr_curr_addr; - check_if_writes_done; - } - } - //end writing to internal mem - reset_curr_addr; - init_n_finished_last_trnsfr; - while n_finished_last_trnsfr.out{ - seq{ - reset_bt; - do_write_transfer; - par{ - incr_curr_addr; - incr_curr_trnsfr_count; - } - } - } - } - } -} - - -//We assume that all responses are OKAY because we dont have any error handling. -//So basically this just sets BREADY high then lowers it -component m_bresp_channel( - ARESET : 1, - BVALID : 1, - // We assume all writes are valid. - //BRESP : 2, -) -> ( - // NOTE: In general, according to ZipCPU we want xREADY signals to be registered - // because (IIRC) it helps avoid combinational loops between READY and VALID. - BREADY : 1, -) { - cells{ - bready = std_reg(1); - bt_reg = std_reg(1); - - } - wires{ - BREADY = bready.out; - group reset_bt_reg{ - bt_reg.in = 1'b0; - bt_reg.write_en = 1'b1; - reset_bt_reg[done] = bt_reg.done; - } - - // TODO(nathanielnrn): This is probably very unoptimal and takes multiple - // cycles to simply do a handshake. Can probably be much better - group block_transfer{ - bready.in = !(BVALID & bready.out) ? 1'b1; - bready.in = BVALID & bready.out ? 1'b0; - bready.write_en = 1'b1; - - bt_reg.in = bready.out & BVALID ? 1'b1; - bt_reg.in = !(bready.out & BVALID) ? 1'b0; - bt_reg.write_en = 1'b1; - block_transfer[done] = bt_reg.out; - } - - } - control{ - seq{ - reset_bt_reg; - block_transfer; - } - } -} - - - -//TODO(nathanielnrn): this is axi_wrapper, prefer to use @toplevel attribute but its not working -// See individual channel components for explanations of signals -component main( - m_ARESET : 1, - m_AWREADY : 1, - - m_WRESP : 2, - m_WREADY : 1, - - m_BVALID : 1, - // Used only for waveform tracing. Not sent anywhere - // Note this AXI4 has this at 2 bits, while latest has it at 3. - m_BRESP : 2, -) -> ( - - m_AWVALID : 1, - m_AWADDR: 64, - m_AWSIZE: 3, - m_AWLEN : 8, - m_AWBURST : 2, - m_AWPROT : 3, - - m_WVALID : 1, - m_WLAST : 1, - m_WDATA : 32, - - m_BREADY : 1, - //NOTE: Only used for cocotb compatability, doesn't do anything within the wrapper itself currently. - m_AWID : 1, - m_WID : 1, - m_BID : 1, -) { - cells{ - vec1_data = seq_mem_d1(32,16,64); - output_data = seq_mem_d1(32,1,0); - - curr_addr = std_reg(64); - base_addr = std_reg(64); - - max_trnsfrs = std_reg(8); - - awwrite_channel = m_awwrite_channel(); - write_channel = m_write_channel(); - bresp_channel = m_bresp_channel(); - - } - - wires{ - - m_AWID = 1'b0; - m_WID = 1'b0; - m_BID = 1'b0; - - group set_curr_to_base_addr{ - curr_addr.in = base_addr.out; - curr_addr.write_en = 1'b1; - set_curr_to_base_addr[done] = curr_addr.done; - } - } - control{ - seq{ - invoke awwrite_channel[base_addr = base_addr, max_trnsfrs = max_trnsfrs] - ( - ARESET = m_ARESET, - AWREADY = m_AWREADY - ) - ( - AWVALID = m_AWVALID, - AWADDR = m_AWADDR, - AWSIZE = m_AWSIZE, - AWLEN = m_AWLEN, - AWBURST = m_AWBURST, - AWPROT = m_AWPROT - ); - - set_curr_to_base_addr; - - invoke write_channel[internal_mem = vec1_data, curr_addr = curr_addr, max_trnsfrs = max_trnsfrs] - ( - ARESET = m_ARESET, - WREADY = m_WREADY - ) - ( - WVALID = m_WVALID, - WLAST = m_WLAST, - WDATA = m_WDATA - ); - - invoke bresp_channel - ( - BVALID = m_BVALID - ) - ( - BREADY = m_BREADY - ); - } - } - - -} diff --git a/yxi/axi-calyx/cocotb/Makefile b/yxi/axi-calyx/cocotb/Makefile index dc468c6d5b..9d376e0712 100644 --- a/yxi/axi-calyx/cocotb/Makefile +++ b/yxi/axi-calyx/cocotb/Makefile @@ -7,13 +7,13 @@ TOPLEVEL_LANG ?= verilog #Needed to extract desired test from runt invocation -VERILOG_SOURCES += $(PWD)/../outputs/axi-combined.v +VERILOG_SOURCES += $(PWD)/../outputs/generated-axi-with-vec-add.v #Defines build directory, if left to default only a single computation is run SIM_BUILD=sim_build/axi-combined # TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file -TOPLEVEL = main +TOPLEVEL = wrapper # MODULE is the basename of the Python test file MODULE = axi-combined-tests diff --git a/yxi/axi-calyx/cocotb/axi-combined-tests.py b/yxi/axi-calyx/cocotb/axi-combined-tests.py index f99782174e..978d6e44e0 100644 --- a/yxi/axi-calyx/cocotb/axi-combined-tests.py +++ b/yxi/axi-calyx/cocotb/axi-combined-tests.py @@ -20,9 +20,9 @@ async def read_channels_happy_path(main): B0_in = [126, 62, 30, 14, 6, 2, 0, 1] expected_sum = [A0_in[i] + B0_in[i] for i in range(len(B0_in))] await run_module(main, A0_in, B0_in, expected_sum) # checks cocotb axi rams - await assert_mem_content(main.A0, A0_in) # checks in verilog module, as opposed to axiram - await assert_mem_content(main.B0, B0_in) - await assert_mem_content(main.Sum0, expected_sum) + await assert_mem_content(main.internal_mem_A0, A0_in) # checks in verilog module, as opposed to axiram + await assert_mem_content(main.internal_mem_B0, B0_in) + await assert_mem_content(main.internal_mem_Sum0, expected_sum) # Adding extra data to backing mmap does not ruin reading of 8 elements and writing them correctly. @@ -43,9 +43,9 @@ async def read_channels_extra_mmap_data(main): expected_sum = [A0_in[i] + B0_in[i] for i in range(len(B0_in))] await run_module(main, A0_in, B0_in, expected_sum) - await assert_mem_content(main.Sum0, expected_sum[0:8]) - await assert_mem_content(main.A0, A0_in[0:8]) - await assert_mem_content(main.B0, B0_in[0:8]) + await assert_mem_content(main.internal_mem_Sum0, expected_sum[0:8]) + await assert_mem_content(main.internal_mem_A0, A0_in[0:8]) + await assert_mem_content(main.internal_mem_B0, B0_in[0:8]) ################## @@ -117,7 +117,7 @@ async def run_module( A0 = AxiRam( # NOTE: prefix should not contain the final "_" - AxiBus.from_prefix(module, "m0"), + AxiBus.from_prefix(module, "A0"), module.clk, module.reset, # size in bytes @@ -127,7 +127,7 @@ async def run_module( B0 = AxiRam( # NOTE: prefix should not contain the final "_" - AxiBus.from_prefix(module, "m1"), + AxiBus.from_prefix(module, "B0"), module.clk, module.reset, # size in bytes @@ -137,7 +137,7 @@ async def run_module( Sum0 = AxiRam( # NOTE: prefix should not contain the final "_" - AxiBus.from_prefix(module, "m2"), + AxiBus.from_prefix(module, "Sum0"), module.clk, module.reset, # size in bytes @@ -176,9 +176,9 @@ async def run_module( await assert_axi_ram_content(Sum0, Sum0_expected[0:8], base_address) if debug: - print(f"A0 is: {module.A0.mem.value}") - print(f"B0 is: {module.B0.mem.value}") - print(f"Sum0 is: {module.Sum0.mem.value}") + print(f"A0 is: {module.internal_mem_A0.mem.value}") + print(f"B0 is: {module.internal_mem_B0.mem.value}") + print(f"Sum0 is: {module.internal_mem_Sum0.mem.value}") # TODO(nathanielnrn): Decide between these and xilinx cocotb tests, refactor out diff --git a/yxi/axi-calyx/cocotb/sim.sh b/yxi/axi-calyx/cocotb/sim.sh index 1e991788f6..be403506ae 100644 --- a/yxi/axi-calyx/cocotb/sim.sh +++ b/yxi/axi-calyx/cocotb/sim.sh @@ -2,7 +2,7 @@ # Intended to convert from calyx to synthesizable verilog, enable waveform tracing and run tests defined in Makefile #expects an outputs/ dir one level up from here -fud e ../axi-combined-calyx.futil --from calyx --to synth-verilog -o ../outputs/axi-combined.v \ - && ../vcdump.py ../outputs/axi-combined.v \ +fud e ../generated-axi-with-vec-add.futil --from calyx --to synth-verilog -o ../outputs/generated-axi-with-vec-add.v \ + && ../vcdump.py ../outputs/generated-axi-with-vec-add.v \ && make WAVES=1 \ - && mv out.vcd axi-combined.fst + && mv out.vcd generated-axi-with-vec-add.fst diff --git a/yxi/axi-calyx/fixed-vec-add.futil b/yxi/axi-calyx/fixed-vec-add.futil new file mode 100644 index 0000000000..fae769cff9 --- /dev/null +++ b/yxi/axi-calyx/fixed-vec-add.futil @@ -0,0 +1,77 @@ +component main() -> () { + cells { + //Modified to 64 width address because XRT expects 64 bit memory addresses + ref A0 = seq_mem_d1(32,8,3); + A_read0_0 = std_reg(32); + ref B0 = seq_mem_d1(32,8,3); + B_read0_0 = std_reg(32); + ref Sum0 = seq_mem_d1(32,8,3); + add0 = std_add(32); + add1 = std_add(4); + const0 = std_const(4,0); + const1 = std_const(4,7); + const2 = std_const(4,1); + i0 = std_reg(4); + le0 = std_le(4); + bit_slice = std_bit_slice(4,0,2,3); + } + wires { + + bit_slice.in = i0.out; + comb group cond0 { + le0.left = i0.out; + le0.right = const1.out; + } + group let0<"static"=1> { + i0.in = const0.out; + i0.write_en = 1'd1; + let0[done] = i0.done; + } + //modified upd0 and upd1 to use seq_mem correctly + group upd0<"static"=2> { + A_read0_0.write_en = A0.read_done; + A0.addr0 = bit_slice.out; + A0.read_en = 1'b1; + A_read0_0.in = 1'd1 ? A0.read_data; + upd0[done] = A_read0_0.done ? 1'd1; + } + //see comment for upd0 + group upd1<"static"=2> { + B_read0_0.write_en = B0.read_done; + B0.addr0 = bit_slice.out; + B0.read_en = 1'b1; + B_read0_0.in = 1'd1 ? B0.read_data; + upd1[done] = B_read0_0.done ? 1'd1; + } + group upd2<"static"=1> { + Sum0.addr0 = bit_slice.out; + Sum0.write_en = 1'd1; + add0.left = B_read0_0.out; + add0.right = A_read0_0.out; + Sum0.write_data = 1'd1 ? add0.out; + upd2[done] = Sum0.write_done ? 1'd1; + } + group upd3<"static"=1> { + i0.write_en = 1'd1; + add1.left = i0.out; + add1.right = const2.out; + i0.in = 1'd1 ? add1.out; + upd3[done] = i0.done ? 1'd1; + } + } + control { + seq { + let0; + while le0.out with cond0 { + seq { + par { + upd0; + upd1; + } + upd2; + upd3; + } + } + } + } +} diff --git a/yxi/axi-calyx/generated-axi-with-vec-add.futil b/yxi/axi-calyx/generated-axi-with-vec-add.futil new file mode 100644 index 0000000000..d071e1fd85 --- /dev/null +++ b/yxi/axi-calyx/generated-axi-with-vec-add.futil @@ -0,0 +1,470 @@ +import "primitives/core.futil"; +import "primitives/binary_operators.futil"; +import "primitives/memories/seq.futil"; +component m_ar_channel(ARESETn: 1, ARREADY: 1) -> (ARVALID: 1, ARADDR: 64, ARSIZE: 3, ARLEN: 8, ARBURST: 2, ARPROT: 3) { + cells { + arvalid = std_reg(1); + ar_handshake_occurred = std_reg(1); + ref curr_addr_axi = std_reg(64); + arlen = std_reg(8); + txn_n = std_const(32, 1); + txn_count = std_reg(32); + txn_adder = std_add(32); + bt_reg = std_reg(1); + perform_reads = std_neq(32); + } + wires { + ARVALID = arvalid.out; + group do_ar_transfer { + arvalid.in = (!(arvalid.out & ARREADY) & !ar_handshake_occurred.out) ? 1'd1; + arvalid.in = ((arvalid.out & ARREADY) | ar_handshake_occurred.out) ? 1'd0; + arvalid.write_en = 1'd1; + ar_handshake_occurred.in = (arvalid.out & ARREADY) ? 1'd1; + ar_handshake_occurred.write_en = !ar_handshake_occurred.out ? 1'd1; + ARADDR = curr_addr_axi.out; + ARSIZE = 3'd2; + ARLEN = arlen.out; + ARBURST = 2'd1; + ARPROT = 3'd6; + bt_reg.in = (ARREADY & arvalid.out) ? 1'd1; + bt_reg.in = !(ARREADY & arvalid.out) ? 1'd0; + bt_reg.write_en = 1'd1; + do_ar_transfer[done] = bt_reg.out; + } + group incr_txn_count { + txn_adder.left = txn_count.out; + txn_adder.right = 32'd1; + txn_count.in = txn_adder.out; + txn_count.write_en = 1'd1; + incr_txn_count[done] = txn_count.done; + } + comb group perform_reads_group { + perform_reads.left = txn_count.out; + perform_reads.right = txn_n.out; + } + } + control { + seq { + invoke txn_count(in=32'd0)(); + invoke arlen(in=8'd7)(); + while perform_reads.out with perform_reads_group { + seq { + par { + invoke bt_reg(in=1'd0)(); + invoke ar_handshake_occurred(in=1'd0)(); + } + do_ar_transfer; + invoke arvalid(in=1'd0)(); + incr_txn_count; + } + } + } + } +} +component m_aw_channel(ARESETn: 1, AWREADY: 1) -> (AWVALID: 1, AWADDR: 64, AWSIZE: 3, AWLEN: 8, AWBURST: 2, AWPROT: 3) { + cells { + awvalid = std_reg(1); + aw_handshake_occurred = std_reg(1); + ref curr_addr_axi = std_reg(64); + awlen = std_reg(8); + txn_n = std_const(32, 1); + txn_count = std_reg(32); + txn_adder = std_add(32); + bt_reg = std_reg(1); + perform_writes = std_neq(32); + ref max_transfers = std_reg(8); + } + wires { + AWVALID = awvalid.out; + group do_aw_transfer { + awvalid.in = (!(awvalid.out & AWREADY) & !aw_handshake_occurred.out) ? 1'd1; + awvalid.in = ((awvalid.out & AWREADY) | aw_handshake_occurred.out) ? 1'd0; + awvalid.write_en = 1'd1; + aw_handshake_occurred.in = (awvalid.out & AWREADY) ? 1'd1; + aw_handshake_occurred.write_en = !aw_handshake_occurred.out ? 1'd1; + AWADDR = curr_addr_axi.out; + AWSIZE = 3'd2; + AWLEN = awlen.out; + AWBURST = 2'd1; + AWPROT = 3'd6; + bt_reg.in = (AWREADY & awvalid.out) ? 1'd1; + bt_reg.in = !(AWREADY & awvalid.out) ? 1'd0; + bt_reg.write_en = 1'd1; + do_aw_transfer[done] = bt_reg.out; + max_transfers.in = 8'd7; + max_transfers.write_en = 1'd1; + } + group incr_txn_count { + txn_adder.left = txn_count.out; + txn_adder.right = 32'd1; + txn_count.in = txn_adder.out; + txn_count.write_en = 1'd1; + incr_txn_count[done] = txn_count.done; + } + comb group perform_writes_group { + perform_writes.left = txn_count.out; + perform_writes.right = txn_n.out; + } + } + control { + seq { + invoke txn_count(in=32'd0)(); + invoke awlen(in=8'd7)(); + while perform_writes.out with perform_writes_group { + seq { + par { + invoke bt_reg(in=1'd0)(); + invoke aw_handshake_occurred(in=1'd0)(); + } + do_aw_transfer; + invoke awvalid(in=1'd0)(); + incr_txn_count; + } + } + } + } +} +component m_read_channel(ARESETn: 1, RVALID: 1, RLAST: 1, RDATA: 32, RRESP: 2) -> (RREADY: 1) { + cells { + ref mem_ref = seq_mem_d1(32, 8, 3); + rready = std_reg(1); + ref curr_addr_internal_mem = std_reg(3); + ref curr_addr_axi = std_reg(64); + n_RLAST = std_reg(1); + read_data_reg = std_reg(32); + bt_reg = std_reg(1); + curr_addr_internal_mem_incr = std_add(3); + curr_addr_axi_incr = std_add(64); + } + wires { + RREADY = rready.out; + mem_ref.read_en = 1'd0; + group block_transfer { + rready.in = !(rready.out & RVALID) ? 1'd1; + rready.in = (rready.out & RVALID) ? 1'd0; + rready.write_en = 1'd1; + read_data_reg.in = RDATA; + read_data_reg.write_en = (rready.out & RVALID) ? 1'd1; + read_data_reg.write_en = !(rready.out & RVALID) ? 1'd0; + n_RLAST.in = RLAST ? 1'd0; + n_RLAST.in = !RLAST ? 1'd1; + n_RLAST.write_en = 1'd1; + bt_reg.in = (rready.out & RVALID) ? 1'd1; + bt_reg.in = !(rready.out & RVALID) ? 1'd0; + bt_reg.write_en = 1'd1; + block_transfer[done] = bt_reg.out; + } + group service_read_transfer { + rready.in = 1'd0; + rready.write_en = 1'd1; + mem_ref.addr0 = curr_addr_internal_mem.out; + mem_ref.write_data = read_data_reg.out; + mem_ref.write_en = 1'd1; + service_read_transfer[done] = mem_ref.write_done; + } + group curr_addr_internal_mem_incr_group { + curr_addr_internal_mem_incr.left = curr_addr_internal_mem.out; + curr_addr_internal_mem_incr.right = 3'd1; + curr_addr_internal_mem.write_en = 1'd1; + curr_addr_internal_mem.in = curr_addr_internal_mem_incr.out; + curr_addr_internal_mem_incr_group[done] = curr_addr_internal_mem.done; + } + group curr_addr_axi_incr_group { + curr_addr_axi_incr.left = curr_addr_axi.out; + curr_addr_axi_incr.right = 64'd4; + curr_addr_axi.write_en = 1'd1; + curr_addr_axi.in = curr_addr_axi_incr.out; + curr_addr_axi_incr_group[done] = curr_addr_axi.done; + } + } + control { + seq { + invoke n_RLAST(in=1'd1)(); + while n_RLAST.out { + seq { + invoke bt_reg(in=1'd0)(); + block_transfer; + service_read_transfer; + par { + curr_addr_internal_mem_incr_group; + curr_addr_axi_incr_group; + } + } + } + } + } +} +component m_write_channel(ARESETn: 1, WREADY: 1) -> (WVALID: 1, WLAST: 1, WDATA: 32) { + cells { + ref mem_ref = seq_mem_d1(32, 8, 3); + wvalid = std_reg(1); + w_handshake_occurred = std_reg(1); + ref curr_addr_internal_mem = std_reg(3); + ref curr_addr_axi = std_reg(64); + curr_trsnfr_count = std_reg(8); + ref max_transfers = std_reg(8); + n_finished_last_trnsfr = std_reg(1); + bt_reg = std_reg(1); + curr_addr_internal_mem_incr = std_add(3); + curr_addr_axi_incr = std_add(64); + curr_trsnfr_count_incr = std_add(8); + } + wires { + WVALID = wvalid.out; + group service_write_transfer { + wvalid.in = (!(wvalid.out & WREADY) & !w_handshake_occurred.out) ? 1'd1; + wvalid.in = ((wvalid.out & WREADY) | w_handshake_occurred.out) ? 1'd0; + wvalid.write_en = 1'd1; + w_handshake_occurred.in = (wvalid.out & WREADY) ? 1'd1; + w_handshake_occurred.write_en = !w_handshake_occurred.out ? 1'd1; + mem_ref.addr0 = curr_addr_internal_mem.out; + mem_ref.read_en = 1'd1; + WDATA = mem_ref.read_data; + WLAST = (max_transfers.out == curr_trsnfr_count.out) ? 1'd1; + WLAST = (max_transfers.out != curr_trsnfr_count.out) ? 1'd0; + n_finished_last_trnsfr.in = ((max_transfers.out == curr_trsnfr_count.out) & (wvalid.out & WREADY)) ? 1'd0; + n_finished_last_trnsfr.write_en = ((max_transfers.out == curr_trsnfr_count.out) & (wvalid.out & WREADY)) ? 1'd1; + bt_reg.in = (wvalid.out & WREADY) ? 1'd1; + bt_reg.in = !(wvalid.out & WREADY) ? 1'd0; + bt_reg.write_en = 1'd1; + service_write_transfer[done] = bt_reg.out; + } + group curr_addr_internal_mem_incr_group { + curr_addr_internal_mem_incr.left = curr_addr_internal_mem.out; + curr_addr_internal_mem_incr.right = 3'd1; + curr_addr_internal_mem.write_en = 1'd1; + curr_addr_internal_mem.in = curr_addr_internal_mem_incr.out; + curr_addr_internal_mem_incr_group[done] = curr_addr_internal_mem.done; + } + group curr_addr_axi_incr_group { + curr_addr_axi_incr.left = curr_addr_axi.out; + curr_addr_axi_incr.right = 64'd4; + curr_addr_axi.write_en = 1'd1; + curr_addr_axi.in = curr_addr_axi_incr.out; + curr_addr_axi_incr_group[done] = curr_addr_axi.done; + } + group curr_trsnfr_count_incr_group { + curr_trsnfr_count_incr.left = curr_trsnfr_count.out; + curr_trsnfr_count_incr.right = 8'd1; + curr_trsnfr_count.write_en = 1'd1; + curr_trsnfr_count.in = curr_trsnfr_count_incr.out; + curr_trsnfr_count_incr_group[done] = curr_trsnfr_count.done; + } + } + control { + seq { + invoke curr_addr_internal_mem(in=3'd0)(); + invoke n_finished_last_trnsfr(in=1'd1)(); + while n_finished_last_trnsfr.out { + seq { + invoke bt_reg(in=1'd0)(); + service_write_transfer; + par { + curr_addr_internal_mem_incr_group; + curr_trsnfr_count_incr_group; + curr_addr_axi_incr_group; + invoke w_handshake_occurred(in=1'd0)(); + } + } + } + } + } +} +component m_bresp_channel(ARESETn: 1, BVALID: 1) -> (BREADY: 1) { + cells { + bready = std_reg(1); + bt_reg = std_reg(1); + } + wires { + BREADY = bready.out; + group block_transfer { + bready.in = !(bready.out & BVALID) ? 1'd1; + bready.in = (bready.out & BVALID) ? 1'd0; + bready.write_en = 1'd1; + bt_reg.in = (bready.out & BVALID) ? 1'd1; + bt_reg.in = !(bready.out & BVALID) ? 1'd0; + bt_reg.write_en = 1'd1; + block_transfer[done] = bt_reg.out; + } + } + control { + seq { + invoke bt_reg(in=1'd0)(); + block_transfer; + } + } +} +component wrapper<"toplevel"=1>(A0_ARESETn: 1, A0_ARREADY: 1, A0_RVALID: 1, A0_RLAST: 1, A0_RDATA: 32, A0_RRESP: 2, A0_AWREADY: 1, A0_WRESP: 2, A0_WREADY: 1, A0_BVALID: 1, A0_BRESP: 2, A0_RID: 1, B0_ARESETn: 1, B0_ARREADY: 1, B0_RVALID: 1, B0_RLAST: 1, B0_RDATA: 32, B0_RRESP: 2, B0_AWREADY: 1, B0_WRESP: 2, B0_WREADY: 1, B0_BVALID: 1, B0_BRESP: 2, B0_RID: 1, Sum0_ARESETn: 1, Sum0_ARREADY: 1, Sum0_RVALID: 1, Sum0_RLAST: 1, Sum0_RDATA: 32, Sum0_RRESP: 2, Sum0_AWREADY: 1, Sum0_WRESP: 2, Sum0_WREADY: 1, Sum0_BVALID: 1, Sum0_BRESP: 2, Sum0_RID: 1) -> (A0_ARVALID: 1, A0_ARADDR: 64, A0_ARSIZE: 3, A0_ARLEN: 8, A0_ARBURST: 2, A0_RREADY: 1, A0_AWVALID: 1, A0_AWADDR: 64, A0_AWSIZE: 3, A0_AWLEN: 8, A0_AWBURST: 2, A0_AWPROT: 3, A0_WVALID: 1, A0_WLAST: 1, A0_WDATA: 32, A0_BREADY: 1, A0_ARID: 1, A0_AWID: 1, A0_WID: 1, A0_BID: 1, B0_ARVALID: 1, B0_ARADDR: 64, B0_ARSIZE: 3, B0_ARLEN: 8, B0_ARBURST: 2, B0_RREADY: 1, B0_AWVALID: 1, B0_AWADDR: 64, B0_AWSIZE: 3, B0_AWLEN: 8, B0_AWBURST: 2, B0_AWPROT: 3, B0_WVALID: 1, B0_WLAST: 1, B0_WDATA: 32, B0_BREADY: 1, B0_ARID: 1, B0_AWID: 1, B0_WID: 1, B0_BID: 1, Sum0_ARVALID: 1, Sum0_ARADDR: 64, Sum0_ARSIZE: 3, Sum0_ARLEN: 8, Sum0_ARBURST: 2, Sum0_RREADY: 1, Sum0_AWVALID: 1, Sum0_AWADDR: 64, Sum0_AWSIZE: 3, Sum0_AWLEN: 8, Sum0_AWBURST: 2, Sum0_AWPROT: 3, Sum0_WVALID: 1, Sum0_WLAST: 1, Sum0_WDATA: 32, Sum0_BREADY: 1, Sum0_ARID: 1, Sum0_AWID: 1, Sum0_WID: 1, Sum0_BID: 1) { + cells { + main_compute = main(); + curr_addr_internal_mem_A0 = std_reg(3); + curr_addr_axi_A0 = std_reg(64); + ar_channel_A0 = m_ar_channel(); + read_channel_A0 = m_read_channel(); + internal_mem_A0 = seq_mem_d1(32, 8, 3); + max_transfers_A0 = std_reg(8); + aw_channel_A0 = m_aw_channel(); + write_channel_A0 = m_write_channel(); + bresp_channel_A0 = m_bresp_channel(); + curr_addr_internal_mem_B0 = std_reg(3); + curr_addr_axi_B0 = std_reg(64); + ar_channel_B0 = m_ar_channel(); + read_channel_B0 = m_read_channel(); + internal_mem_B0 = seq_mem_d1(32, 8, 3); + max_transfers_B0 = std_reg(8); + aw_channel_B0 = m_aw_channel(); + write_channel_B0 = m_write_channel(); + bresp_channel_B0 = m_bresp_channel(); + curr_addr_internal_mem_Sum0 = std_reg(3); + curr_addr_axi_Sum0 = std_reg(64); + ar_channel_Sum0 = m_ar_channel(); + read_channel_Sum0 = m_read_channel(); + internal_mem_Sum0 = seq_mem_d1(32, 8, 3); + max_transfers_Sum0 = std_reg(8); + aw_channel_Sum0 = m_aw_channel(); + write_channel_Sum0 = m_write_channel(); + bresp_channel_Sum0 = m_bresp_channel(); + } + wires { + A0_ARID = 1'd0; + A0_AWID = 1'd0; + A0_WID = 1'd0; + A0_BID = 1'd0; + B0_ARID = 1'd0; + B0_AWID = 1'd0; + B0_WID = 1'd0; + B0_BID = 1'd0; + Sum0_ARID = 1'd0; + Sum0_AWID = 1'd0; + Sum0_WID = 1'd0; + Sum0_BID = 1'd0; + } + control { + seq { + par { + invoke curr_addr_axi_A0(in=64'd4096)(); + invoke curr_addr_axi_B0(in=64'd4096)(); + invoke curr_addr_axi_Sum0(in=64'd4096)(); + } + par { + invoke curr_addr_internal_mem_A0(in=3'd0)(); + invoke curr_addr_internal_mem_B0(in=3'd0)(); + invoke curr_addr_internal_mem_Sum0(in=3'd0)(); + } + par { + seq { + invoke ar_channel_A0[curr_addr_axi=curr_addr_axi_A0](ARESETn=A0_ARESETn, ARREADY=A0_ARREADY)(ARVALID=A0_ARVALID, ARADDR=A0_ARADDR, ARSIZE=A0_ARSIZE, ARLEN=A0_ARLEN, ARBURST=A0_ARBURST); + invoke read_channel_A0[mem_ref=internal_mem_A0, curr_addr_internal_mem=curr_addr_internal_mem_A0, curr_addr_axi=curr_addr_axi_A0](ARESETn=A0_ARESETn, RVALID=A0_RVALID, RLAST=A0_RLAST, RDATA=A0_RDATA, RRESP=A0_RRESP)(RREADY=A0_RREADY); + } + seq { + invoke ar_channel_B0[curr_addr_axi=curr_addr_axi_B0](ARESETn=B0_ARESETn, ARREADY=B0_ARREADY)(ARVALID=B0_ARVALID, ARADDR=B0_ARADDR, ARSIZE=B0_ARSIZE, ARLEN=B0_ARLEN, ARBURST=B0_ARBURST); + invoke read_channel_B0[mem_ref=internal_mem_B0, curr_addr_internal_mem=curr_addr_internal_mem_B0, curr_addr_axi=curr_addr_axi_B0](ARESETn=B0_ARESETn, RVALID=B0_RVALID, RLAST=B0_RLAST, RDATA=B0_RDATA, RRESP=B0_RRESP)(RREADY=B0_RREADY); + } + seq { + invoke ar_channel_Sum0[curr_addr_axi=curr_addr_axi_Sum0](ARESETn=Sum0_ARESETn, ARREADY=Sum0_ARREADY)(ARVALID=Sum0_ARVALID, ARADDR=Sum0_ARADDR, ARSIZE=Sum0_ARSIZE, ARLEN=Sum0_ARLEN, ARBURST=Sum0_ARBURST); + invoke read_channel_Sum0[mem_ref=internal_mem_Sum0, curr_addr_internal_mem=curr_addr_internal_mem_Sum0, curr_addr_axi=curr_addr_axi_Sum0](ARESETn=Sum0_ARESETn, RVALID=Sum0_RVALID, RLAST=Sum0_RLAST, RDATA=Sum0_RDATA, RRESP=Sum0_RRESP)(RREADY=Sum0_RREADY); + } + } + invoke main_compute[A0=internal_mem_A0, B0=internal_mem_B0, Sum0=internal_mem_Sum0]()(); + par { + invoke curr_addr_axi_A0(in=64'd4096)(); + invoke curr_addr_axi_B0(in=64'd4096)(); + invoke curr_addr_axi_Sum0(in=64'd4096)(); + } + par { + seq { + invoke aw_channel_A0[curr_addr_axi=curr_addr_axi_A0, max_transfers=max_transfers_A0](ARESETn=A0_ARESETn, AWREADY=A0_AWREADY)(AWVALID=A0_AWVALID, AWADDR=A0_AWADDR, AWSIZE=A0_AWSIZE, AWLEN=A0_AWLEN, AWBURST=A0_AWBURST, AWPROT=A0_AWPROT); + invoke write_channel_A0[mem_ref=internal_mem_A0, curr_addr_internal_mem=curr_addr_internal_mem_A0, curr_addr_axi=curr_addr_axi_A0, max_transfers=max_transfers_A0](ARESETn=A0_ARESETn, WREADY=A0_WREADY)(WVALID=A0_WVALID, WLAST=A0_WLAST, WDATA=A0_WDATA); + invoke bresp_channel_A0(BVALID=A0_BVALID)(BREADY=A0_BREADY); + } + seq { + invoke aw_channel_B0[curr_addr_axi=curr_addr_axi_B0, max_transfers=max_transfers_B0](ARESETn=B0_ARESETn, AWREADY=B0_AWREADY)(AWVALID=B0_AWVALID, AWADDR=B0_AWADDR, AWSIZE=B0_AWSIZE, AWLEN=B0_AWLEN, AWBURST=B0_AWBURST, AWPROT=B0_AWPROT); + invoke write_channel_B0[mem_ref=internal_mem_B0, curr_addr_internal_mem=curr_addr_internal_mem_B0, curr_addr_axi=curr_addr_axi_B0, max_transfers=max_transfers_B0](ARESETn=B0_ARESETn, WREADY=B0_WREADY)(WVALID=B0_WVALID, WLAST=B0_WLAST, WDATA=B0_WDATA); + invoke bresp_channel_B0(BVALID=B0_BVALID)(BREADY=B0_BREADY); + } + seq { + invoke aw_channel_Sum0[curr_addr_axi=curr_addr_axi_Sum0, max_transfers=max_transfers_Sum0](ARESETn=Sum0_ARESETn, AWREADY=Sum0_AWREADY)(AWVALID=Sum0_AWVALID, AWADDR=Sum0_AWADDR, AWSIZE=Sum0_AWSIZE, AWLEN=Sum0_AWLEN, AWBURST=Sum0_AWBURST, AWPROT=Sum0_AWPROT); + invoke write_channel_Sum0[mem_ref=internal_mem_Sum0, curr_addr_internal_mem=curr_addr_internal_mem_Sum0, curr_addr_axi=curr_addr_axi_Sum0, max_transfers=max_transfers_Sum0](ARESETn=Sum0_ARESETn, WREADY=Sum0_WREADY)(WVALID=Sum0_WVALID, WLAST=Sum0_WLAST, WDATA=Sum0_WDATA); + invoke bresp_channel_Sum0(BVALID=Sum0_BVALID)(BREADY=Sum0_BREADY); + } + } + } + } +} +component main() -> () { + cells { + //Modified to 64 width address because XRT expects 64 bit memory addresses + ref A0 = seq_mem_d1(32,8,3); + A_read0_0 = std_reg(32); + ref B0 = seq_mem_d1(32,8,3); + B_read0_0 = std_reg(32); + ref Sum0 = seq_mem_d1(32,8,3); + add0 = std_add(32); + add1 = std_add(4); + const0 = std_const(4,0); + const1 = std_const(4,7); + const2 = std_const(4,1); + i0 = std_reg(4); + le0 = std_le(4); + bit_slice = std_bit_slice(4,0,2,3); + } + wires { + + bit_slice.in = i0.out; + comb group cond0 { + le0.left = i0.out; + le0.right = const1.out; + } + group let0<"static"=1> { + i0.in = const0.out; + i0.write_en = 1'd1; + let0[done] = i0.done; + } + //modified upd0 and upd1 to use seq_mem correctly + group upd0<"static"=2> { + A_read0_0.write_en = A0.read_done; + A0.addr0 = bit_slice.out; + A0.read_en = 1'b1; + A_read0_0.in = 1'd1 ? A0.read_data; + upd0[done] = A_read0_0.done ? 1'd1; + } + //see comment for upd0 + group upd1<"static"=2> { + B_read0_0.write_en = B0.read_done; + B0.addr0 = bit_slice.out; + B0.read_en = 1'b1; + B_read0_0.in = 1'd1 ? B0.read_data; + upd1[done] = B_read0_0.done ? 1'd1; + } + group upd2<"static"=1> { + Sum0.addr0 = bit_slice.out; + Sum0.write_en = 1'd1; + add0.left = B_read0_0.out; + add0.right = A_read0_0.out; + Sum0.write_data = 1'd1 ? add0.out; + upd2[done] = Sum0.write_done ? 1'd1; + } + group upd3<"static"=1> { + i0.write_en = 1'd1; + add1.left = i0.out; + add1.right = const2.out; + i0.in = 1'd1 ? add1.out; + upd3[done] = i0.done ? 1'd1; + } + } + control { + seq { + let0; + while le0.out with cond0 { + seq { + par { + upd0; + upd1; + } + upd2; + upd3; + } + } + } + } +} diff --git a/yxi/axi-calyx/vcdump.py b/yxi/axi-calyx/vcdump.py index 09772d5b27..ca27611662 100755 --- a/yxi/axi-calyx/vcdump.py +++ b/yxi/axi-calyx/vcdump.py @@ -31,7 +31,7 @@ def replace_line(file_path, old_line, new_line): `ifdef COCOTB_SIM initial begin $dumpfile ("out.vcd"); - $dumpvars (0, main); + $dumpvars (0, wrapper); #1; end `endif