Skip to content

Commit 37da564

Browse files
wkkunakgugala
authored andcommitted
ver: top: Add AXI ID filtering test
Signed-off-by: Wiktoria Kuna <[email protected]>
1 parent 9591af8 commit 37da564

File tree

2 files changed

+123
-4
lines changed

2 files changed

+123
-4
lines changed

verification/cocotb/common/bus2csr.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ async def read_access_monitor(self):
249249
assert rresp == AxiResp.OKAY, self._report_response(rresp, AxiResp.OKAY, True)
250250
else:
251251
assert rresp == AxiResp.SLVERR, self._report_response(rresp, AxiResp.SLVERR, True)
252+
assert self.dut.rdata.value == 0
252253

253254
await RisingEdge(self.dut.aclk)
254255

verification/cocotb/top/lib_i3c_top/test_bypass.py

Lines changed: 122 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
# SPDX-License-Identifier: Apache-2.0
22

3+
import os
34
import logging
45
import random
56

6-
from bus2csr import dword2int, int2dword
7+
from bus2csr import compare_values, dword2int, int2bytes, int2dword
8+
from cocotb_helpers import reset_n
79
from cocotbext_i3c.i3c_controller import I3cController
810
from cocotbext_i3c.i3c_target import I3CTarget
911
from interface import I3CTopTestInterface
12+
from utils import Access, draw_axi_priv_ids, get_axi_ids_seq
1013

1114
import cocotb
1215
from cocotb.triggers import ClockCycles, Combine, Event, Join, RisingEdge, Timer
1316

1417

15-
async def write_to_indirect_fifo(tb, data=None, format="bytes"):
18+
async def write_to_indirect_fifo(tb, data=None, awid=None, format="bytes"):
1619
"""
1720
Issues a write command to the target
1821
"""
@@ -34,7 +37,7 @@ async def write_to_indirect_fifo(tb, data=None, format="bytes"):
3437
# Do the I3C write transfer using the controller functionality
3538
for d in xfer:
3639
tb.dut._log.info(f"Writing data to TTI TX Data Queue: 0x{d:08X}")
37-
await tb.write_csr(tb.reg_map.I3C_EC.TTI.TX_DATA_PORT.base_addr, int2dword(d))
40+
await tb.write_csr(tb.reg_map.I3C_EC.TTI.TX_DATA_PORT.base_addr, int2dword(d), awid=awid)
3841

3942

4043
async def timeout_task(timeout):
@@ -54,7 +57,6 @@ async def initialize(dut, timeout=50):
5457

5558
tb = I3CTopTestInterface(dut)
5659
await tb.setup()
57-
5860
# Set recovery indirect FIFO size and max transfer size (in 4B units)
5961
# Set low values to easy trigger pointer wrap in tests.
6062
fifo_size = 8
@@ -723,3 +725,119 @@ async def rot_agent(buffer):
723725

724726
# Check if generated image matches received image
725727
assert image_dwords == xferd_words
728+
729+
730+
def csr_access_test_data(tb, rd_acc=Access.Priv, wr_acc=Access.Priv):
731+
test_data = []
732+
for reg_name in tb.reg_map.I3C_EC.SECFWRECOVERYIF:
733+
if reg_name in ["start_addr", "INDIRECT_FIFO_DATA"]:
734+
continue
735+
reg = getattr(tb.reg_map.I3C_EC.SECFWRECOVERYIF, reg_name)
736+
addr = reg.base_addr
737+
wdata = random.randint(0, 2**32 - 1)
738+
exp_rd = 0
739+
for f_name in reg:
740+
if f_name in ["base_addr", "offset"]:
741+
continue
742+
f = getattr(reg, f_name)
743+
if f.sw == "r" or ((wr_acc == Access.Unpriv) and (rd_acc == Access.Priv)):
744+
data = (f.reset << f.low) & f.mask
745+
elif f.woclr or f.hwclr:
746+
data = 0
747+
else:
748+
data = wdata & f.mask
749+
# The reset value of 'INDIRECT_FIFO_STATUS_3' is 0 but it's set
750+
# by 'recovery_executor' to 'IndirectFifoDepth' parameter
751+
if reg_name == "INDIRECT_FIFO_STATUS_3" and f_name == "FIFO_SIZE":
752+
data = 0x40
753+
if reg_name == "INDIRECT_FIFO_STATUS_4" and f_name == "MAX_TRANSFER_SIZE":
754+
data = 0x40
755+
756+
if rd_acc == Access.Unpriv:
757+
data = 0x0
758+
759+
exp_rd |= data
760+
test_data.append([addr, wdata, exp_rd])
761+
return test_data
762+
763+
764+
@cocotb.test(skip=os.getenv("FrontendBusInterface") != "AXI")
765+
async def test_check_axi_filtering(dut):
766+
"""
767+
Verifies AXI ID filtering in Secure Firmware Recovery registers access.
768+
"""
769+
770+
# Initialize
771+
tb = await initialize(dut)
772+
cocotb.start_soon(tb.busIf.write_access_monitor())
773+
cocotb.start_soon(tb.busIf.read_access_monitor())
774+
priv_ids = draw_axi_priv_ids()
775+
dut.disable_id_filtering_i.value = 0
776+
dut.priv_ids_i.value = priv_ids
777+
778+
#########################################################################
779+
# Verify privileged & unprivileged registers access #
780+
#########################################################################
781+
acc_pairs = [(x, y) for x in [Access.Priv, Access.Unpriv] for y in [Access.Priv, Access.Unpriv]]
782+
for rd_acc, wr_acc in acc_pairs:
783+
sfr_seq = csr_access_test_data(tb, rd_acc, wr_acc)
784+
785+
for addr, wdata, exp_rd in sfr_seq:
786+
awid = get_axi_ids_seq(priv_ids, 1, wr_acc)[0]
787+
arid = get_axi_ids_seq(priv_ids, 1, rd_acc)[0]
788+
await tb.write_csr(addr, int2dword(wdata), 4, awid=awid)
789+
resp = await tb.read_csr(addr, arid=arid)
790+
compare_values(int2bytes(exp_rd), resp, addr)
791+
792+
# Skip the indirect fifo data check as it will cause a read from an empty FIFO
793+
if wr_acc == Access.Unpriv:
794+
continue
795+
796+
# Writes to `INDIRECT_FIFO_DATA` are executed through the I3C
797+
await tb.write_csr(
798+
tb.reg_map.I3C_EC.SECFWRECOVERYIF.INDIRECT_FIFO_STATUS_3.base_addr,
799+
int2dword(2),
800+
4,
801+
awid=awid,
802+
)
803+
addr = tb.reg_map.I3C_EC.SECFWRECOVERYIF.INDIRECT_FIFO_DATA.base_addr
804+
# Burst ID cannot be 0
805+
awid = get_axi_ids_seq(priv_ids, 1, wr_acc)[0]
806+
while awid == 0:
807+
awid = get_axi_ids_seq(priv_ids, 1, wr_acc)[0]
808+
payload_data = [random.randint(0, 2**32 - 1) for _ in range(2)]
809+
await write_to_indirect_fifo(tb, payload_data, format="dwords", awid=awid)
810+
811+
resp = await tb.read_csr(addr, arid=get_axi_ids_seq(priv_ids, 1, rd_acc)[0])
812+
exp_rd = 0 if rd_acc == Access.Unpriv or wr_acc == Access.Unpriv else payload_data[0]
813+
compare_values(int2bytes(exp_rd), resp, addr)
814+
815+
await reset_n(dut.aclk, dut.areset_n, 2)
816+
817+
#########################################################################
818+
# Verify registers access with unprivileged IDs & configuration changes #
819+
#########################################################################
820+
821+
async def disable_random():
822+
while True:
823+
filter_off = int(dut.disable_id_filtering_i.value)
824+
if abs(random.random()) < 0.1:
825+
dut.disable_id_filtering_i.value = not filter_off
826+
await RisingEdge(dut.aclk)
827+
828+
async def priv_id_swap_random():
829+
while True:
830+
if abs(random.random()) < 0.2:
831+
dut.priv_ids_i.value = draw_axi_priv_ids()
832+
await RisingEdge(dut.aclk)
833+
834+
cocotb.start_soon(disable_random())
835+
cocotb.start_soon(priv_id_swap_random())
836+
837+
sfr_seq = csr_access_test_data(tb)
838+
839+
for addr, wdata, _ in sfr_seq:
840+
awid = get_axi_ids_seq(priv_ids, 1, Access.Mixed)[0]
841+
arid = get_axi_ids_seq(priv_ids, 1, Access.Mixed)[0]
842+
await tb.write_csr(addr, int2dword(wdata), 4, awid=awid)
843+
_ = await tb.read_csr(addr, arid=arid)

0 commit comments

Comments
 (0)