@@ -2255,6 +2255,104 @@ async def test_ccc_setdasa_padding_err(dut):
22552255
22562256
22572257@cocotb .test ()
2258+ async def test_ccc_setdasa_padding_err_det_disabled (dut ):
2259+ """
2260+ Verify that SETDASA/SETNEWDA with padding bit[0]=1 and FRAMING_ERR_DET_EN=0
2261+ applies the address normally (rx_data_valid fires) and does NOT set the framing
2262+ error status or increment the framing error counter. Per ccc.sv:1119-1127.
2263+ """
2264+ log = logging .getLogger ("test_ccc_setdasa_padding_err_det_disabled" )
2265+
2266+ (STATIC_ADDR , VIRT_STATIC_ADDR , DYNAMIC_ADDR , VIRT_DYNAMIC_ADDR ) = random .sample (VALID_I3C_ADDRESSES , 4 )
2267+ i3c_controller , i3c_target , tb = await test_setup (dut , STATIC_ADDR , VIRT_STATIC_ADDR )
2268+
2269+ err_intr_addr = tb .reg_map .I3C_EC .TTI .TARGET_ERR_INTR_STATUS .base_addr
2270+ framing_stat_field = tb .reg_map .I3C_EC .TTI .TARGET_ERR_INTR_STATUS .FRAMING_ERR_STAT
2271+ framing_cnt_addr = tb .reg_map .I3C_EC .TTI .TARGET_ERR_CNT_FRAMING .base_addr
2272+ framing_cnt_field = tb .reg_map .I3C_EC .TTI .TARGET_ERR_CNT_FRAMING .CNT
2273+
2274+ da_reg_addr = tb .reg_map .I3C_EC .STDBYCTRLMODE .STBY_CR_DEVICE_ADDR .base_addr
2275+ da_valid_field = tb .reg_map .I3C_EC .STDBYCTRLMODE .STBY_CR_DEVICE_ADDR .DYNAMIC_ADDR_VALID
2276+ da_field = tb .reg_map .I3C_EC .STDBYCTRLMODE .STBY_CR_DEVICE_ADDR .DYNAMIC_ADDR
2277+
2278+ err_ctrl_addr = tb .reg_map .I3C_EC .TTI .TARGET_ERR_CTRL .base_addr
2279+ framing_det_field = tb .reg_map .I3C_EC .TTI .TARGET_ERR_CTRL .FRAMING_ERR_DET_EN
2280+
2281+ # Enable framing error interrupt so any spurious error would be captured
2282+ err_en_addr = tb .reg_map .I3C_EC .TTI .TARGET_ERR_INTR_ENABLE .base_addr
2283+ framing_en_field = tb .reg_map .I3C_EC .TTI .TARGET_ERR_INTR_ENABLE .FRAMING_ERR_EN
2284+ await tb .write_csr_field (err_en_addr , framing_en_field , 1 )
2285+
2286+ # Clear any stale framing error status (W1C)
2287+ await tb .write_csr_field (err_intr_addr , framing_stat_field , 1 )
2288+
2289+ log .info ("Disabling FRAMING_ERR_DET_EN" )
2290+ await tb .write_csr_field (err_ctrl_addr , framing_det_field , 0 )
2291+
2292+ # ---- Test 1: SETDASA with bad padding and det_en=0 -> address IS applied ----
2293+ cnt_before = await tb .read_csr_field (framing_cnt_addr , framing_cnt_field )
2294+
2295+ log .info (f"SETDASA with bad padding (det_en=0): addr={ STATIC_ADDR :#x} -> DA={ DYNAMIC_ADDR :#x} | 1" )
2296+ bad_data_byte = (DYNAMIC_ADDR << 1 ) | 1
2297+ await i3c_controller .i3c_ccc_write (
2298+ ccc = CCC .DIRECT .SETDASA , directed_data = [(STATIC_ADDR , [bad_data_byte ])])
2299+
2300+ # Detection disabled: bad padding is ignored, address IS applied
2301+ da_valid = await tb .read_csr_field (da_reg_addr , da_valid_field )
2302+ assert da_valid == 1 , f"DA_VALID should be 1 with framing det disabled, got { da_valid } "
2303+ da_val = await tb .read_csr_field (da_reg_addr , da_field )
2304+ assert da_val == DYNAMIC_ADDR , f"DA should be { DYNAMIC_ADDR :#x} with det disabled, got { da_val :#x} "
2305+
2306+ framing_stat = await tb .read_csr_field (err_intr_addr , framing_stat_field )
2307+ assert framing_stat == 0 , f"FRAMING_ERR_STAT should be 0 with det disabled (SETDASA), got { framing_stat } "
2308+
2309+ cnt_after = await tb .read_csr_field (framing_cnt_addr , framing_cnt_field )
2310+ assert cnt_after == cnt_before , (
2311+ f"Framing counter must not increment with det_en=0 (SETDASA): "
2312+ f"before={ cnt_before } , after={ cnt_after } "
2313+ )
2314+
2315+ # Assign virtual target address for later GETBCR verification
2316+ await i3c_controller .i3c_ccc_write (
2317+ ccc = CCC .DIRECT .SETDASA , directed_data = [(VIRT_STATIC_ADDR , [VIRT_DYNAMIC_ADDR << 1 ])])
2318+
2319+ # ---- Test 2: SETNEWDA with bad padding and det_en=0 -> address IS changed ----
2320+ NEW_ADDR = random .choice ([a for a in VALID_I3C_ADDRESSES
2321+ if a not in (STATIC_ADDR , VIRT_STATIC_ADDR , DYNAMIC_ADDR , VIRT_DYNAMIC_ADDR )])
2322+ await tb .write_csr_field (err_intr_addr , framing_stat_field , 1 )
2323+ cnt_before = cnt_after
2324+
2325+ log .info (f"SETNEWDA with bad padding (det_en=0): DA={ DYNAMIC_ADDR :#x} -> { NEW_ADDR :#x} | 1" )
2326+ bad_data_byte = (NEW_ADDR << 1 ) | 1
2327+ await i3c_controller .i3c_ccc_write (
2328+ ccc = CCC .DIRECT .SETNEWDA , directed_data = [(DYNAMIC_ADDR , [bad_data_byte ])])
2329+
2330+ # Detection disabled: bad padding is ignored, address IS changed to NEW_ADDR
2331+ da_val = await tb .read_csr_field (da_reg_addr , da_field )
2332+ assert da_val == NEW_ADDR , f"DA should be { NEW_ADDR :#x} with det disabled, got { da_val :#x} "
2333+
2334+ framing_stat = await tb .read_csr_field (err_intr_addr , framing_stat_field )
2335+ assert framing_stat == 0 , f"FRAMING_ERR_STAT should be 0 with det disabled (SETNEWDA), got { framing_stat } "
2336+
2337+ cnt_after = await tb .read_csr_field (framing_cnt_addr , framing_cnt_field )
2338+ assert cnt_after == cnt_before , (
2339+ f"Framing counter must not increment with det_en=0 (SETNEWDA): "
2340+ f"before={ cnt_before } , after={ cnt_after } "
2341+ )
2342+
2343+ # Re-enable framing error detection
2344+ await tb .write_csr_field (err_ctrl_addr , framing_det_field , 1 )
2345+
2346+ # Target should still respond at updated address
2347+ responses = await i3c_controller .i3c_ccc_read (
2348+ ccc = CCC .DIRECT .GETBCR , addr = NEW_ADDR , count = 1 )
2349+ assert responses [0 ][0 ] == True , "Target should ACK at new DA with detection re-enabled"
2350+
2351+ tb .te_error_monitor .check ()
2352+
2353+ await tb .teardown ()
2354+
2355+
22582356async def test_ccc_te2_parity (dut ):
22592357 """
22602358 Verify TE2 error detection: bad T-bit parity on CCC defining byte causes
0 commit comments