diff --git a/verification/cocotb/noxfile.py b/verification/cocotb/noxfile.py index d45c868cb..b4e1ebbc6 100644 --- a/verification/cocotb/noxfile.py +++ b/verification/cocotb/noxfile.py @@ -312,6 +312,7 @@ def i2c_target_fsm_verify(session, test_group, test_name, coverage, simulator): "test_ibi_multi_queue", "test_te_errors", "test_tsco_violation", + "test_bus_idle", ], ) @nox.parametrize("coverage", coverage_types) @@ -339,6 +340,7 @@ def i3c_ahb_verify(session, test_group, test_name, coverage, simulator): "test_ibi_multi_queue", "test_te_errors", "test_tsco_violation", + "test_bus_idle", ], ) @nox.parametrize("coverage", coverage_types) @@ -530,6 +532,7 @@ def recovery_pec_verify(session, test_group, test_name, coverage, simulator): "test_ibi_multi_queue", "test_te_errors", "test_tsco_violation", + "test_bus_idle", ], ) @nox.parametrize("coverage", coverage_types) diff --git a/verification/cocotb/top/i3c_ahb/test_bus_idle.py b/verification/cocotb/top/i3c_ahb/test_bus_idle.py new file mode 120000 index 000000000..943f955d7 --- /dev/null +++ b/verification/cocotb/top/i3c_ahb/test_bus_idle.py @@ -0,0 +1 @@ +verification/cocotb/top/lib_i3c_top/test_bus_idle.py \ No newline at end of file diff --git a/verification/cocotb/top/i3c_axi/test_bus_idle.py b/verification/cocotb/top/i3c_axi/test_bus_idle.py new file mode 120000 index 000000000..943f955d7 --- /dev/null +++ b/verification/cocotb/top/i3c_axi/test_bus_idle.py @@ -0,0 +1 @@ +verification/cocotb/top/lib_i3c_top/test_bus_idle.py \ No newline at end of file diff --git a/verification/cocotb/top/lib_i3c_top/test_bus_idle.py b/verification/cocotb/top/lib_i3c_top/test_bus_idle.py new file mode 100644 index 000000000..de108fff4 --- /dev/null +++ b/verification/cocotb/top/lib_i3c_top/test_bus_idle.py @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: Apache-2.0 + +import logging +import cocotb +from cocotb.triggers import ClockCycles, Timer +from boot import boot_init +from i3c_controller_fixed import I3cControllerFixed as I3cController +from interface import I3CTopTestInterface +from common import log_seed + + +_BUS_IDLE_PATH = ( + "xi3c_wrapper.i3c.xcontroller.xcontroller_standby" + ".xcontroller_standby_i3c.xbus_timers.bus_idle_o" +) + + +async def test_setup(dut): + cocotb.log.setLevel(logging.DEBUG) + log_seed(dut) + i3c_controller = I3cController( + sda_i=dut.bus_sda, sda_o=dut.sda_sim_ctrl_i, + scl_i=dut.bus_scl, scl_o=dut.scl_sim_ctrl_i, + debug_state_o=None, speed=12.5e6, + ) + i3c_controller.monitor_enable.clear() + await i3c_controller.monitor_idle.wait() + dut.sda_sim_target_i.value = 1 + dut.scl_sim_target_i.value = 1 + dut.peripheral_reset_done_i.value = 0 + tb = I3CTopTestInterface(dut) + await tb.setup(fclk=333.0) + await ClockCycles(tb.clk, 50) + await boot_init(tb, fclk=333.0) + return i3c_controller, tb + + +@cocotb.test() +async def test_bus_idle(dut): + """ + Ensures target enters and leaves bus idle state after certain delays. + """ + i3c_controller, tb = await test_setup(dut) + bus_idle_sig = getattr(dut, _BUS_IDLE_PATH) + + # 1. Generate a manual STOP condition to start the bus timers + # (The timer requires a STOP detection edge to restart its internal counters) + dut._log.info("Generating STOP condition (SDA 0->1 while SCL=1) to start bus timers") + i3c_controller.scl = 1 + i3c_controller.sda = 0 + await Timer(2, "us") + i3c_controller.sda = 1 # STOP edge + await Timer(2, "us") + + # 2. Wait > 200us for T_IDLE. This forces bus_idle_o to toggle 0 -> 1. + dut._log.info("Waiting 210us for bus_idle_o to assert") + await Timer(210, "us") + assert bus_idle_sig.value == 1, "Target should be in bus idle state" + + # 3. Generate a manual START condition to break the idle state (1 -> 0 toggle) + dut._log.info("Generating START condition (SDA 1->0 while SCL=1) to deassert bus_idle_o") + i3c_controller.sda = 0 + await Timer(2, "us") + assert bus_idle_sig.value == 0, "Target should not be in bus idle state" + + await tb.teardown() diff --git a/verification/testplan/source-maps.yml b/verification/testplan/source-maps.yml index b118514a6..df0ddf98f 100644 --- a/verification/testplan/source-maps.yml +++ b/verification/testplan/source-maps.yml @@ -39,7 +39,8 @@ testplans: testpoints: - name: "^(.*)$" source: ".*verification/cocotb/top/lib_i3c_top/test_i3c_target.py" - cocotb_xml: ".*verification/cocotb/top/i3c_axi/test_i3c_target(_[0-9]+)?.xml" + # test_bus_idle here is for bus_idle_coverage + cocotb_xml: ".*verification/cocotb/top/i3c_axi/test_(i3c_target|bus_idle)(_[0-9]+)?.xml" - name: 'Recovery mode tests' testpoints: - name: "^(.*)$" diff --git a/verification/testplan/top/target.hjson b/verification/testplan/top/target.hjson index 3070268b9..dffd974a7 100644 --- a/verification/testplan/top/target.hjson +++ b/verification/testplan/top/target.hjson @@ -357,5 +357,15 @@ tests: [""] tags: ["top"] } + { + name: bus_idle + desc: + ''' + Generate STOP condition, wait for over 200us and ensure the target entered idle state. Then + generate START condition and ensure target left idle state. + ''' + tests: ["bus_idle"] + tags: ["top"] + } ] }