Skip to content

Commit f230359

Browse files
robertszczepanskikgugala
authored andcommitted
Add test for I3C bypass during active I3C bus traffic
1 parent 30ffbea commit f230359

File tree

7 files changed

+120
-24
lines changed

7 files changed

+120
-24
lines changed

src/ctrl/controller.sv

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,6 @@ module controller
473473
.tx_desc_queue_rvalid_i(tti_tx_desc_queue_rvalid_i),
474474
.tx_desc_queue_rready_o(tti_tx_desc_queue_rready_o),
475475
.tx_desc_queue_rdata_i(tti_tx_desc_queue_rdata_i),
476-
.rx_queue_full_i(tti_rx_queue_full_i),
477476
.rx_queue_depth_i(tti_rx_queue_depth_i),
478477
.rx_queue_start_thld_i(tti_rx_queue_start_thld_i),
479478
.rx_queue_start_thld_trig_i(tti_rx_queue_start_thld_trig_i),

src/ctrl/controller_standby.sv

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ module controller_standby
6060
input logic [TtiTxDescDataWidth-1:0] tx_desc_queue_rdata_i,
6161

6262
// TTI: RX Data
63-
input logic rx_queue_full_i,
6463
input logic [TtiRxFifoDepthWidth-1:0] rx_queue_depth_i,
6564
input logic [TtiRxThldWidth-1:0] rx_queue_start_thld_i,
6665
input logic rx_queue_start_thld_trig_i,
@@ -321,7 +320,6 @@ module controller_standby
321320
.tx_desc_queue_rvalid_i(tx_desc_queue_rvalid_i),
322321
.tx_desc_queue_rready_o(i2c_tx_desc_queue_rready_o),
323322
.tx_desc_queue_rdata_i(tx_desc_queue_rdata_i),
324-
.rx_queue_full_i(rx_queue_full_i),
325323
.rx_queue_start_thld_i(rx_queue_start_thld_i),
326324
.rx_queue_start_thld_trig_i(rx_queue_start_thld_trig_i),
327325
.rx_queue_ready_thld_i(rx_queue_ready_thld_i),
@@ -391,7 +389,7 @@ module controller_standby
391389
.tx_desc_queue_rvalid_i(tx_desc_queue_rvalid_i),
392390
.tx_desc_queue_rready_o(i3c_tx_desc_queue_rready_o),
393391
.tx_desc_queue_rdata_i(tx_desc_queue_rdata_i),
394-
.rx_queue_full_i(rx_queue_full_i),
392+
.rx_queue_wready_i(rx_queue_wready_i),
395393
.rx_queue_wvalid_o(i3c_rx_queue_wvalid_o),
396394
.rx_queue_wdata_o(i3c_rx_queue_wdata_o),
397395
.rx_queue_flush_o(i3c_rx_queue_flush_o),

src/ctrl/controller_standby_i2c.sv

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ module controller_standby_i2c
4848
input logic [TtiTxDescDataWidth-1:0] tx_desc_queue_rdata_i,
4949

5050
// TTI: RX Data
51-
input logic rx_queue_full_i,
5251
input logic [TtiRxThldWidth-1:0] rx_queue_start_thld_i,
5352
input logic rx_queue_start_thld_trig_i,
5453
input logic [TtiRxThldWidth-1:0] rx_queue_ready_thld_i,

src/ctrl/controller_standby_i3c.sv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ module controller_standby_i3c
3535
input logic [TtiTxDescDataWidth-1:0] tx_desc_queue_rdata_i,
3636

3737
// TTI: RX Data
38-
input logic rx_queue_full_i,
38+
input logic rx_queue_wready_i,
3939
output logic rx_queue_wvalid_o,
4040
output logic rx_queue_flush_o,
4141
output logic [TtiRxDataWidth-1:0] rx_queue_wdata_o,
@@ -650,7 +650,7 @@ module controller_standby_i3c
650650
.rst_ni (rst_ni),
651651
.tti_rx_desc_queue_wvalid_o(rx_desc_queue_wvalid_o),
652652
.tti_rx_desc_queue_wdata_o (rx_desc_queue_wdata_o),
653-
.tti_rx_queue_full_i (rx_queue_full_i),
653+
.tti_rx_queue_wready_i (rx_queue_wready_i),
654654
.tti_rx_queue_wvalid_o (rx_queue_wvalid_o),
655655
.tti_rx_queue_flush_o (rx_queue_flush_o),
656656
.tti_rx_queue_wdata_o (rx_queue_wdata_o),

src/ctrl/descriptor_rx.sv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ module descriptor_rx #(
3636
output logic [TtiRxDescDataWidth-1:0] tti_rx_desc_queue_wdata_o,
3737

3838
// TTI: RX Data
39-
input logic tti_rx_queue_full_i,
39+
input logic tti_rx_queue_wready_i,
4040
output logic tti_rx_queue_wvalid_o,
4141
output logic tti_rx_queue_flush_o,
4242
output logic [TtiRxDataWidth-1:0] tti_rx_queue_wdata_o,
@@ -91,7 +91,7 @@ module descriptor_rx #(
9191
end
9292

9393
assign tti_rx_queue_wvalid_o = rx_byte_valid_i;
94-
assign rx_byte_ready_o = ~tti_rx_queue_full_i;
94+
assign rx_byte_ready_o = tti_rx_queue_wready_i;
9595
assign tti_rx_queue_wdata_o = rx_byte_i;
9696

9797
assign rx_descriptor = {rx_error, {12{1'b0}}, byte_counter_q};

src/ctrl/i3c_target_fsm.sv

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,23 @@ module i3c_target_fsm #(
298298
assign rx_overflow_err_o = ~rx_overflow_err_q & rx_overflow_err_r;
299299

300300
// RX FIFO valid when we finish reading byte (leave RxPWriteData) and there was no parity error
301-
assign rx_fifo_wvalid_o = (state_q == RxPWriteTbit) &
301+
logic rx_fifo_wvalid;
302+
assign rx_fifo_wvalid = (state_q == RxPWriteTbit) &
302303
(state_d != RxPWriteTbit) &
303304
~(parity_err | rx_overflow_err_o);
305+
306+
always_ff @(posedge clk_i or negedge rst_ni) begin : latch_rx_fifo_wvalid
307+
if (~rst_ni) begin
308+
rx_fifo_wvalid_o <= 1'b0;
309+
end else begin
310+
if (rx_fifo_wvalid) begin
311+
rx_fifo_wvalid_o <= 1'b1;
312+
end
313+
if (rx_fifo_wvalid_o & rx_fifo_wready_i) begin
314+
rx_fifo_wvalid_o <= 1'b0;
315+
end
316+
end
317+
end
304318
// Last RX byte when we leave Private Write loop
305319
assign rx_last_byte_o = (state_q == RxPWriteData) & (state_d inside {RxFByte, Idle});
306320

verification/cocotb/top/lib_i3c_top/test_bypass.py

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,12 @@
44
import random
55

66
from bus2csr import dword2int, int2dword
7+
from cocotbext_i3c.i3c_controller import I3cController
8+
from cocotbext_i3c.i3c_target import I3CTarget
79
from interface import I3CTopTestInterface
810

911
import cocotb
10-
from cocotb.triggers import ClockCycles, Combine, Event, RisingEdge, Timer
11-
12-
STATIC_ADDR = 0x5A
13-
VIRT_STATIC_ADDR = 0x5B
14-
DYNAMIC_ADDR = 0x52
15-
VIRT_DYNAMIC_ADDR = 0x53
12+
from cocotb.triggers import ClockCycles, Combine, Event, Join, RisingEdge, Timer
1613

1714

1815
async def write_to_indirect_fifo(tb, data=None, format="bytes"):
@@ -180,7 +177,7 @@ async def get_fifo_ptrs():
180177
assert (wrptr3, rdptr3) == (0, 0)
181178

182179
# If top pointer is equal to 0, then FIFO should be full after write
183-
fifo_full_at_top = (top_ptr == 0)
180+
fifo_full_at_top = top_ptr == 0
184181

185182
# Check empty/full progression
186183
assert (full0, empty0) == (False, True)
@@ -307,12 +304,18 @@ async def test_read(dut):
307304
assert recovery_data == device_id
308305

309306
# Ensure there is access to rest of basic registers
310-
hw_status = dword2int(await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.HW_STATUS.base_addr, 4))
307+
hw_status = dword2int(
308+
await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.HW_STATUS.base_addr, 4)
309+
)
311310
assert hw_status == 0x0
312311

313312
device_status = [
314-
dword2int(await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.DEVICE_STATUS_0.base_addr, 4)),
315-
dword2int(await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.DEVICE_STATUS_1.base_addr, 4)),
313+
dword2int(
314+
await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.DEVICE_STATUS_0.base_addr, 4)
315+
),
316+
dword2int(
317+
await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.DEVICE_STATUS_1.base_addr, 4)
318+
),
316319
]
317320
assert device_status == [0x3, 0x0] # DEVICE_STATUS_0 was earlier set to 0x3
318321

@@ -326,9 +329,12 @@ async def test_payload_available(dut):
326329
# Initialize
327330
tb = await initialize(dut, timeout=50)
328331

329-
payload_size = dword2int(
330-
await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.INDIRECT_FIFO_STATUS_4.base_addr, 4)
331-
) * 4 # Multiply by 4 to get bytes from dwords
332+
payload_size = (
333+
dword2int(
334+
await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.INDIRECT_FIFO_STATUS_4.base_addr, 4)
335+
)
336+
* 4
337+
) # Multiply by 4 to get bytes from dwords
332338

333339
payload_available = dut.xi3c_wrapper.recovery_payload_available_o
334340

@@ -418,6 +424,86 @@ async def test_image_activated(dut):
418424
), "Upon writing 0xFF to RECOVERY_CTRL byte 2 image_activated should be deasserted"
419425

420426

427+
@cocotb.test()
428+
async def test_i3c_bus_traffic_during_loopback(dut):
429+
tb = await initialize(dut, timeout=500)
430+
431+
rtl_target_addr = 0x5A
432+
sim_target_addr = 0x23 # Arbitrary
433+
434+
fbus = 12.5
435+
i3c_controller = I3cController(
436+
sda_i=dut.bus_sda,
437+
sda_o=dut.sda_sim_ctrl_i,
438+
scl_i=dut.bus_scl,
439+
scl_o=dut.scl_sim_ctrl_i,
440+
debug_state_o=None,
441+
speed=fbus * 1e6,
442+
)
443+
444+
i3c_target = I3CTarget( # noqa
445+
sda_i=dut.bus_sda,
446+
sda_o=dut.sda_sim_target_i,
447+
scl_i=dut.bus_scl,
448+
scl_o=dut.scl_sim_target_i,
449+
debug_state_o=None,
450+
speed=fbus * 1e6,
451+
address=sim_target_addr,
452+
)
453+
454+
run_target_bus_traffic = Event()
455+
456+
async def target_bus_traffic(addr, run_condition):
457+
await run_condition.wait()
458+
while run_condition.is_set():
459+
# Send data to simulated target
460+
await i3c_controller.i3c_write(addr, [random.randint(0, 255)])
461+
462+
fifo_size = dword2int(
463+
await tb.read_csr(tb.reg_map.I3C_EC.SECFWRECOVERYIF.INDIRECT_FIFO_STATUS_4.base_addr, 4)
464+
)
465+
466+
for addr in [sim_target_addr, rtl_target_addr]:
467+
# Random delay to start transfer in the middle of I3C transaction
468+
469+
for _ in range(10): # Arbitrary number of repetitions
470+
payload_data = [random.randint(0, 2**32 - 1) for _ in range(fifo_size)]
471+
delay_cycles = random.randint(0, 1000)
472+
dut._log.info(f"Randomized delay is {delay_cycles} clock cycles")
473+
474+
# Start I3C traffic
475+
bus_traffic = cocotb.start_soon(target_bus_traffic(addr, run_target_bus_traffic))
476+
run_target_bus_traffic.set()
477+
478+
# Wait for random number of cycles and start write to Indirect FIFO via bypass
479+
await ClockCycles(tb.clk, delay_cycles)
480+
write_fifo = cocotb.start_soon(
481+
write_to_indirect_fifo(tb, payload_data, format="dwords")
482+
)
483+
484+
# Wait for random number of cycles and start read from Indirect FIFO via bypass
485+
await ClockCycles(tb.clk, delay_cycles)
486+
payload_received = []
487+
for _ in range(fifo_size):
488+
d = dword2int(
489+
await tb.read_csr(
490+
tb.reg_map.I3C_EC.SECFWRECOVERYIF.INDIRECT_FIFO_DATA.base_addr, 4
491+
)
492+
)
493+
payload_received.append(d)
494+
495+
# Payload write/read to I3C Core finished so disable I3C bus traffic generator
496+
await Join(write_fifo)
497+
run_target_bus_traffic.clear()
498+
await Join(bus_traffic)
499+
500+
dut._log.info("Received data: " + " ".join([hex(w) for w in payload_received]))
501+
dut._log.info("Expected data: " + " ".join([hex(w) for w in payload_data]))
502+
assert (
503+
payload_data == payload_received
504+
), "Reiceved payload data does not match sent data!"
505+
506+
421507
@cocotb.test()
422508
async def test_recovery_flow(dut):
423509
"""
@@ -479,7 +565,7 @@ async def mcu_agent():
479565
# Write image size to Indirect FIFO Control Image size field
480566
await tb.write_csr_field(
481567
tb.reg_map.I3C_EC.SECFWRECOVERYIF.INDIRECT_FIFO_CTRL_1.base_addr,
482-
tb.reg_map.I3C_EC.SECFWRECOVERYIF.INDIRECT_FIFO_CTRL_1.IMAGE_SIZE_LSB,
568+
tb.reg_map.I3C_EC.SECFWRECOVERYIF.INDIRECT_FIFO_CTRL_1.IMAGE_SIZE,
483569
image_size,
484570
)
485571
# Clear Indirect FIFO Reset

0 commit comments

Comments
 (0)