refactor(bus): Clean up AXI/TL-UL bridges and tests This commit refactors the AXI-to-TileLink and TileLink-to-AXI bridge logic and cleans up the associated test infrastructure. Key changes: - Simplified the ready signal logic in `Axi2TLUL.scala` for better clarity and correctness. - Moved the cocotb test files for the AXI/TL-UL bridges from `hdl/chisel/src/bus` to a dedicated `tests/cocotb/tlul` directory. - Reorganized the Bazel BUILD files to reflect the new test locations and improve dependency management. - Added minor delays at the end of the `tlul2axi` tests to facilitate easier waveform debugging. Change-Id: I9a2a3c6510d34b010e0ecc2ba1da1db3e1462f2b
diff --git a/hdl/chisel/src/bus/Axi2TLUL.scala b/hdl/chisel/src/bus/Axi2TLUL.scala index f0a8e57..c5ab3d3 100644 --- a/hdl/chisel/src/bus/Axi2TLUL.scala +++ b/hdl/chisel/src/bus/Axi2TLUL.scala
@@ -16,6 +16,7 @@ import chisel3._ import chisel3.util._ +import common.KelvinRRArbiter import kelvin.Parameters @@ -47,39 +48,45 @@ val write_addr_q = Queue(io.axi.write.addr, entries = 2) val write_data_q = Queue(io.axi.write.data, entries = 2) - // Prioritize reads over writes. - val is_write = write_addr_q.valid && write_data_q.valid - val is_read = read_addr_q.valid + private def axiToTl(addr: AxiAddress, data: Option[AxiWriteData]): TileLink_A_ChannelBase[A_USER] = { + val tl_a = Wire(new TileLink_A_ChannelBase(tlul_p, userAGen)) + tl_a.opcode := data.map(_ => TLULOpcodesA.PutFullData.asUInt).getOrElse(TLULOpcodesA.Get.asUInt) + tl_a.param := 0.U + tl_a.address := addr.addr + tl_a.source := addr.id + tl_a.size := addr.size + tl_a.mask := data.map(_.strb).getOrElse(0.U(tlul_p.w.W)) + tl_a.data := data.map(_.data).getOrElse(0.U((8 * p.axi2DataBits).W)) + tl_a.user := 0.U.asTypeOf(io.tl_a.bits.user) + tl_a + } - io.tl_a.valid := is_read || is_write - read_addr_q.ready := false.B - write_addr_q.ready := false.B - write_data_q.ready := false.B + val read_stream = read_addr_q.map(axiToTl(_, None)) - read_addr_q.ready := Mux(is_read, io.tl_a.ready, false.B) - write_addr_q.ready := !is_read && io.tl_a.ready - write_data_q.ready := !is_read && io.tl_a.ready + val write_stream = Wire(Decoupled(new TileLink_A_ChannelBase(tlul_p, userAGen))) + write_stream.valid := write_addr_q.valid && write_data_q.valid + write_stream.bits := axiToTl(write_addr_q.bits, Some(write_data_q.bits)) - io.tl_a.bits.opcode := Mux(is_read, TLULOpcodesA.Get.asUInt, TLULOpcodesA.PutFullData.asUInt) - io.tl_a.bits.param := 0.U - io.tl_a.bits.address := Mux(is_read, read_addr_q.bits.addr, write_addr_q.bits.addr) - io.tl_a.bits.source := Mux(is_read, read_addr_q.bits.id, write_addr_q.bits.id) - io.tl_a.bits.size := Mux(is_read, read_addr_q.bits.size, write_addr_q.bits.size) - io.tl_a.bits.mask := Mux(is_read, 0.U, write_data_q.bits.strb) - io.tl_a.bits.data := Mux(is_read, 0.U, write_data_q.bits.data) - io.tl_a.bits.user := 0.U.asTypeOf(io.tl_a.bits.user) + // Reads are given higher priority. + val arb = Module(new KelvinRRArbiter(new TileLink_A_ChannelBase(tlul_p, userAGen), 2)) + arb.io.in(0) <> read_stream + arb.io.in(1) <> write_stream + io.tl_a <> arb.io.out + + write_addr_q.ready := write_stream.fire + write_data_q.ready := write_stream.fire val d_is_write = io.tl_d.bits.opcode === TLULOpcodesD.AccessAck.asUInt val d_is_read = io.tl_d.bits.opcode === TLULOpcodesD.AccessAckData.asUInt io.axi.write.resp.valid := io.tl_d.valid && d_is_write io.axi.write.resp.bits.id := io.tl_d.bits.source - io.axi.write.resp.bits.resp := 0.U + io.axi.write.resp.bits.resp := Mux(io.tl_d.bits.error, AxiResponseType.SLVERR.asUInt, AxiResponseType.OKAY.asUInt) io.axi.read.data.valid := io.tl_d.valid && d_is_read io.axi.read.data.bits.id := io.tl_d.bits.source io.axi.read.data.bits.data := io.tl_d.bits.data - io.axi.read.data.bits.resp := Mux(io.tl_d.bits.error, "b10".U, "b00".U) + io.axi.read.data.bits.resp := Mux(io.tl_d.bits.error, AxiResponseType.SLVERR.asUInt, AxiResponseType.OKAY.asUInt) io.axi.read.data.bits.last := true.B io.tl_d.ready := Mux(d_is_read, io.axi.read.data.ready, io.axi.write.resp.ready)
diff --git a/hdl/chisel/src/bus/BUILD b/hdl/chisel/src/bus/BUILD index 48737ef..3e2be71 100644 --- a/hdl/chisel/src/bus/BUILD +++ b/hdl/chisel/src/bus/BUILD
@@ -47,6 +47,13 @@ ) chisel_cc_library( + name = "axi2tlul_cc_library", + chisel_lib = ":bus", + emit_class = "bus.EmitAxi2TLUL", + module_name = "Axi2TLUL", +) + +chisel_cc_library( name = "tlul2axi_cc_library", chisel_lib = ":bus", emit_class = "bus.EmitTLUL2Axi", @@ -54,81 +61,19 @@ ) verilator_cocotb_model( - name = "tlul2axi_model", - hdl_toplevel = "TLUL2Axi", - verilog_source = "//hdl/chisel/src/bus:TLUL2Axi.sv", - cflags = [], + name = "axi2tlul_model", + cflags = VERILATOR_BUILD_ARGS, + hdl_toplevel = "Axi2TLUL", trace = True, -) - -# BEGIN_TESTCASES_FOR_tlul2axi_cocotb_test -TLUL2AXI_TESTCASES = [ - "test_put_request", - "test_get_request", - "test_backpressure", - "test_put_then_get", -] -# END_TESTCASES_FOR_tlul2axi_cocotb_test - -cocotb_test_suite( - name = "tlul2axi_cocotb_test", - simulators = ["verilator", "vcs"], - testcases = TLUL2AXI_TESTCASES, - testcases_vname = "TLUL2AXI_TESTCASES", - tests_kwargs = { - "hdl_toplevel": "TLUL2Axi", - "test_module": ["tlul2axi_cocotb_test.py"], - "size": "large", - "deps": [ - "@bazel_tools//tools/python/runfiles", - requirement("tqdm"), - ], - "waves": True, - }, - vcs_verilog_sources = ["//hdl/chisel/src/bus:tlul2axi_cc_library_verilog"], - verilator_model = ":tlul2axi_model", -) - -chisel_cc_library( - name = "axi2tlul_cc_library", - chisel_lib = ":bus", - emit_class = "bus.EmitAxi2TLUL", - module_name = "Axi2TLUL", + verilog_source = "//hdl/chisel/src/bus:Axi2TLUL.sv", ) verilator_cocotb_model( - name = "axi2tlul_model", - hdl_toplevel = "Axi2TLUL", - verilog_source = "//hdl/chisel/src/bus:Axi2TLUL.sv", - cflags = [], + name = "tlul2axi_model", + cflags = VERILATOR_BUILD_ARGS, + hdl_toplevel = "TLUL2Axi", trace = True, -) - -# BEGIN_TESTCASES_FOR_axi2tlul_cocotb_test -AXI2TLUL_TESTCASES = [ - "test_write_request", - "test_read_request", - "test_read_error", -] -# END_TESTCASES_FOR_axi2tlul_cocotb_test - -cocotb_test_suite( - name = "axi2tlul_cocotb_test", - simulators = ["verilator", "vcs"], - testcases = AXI2TLUL_TESTCASES, - testcases_vname = "AXI2TLUL_TESTCASES", - tests_kwargs = { - "hdl_toplevel": "Axi2TLUL", - "test_module": ["axi2tlul_cocotb_test.py"], - "size": "large", - "deps": [ - "@bazel_tools//tools/python/runfiles", - requirement("tqdm"), - ], - "waves": True, - }, - vcs_verilog_sources = ["//hdl/chisel/src/bus:axi2tlul_cc_library_verilog"], - verilator_model = ":axi2tlul_model", + verilog_source = "//hdl/chisel/src/bus:TLUL2Axi.sv", ) chisel_cc_library( @@ -189,4 +134,4 @@ hdl_toplevel = "SecdedEncoderTestbench57", trace = True, verilog_source = "//hdl/chisel/src/bus:SecdedEncoderTestbench57.sv", -) \ No newline at end of file +)
diff --git a/tests/cocotb/tlul/BUILD b/tests/cocotb/tlul/BUILD index 9b16b9c..4740777 100644 --- a/tests/cocotb/tlul/BUILD +++ b/tests/cocotb/tlul/BUILD
@@ -24,6 +24,73 @@ "VCS_TEST_ARGS", ) +# BEGIN_TESTCASES_FOR_tlul2axi_cocotb_test +TLUL2AXI_TESTCASES = [ + "test_put_request", + "test_get_request", + "test_backpressure", + "test_put_then_get", +] +# END_TESTCASES_FOR_tlul2axi_cocotb_test + +cocotb_test_suite( + name = "tlul2axi_cocotb_test", + simulators = [ + "verilator", + "vcs", + ], + testcases = TLUL2AXI_TESTCASES, + testcases_vname = "TLUL2AXI_TESTCASES", + tests_kwargs = { + "hdl_toplevel": "TLUL2Axi", + "test_module": ["tlul2axi_cocotb_test.py"], + "size": "large", + "deps": [ + "@bazel_tools//tools/python/runfiles", + requirement("tqdm"), + ], + "waves": True, + }, + vcs_verilog_sources = ["//hdl/chisel/src/bus:tlul2axi_cc_library_verilog"], + verilator_model = "//hdl/chisel/src/bus:tlul2axi_model", + vcs_build_args = VCS_BUILD_ARGS, + vcs_test_args = VCS_TEST_ARGS, + vcs_defines = VCS_DEFINES, +) + +# BEGIN_TESTCASES_FOR_axi2tlul_cocotb_test +AXI2TLUL_TESTCASES = [ + "test_write_request", + "test_read_request", + "test_read_error", +] +# END_TESTCASES_FOR_axi2tlul_cocotb_test + +cocotb_test_suite( + name = "axi2tlul_cocotb_test", + simulators = [ + "verilator", + "vcs", + ], + testcases = AXI2TLUL_TESTCASES, + testcases_vname = "AXI2TLUL_TESTCASES", + tests_kwargs = { + "hdl_toplevel": "Axi2TLUL", + "test_module": ["axi2tlul_cocotb_test.py"], + "size": "large", + "deps": [ + "@bazel_tools//tools/python/runfiles", + requirement("tqdm"), + ], + "waves": True, + }, + vcs_verilog_sources = ["//hdl/chisel/src/bus:axi2tlul_cc_library_verilog"], + verilator_model = "//hdl/chisel/src/bus:axi2tlul_model", + vcs_build_args = VCS_BUILD_ARGS, + vcs_test_args = VCS_TEST_ARGS, + vcs_defines = VCS_DEFINES, +) + # BEGIN_TESTCASES_FOR_tlul_integrity_cocotb_test TLUL_INTEGRITY_TESTCASES = [ "test_request_integrity_gen",
diff --git a/hdl/chisel/src/bus/axi2tlul_cocotb_test.py b/tests/cocotb/tlul/axi2tlul_cocotb_test.py similarity index 99% rename from hdl/chisel/src/bus/axi2tlul_cocotb_test.py rename to tests/cocotb/tlul/axi2tlul_cocotb_test.py index e6b721c..2abe7f4 100644 --- a/hdl/chisel/src/bus/axi2tlul_cocotb_test.py +++ b/tests/cocotb/tlul/axi2tlul_cocotb_test.py
@@ -179,6 +179,7 @@ dut.io_tl_d_bits_opcode.value = TLUL_OpcodeD.AccessAckData dut.io_tl_d_bits_source.value = test_source dut.io_tl_d_bits_data.value = test_data + dut.io_tl_d_bits_error.value = 0 dut.io_axi_read_data_ready.value = 1
diff --git a/hdl/chisel/src/bus/tlul2axi_cocotb_test.py b/tests/cocotb/tlul/tlul2axi_cocotb_test.py similarity index 98% rename from hdl/chisel/src/bus/tlul2axi_cocotb_test.py rename to tests/cocotb/tlul/tlul2axi_cocotb_test.py index e50b25b..e62a48f 100644 --- a/hdl/chisel/src/bus/tlul2axi_cocotb_test.py +++ b/tests/cocotb/tlul/tlul2axi_cocotb_test.py
@@ -165,6 +165,7 @@ assert not dut.io_tl_d_bits_error.value, "TL D_ERROR should be low" dut.io_tl_d_ready.value = 0 + # Allow a few extra cycles for waveform viewing. await ClockCycles(dut.clock, 5) @cocotb.test() @@ -240,6 +241,7 @@ assert not dut.io_tl_d_bits_error.value, "TL D_ERROR should be low" dut.io_tl_d_ready.value = 0 + # Allow a few extra cycles for waveform viewing. await ClockCycles(dut.clock, 5) @@ -326,6 +328,7 @@ assert not dut.io_tl_d_bits_error.value, "TL D_ERROR should be low" dut.io_tl_d_ready.value = 0 + # Allow a few extra cycles for waveform viewing. await ClockCycles(dut.clock, 5) @@ -417,4 +420,5 @@ assert dut.io_tl_d_bits_opcode.value == TLUL_OpcodeD.AccessAckData, "TL D_OPCODE should be AccessAckData for Get" dut.io_tl_d_ready.value = 0 + # Allow a few extra cycles for waveform viewing. await ClockCycles(dut.clock, 5) \ No newline at end of file