Problems with OSVVM Functional Coverage
Why OSVVM™? › Forums › OSVVM › Problems with OSVVM Functional Coverage
Tagged: osvvm coverage
- This topic has 3 replies, 2 voices, and was last updated 18 hours, 57 minutes ago by
Jim Lewis.
-
AuthorPosts
-
April 15, 2025 at 13:00 #2672
Alex
MemberI am exploring functional coverage. But cannot get a simple coverage running. Please point out what is wrong here:
rx_cnt_s counts upto 20 which has been verified.Background: This is a VUNIT testbench with where the DUT has AXI slaves. I use the Axi4Lite Manager as a master to access the AXI slaves in the DUT. The snippet below is part of the testbench where I am trying to do a functional coverage.
Still does not work when I added delta delays before Icover as suggested by Jim. Strange that the coverage is always zero. Could it be a framework or structural issue that I am missing?
RxCov is a signal.
rx_process : process is variable cnt : integer := 0; variable rd_data : std_logic_vector(31 downto 0) := (others => '0'); begin rx_cnt_s <= 0; RxCov <= NewID("RxCov") ; -- Get a Coverage ID wait for 0 ns ; osvvm.CoveragePkg.AddBins(RxCov, "count", GenBin(1,20,1) ) ; loop WaitForClock(InterruptRec, 1) ; report "Interrupt Handler Started" ; Read(InterruptRec, X"A80", rd_data); if (rd_data(10) = '1') then Read(InterruptRec, x"920", rd_data); if (rd_data(30 downto 26) = rd_data(20 downto 16)) then report "RX FIFO EMPTY"; else osvvm.TbUtilPkg.WaitForClock(clk, 2); cnt := rx_cnt_s; cnt := cnt + 1; rx_cnt_s <= cnt; osvvm.CoveragePkg.ICover(RxCov, rx_cnt_s) ; -- Collect functional coverage end if; end if; report "Interrupt Handler Done" ; InterruptReturn(InterruptRec) ; wait for 1 ns ; end loop; osvvm.CoveragePkg.WriteBin(RxCov); --print results wait; end process;
Also the control Process:
----------------------------------------------------------- -- ControlProc -- Set up AlertLog and wait for end of test ------------------------------------------------------------ ControlProc : process begin -- Initialization of test SetTestName("test") ; SetLogEnable(PASSED, TRUE) ; -- Enable PASSED logs SetLogEnable(INFO, TRUE) ; -- Enable INFO logs -- SetLogEnable(DEBUG, TRUE) ; -- Enable INFO logs -- Wait for testbench initialization wait for 0 ns ; wait for 0 ns ; TranscriptOpen(OSVVM_RESULTS_DIR & "test.txt") ; SetTranscriptMirror(TRUE) ; SetAlertLogOptions(WriteTimeLast => FALSE) ; SetAlertLogOptions(TimeJustifyAmount => 15) ; SetAlertLogJustify ; -- Wait for Design Reset wait until nreset = '1' ; ClearAlerts ; -- Wait for test to finish WaitForBarrier(TestDone, 1 ms) ; AlertIf(now >= 20 ms, "Test finished due to timeout") ; AlertIf(GetAffirmCount < 1, "Test is not Self-Checking"); TranscriptClose ; EndOfTestReports ; -- std.env.stop ; wait for 7ms ; end process ControlProc ;
Generated YAML Coverage report:
Version: "1.0" Coverage: 0.00 Settings: WritePassFail: 0 Models: - Name: "RxCov" TestCases: - "count" Coverage: 0.00 Settings: CovWeight: 1 Goal: 100.0 WeightMode: "AT_LEAST" Seeds: [1129194420, 352562534] CountMode: "COUNT_FIRST" IllegalMode: "ILLEGAL_ON" Threshold: 45.0 ThresholdEnable: "FALSE" IsRequirement: "FALSE" TotalCovCount: 0 TotalCovGoal: 1 BinInfo: Dimensions: 1 FieldNames: - "Bin1" NumBins: 1 Bins: - Name: "count" Type: "COUNT" Range: - {Min: 1, Max: 20} Count: 0 AtLeast: 1 PercentCov: 0.0000
April 15, 2025 at 15:45 #2674Jim Lewis
MemberHi ALex,
I added the two suggestions I made previously to the code. Choose one of them.
I also changed the WaitForClock(clk, 2) to WaitForClock(InterruptRec, 2).
Usually I do not put clock in TestCtrl. The reason being is if you have lots of
different clocks in your system, it is easy to use the wrong one.rx_process : process is variable cnt : integer := 0; -- this value is applied at time 0 ns variable rd_data : std_logic_vector(31 downto 0) := (others => '0'); begin rx_cnt_s <= 0; RxCov <= NewID("RxCov") ; -- Get a Coverage ID wait for 0 ns ; -- This puts all counts in a single bin with range 1 to 20 osvvm.CoveragePkg.AddBins(RxCov, "count", GenBin(1,20,1) ) ; -- This puts all counts in a separate bins range 1 to 1, 2 to 2, ... osvvm.CoveragePkg.AddBins(RxCov, "count", GenBin(1,20) ) ; loop WaitForClock(InterruptRec, 1) ; report "Interrupt Handler Started" ; Read(InterruptRec, X"A80", rd_data); if (rd_data(10) = '1') then Read(InterruptRec, x"920", rd_data); if (rd_data(30 downto 26) = rd_data(20 downto 16)) then report "RX FIFO EMPTY"; else -- The following is a problem if you do not have clk here - I generally recommend against clock here -- osvvm.TbUtilPkg.WaitForClock(clk, 2); -- Instead let the VC do the waiting WaitForClock(InterruptRec, 2); -- wait for VC number of clocks -- Note the previous waits are not needed by OSVVM. cnt := rx_cnt_s; cnt := cnt + 1; -- Either Check cnt in ICover because rx_cnt_s does not update until a delta cycle later osvvm.CoveragePkg.ICover(RxCov, cnt) ; -- Collect functional coverage log("cnt value: " & to_string(cnt)) ; -- log values of cnt to correlate with functional coverage rx_cnt_s <= cnt; -- Or add a delta cycle by doing wait for 0 ns here: rx_cnt_s <= cnt; wait for 0 ns ; osvvm.CoveragePkg.ICover(RxCov, rx_cnt_s ) ; -- Collect functional coverage log("cnt value: " & to_string(rx_cnt_s)) ; -- log values of cnt to correlate with functional coverage end if; end if; report "Interrupt Handler Done" ; InterruptReturn(InterruptRec) ; wait for 1 ns ; end loop; -- The loop is never exited so this code never runs. osvvm.CoveragePkg.WriteBin(RxCov); -- generates a test report wait; end process;
Your control process cannot iterate, so change it as follows:
ControlProc : process begin -- Initialization of test SetTestName("test") ; SetLogEnable(PASSED, TRUE) ; -- Enable PASSED logs SetLogEnable(INFO, TRUE) ; -- Enable INFO logs -- SetLogEnable(DEBUG, TRUE) ; -- Enable INFO logs -- Wait for testbench initialization wait for 0 ns ; wait for 0 ns ; TranscriptOpen(OSVVM_RESULTS_DIR & "test.txt") ; SetTranscriptMirror(TRUE) ; SetAlertLogOptions(WriteTimeLast => FALSE) ; SetAlertLogOptions(TimeJustifyAmount => 15) ; SetAlertLogJustify ; -- Wait for Design Reset wait until nreset = '1' ; ClearAlerts ; -- Wait for test to finish -- If you have a process that uses WaitForBarrier(TestDone) somewhere else the following is ok WaitForBarrier(TestDone, 20 ms) ; -- note I change the wait time to match the timeout period AlertIf(now >= 20 ms, "Test finished due to timeout") ; -- If not, replace the WaitForBarrier with wait for 20 ms ; AlertIf(GetAffirmCount < 1, "Test is not Self-Checking"); TranscriptClose ; EndOfTestReports ; -- add stop, remove wait for 7 ms std.env.stop ; -- wait for 7ms ; wait ; end process ControlProc ;
April 15, 2025 at 15:48 #2675Alex
MemberI tried printing the logs with writebin. The coverage seems to work. its onyl the YAML reports which does not print it right I suppose:
%% WriteBin: RxCov %% count PASSED Bin:(1) Count = 1 AtLeast = 1 %% count PASSED Bin:(2) Count = 1 AtLeast = 1 %% count PASSED Bin:(3) Count = 1 AtLeast = 1 %% count PASSED Bin:(4) Count = 1 AtLeast = 1 %% count PASSED Bin:(5) Count = 1 AtLeast = 1 %% count PASSED Bin:(6) Count = 1 AtLeast = 1 %% count PASSED Bin:(7) Count = 1 AtLeast = 1 %% count PASSED Bin:(8) Count = 1 AtLeast = 1 %% count PASSED Bin:(9) Count = 1 AtLeast = 1 %% count PASSED Bin:(10) Count = 1 AtLeast = 1 %% count PASSED Bin:(11) Count = 1 AtLeast = 1 %% count PASSED Bin:(12) Count = 1 AtLeast = 1 %% count PASSED Bin:(13) Count = 1 AtLeast = 1 %% count PASSED Bin:(14) Count = 1 AtLeast = 1 %% count PASSED Bin:(15) Count = 1 AtLeast = 1 %% count PASSED Bin:(16) Count = 1 AtLeast = 1 %% count PASSED Bin:(17) Count = 1 AtLeast = 1 %% count PASSED Bin:(18) Count = 1 AtLeast = 1 %% count PASSED Bin:(19) Count = 1 AtLeast = 1 %% count PASSED Bin:(20) Count = 1 AtLeast = 1
April 15, 2025 at 15:54 #2676Jim Lewis
MemberThese above write bin values were not generated by the code you posted. See annotations in the code.
-
AuthorPosts
- You must be logged in to reply to this topic.