Starting with your code, I see two candidates for improvement. First, you can watch the signal changes using a single process:
process is begin wait on axi_arvalid, axi_awvalid for 10 us ; assert axi_arvalid'last_event = 0 sec or axi_awvalid'last_event = 0 sec report "watchdog timeout" severity failure ; end process ;
Alternately, you can track time. This is similar and assumes that the timeout is big enough that even if XxValid changed right at 10 us, it is ok to fail anyway. This has a simpler check if you are trying to check all of the AXI channels at the same time.
process is variable WaitStartTime : time ; begin WaitStartTime := now ; wait on axi_arvalid, axi_awvalid for 10 us ; assert now - WaitStartTime < 10 us report "watchdog timeout" severity failure ; end process ;
For the AXI interface, especially when the testbench is interacting with a subordinate, instead of checking for XxValid activity, I watch how long the valid signal high without a ready in response. As a result, I have one checker per AXI channel. The checks then work more like:
process begin wait until ArValid = '1' and rising_edge(Clk) ; if ArReady /= '1' then wait until ArReady = '1' and rising_edge(Clk) for TIMEOUT_PERIOD ; assert ArReady = '1' report "Timeout on ArReady" severity FAILURE ; end if ; end process ;
When I have an Axi4Manager VC, I generally put these sort of stall checks inside the VC. This simplifies the above as the Axi4Manager is also the source of ArValid.
You could minimize your effort some by encapsulating the above into a subprogram:
procedure CheckAxiReady ( signal Clk : in std_logic ; signal Valid : in std_logic ; signal Ready : in std_logic ; constant Message : in string ; constant TimeOutPeriod : in time ) is begin loop wait until Valid = '1' and rising_edge(Clk) ; if Ready /= '1' then wait until Ready = '1' and rising_edge(Clk) for TimeOutPeriod ; assert Ready = '1' report Message severity FAILURE ; end if ; end loop ; end procedure CheckAxiReady ;
Then call it concurrently:
CheckAxiReady ( Clk => Clk, Valid => ArValid, Ready => ArReady, Message => "AXI Read Address, Timeout on ArReady", TimeOutPeriod => 10 us ) ;