From 59224ac7fb7577cbc58f167cb23449dd43901b7d Mon Sep 17 00:00:00 2001 From: Daniel Keller Date: Thu, 3 Sep 2026 18:06:27 +0200 Subject: [PATCH 1/6] backend: Fold the force-decouple test when a port cannot burst The legalizer already folds the bursting decision to a literal when a port carries a single protocol class, but it still emitted a runtime protocol test to decide whether to decouple. On a port where every protocol forces decoupling the test is constant, so five of the nine backend variants shipped dead logic, and rw_obi evaluated a condition that can never be false. The test also mattered when it should not have. Software that leaves dst_protocol at its reset value gets AXI, so on an OBI-only write port the condition read false and the legalizer ran coupled and non-bursting while every other protocol-dependent decision had already folded to OBI. MAGIA hit this as a throughput collapse and worked around it in software. AXI is the only protocol with bursts != not_supported and legalizer_force_decouple false, so a port folds exactly when AXI is not one of its protocols. Drop the coupled branch, its page-boundary comparator and the now unused c_num_bytes_to_pb for those variants. --- src/backend/tpl/idma_legalizer.sv.tpl | 19 +++++++++++++++++++ util/mario/legalizer.py | 10 +++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/backend/tpl/idma_legalizer.sv.tpl b/src/backend/tpl/idma_legalizer.sv.tpl index 4806a3209..e2be53ecd 100644 --- a/src/backend/tpl/idma_legalizer.sv.tpl +++ b/src/backend/tpl/idma_legalizer.sv.tpl @@ -170,7 +170,9 @@ ${database[p]['max_beats_per_burst']} * StrbWidth > ${database[p]['page_size']}\ % endif % endfor page_len_t w_num_bytes_to_pb; +% if not always_decoupled: page_len_t c_num_bytes_to_pb; +% endif // read process page_len_t r_num_bytes_possible; @@ -351,16 +353,23 @@ w_num_bytes_to_pb = w_page_num_bytes_to_pb; //-------------------------------------- // page boundary check //-------------------------------------- +% if not always_decoupled: // how many transfers are remaining when concerning both r/w pages? // take the boundary that is closer assign c_num_bytes_to_pb = (r_num_bytes_to_pb > w_num_bytes_to_pb) ? w_num_bytes_to_pb : r_num_bytes_to_pb; +% endif //-------------------------------------- // Synchronized R/W process //-------------------------------------- always_comb begin : proc_num_bytes_possible +% if always_decoupled: + // Every protocol here forces decoupling: never coupled + r_num_bytes_possible = r_num_bytes_to_pb; + w_num_bytes_possible = w_num_bytes_to_pb; +% else: // Default: Coupled r_num_bytes_possible = c_num_bytes_to_pb; w_num_bytes_possible = c_num_bytes_to_pb; @@ -392,6 +401,7 @@ w_num_bytes_to_pb = w_page_num_bytes_to_pb; r_num_bytes_possible = r_num_bytes_to_pb; w_num_bytes_possible = w_num_bytes_to_pb; end +% endif end assign r_addr_offset = r_tf_q.addr[OffsetWidth-1:0]; @@ -644,6 +654,14 @@ ${database[protocol]['legalizer_write_data_path']} // * rw_decoupled: either machine advances always_comb begin : proc_legalizer_flow_control +% if always_decoupled: + // Every protocol here forces decoupling: never coupled + r_tf_ena = (r_ready_i & !flush_i) | kill_i; + w_tf_ena = (w_ready_i & !flush_i) | kill_i; + + r_valid_o = r_tf_q.valid & r_ready_i & !flush_i; + w_valid_o = w_tf_q.valid & w_ready_i & !flush_i; +% else: if ( opt_tf_q.decouple_rw\ % if len(used_non_bursting_or_force_decouple_read_protocols) != 0: @@ -680,6 +698,7 @@ ${database[protocol]['legalizer_write_data_path']} r_valid_o = r_tf_q.valid & w_ready_i & r_ready_i & !flush_i; w_valid_o = w_tf_q.valid & r_ready_i & w_ready_i & !flush_i; end +% endif end // load next idma request: if both machines are done! diff --git a/util/mario/legalizer.py b/util/mario/legalizer.py index 517e1885d..52ec98fb7 100644 --- a/util/mario/legalizer.py +++ b/util/mario/legalizer.py @@ -62,6 +62,12 @@ def render_legalizer(prot_ids: dict, db: dict, tpl_file: str) -> str: has_page_write_bursting = eval_key(used_write_prots, 'bursts', 'split_at_page_boundary', db) has_pow2_write_bursting = eval_key(used_write_prots, 'bursts', 'only_pow2', db) has_write_bursting = has_page_write_bursting or has_pow2_write_bursting + # A port whose every protocol forces decoupling can never run coupled, so the + # runtime protocol test collapses to a constant. + all_read_force_decouple = len(used_read_prots) != 0 and \ + set(prot_force_decouple(used_read_prots, db)) == set(used_read_prots) + all_write_force_decouple = len(used_write_prots) != 0 and \ + set(prot_force_decouple(used_write_prots, db)) == set(used_write_prots) # assemble context context = { 'name_uniqueifier': prot_id, @@ -91,7 +97,9 @@ def render_legalizer(prot_ids: dict, db: dict, tpl_file: str) -> str: 'used_non_bursting_or_force_decouple_read_protocols': prot_force_decouple(used_read_prots, db), 'used_non_bursting_or_force_decouple_write_protocols': - prot_force_decouple(used_write_prots, db) + prot_force_decouple(used_write_prots, db), + 'always_decoupled': + all_read_force_decouple or all_write_force_decouple } # render From 1103014195d04d3f88fc7c209e4f1bf8c976ab48 Mon Sep 17 00:00:00 2001 From: Daniel Keller Date: Thu, 3 Sep 2026 18:06:51 +0200 Subject: [PATCH 2/6] midend: Use the full start address when splitting distributed transfers The distributed midend rebases each slice onto its region by subtracting the transfer start address, but it subtracted only the low DmaRegionAddressBits of it. For a transfer whose start lies outside region zero that drops the region index, so every slice after the first was rebased to the wrong counterpart address. Only the two address expressions are affected; the length terms subtract a within-region residue and stay truncated. MemPool hit this and fixed it downstream in mempool 1b4dc47b on 2024-01-25, but the fix was never sent back upstream. --- src/midend/idma_mp_dist_midend.sv | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/midend/idma_mp_dist_midend.sv b/src/midend/idma_mp_dist_midend.sv index 99b34c04e..40ee1bb96 100644 --- a/src/midend/idma_mp_dist_midend.sv +++ b/src/midend/idma_mp_dist_midend.sv @@ -160,11 +160,9 @@ module idma_mp_dist_midend #( if (($unsigned(idma_req_i.src_addr) >= RegionStart) && ($unsigned(idma_req_i.src_addr) < RegionEnd )) begin idma_req_o[i].src_addr[FullRegionAddressBits-1:0] = i*RegionWidth; - idma_req_o[i].dst_addr = idma_req_i.dst_addr + i*RegionWidth - - start_addr[DmaRegionAddressBits-1:0]; + idma_req_o[i].dst_addr = idma_req_i.dst_addr + i*RegionWidth - start_addr; end else begin - idma_req_o[i].src_addr = idma_req_i.src_addr + i*RegionWidth - - start_addr[DmaRegionAddressBits-1:0]; + idma_req_o[i].src_addr = idma_req_i.src_addr + i*RegionWidth - start_addr; idma_req_o[i].dst_addr[FullRegionAddressBits-1:0] = i*RegionWidth; end if ($unsigned(end_addr) >= (i+1)*RegionWidth) begin From e3891e73344b5877775f4b1ee4253cb078de8426 Mon Sep 17 00:00:00 2001 From: Daniel Keller Date: Thu, 3 Sep 2026 18:11:20 +0200 Subject: [PATCH 3/6] test: Add a testbench for the distributed midend The multi-processor midends were pickled and documented but never simulated, which is why the distributed midend shipped a wrong counterpart address for two years. Check the split geometry directly: the distributed side must carry the region-local address and the counterpart side the rebased one, for transfers that start in a non-zero region, that start in region zero, that are driven from either side, that fit in one region, and that span every back-end. The split is combinational, so the testbench never handshakes and the stream fork stays idle. Expectations derive from the parameters, so the topology sweeps without a golden table. --- Bender.yml | 1 + idma.mk | 7 + jobs/jobs.json | 1422 ++++++++++++++++++------------ test/midend/tb_idma_mp_midend.sv | 168 ++++ 4 files changed, 1027 insertions(+), 571 deletions(-) create mode 100644 test/midend/tb_idma_mp_midend.sv diff --git a/Bender.yml b/Bender.yml index b2b62ee9c..ddf3a281e 100644 --- a/Bender.yml +++ b/Bender.yml @@ -128,6 +128,7 @@ sources: - test/midend/tb_idma_nd_midend_b2b.sv - test/midend/tb_idma_rt_midend.sv - test/midend/tb_idma_transpose_midend.sv + - test/midend/tb_idma_mp_midend.sv # Level 2 - test/future/idma_obi2axi_bridge.sv - test/future/idma_tilelink2axi_bridge.sv diff --git a/idma.mk b/idma.mk index 7c2ac0f8e..50438216e 100644 --- a/idma.mk +++ b/idma.mk @@ -512,6 +512,13 @@ idma_sim_tb_idma_transpose_midend: $(IDMA_VSIM_DIR)/compile.tcl cd $(IDMA_VSIM_DIR); $(VSIM) -c -t 1ps -voptargs=+acc -gDataWidth=64 tb_idma_transpose_midend -do "run -all; quit" cd $(IDMA_VSIM_DIR); $(VSIM) -c -t 1ps -voptargs=+acc -gDataWidth=512 tb_idma_transpose_midend -do "run -all; quit" +.PHONY: idma_sim_tb_idma_mp_midend +idma_sim_tb_idma_mp_midend: $(IDMA_VSIM_DIR)/compile.tcl + cd $(IDMA_VSIM_DIR); $(VSIM) -c -do "source compile.tcl; quit" + # the TB derives its geometry from the parameters; one run per topology + cd $(IDMA_VSIM_DIR); $(VSIM) -c -t 1ps -voptargs=+acc -gNumBEs=4 -gRegionWidth=4096 tb_idma_mp_midend -do "run -all; quit" + cd $(IDMA_VSIM_DIR); $(VSIM) -c -t 1ps -voptargs=+acc -gNumBEs=8 -gRegionWidth=1024 tb_idma_mp_midend -do "run -all; quit" + .PHONY: idma_sim_tb_idma_rt_midend idma_sim_tb_idma_rt_midend: $(IDMA_VSIM_DIR)/compile.tcl diff --git a/jobs/jobs.json b/jobs/jobs.json index d9607dd9a..da056c9ec 100644 --- a/jobs/jobs.json +++ b/jobs/jobs.json @@ -1,592 +1,872 @@ { - "rw_axi" : { - "jobs" : { - "simple" : "backend_rw_axi/simple.txt", - "same_dst" : "backend_rw_axi/same_dst.txt", - "linear" : "backend_rw_axi/linear.txt", - "huge" : "backend_rw_axi/huge.txt", - "large" : "backend_rw_axi/large.txt", - "medium" : "backend_rw_axi/medium.txt", - "mixed" : "backend_rw_axi/mixed.txt", - "small" : "backend_rw_axi/small.txt", - "tiny" : "backend_rw_axi/tiny.txt", - "error_simple" : "backend_rw_axi/error_simple.txt", - "error_mixed" : "backend_rw_axi/error_mixed.txt", - "zero_transfer" : "backend_rw_axi/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 1, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 1, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 1 - }, - "proc_id" : "rw_axi", - "testbench": "tb_idma_backend_rw_axi", - "synth_top": "idma_backend_synth_rw_axi" - }, - "rw_axi_stall" : { - "jobs" : { - "simple" : "backend_rw_axi/simple.txt", - "same_dst" : "backend_rw_axi/same_dst.txt", - "linear" : "backend_rw_axi/linear.txt", - "huge" : "backend_rw_axi/huge.txt", - "large" : "backend_rw_axi/large.txt", - "medium" : "backend_rw_axi/medium.txt", - "mixed" : "backend_rw_axi/mixed.txt", - "small" : "backend_rw_axi/small.txt", - "tiny" : "backend_rw_axi/tiny.txt", - "error_simple" : "backend_rw_axi/error_simple.txt", - "error_mixed" : "backend_rw_axi/error_mixed.txt", - "zero_transfer" : "backend_rw_axi/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 8, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 1, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 1, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 1 - }, - "tb_params" : { - "AXI_IdealMemory" : 0, - "AXI_MemNumReqOutst" : 2, - "AXI_MemLatency" : 8, - "WatchDogNumCycles" : 5000 - }, - "proc_id" : "rw_axi", - "testbench": "tb_idma_backend_rw_axi", - "synth_top": "idma_backend_synth_rw_axi" - }, - "r_axi_w_obi" : { - "jobs" : { - "simple" : "backend_r_axi_w_obi/simple.txt", - "same_dst" : "backend_r_axi_w_obi/same_dst.txt", - "linear" : "backend_r_axi_w_obi/linear.txt", - "huge" : "backend_r_axi_w_obi/huge.txt", - "large" : "backend_r_axi_w_obi/large.txt", - "medium" : "backend_r_axi_w_obi/medium.txt", - "mixed" : "backend_r_axi_w_obi/mixed.txt", - "small" : "backend_r_axi_w_obi/small.txt", - "tiny" : "backend_r_axi_w_obi/tiny.txt", - "zero_transfer" : "backend_r_axi_w_obi/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 0, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 0, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 0 - }, - "proc_id" : "r_axi_w_obi", - "testbench": "tb_idma_backend_r_axi_w_obi", - "synth_top": "idma_backend_synth_r_axi_w_obi" - }, - "r_obi_w_axi" : { - "jobs" : { - "simple" : "backend_r_obi_w_axi/simple.txt", - "same_dst" : "backend_r_obi_w_axi/same_dst.txt", - "linear" : "backend_r_obi_w_axi/linear.txt", - "huge" : "backend_r_obi_w_axi/huge.txt", - "large" : "backend_r_obi_w_axi/large.txt", - "medium" : "backend_r_obi_w_axi/medium.txt", - "mixed" : "backend_r_obi_w_axi/mixed.txt", - "small" : "backend_r_obi_w_axi/small.txt", - "tiny" : "backend_r_obi_w_axi/tiny.txt", - "zero_transfer" : "backend_r_obi_w_axi/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 0, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 0, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 0 - }, - "proc_id" : "r_obi_w_axi", - "testbench": "tb_idma_backend_r_obi_w_axi", - "synth_top": "idma_backend_synth_r_obi_w_axi" - }, - "snitch_read" : { - "jobs" : { - "simple" : "backend_r_axi_rw_init_rw_obi/simple.txt", - "same_dst" : "backend_r_axi_rw_init_rw_obi/same_dst.txt", - "linear" : "backend_r_axi_rw_init_rw_obi/linear.txt", - "huge" : "backend_r_axi_rw_init_rw_obi/huge.txt", - "large" : "backend_r_axi_rw_init_rw_obi/large.txt", - "medium" : "backend_r_axi_rw_init_rw_obi/medium.txt", - "mixed" : "backend_r_axi_rw_init_rw_obi/mixed.txt", - "small" : "backend_r_axi_rw_init_rw_obi/small.txt", - "tiny" : "backend_r_axi_rw_init_rw_obi/tiny.txt", - "zero_transfer" : "backend_r_axi_rw_init_rw_obi/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 1, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 0, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 0 - }, - "proc_id" : "r_axi_rw_init_rw_obi", - "testbench": "tb_idma_backend_r_axi_rw_init_rw_obi", - "synth_top": "idma_backend_synth_r_axi_rw_init_rw_obi" - }, - "snitch_init_read" : { - "jobs" : { - "simple" : "backend_r_init_rw_axi_rw_obi/simple.txt", - "same_dst" : "backend_r_init_rw_axi_rw_obi/same_dst.txt", - "linear" : "backend_r_init_rw_axi_rw_obi/linear.txt", - "huge" : "backend_r_init_rw_axi_rw_obi/huge.txt", - "large" : "backend_r_init_rw_axi_rw_obi/large.txt", - "medium" : "backend_r_init_rw_axi_rw_obi/medium.txt", - "mixed" : "backend_r_init_rw_axi_rw_obi/mixed.txt", - "small" : "backend_r_init_rw_axi_rw_obi/small.txt", - "tiny" : "backend_r_init_rw_axi_rw_obi/tiny.txt", - "zero_transfer" : "backend_r_init_rw_axi_rw_obi/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 1, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 0, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 0 - }, - "proc_id" : "r_init_rw_axi_rw_obi", - "testbench": "tb_idma_backend_r_init_rw_axi_rw_obi", - "synth_top": "idma_backend_synth_r_init_rw_axi_rw_obi" - }, - "snitch_write" : { - "jobs" : { - "simple" : "backend_r_obi_rw_init_w_axi/simple.txt", - "same_dst" : "backend_r_obi_rw_init_w_axi/same_dst.txt", - "linear" : "backend_r_obi_rw_init_w_axi/linear.txt", - "huge" : "backend_r_obi_rw_init_w_axi/huge.txt", - "large" : "backend_r_obi_rw_init_w_axi/large.txt", - "medium" : "backend_r_obi_rw_init_w_axi/medium.txt", - "mixed" : "backend_r_obi_rw_init_w_axi/mixed.txt", - "small" : "backend_r_obi_rw_init_w_axi/small.txt", - "tiny" : "backend_r_obi_rw_init_w_axi/tiny.txt", - "zero_transfer" : "backend_r_obi_rw_init_w_axi/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 1, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 0, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 0 - }, - "proc_id" : "r_obi_rw_init_w_axi", - "testbench": "tb_idma_backend_r_obi_rw_init_w_axi", - "synth_top": "idma_backend_synth_r_obi_rw_init_w_axi" - }, - "snitch_read_write" : { - "jobs" : { - "simple" : "backend_rw_axi_rw_init_rw_obi/simple.txt", - "same_dst" : "backend_rw_axi_rw_init_rw_obi/same_dst.txt", - "linear" : "backend_rw_axi_rw_init_rw_obi/linear.txt", - "huge" : "backend_rw_axi_rw_init_rw_obi/huge.txt", - "large" : "backend_rw_axi_rw_init_rw_obi/large.txt", - "medium" : "backend_rw_axi_rw_init_rw_obi/medium.txt", - "mixed" : "backend_rw_axi_rw_init_rw_obi/mixed.txt", - "small" : "backend_rw_axi_rw_init_rw_obi/small.txt", - "tiny" : "backend_rw_axi_rw_init_rw_obi/tiny.txt", - "zero_transfer" : "backend_rw_axi_rw_init_rw_obi/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 1, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 0, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 0 - }, - "proc_id" : "rw_axi_rw_init_rw_obi", - "testbench": "tb_idma_backend_rw_axi_rw_init_rw_obi", - "synth_top": "idma_backend_synth_rw_axi_rw_init_rw_obi" - }, - "rw_axi_rw_axis": { - "jobs" : { - "simple" : "backend_rw_axi_rw_axis/simple.txt", - "same_dst" : "backend_rw_axi_rw_axis/same_dst.txt", - "linear" : "backend_rw_axi_rw_axis/linear.txt", - "huge" : "backend_rw_axi_rw_axis/huge.txt", - "large" : "backend_rw_axi_rw_axis/large.txt", - "medium" : "backend_rw_axi_rw_axis/medium.txt", - "mixed" : "backend_rw_axi_rw_axis/mixed.txt", - "small" : "backend_rw_axi_rw_axis/small.txt", - "tiny" : "backend_rw_axi_rw_axis/tiny.txt", - "zero_transfer" : "backend_rw_axi_rw_axis/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 0, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 0, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 0 - }, - "proc_id" : "rw_axi_rw_axis", - "testbench" : "tb_idma_backend_rw_axi_rw_axis", - "synth_top" : "idma_backend_synth_rw_axi_rw_axis" - }, - "rw_obi": { - "jobs" : { - "simple" : "backend_rw_obi/simple.txt", - "same_dst" : "backend_rw_obi/same_dst.txt", - "linear" : "backend_rw_obi/linear.txt", - "huge" : "backend_rw_obi/huge.txt", - "large" : "backend_rw_obi/large.txt", - "medium" : "backend_rw_obi/medium.txt", - "mixed" : "backend_rw_obi/mixed.txt", - "small" : "backend_rw_obi/small.txt", - "tiny" : "backend_rw_obi/tiny.txt", - "zero_transfer" : "backend_rw_obi/zero_transfer.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "CombinedShifter" : 0, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 0, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 0 - }, - "proc_id" : "rw_obi", - "testbench" : "tb_idma_backend_rw_obi", - "synth_top" : "idma_backend_synth_rw_obi" - }, - "4d_extension" : { - "jobs" : { - "simple" : "4d_extension/simple.txt", - "linear_2d" : "4d_extension/linear_2D.txt" - }, - "params" : { - "DataWidth" : 32, - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "NumAxInFlight" : 3, - "BufferDepth" : 3, - "TFLenWidth" : 32, - "MemSysDepth" : 0, - "NumDim" : 4, - "RepWidth" : 32, - "StrideWidth" : 32, - "CombinedShifter" : 0, - "MaskInvalidData" : 1, - "RAWCouplingAvail" : 1, - "HardwareLegalizer" : 1, - "RejectZeroTransfers" : 1, - "ErrorHandling" : 0 - }, - "proc_id" : "rw_axi", - "testbench": "tb_idma_nd_midend", - "synth_top": "idma_nd_midend_synth" + "rw_axi": { + "jobs": { + "simple": "backend_rw_axi/simple.txt", + "same_dst": "backend_rw_axi/same_dst.txt", + "linear": "backend_rw_axi/linear.txt", + "huge": "backend_rw_axi/huge.txt", + "large": "backend_rw_axi/large.txt", + "medium": "backend_rw_axi/medium.txt", + "mixed": "backend_rw_axi/mixed.txt", + "small": "backend_rw_axi/small.txt", + "tiny": "backend_rw_axi/tiny.txt", + "error_simple": "backend_rw_axi/error_simple.txt", + "error_mixed": "backend_rw_axi/error_mixed.txt", + "zero_transfer": "backend_rw_axi/zero_transfer.txt" }, - "desc64": { - "jobs" : { - "simple" : "jobs.json" - }, - "params" : { - }, - "proc_id" : "none", - "testbench" : "tb_idma_desc64_top", - "synth_top" : "idma_desc64_synth" + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 1, + "MaskInvalidData": 1, + "RAWCouplingAvail": 1, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 1 }, - "desc64_dma": { - "jobs" : { - "simple" : "jobs.json" - }, - "params" : { - }, - "proc_id" : "none", - "testbench" : "tb_idma_desc64_bench", - "synth_top" : "idma_desc64_synth" + "proc_id": "rw_axi", + "testbench": "tb_idma_backend_rw_axi", + "synth_top": "idma_backend_synth_rw_axi" + }, + "rw_axi_stall": { + "jobs": { + "simple": "backend_rw_axi/simple.txt", + "same_dst": "backend_rw_axi/same_dst.txt", + "linear": "backend_rw_axi/linear.txt", + "huge": "backend_rw_axi/huge.txt", + "large": "backend_rw_axi/large.txt", + "medium": "backend_rw_axi/medium.txt", + "mixed": "backend_rw_axi/mixed.txt", + "small": "backend_rw_axi/small.txt", + "tiny": "backend_rw_axi/tiny.txt", + "error_simple": "backend_rw_axi/error_simple.txt", + "error_mixed": "backend_rw_axi/error_mixed.txt", + "zero_transfer": "backend_rw_axi/zero_transfer.txt" }, - "rt_midend": { - "jobs" : { - "simple" : "jobs.json" - }, - "params" : { - }, - "proc_id" : "none", - "testbench" : "tb_idma_rt_midend", - "synth_top" : "idma_rt_midend_synth" + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 8, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 1, + "MaskInvalidData": 1, + "RAWCouplingAvail": 1, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 1 }, - "mp_midend": { - "jobs" : { - "simple" : "jobs.json" - }, - "params" : { - }, - "proc_id" : "none", - "testbench" : "idma_mp_midend_synth", - "synth_top" : "idma_mp_midend_synth" + "tb_params": { + "AXI_IdealMemory": 0, + "AXI_MemNumReqOutst": 2, + "AXI_MemLatency": 8, + "WatchDogNumCycles": 5000 }, - "mxquant" : { - "jobs" : { - }, - "params" : { - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "TFLenWidth" : 32 - }, - "testbench" : "tb_idma_mxquant", - "verify" : { - "dpi" : "idma_mxquant_dpi", - "token" : "[MXQ] ALL PASS", - "legs" : [ - { "tag" : "mxquant_32", "params" : { "DataWidth" : 32 } }, - { "tag" : "mxquant_64", "params" : { "DataWidth" : 64 } }, - { "tag" : "mxquant_256", "params" : { "DataWidth" : 256 } }, - { "tag" : "mxquant_512", "params" : { "DataWidth" : 512 } }, - { "tag" : "mxquant_1024", "params" : { "DataWidth" : 1024 } } - ] - } + "proc_id": "rw_axi", + "testbench": "tb_idma_backend_rw_axi", + "synth_top": "idma_backend_synth_rw_axi" + }, + "r_axi_w_obi": { + "jobs": { + "simple": "backend_r_axi_w_obi/simple.txt", + "same_dst": "backend_r_axi_w_obi/same_dst.txt", + "linear": "backend_r_axi_w_obi/linear.txt", + "huge": "backend_r_axi_w_obi/huge.txt", + "large": "backend_r_axi_w_obi/large.txt", + "medium": "backend_r_axi_w_obi/medium.txt", + "mixed": "backend_r_axi_w_obi/mixed.txt", + "small": "backend_r_axi_w_obi/small.txt", + "tiny": "backend_r_axi_w_obi/tiny.txt", + "zero_transfer": "backend_r_axi_w_obi/zero_transfer.txt" }, - "mxroundtrip" : { - "jobs" : { - }, - "params" : { - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "TFLenWidth" : 32 - }, - "testbench" : "tb_idma_mxroundtrip", - "verify" : { - "dpi" : "idma_mxquant_dpi", - "token" : "[MXRT] ALL PASS", - "legs" : [ - { "tag" : "mxroundtrip_32", "params" : { "DataWidth" : 32 } }, - { "tag" : "mxroundtrip_64", "params" : { "DataWidth" : 64 } }, - { "tag" : "mxroundtrip_256", "params" : { "DataWidth" : 256 } } - ], - "exclude" : [ - { "values" : [512, 1024], "why" : "heap abort during model construction, see #196" } - ] + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 0, + "MaskInvalidData": 1, + "RAWCouplingAvail": 0, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 0 + }, + "proc_id": "r_axi_w_obi", + "testbench": "tb_idma_backend_r_axi_w_obi", + "synth_top": "idma_backend_synth_r_axi_w_obi" + }, + "r_obi_w_axi": { + "jobs": { + "simple": "backend_r_obi_w_axi/simple.txt", + "same_dst": "backend_r_obi_w_axi/same_dst.txt", + "linear": "backend_r_obi_w_axi/linear.txt", + "huge": "backend_r_obi_w_axi/huge.txt", + "large": "backend_r_obi_w_axi/large.txt", + "medium": "backend_r_obi_w_axi/medium.txt", + "mixed": "backend_r_obi_w_axi/mixed.txt", + "small": "backend_r_obi_w_axi/small.txt", + "tiny": "backend_r_obi_w_axi/tiny.txt", + "zero_transfer": "backend_r_obi_w_axi/zero_transfer.txt" + }, + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 0, + "MaskInvalidData": 1, + "RAWCouplingAvail": 0, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 0 + }, + "proc_id": "r_obi_w_axi", + "testbench": "tb_idma_backend_r_obi_w_axi", + "synth_top": "idma_backend_synth_r_obi_w_axi" + }, + "snitch_read": { + "jobs": { + "simple": "backend_r_axi_rw_init_rw_obi/simple.txt", + "same_dst": "backend_r_axi_rw_init_rw_obi/same_dst.txt", + "linear": "backend_r_axi_rw_init_rw_obi/linear.txt", + "huge": "backend_r_axi_rw_init_rw_obi/huge.txt", + "large": "backend_r_axi_rw_init_rw_obi/large.txt", + "medium": "backend_r_axi_rw_init_rw_obi/medium.txt", + "mixed": "backend_r_axi_rw_init_rw_obi/mixed.txt", + "small": "backend_r_axi_rw_init_rw_obi/small.txt", + "tiny": "backend_r_axi_rw_init_rw_obi/tiny.txt", + "zero_transfer": "backend_r_axi_rw_init_rw_obi/zero_transfer.txt" + }, + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 1, + "MaskInvalidData": 1, + "RAWCouplingAvail": 0, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 0 + }, + "proc_id": "r_axi_rw_init_rw_obi", + "testbench": "tb_idma_backend_r_axi_rw_init_rw_obi", + "synth_top": "idma_backend_synth_r_axi_rw_init_rw_obi" + }, + "snitch_init_read": { + "jobs": { + "simple": "backend_r_init_rw_axi_rw_obi/simple.txt", + "same_dst": "backend_r_init_rw_axi_rw_obi/same_dst.txt", + "linear": "backend_r_init_rw_axi_rw_obi/linear.txt", + "huge": "backend_r_init_rw_axi_rw_obi/huge.txt", + "large": "backend_r_init_rw_axi_rw_obi/large.txt", + "medium": "backend_r_init_rw_axi_rw_obi/medium.txt", + "mixed": "backend_r_init_rw_axi_rw_obi/mixed.txt", + "small": "backend_r_init_rw_axi_rw_obi/small.txt", + "tiny": "backend_r_init_rw_axi_rw_obi/tiny.txt", + "zero_transfer": "backend_r_init_rw_axi_rw_obi/zero_transfer.txt" + }, + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 1, + "MaskInvalidData": 1, + "RAWCouplingAvail": 0, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 0 + }, + "proc_id": "r_init_rw_axi_rw_obi", + "testbench": "tb_idma_backend_r_init_rw_axi_rw_obi", + "synth_top": "idma_backend_synth_r_init_rw_axi_rw_obi" + }, + "snitch_write": { + "jobs": { + "simple": "backend_r_obi_rw_init_w_axi/simple.txt", + "same_dst": "backend_r_obi_rw_init_w_axi/same_dst.txt", + "linear": "backend_r_obi_rw_init_w_axi/linear.txt", + "huge": "backend_r_obi_rw_init_w_axi/huge.txt", + "large": "backend_r_obi_rw_init_w_axi/large.txt", + "medium": "backend_r_obi_rw_init_w_axi/medium.txt", + "mixed": "backend_r_obi_rw_init_w_axi/mixed.txt", + "small": "backend_r_obi_rw_init_w_axi/small.txt", + "tiny": "backend_r_obi_rw_init_w_axi/tiny.txt", + "zero_transfer": "backend_r_obi_rw_init_w_axi/zero_transfer.txt" + }, + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 1, + "MaskInvalidData": 1, + "RAWCouplingAvail": 0, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 0 + }, + "proc_id": "r_obi_rw_init_w_axi", + "testbench": "tb_idma_backend_r_obi_rw_init_w_axi", + "synth_top": "idma_backend_synth_r_obi_rw_init_w_axi" + }, + "snitch_read_write": { + "jobs": { + "simple": "backend_rw_axi_rw_init_rw_obi/simple.txt", + "same_dst": "backend_rw_axi_rw_init_rw_obi/same_dst.txt", + "linear": "backend_rw_axi_rw_init_rw_obi/linear.txt", + "huge": "backend_rw_axi_rw_init_rw_obi/huge.txt", + "large": "backend_rw_axi_rw_init_rw_obi/large.txt", + "medium": "backend_rw_axi_rw_init_rw_obi/medium.txt", + "mixed": "backend_rw_axi_rw_init_rw_obi/mixed.txt", + "small": "backend_rw_axi_rw_init_rw_obi/small.txt", + "tiny": "backend_rw_axi_rw_init_rw_obi/tiny.txt", + "zero_transfer": "backend_rw_axi_rw_init_rw_obi/zero_transfer.txt" + }, + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 1, + "MaskInvalidData": 1, + "RAWCouplingAvail": 0, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 0 + }, + "proc_id": "rw_axi_rw_init_rw_obi", + "testbench": "tb_idma_backend_rw_axi_rw_init_rw_obi", + "synth_top": "idma_backend_synth_rw_axi_rw_init_rw_obi" + }, + "rw_axi_rw_axis": { + "jobs": { + "simple": "backend_rw_axi_rw_axis/simple.txt", + "same_dst": "backend_rw_axi_rw_axis/same_dst.txt", + "linear": "backend_rw_axi_rw_axis/linear.txt", + "huge": "backend_rw_axi_rw_axis/huge.txt", + "large": "backend_rw_axi_rw_axis/large.txt", + "medium": "backend_rw_axi_rw_axis/medium.txt", + "mixed": "backend_rw_axi_rw_axis/mixed.txt", + "small": "backend_rw_axi_rw_axis/small.txt", + "tiny": "backend_rw_axi_rw_axis/tiny.txt", + "zero_transfer": "backend_rw_axi_rw_axis/zero_transfer.txt" + }, + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 0, + "MaskInvalidData": 1, + "RAWCouplingAvail": 0, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 0 + }, + "proc_id": "rw_axi_rw_axis", + "testbench": "tb_idma_backend_rw_axi_rw_axis", + "synth_top": "idma_backend_synth_rw_axi_rw_axis" + }, + "rw_obi": { + "jobs": { + "simple": "backend_rw_obi/simple.txt", + "same_dst": "backend_rw_obi/same_dst.txt", + "linear": "backend_rw_obi/linear.txt", + "huge": "backend_rw_obi/huge.txt", + "large": "backend_rw_obi/large.txt", + "medium": "backend_rw_obi/medium.txt", + "mixed": "backend_rw_obi/mixed.txt", + "small": "backend_rw_obi/small.txt", + "tiny": "backend_rw_obi/tiny.txt", + "zero_transfer": "backend_rw_obi/zero_transfer.txt" + }, + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "CombinedShifter": 0, + "MaskInvalidData": 1, + "RAWCouplingAvail": 0, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 0 + }, + "proc_id": "rw_obi", + "testbench": "tb_idma_backend_rw_obi", + "synth_top": "idma_backend_synth_rw_obi" + }, + "4d_extension": { + "jobs": { + "simple": "4d_extension/simple.txt", + "linear_2d": "4d_extension/linear_2D.txt" + }, + "params": { + "DataWidth": 32, + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "NumAxInFlight": 3, + "BufferDepth": 3, + "TFLenWidth": 32, + "MemSysDepth": 0, + "NumDim": 4, + "RepWidth": 32, + "StrideWidth": 32, + "CombinedShifter": 0, + "MaskInvalidData": 1, + "RAWCouplingAvail": 1, + "HardwareLegalizer": 1, + "RejectZeroTransfers": 1, + "ErrorHandling": 0 + }, + "proc_id": "rw_axi", + "testbench": "tb_idma_nd_midend", + "synth_top": "idma_nd_midend_synth" + }, + "desc64": { + "jobs": { + "simple": "jobs.json" + }, + "params": {}, + "proc_id": "none", + "testbench": "tb_idma_desc64_top", + "synth_top": "idma_desc64_synth" + }, + "desc64_dma": { + "jobs": { + "simple": "jobs.json" + }, + "params": {}, + "proc_id": "none", + "testbench": "tb_idma_desc64_bench", + "synth_top": "idma_desc64_synth" + }, + "rt_midend": { + "jobs": { + "simple": "jobs.json" + }, + "params": {}, + "proc_id": "none", + "testbench": "tb_idma_rt_midend", + "synth_top": "idma_rt_midend_synth" + }, + "mp_midend": { + "jobs": { + "simple": "jobs.json" + }, + "params": {}, + "proc_id": "none", + "testbench": "tb_idma_mp_midend", + "synth_top": "idma_mp_midend_synth", + "verify": { + "token": "[MID] ALL PASS", + "legs": [ + { + "tag": "mp_midend_4x4k", + "params": { + "NumBEs": 4, + "RegionWidth": 4096 + } + }, + { + "tag": "mp_midend_8x1k", + "params": { + "NumBEs": 8, + "RegionWidth": 1024 + } } + ] + } + }, + "mxquant": { + "jobs": {}, + "params": { + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "TFLenWidth": 32 }, - "transpose" : { - "jobs" : { - }, - "params" : { - }, - "testbench" : "tb_idma_otf_transpose", - "verify" : { - "dpi" : "idma_transpose_dpi", - "token" : "[TB] ALL PASS", - "legs" : [ - { "tag" : "otf_transpose", "params" : { "StrbWidth" : 8, "FullDuplex" : 1 } }, - { "tag" : "otf_transpose_bp", "params" : { "StrbWidth" : 8, "FullDuplex" : 1 }, "plusargs" : ["+BP"] }, - { "tag" : "otf_transpose_8_0", "params" : { "StrbWidth" : 8, "FullDuplex" : 0 }, "plusargs" : ["+BP"] }, - { "tag" : "otf_transpose_64_1", "params" : { "StrbWidth" : 64, "FullDuplex" : 1 }, "plusargs" : ["+BP"] }, - { "tag" : "otf_transpose_64_0", "params" : { "StrbWidth" : 64, "FullDuplex" : 0 }, "plusargs" : ["+BP"] } - ] + "testbench": "tb_idma_mxquant", + "verify": { + "dpi": "idma_mxquant_dpi", + "token": "[MXQ] ALL PASS", + "legs": [ + { + "tag": "mxquant_32", + "params": { + "DataWidth": 32 + } + }, + { + "tag": "mxquant_64", + "params": { + "DataWidth": 64 + } + }, + { + "tag": "mxquant_256", + "params": { + "DataWidth": 256 + } + }, + { + "tag": "mxquant_512", + "params": { + "DataWidth": 512 + } + }, + { + "tag": "mxquant_1024", + "params": { + "DataWidth": 1024 + } } + ] + } + }, + "mxroundtrip": { + "jobs": {}, + "params": { + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "TFLenWidth": 32 }, - "transpose_midend" : { - "jobs" : { - }, - "params" : { - "AddrWidth" : 64 - }, - "testbench" : "tb_idma_transpose_midend", - "verify" : { - "dpi" : "idma_transpose_dpi", - "token" : "[MID] ALL PASS", - "legs" : [ - { "tag" : "transpose_midend_64", "params" : { "DataWidth" : 64 } }, - { "tag" : "transpose_midend_512", "params" : { "DataWidth" : 512 } } - ] + "testbench": "tb_idma_mxroundtrip", + "verify": { + "dpi": "idma_mxquant_dpi", + "token": "[MXRT] ALL PASS", + "legs": [ + { + "tag": "mxroundtrip_32", + "params": { + "DataWidth": 32 + } + }, + { + "tag": "mxroundtrip_64", + "params": { + "DataWidth": 64 + } + }, + { + "tag": "mxroundtrip_256", + "params": { + "DataWidth": 256 + } + } + ], + "exclude": [ + { + "values": [ + 512, + 1024 + ], + "why": "heap abort during model construction, see #196" } + ] + } + }, + "transpose": { + "jobs": {}, + "params": {}, + "testbench": "tb_idma_otf_transpose", + "verify": { + "dpi": "idma_transpose_dpi", + "token": "[TB] ALL PASS", + "legs": [ + { + "tag": "otf_transpose", + "params": { + "StrbWidth": 8, + "FullDuplex": 1 + } + }, + { + "tag": "otf_transpose_bp", + "params": { + "StrbWidth": 8, + "FullDuplex": 1 + }, + "plusargs": [ + "+BP" + ] + }, + { + "tag": "otf_transpose_8_0", + "params": { + "StrbWidth": 8, + "FullDuplex": 0 + }, + "plusargs": [ + "+BP" + ] + }, + { + "tag": "otf_transpose_64_1", + "params": { + "StrbWidth": 64, + "FullDuplex": 1 + }, + "plusargs": [ + "+BP" + ] + }, + { + "tag": "otf_transpose_64_0", + "params": { + "StrbWidth": 64, + "FullDuplex": 0 + }, + "plusargs": [ + "+BP" + ] + } + ] + } + }, + "transpose_midend": { + "jobs": {}, + "params": { + "AddrWidth": 64 }, - "mxclear" : { - "jobs" : { - }, - "params" : { - "StrbWidth" : 8 - }, - "testbench" : "tb_idma_mxclear", - "verify" : { - "expect" : "fail", - "defines" : ["INC_ASSERT"], - "token" : "clear with in-flight state", - "legs" : [ - { "tag" : "mxclear_1", "params" : { "Quant" : 1 } }, - { "tag" : "mxclear_0", "params" : { "Quant" : 0 } } - ] + "testbench": "tb_idma_transpose_midend", + "verify": { + "dpi": "idma_transpose_dpi", + "token": "[MID] ALL PASS", + "legs": [ + { + "tag": "transpose_midend_64", + "params": { + "DataWidth": 64 + } + }, + { + "tag": "transpose_midend_512", + "params": { + "DataWidth": 512 + } } + ] + } + }, + "mxclear": { + "jobs": {}, + "params": { + "StrbWidth": 8 }, - "mxneg" : { - "jobs" : { - }, - "params" : { - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "TFLenWidth" : 32 - }, - "testbench" : "tb_idma_mxneg", - "verify" : { - "dpi" : "idma_mxquant_dpi", - "expect" : "fail", - "defines" : ["INC_ASSERT"], - "legs" : [ - { "tag" : "mxneg_1", "params" : { "NegCase" : 1, "DataWidth" : 64, "EnDequant" : 1, "EnFp16" : 1 }, "token" : "ComputeSizeAligned" }, - { "tag" : "mxneg_2", "params" : { "NegCase" : 2, "DataWidth" : 64, "EnDequant" : 1, "EnFp16" : 1 }, "token" : "ComputeSrcAligned" }, - { "tag" : "mxneg_3", "params" : { "NegCase" : 3, "DataWidth" : 64, "EnDequant" : 1, "EnFp16" : 1 }, "token" : "ComputeDstAligned" }, - { "tag" : "mxneg_5", "params" : { "NegCase" : 5, "DataWidth" : 64, "EnDequant" : 1, "EnFp16" : 1 }, "token" : "ComputeMxdequantBeatAligned" }, - { "tag" : "mxneg_6", "params" : { "NegCase" : 6, "DataWidth" : 64, "EnDequant" : 0, "EnFp16" : 1 }, "token" : "ComputeOpUnsupported" }, - { "tag" : "mxneg_7", "params" : { "NegCase" : 7, "DataWidth" : 64, "EnDequant" : 1, "EnFp16" : 1 }, "token" : "ComputeMxSrcProtocol" }, - { "tag" : "mxneg_8", "params" : { "NegCase" : 8, "DataWidth" : 64, "EnDequant" : 1, "EnFp16" : 1 }, "token" : "ComputeMxDstProtocol" }, - { "tag" : "mxneg_10", "params" : { "NegCase" : 10, "DataWidth" : 64, "EnDequant" : 1, "EnFp16" : 1 }, "token" : "ComputeTransposeSingleBeat" }, - { "tag" : "mxneg_13", "params" : { "NegCase" : 13, "DataWidth" : 64, "EnDequant" : 1, "EnFp16" : 0 }, "token" : "ComputeOpUnsupported" } - ], - "exclude" : [ - { "case" : 4, "why" : "DataWidth 1024 SIGSEGVs on verilator 5.020; passes on 5.046" }, - { "case" : 11, "why" : "the request is never accepted, so the guard is never sampled" }, - { "case" : 12, "why" : "DataWidth 1024 SIGSEGVs on verilator 5.020; passes on 5.046" } - ] + "testbench": "tb_idma_mxclear", + "verify": { + "expect": "fail", + "defines": [ + "INC_ASSERT" + ], + "token": "clear with in-flight state", + "legs": [ + { + "tag": "mxclear_1", + "params": { + "Quant": 1 + } + }, + { + "tag": "mxclear_0", + "params": { + "Quant": 0 + } } + ] + } + }, + "mxneg": { + "jobs": {}, + "params": { + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "TFLenWidth": 32 }, - "mxperf" : { - "jobs" : { - }, - "params" : { - "AddrWidth" : 32, - "UserWidth" : 1, - "AxiIdWidth" : 12, - "TFLenWidth" : 32 - }, - "testbench" : "tb_idma_mxperf", - "verify" : { - "token" : "[MXPF] ALL PASS", - "legs" : [ - { "tag" : "mxperf_32", "params" : { "DataWidth" : 32 } }, - { "tag" : "mxperf_64", "params" : { "DataWidth" : 64 } } - ] + "testbench": "tb_idma_mxneg", + "verify": { + "dpi": "idma_mxquant_dpi", + "expect": "fail", + "defines": [ + "INC_ASSERT" + ], + "legs": [ + { + "tag": "mxneg_1", + "params": { + "NegCase": 1, + "DataWidth": 64, + "EnDequant": 1, + "EnFp16": 1 + }, + "token": "ComputeSizeAligned" + }, + { + "tag": "mxneg_2", + "params": { + "NegCase": 2, + "DataWidth": 64, + "EnDequant": 1, + "EnFp16": 1 + }, + "token": "ComputeSrcAligned" + }, + { + "tag": "mxneg_3", + "params": { + "NegCase": 3, + "DataWidth": 64, + "EnDequant": 1, + "EnFp16": 1 + }, + "token": "ComputeDstAligned" + }, + { + "tag": "mxneg_5", + "params": { + "NegCase": 5, + "DataWidth": 64, + "EnDequant": 1, + "EnFp16": 1 + }, + "token": "ComputeMxdequantBeatAligned" + }, + { + "tag": "mxneg_6", + "params": { + "NegCase": 6, + "DataWidth": 64, + "EnDequant": 0, + "EnFp16": 1 + }, + "token": "ComputeOpUnsupported" + }, + { + "tag": "mxneg_7", + "params": { + "NegCase": 7, + "DataWidth": 64, + "EnDequant": 1, + "EnFp16": 1 + }, + "token": "ComputeMxSrcProtocol" + }, + { + "tag": "mxneg_8", + "params": { + "NegCase": 8, + "DataWidth": 64, + "EnDequant": 1, + "EnFp16": 1 + }, + "token": "ComputeMxDstProtocol" + }, + { + "tag": "mxneg_10", + "params": { + "NegCase": 10, + "DataWidth": 64, + "EnDequant": 1, + "EnFp16": 1 + }, + "token": "ComputeTransposeSingleBeat" + }, + { + "tag": "mxneg_13", + "params": { + "NegCase": 13, + "DataWidth": 64, + "EnDequant": 1, + "EnFp16": 0 + }, + "token": "ComputeOpUnsupported" + } + ], + "exclude": [ + { + "case": 4, + "why": "DataWidth 1024 SIGSEGVs on verilator 5.020; passes on 5.046" + }, + { + "case": 11, + "why": "the request is never accepted, so the guard is never sampled" + }, + { + "case": 12, + "why": "DataWidth 1024 SIGSEGVs on verilator 5.020; passes on 5.046" } + ] + } + }, + "mxperf": { + "jobs": {}, + "params": { + "AddrWidth": 32, + "UserWidth": 1, + "AxiIdWidth": 12, + "TFLenWidth": 32 }, - "_verify" : { - "elab_widths" : [32, 64, 512, 1024], - "elab_compute" : [ - { "width" : 64, "ops" : 15, "tuning" : 1 }, - { "width" : 512, "ops" : 15, "tuning" : 1 }, - { "width" : 64, "ops" : 8, "tuning" : 0 }, - { "width" : 64, "ops" : 6, "tuning" : 1 } - ], - "elab_shared_tops" : [ - "idma_desc64_synth", "idma_nd_midend_synth", - "idma_mp_midend_synth", "idma_rt_midend_synth" - ], - "multihead_ids" : ["2r_axi_w_axi", "2rw_axi"], - "reg_variants" : [ - { "variant" : 3, "module" : "idma_reg32_3d" }, - { "variant" : 2, "module" : "idma_reg64_2d" }, - { "variant" : 1, "module" : "idma_reg64_1d" } - ], - "elab_covered_elsewhere" : ["tb_idma_reg_frontend"], - "guards_untested" : [ - { "guard" : "ComputeMxFp16Width", "why" : "only reachable from the excluded 1024 cases" }, - { "guard" : "ComputeMxdequantLengthFits", "why" : "case 11 is never accepted" }, - { "guard" : "ComputeDstTilelink", "why" : "no TileLink backend variant exists" } - ], - "tops_untested" : [ - { "top" : "tb_idma_nd_midend_b2b", "why" : "hangs ([B2B] timeout); latent reset/LFSR race" }, - { "top" : "tb_idma_transpose_nd", - "why" : "verilator only: the ND response never fires once the first case drains" }, - { "top" : "tb_idma_transpose_b2b", - "why" : "verilator only: the first geometry never completes, watchdog trip" }, - { "top" : "tb_idma_mxrand", - "why" : "verilator only: transfer 1 never completes, even at NumXfers=1 StallPct=0" }, - { "top" : "tb_idma_rt_midend", "why" : "fails under --assert on cc_rr_arb_tree lock" }, - { "top" : "the directed backend job runs", "why" : "verilator cannot drive the class-based stimulus" } - ] + "testbench": "tb_idma_mxperf", + "verify": { + "token": "[MXPF] ALL PASS", + "legs": [ + { + "tag": "mxperf_32", + "params": { + "DataWidth": 32 + } + }, + { + "tag": "mxperf_64", + "params": { + "DataWidth": 64 + } + } + ] } + }, + "_verify": { + "elab_widths": [ + 32, + 64, + 512, + 1024 + ], + "elab_compute": [ + { + "width": 64, + "ops": 15, + "tuning": 1 + }, + { + "width": 512, + "ops": 15, + "tuning": 1 + }, + { + "width": 64, + "ops": 8, + "tuning": 0 + }, + { + "width": 64, + "ops": 6, + "tuning": 1 + } + ], + "elab_shared_tops": [ + "idma_desc64_synth", + "idma_nd_midend_synth", + "idma_mp_midend_synth", + "idma_rt_midend_synth" + ], + "multihead_ids": [ + "2r_axi_w_axi", + "2rw_axi" + ], + "reg_variants": [ + { + "variant": 3, + "module": "idma_reg32_3d" + }, + { + "variant": 2, + "module": "idma_reg64_2d" + }, + { + "variant": 1, + "module": "idma_reg64_1d" + } + ], + "elab_covered_elsewhere": [ + "tb_idma_reg_frontend" + ], + "guards_untested": [ + { + "guard": "ComputeMxFp16Width", + "why": "only reachable from the excluded 1024 cases" + }, + { + "guard": "ComputeMxdequantLengthFits", + "why": "case 11 is never accepted" + }, + { + "guard": "ComputeDstTilelink", + "why": "no TileLink backend variant exists" + } + ], + "tops_untested": [ + { + "top": "tb_idma_nd_midend_b2b", + "why": "hangs ([B2B] timeout); latent reset/LFSR race" + }, + { + "top": "tb_idma_transpose_nd", + "why": "verilator only: the ND response never fires once the first case drains" + }, + { + "top": "tb_idma_transpose_b2b", + "why": "verilator only: the first geometry never completes, watchdog trip" + }, + { + "top": "tb_idma_mxrand", + "why": "verilator only: transfer 1 never completes, even at NumXfers=1 StallPct=0" + }, + { + "top": "tb_idma_rt_midend", + "why": "fails under --assert on cc_rr_arb_tree lock" + }, + { + "top": "the directed backend job runs", + "why": "verilator cannot drive the class-based stimulus" + } + ] + } } diff --git a/test/midend/tb_idma_mp_midend.sv b/test/midend/tb_idma_mp_midend.sv new file mode 100644 index 000000000..4266cbfd9 --- /dev/null +++ b/test/midend/tb_idma_mp_midend.sv @@ -0,0 +1,168 @@ +// Copyright 2026 ETH Zurich and University of Bologna. +// Solderpad Hardware License, Version 0.51, see LICENSE for details. +// SPDX-License-Identifier: SHL-0.51 + +// Authors: +// - Daniel Keller + +`include "idma/typedef.svh" + +/// Unit check for idma_mp_dist_midend: every slice must carry the region-local +/// address on the distributed side and the correctly rebased address on the +/// counterpart side. Covers transfers starting in a non-zero region, which is +/// where truncating the start address silently mis-rebases every slice after +/// the first. +module tb_idma_mp_midend #( + parameter int unsigned NumBEs = 32'd4, + parameter int unsigned RegionWidth = 32'h1000, + parameter int unsigned AddrWidth = 32'd32 +); + + localparam int unsigned RegionStart = 32'h0000_0000; + localparam int unsigned RegionEnd = RegionStart + NumBEs * RegionWidth; + localparam int unsigned NotInvolvedLen = 32'd1; + + typedef logic [AddrWidth-1:0] addr_t; + typedef logic [ 31:0] tf_len_t; + typedef logic [ 2:0] id_t; + + `IDMA_TYPEDEF_FULL_REQ_T(idma_req_t, id_t, addr_t, tf_len_t) + `IDMA_TYPEDEF_FULL_RSP_T(idma_rsp_t, addr_t) + + logic clk, rst_n; + + idma_req_t req_in; + idma_req_t [NumBEs-1:0] req_out; + logic [NumBEs-1:0] req_valid_out, req_ready_in, rsp_valid_in, rsp_ready_out; + idma_rsp_t [NumBEs-1:0] rsp_in; + idma_pkg::idma_busy_t [NumBEs-1:0] busy_in; + + assign req_ready_in = '1; + assign rsp_valid_in = '0; + assign rsp_in = '0; + assign busy_in = '0; + + idma_mp_dist_midend #( + .NumBEs ( NumBEs ), + .RegionWidth ( RegionWidth ), + .RegionStart ( RegionStart ), + .RegionEnd ( RegionEnd ), + .AddrWidth ( AddrWidth ), + .idma_req_t ( idma_req_t ), + .idma_rsp_t ( idma_rsp_t ) + ) i_dut ( + .clk_i ( clk ), + .rst_ni ( rst_n ), + .idma_req_i ( req_in ), + .idma_req_valid_i ( 1'b0 ), + .idma_req_ready_o ( ), + .idma_rsp_o ( ), + .idma_rsp_valid_o ( ), + .idma_rsp_ready_i ( 1'b1 ), + .idma_busy_o ( ), + .idma_req_o ( req_out ), + .idma_req_valid_o ( req_valid_out ), + .idma_req_ready_i ( req_ready_in ), + .idma_rsp_i ( rsp_in ), + .idma_rsp_valid_i ( rsp_valid_in ), + .idma_rsp_ready_o ( rsp_ready_out ), + .idma_busy_i ( busy_in ) + ); + + initial begin + clk = 1'b0; + forever #0.5ns clk = ~clk; + end + + int errs = 0; + + task automatic chk(input string name, input logic [63:0] got, input logic [63:0] exp); + if (got !== exp) begin + errs++; + $display("[MID] %s: got 0x%0h exp 0x%0h", name, got, exp); + end + endtask + + /// Check one slice of a transfer whose distributed side is `src`. + task automatic chk_slice(input string name, + input int unsigned i, + input logic [63:0] exp_src, + input logic [63:0] exp_dst, + input logic [63:0] exp_len); + chk($sformatf("%s be%0d src", name, i), req_out[i].src_addr, exp_src); + chk($sformatf("%s be%0d dst", name, i), req_out[i].dst_addr, exp_dst); + chk($sformatf("%s be%0d len", name, i), req_out[i].length, exp_len); + endtask + + /// A back-end outside the transfer emits the tie-off request, not a slice. + task automatic chk_idle(input string name, input int unsigned i); + chk($sformatf("%s be%0d len", name, i), req_out[i].length, NotInvolvedLen); + chk($sformatf("%s be%0d src", name, i), req_out[i].src_addr, '0); + chk($sformatf("%s be%0d dst", name, i), req_out[i].dst_addr, '0); + endtask + + task automatic drive(input logic [63:0] src, input logic [63:0] dst, input logic [63:0] len); + req_in = '0; + req_in.src_addr = addr_t'(src); + req_in.dst_addr = addr_t'(dst); + req_in.length = tf_len_t'(len); + #1ns; + endtask + + // Counterpart base, well clear of the distributed region. + localparam longint unsigned CpBase = 64'h0010_0000; + localparam longint unsigned RW = 64'(RegionWidth); + localparam longint unsigned Half = RW / 2; + + /// Every back-end outside [lo, hi] must carry the tie-off request. + task automatic chk_idle_outside(input string name, input int unsigned lo, input int unsigned hi); + for (int unsigned i = 0; i < NumBEs; i++) begin + if (i < lo || i > hi) chk_idle(name, i); + end + endtask + + initial begin + req_in = '0; + rst_n = 1'b0; + #5ns; + rst_n = 1'b1; + #5ns; + + // --- Start half way into region 1 and run one region long, so the transfer + // --- ends half way into region 2. Slice 2 is rebased, and its counterpart + // --- address is only right if the whole start address is subtracted. + drive(RW + Half, CpBase, RW); + chk_slice("r1span", 1, RW + Half, CpBase, RW - Half); + chk_slice("r1span", 2, 2*RW, CpBase + Half, Half); + chk_idle_outside("r1span", 1, 2); + + // --- The same shape starting in region 0, where truncating the start + // --- address is a no-op. Guards the fix against over-correcting. + drive(Half, CpBase, RW); + chk_slice("r0span", 0, Half, CpBase, RW - Half); + chk_slice("r0span", 1, RW, CpBase + RW - Half, Half); + chk_idle_outside("r0span", 0, 1); + + // --- Distributed side on the destination; the source is the counterpart. + drive(CpBase, RW + Half, RW); + chk_slice("dstdist", 1, CpBase, RW + Half, RW - Half); + chk_slice("dstdist", 2, CpBase + Half, 2*RW, Half); + chk_idle_outside("dstdist", 1, 2); + + // --- Wholly inside one region: a single slice carries the full length. + drive(RW + Half, CpBase, Half / 2); + chk_slice("single", 1, RW + Half, CpBase, Half / 2); + chk_idle_outside("single", 1, 1); + + // --- Full span: every back-end takes exactly one region. + drive(64'd0, CpBase, 64'(NumBEs) * RW); + for (int unsigned i = 0; i < NumBEs; i++) begin + chk_slice("fullspan", i, 64'(i) * RW, CpBase + 64'(i) * RW, RW); + end + + if (errs == 0) $display("[MID] ALL PASS (NumBEs=%0d RegionWidth=0x%0h)", NumBEs, RegionWidth); + else $fatal(1, "[MID] FAIL: %0d mismatches", errs); + $finish; + end + +endmodule From ec7fa3c9641f793e60c25fcd5cf7550223e198f3 Mon Sep 17 00:00:00 2001 From: Daniel Keller Date: Thu, 3 Sep 2026 18:12:44 +0200 Subject: [PATCH 4/6] include: Let the full request typedef carry a user type IDMA_TYPEDEF_REQ_T has taken a user type since the Snitch multicast work, but IDMA_TYPEDEF_FULL_REQ_T never forwarded one, so every user of the convenience macro got the logic default and a one bit user field no matter how wide the request was meant to be. That covers nearly all of the testbenches, which is why the field has never been driven or checked anywhere. Forward an optional user type. All existing call sites omit it and keep the one bit field, so nothing changes for them. The distributed midend testbench opts in with a 36 bit tag and checks it survives onto every slice. --- src/include/idma/typedef.svh | 6 +++--- test/midend/tb_idma_mp_midend.sv | 12 ++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/include/idma/typedef.svh b/src/include/idma/typedef.svh index 642923f09..f1836f808 100644 --- a/src/include/idma/typedef.svh +++ b/src/include/idma/typedef.svh @@ -58,11 +58,11 @@ // iDMA Full Request and Response Structs // // Usage Example: -// `IDMA_TYPEDEF_FULL_REQ_T(idma_req_t, axi_id_t, axi_addr_t, tf_len_t) +// `IDMA_TYPEDEF_FULL_REQ_T(idma_req_t, axi_id_t, axi_addr_t, tf_len_t[, user_t]) // `IDMA_TYPEDEF_FULL_RSP_T(idma_rsp_t, axi_addr_t) -`define IDMA_TYPEDEF_FULL_REQ_T(idma_req_t, axi_id_t, axi_addr_t, tf_len_t) \ +`define IDMA_TYPEDEF_FULL_REQ_T(idma_req_t, axi_id_t, axi_addr_t, tf_len_t, user_t = logic) \ `IDMA_TYPEDEF_OPTIONS_T(options_t, axi_id_t) \ - `IDMA_TYPEDEF_REQ_T(idma_req_t, tf_len_t, axi_addr_t, options_t) + `IDMA_TYPEDEF_REQ_T(idma_req_t, tf_len_t, axi_addr_t, options_t, user_t) `define IDMA_TYPEDEF_FULL_RSP_T(idma_rsp_t, axi_addr_t) \ `IDMA_TYPEDEF_ERR_PAYLOAD_T(err_payload_t, axi_addr_t) \ `IDMA_TYPEDEF_RSP_T(idma_rsp_t, err_payload_t) diff --git a/test/midend/tb_idma_mp_midend.sv b/test/midend/tb_idma_mp_midend.sv index 4266cbfd9..d5acedc21 100644 --- a/test/midend/tb_idma_mp_midend.sv +++ b/test/midend/tb_idma_mp_midend.sv @@ -15,20 +15,25 @@ module tb_idma_mp_midend #( parameter int unsigned NumBEs = 32'd4, parameter int unsigned RegionWidth = 32'h1000, - parameter int unsigned AddrWidth = 32'd32 + parameter int unsigned AddrWidth = 32'd32, + parameter int unsigned UserWidth = 32'd36 ); localparam int unsigned RegionStart = 32'h0000_0000; localparam int unsigned RegionEnd = RegionStart + NumBEs * RegionWidth; localparam int unsigned NotInvolvedLen = 32'd1; + typedef logic [UserWidth-1:0] user_t; typedef logic [AddrWidth-1:0] addr_t; typedef logic [ 31:0] tf_len_t; typedef logic [ 2:0] id_t; - `IDMA_TYPEDEF_FULL_REQ_T(idma_req_t, id_t, addr_t, tf_len_t) + `IDMA_TYPEDEF_FULL_REQ_T(idma_req_t, id_t, addr_t, tf_len_t, user_t) `IDMA_TYPEDEF_FULL_RSP_T(idma_rsp_t, addr_t) + // recognisable pattern, wider than 32 bits to prove the type is carried + localparam user_t UserTag = user_t'(36'h9_ABCD_EF12); + logic clk, rst_n; idma_req_t req_in; @@ -92,6 +97,8 @@ module tb_idma_mp_midend #( chk($sformatf("%s be%0d src", name, i), req_out[i].src_addr, exp_src); chk($sformatf("%s be%0d dst", name, i), req_out[i].dst_addr, exp_dst); chk($sformatf("%s be%0d len", name, i), req_out[i].length, exp_len); + // metadata, the user field included, is forwarded untouched + chk($sformatf("%s be%0d user", name, i), 64'(req_out[i].user), 64'(UserTag)); endtask /// A back-end outside the transfer emits the tie-off request, not a slice. @@ -106,6 +113,7 @@ module tb_idma_mp_midend #( req_in.src_addr = addr_t'(src); req_in.dst_addr = addr_t'(dst); req_in.length = tf_len_t'(len); + req_in.user = UserTag; #1ns; endtask From 71a79628b21821389acd094dee68faa59d154f39 Mon Sep 17 00:00:00 2001 From: Daniel Keller Date: Thu, 3 Sep 2026 18:13:21 +0200 Subject: [PATCH 5/6] frontend: Make the inst64 ND dimension count a parameter NumDim was a localparam fixed at two, so the ND midend behind the inst64 frontend could never be given more dimensions. idma_transpose_midend asserts NumDim >= 4, which put it out of reach of this frontend entirely. Promote it to a parameter and keep the default at two, so existing instantiations are unaffected and a system that wants the transpose midend or a rank three transfer can ask for it. --- src/frontend/inst64/idma_inst64_top.sv | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/inst64/idma_inst64_top.sv b/src/frontend/inst64/idma_inst64_top.sv index 1edfe626a..1479db7a4 100644 --- a/src/frontend/inst64/idma_inst64_top.sv +++ b/src/frontend/inst64/idma_inst64_top.sv @@ -20,6 +20,8 @@ module idma_inst64_top #( parameter int unsigned NumAxInFlight = 32'd3, parameter int unsigned DMAReqFifoDepth = 32'd3, parameter int unsigned NumChannels = 32'd1, + /// Number of ND dimensions; the transpose midend needs at least 4 + parameter int unsigned NumDim = 32'd2, parameter bit TCDMAliasEnable = 1'b0, parameter int unsigned DMATracing = 32'd0, parameter type axi_ar_chan_t = logic, @@ -69,7 +71,6 @@ module idma_inst64_top #( localparam int unsigned TfIdWidth = 32'd32; localparam int unsigned TFLenWidth = AxiAddrWidth; localparam int unsigned RepWidth = 32'd32; - localparam int unsigned NumDim = 32'd2; localparam int unsigned BufferDepth = 32'd3; localparam int unsigned NumRules = 32'd5; localparam int unsigned AwInFlightCntWidth = From 71531daa60d1a190b84fd992a3fcc056e80786b3 Mon Sep 17 00:00:00 2001 From: Daniel Keller Date: Thu, 3 Sep 2026 18:13:54 +0200 Subject: [PATCH 6/6] docs: Record the alignment rule for in-network collectives An interconnect that resolves collectives in the network joins flits by destination and mask, so participants that decompose a transfer differently never join and the network stalls. The legalizer splits on the page boundary and the source offset, so matching lengths alone do not guarantee matching burst counts. Say so where DMUSER is documented, and record the new NumDim parameter in the same table. --- .../content/docs/architecture/frontend/snitch.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/site/src/content/docs/architecture/frontend/snitch.md b/doc/site/src/content/docs/architecture/frontend/snitch.md index e2d46f3eb..d3f77cc46 100644 --- a/doc/site/src/content/docs/architecture/frontend/snitch.md +++ b/doc/site/src/content/docs/architecture/frontend/snitch.md @@ -38,6 +38,19 @@ All DMA instructions that return a value write to `rd` (destination register). T - Bit 1: Enable 2D mode (use previously set strides/reps). If 2D mode is enabled but `DMSTR`/`DMREP` were not called since the last transfer, the previously set stride and repetition values are reused. On reset, these default to zero - Bits 4:2: Channel select - `$clog2(NumChannels)` bits wide, remaining upper bits are zero-extended. For the common single-channel case (`NumChannels=1`), these bits are unused and only bit 1 (2D enable) matters +### In-network collectives + +`DMUSER` is how a Snitch core reaches an interconnect that resolves collectives in the +network, such as FlooNoC's multicast and reduction. The user word carries the destination +mask and the collective opcode; iDMA forwards it to `aw.user` and interprets none of it. + +Participating cores must issue transfers that the legalizer decomposes identically. A +reduction join matches incoming flits on destination and mask, so two participants that +produce different burst counts for the same logical transfer will never join and the +network stalls. The legalizer splits on the page boundary and the source offset, so equal +lengths are not sufficient: give every participant the same source alignment relative to +the page size, or the same `src_max_llen` with `src_reduce_len` set. + ## Parameters For most Snitch cluster integrations, `NumChannels=1` and `NumAxInFlight=3` are standard. Increase `NumChannels` only if you need independent DMA channels on separate address spaces. @@ -51,6 +64,7 @@ For most Snitch cluster integrations, `NumChannels=1` and `NumAxInFlight=3` are | `NumAxInFlight` | Number of in-flight AXI transactions (default: 3) | | `DMAReqFifoDepth` | Depth of the request FIFO between frontend and midend (default: 3) | | `NumChannels` | Number of independent DMA channels, each with its own backend + ND midend (default: 1) | +| `NumDim` | Number of ND dimensions handed to the ND midend (default: 2). `idma_transpose_midend` requires at least 4 | | `DMATracing` | Enable DMA trace file generation for debugging | ## Programming Sequence