1
1
# SPDX-License-Identifier: Apache-2.0
2
2
3
+ import os
3
4
import logging
4
5
import random
5
6
6
- from bus2csr import dword2int , int2dword
7
+ from bus2csr import compare_values , dword2int , int2bytes , int2dword
8
+ from cocotb_helpers import reset_n
7
9
from cocotbext_i3c .i3c_controller import I3cController
8
10
from cocotbext_i3c .i3c_target import I3CTarget
9
11
from interface import I3CTopTestInterface
12
+ from utils import Access , draw_axi_priv_ids , get_axi_ids_seq
10
13
11
14
import cocotb
12
15
from cocotb .triggers import ClockCycles , Combine , Event , Join , RisingEdge , Timer
13
16
14
17
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" ):
16
19
"""
17
20
Issues a write command to the target
18
21
"""
@@ -34,7 +37,7 @@ async def write_to_indirect_fifo(tb, data=None, format="bytes"):
34
37
# Do the I3C write transfer using the controller functionality
35
38
for d in xfer :
36
39
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 )
38
41
39
42
40
43
async def timeout_task (timeout ):
@@ -54,7 +57,6 @@ async def initialize(dut, timeout=50):
54
57
55
58
tb = I3CTopTestInterface (dut )
56
59
await tb .setup ()
57
-
58
60
# Set recovery indirect FIFO size and max transfer size (in 4B units)
59
61
# Set low values to easy trigger pointer wrap in tests.
60
62
fifo_size = 8
@@ -723,3 +725,119 @@ async def rot_agent(buffer):
723
725
724
726
# Check if generated image matches received image
725
727
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