Skip to content

Commit b7751ad

Browse files
mkurc-antkgugala
authored andcommitted
Add a test for interleaving recovery and non-recovery I3C transfers
Internal-tag: [#72196] Signed-off-by: Maciej Kurc <[email protected]>
1 parent 17e2011 commit b7751ad

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

verification/cocotb/top/lib_i3c_top/test_recovery.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,65 @@ async def test_virtual_write(dut):
200200
assert data0 != 0xDDCCBBAA
201201
assert data1 != 0x44332211
202202

203+
@cocotb.test()
204+
async def test_virtual_write_alternating(dut):
205+
"""
206+
Alternate between recovery CSR write and regular TTI private writes
207+
"""
208+
209+
# Initialize
210+
i3c_controller, i3c_target, tb, recovery = await initialize(dut)
211+
212+
# set regular device dynamic address
213+
await i3c_controller.i3c_ccc_write(
214+
ccc=CCC.DIRECT.SETDASA, directed_data=[(STATIC_ADDR, [DYNAMIC_ADDR << 1])]
215+
)
216+
# set virtual device dynamic address
217+
await i3c_controller.i3c_ccc_write(
218+
ccc=CCC.DIRECT.SETDASA, directed_data=[(VIRT_STATIC_ADDR, [VIRT_DYNAMIC_ADDR << 1])]
219+
)
220+
221+
# Repeat the sequence twice. The second time with the recovery mode disabled
222+
for i in range(2):
223+
224+
# ..........
225+
226+
# Write to the RESET CSR (one word)
227+
data = [random.randint(0, 255) for i in range(3)]
228+
await recovery.command_write(
229+
VIRT_DYNAMIC_ADDR, I3cRecoveryInterface.Command.DEVICE_RESET, data
230+
)
231+
232+
# Wait & read the CSR from the AHB/AXI side
233+
await Timer(1, "us")
234+
readback = dword2int(await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.DEVICE_RESET.base_addr, 4))
235+
assert readback == int.from_bytes(data, byteorder="little")
236+
237+
# ..........
238+
239+
# Do a private write
240+
data = [random.randint(0, 255) for i in range(3)]
241+
await i3c_controller.i3c_write(DYNAMIC_ADDR, data)
242+
243+
# Wait and read data back
244+
await Timer(1, "us")
245+
desc = dword2int(await tb.read_csr(tb.reg_map.I3C_EC.TTI.RX_DESC_QUEUE_PORT.base_addr, 4))
246+
desc = desc & 0xFFFF
247+
assert desc == len(data)
248+
249+
readback = dword2int(await tb.read_csr(tb.reg_map.I3C_EC.TTI.RX_DATA_PORT.base_addr, 4))
250+
assert readback == int.from_bytes(data, byteorder="little")
251+
252+
# ..........
253+
254+
# exit recovery mode
255+
await Timer(1, "us")
256+
status = 0x2
257+
await tb.write_csr(
258+
tb.reg_map.I3C_EC.SECFWRECOVERYIF.DEVICE_STATUS_0.base_addr, int2dword(status), 4
259+
)
260+
await ClockCycles(tb.clk, 50)
261+
203262
@cocotb.test()
204263
async def test_write(dut):
205264
"""
@@ -701,6 +760,90 @@ async def test_virtual_read_illegal(dut):
701760
# Wait
702761
await Timer(1, "us")
703762

763+
@cocotb.test()
764+
async def test_virtual_read_alternating(dut):
765+
"""
766+
Alternate between recovery mode reads and TTI reads
767+
"""
768+
769+
# Initialize
770+
i3c_controller, i3c_target, tb, recovery = await initialize(dut)
771+
772+
# set regular device dynamic address
773+
await i3c_controller.i3c_ccc_write(
774+
ccc=CCC.DIRECT.SETDASA, directed_data=[(STATIC_ADDR, [DYNAMIC_ADDR << 1])]
775+
)
776+
# set virtual device dynamic address
777+
await i3c_controller.i3c_ccc_write(
778+
ccc=CCC.DIRECT.SETDASA, directed_data=[(VIRT_STATIC_ADDR, [VIRT_DYNAMIC_ADDR << 1])]
779+
)
780+
781+
def make_word(bs):
782+
return (bs[3] << 24) | (bs[2] << 16) | (bs[1] << 8) | bs[0]
783+
784+
# Repeat the sequence twice. The second time with the recovery mode disabled
785+
for i in range(2):
786+
787+
# ..........
788+
789+
# Write some data to PROT_CAP CSR
790+
prot_cap = [random.randint(0, 255) for i in range(16)]
791+
792+
await tb.write_csr(
793+
tb.reg_map.I3C_EC.SECFWRECOVERYIF.PROT_CAP_0.base_addr,
794+
int2dword(make_word(prot_cap[0:4])),
795+
4,
796+
)
797+
await tb.write_csr(
798+
tb.reg_map.I3C_EC.SECFWRECOVERYIF.PROT_CAP_1.base_addr,
799+
int2dword(make_word(prot_cap[4:8])),
800+
4,
801+
)
802+
await tb.write_csr(
803+
tb.reg_map.I3C_EC.SECFWRECOVERYIF.PROT_CAP_2.base_addr,
804+
int2dword(make_word(prot_cap[8:12])),
805+
4,
806+
)
807+
await tb.write_csr(
808+
tb.reg_map.I3C_EC.SECFWRECOVERYIF.PROT_CAP_3.base_addr,
809+
int2dword(make_word(prot_cap[12:16])),
810+
4,
811+
)
812+
813+
# Wait, read the PROT_CAP register
814+
await Timer(1, "us")
815+
recovery_data, pec_ok = await recovery.command_read(VIRT_DYNAMIC_ADDR, I3cRecoveryInterface.Command.PROT_CAP)
816+
817+
# PROT_CAP read always returns 15 bytes
818+
assert len(recovery_data) == 15
819+
assert recovery_data == prot_cap[:15]
820+
assert pec_ok
821+
822+
# ..........
823+
824+
# Write data to TTI TX queue
825+
data = [random.randint(0, 255) for i in range(3)]
826+
await tb.write_csr(tb.reg_map.I3C_EC.TTI.TX_DATA_PORT.base_addr,
827+
int2dword(int.from_bytes(data, byteorder="little")), 4)
828+
829+
# Write the TX descriptor
830+
await tb.write_csr(tb.reg_map.I3C_EC.TTI.TX_DESC_QUEUE_PORT.base_addr,
831+
int2dword(len(data)), 4)
832+
833+
# Wait and do a private read
834+
await Timer(1, "us")
835+
readback = await i3c_controller.i3c_read(DYNAMIC_ADDR, len(data))
836+
assert data == list(readback)
837+
838+
# ..........
839+
840+
# Disable recovery mode
841+
await Timer(1, "us")
842+
status = 0x2 # "Recovery Mode"
843+
await tb.write_csr(
844+
tb.reg_map.I3C_EC.SECFWRECOVERYIF.DEVICE_STATUS_0.base_addr, int2dword(status), 4
845+
)
846+
704847
@cocotb.test()
705848
async def test_payload_available(dut):
706849
"""

0 commit comments

Comments
 (0)