@@ -200,6 +200,65 @@ async def test_virtual_write(dut):
200
200
assert data0 != 0xDDCCBBAA
201
201
assert data1 != 0x44332211
202
202
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
+
203
262
@cocotb .test ()
204
263
async def test_write (dut ):
205
264
"""
@@ -701,6 +760,90 @@ async def test_virtual_read_illegal(dut):
701
760
# Wait
702
761
await Timer (1 , "us" )
703
762
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
+
704
847
@cocotb .test ()
705
848
async def test_payload_available (dut ):
706
849
"""
0 commit comments