osvvm / osvvm Goto Github PK
View Code? Open in Web Editor NEWOSVVM Utility Library: AlertLogPkg, CoveragePkg, RandomPkg, ScoreboardGenericPkg, MemoryPkg, TbUtilPkg, TranscriptPkg, ...
License: Other
OSVVM Utility Library: AlertLogPkg, CoveragePkg, RandomPkg, ScoreboardGenericPkg, MemoryPkg, TbUtilPkg, TranscriptPkg, ...
License: Other
FPGA world suffers a lot from fragmentation - some tools produce Verilog, some VHDL, some - only subsets of them, creating low-level LLVM-like alternative will help everyone, so HDL implementations will opt only for generating this low-level HDL and routing/synthesizers accept it. LLVM or WebAssembly - you can see how many languages and targets are supported now by both. With more open source tools for FPGA this is more feasible now than ever. Most of the people suggest to adapt FIRRTL for this. Please check the discussion and provide a feedback if you have any. There is a good paper on FIRRTL design and its reusability across different tools and frameworks.
See f4pga/ideas#19
When AlertIf
is called with an uninitialized AlertLogID
, GHDL emits an overflow detected error, wheras Riviera-PRO keeps quite.
Example code:
entity e is
generic (
PeriodHigh : time
)
end entity;
architecture a of e is
signal ModelID : AlertLogIDType;
impure function getPeriod(PH : time) return time is
begin
AlertIf(ModelID, (PH <= 0 ns), "Period is not a positive value.", FAILURE);
return PH;
end function;
signal Period : time := getPeriod(PeriodHigh);
begin
end architecture;
Messages from GHDL (bigger example code):
Running Testbench ...
Loading simulation 'test.TestCase_GenerateAndObserve'
C:\Tools\GHDL.36-dev-gnatgpl32-mcodin\ghdl.exe:error: overflow detected
from: osvvm.alertlogpkg.alertlogstructptype.alert at AlertLogPkg.vhd:647
from: osvvm.alertlogpkg.alertif at AlertLogPkg.vhd:1708
from: osvvm_clock.clock_monitor(rtl).getclockperiod at clock_Monitor.vhdl:40
from: osvvm_clock.clock_monitor(rtl).DECL_ELAB at clock_Monitor.vhdl:58
from: test.clock_generator_monitor_tb(testharness).monitor.CMP_ELAB at clock_Generator_Monitor_tb.vhdl:27
from: test.clock_generator_monitor_tb(testharness).DECL_ELAB at clock_Generator_Monitor_tb.vhdl:29
from: Elaboration of design
C:\Tools\GHDL.36-dev-gnatgpl32-mcodin\ghdl.exe:error: error during elaboration
[ERROR] While simulating 'test.TestCase_GenerateAndObserve'. ExitCode: 1
After fixing the missing init value, GHDL was happy.
Sorry if you already have plans for this.
Currently, I have In house verification IP entities which have RandomPTypes in them. The seed is passed in via a generic to the testbench so I can set the seed from the CI_JOB_ID system variable to get a new pattern on each run in gitlab CI, but still allow me to recreate the pattern in case of an error. Because this is simply an integer, to ensure each has a unique random pattern, I pass G_RANDOM_SEED
as a generic to the testbench, the for each VIP instatiation, I do the following generic maps:
G_RANDOM_SEED => (G_RANDOM_SEED + 1),
....
G_RANDOM_SEED => (G_RANDOM_SEED + 2),
...
G_RANDOM_SEED => (G_RANDOM_SEED + 3),
...
cov.InitSeed(G_RANDOM_SEED+4);
--etc
With VHDL 2019, I can modify the VIP entities to have a randomPType shared variable in the port map so I can simply use a single randomPType throughout the testbench. Ideally I would have a mechanism to pass the same object into the coverage object(s) so I can simply call InitSeed once.
The current log message can be fairly difficult to decode if there are complex/long types used as the expected/actual types. Here is an example using AXIS record types:
KERNEL: %% Alert ERROR in data_checker_inst, Received: tid: 0xXX tdata: 0x2F2E2D2C2B2A29282726252423222120 tuser: 0x1 tdest: 0xX tkeep: 0xFFFF tstrb: 0xXXXX tlast: 0 Expected: tid: 0xXX tdata: 0x0F0E0D0C0B0A09080706050403020100 tuser: 0x1 tdest: 0xX tkeep: 0xFFFF tstrb: 0xXXXX tlast: 0 Item Number: 1 at 200 ns
I have a custom report function that outputs much more detailed comparison inside the match
function. This currently gives me the following output:
KERNEL: %% Log ALWAYS in testbench_tools_pkg, act: tid: 0xXX tdata: 0x2F2E2D2C2B2A29282726252423222120 tuser: 0x1 tdest: 0xX tkeep: 0xFFFF tstrb: 0xXXXX tlast: 0 at 200 ns
KERNEL: %% Log ALWAYS in testbench_tools_pkg, exp: tid: 0xXX tdata: 0x0F0E0D0C0B0A09080706050403020100 tuser: 0x1 tdest: 0xX tkeep: 0xFFFF tstrb: 0xXXXX tlast: 0 at 200 ns
KERNEL: %% Log ALWAYS in testbench_tools_pkg, X X X X X X X X X X X X X X X X at 200 ns
KERNEL: %% Alert ERROR in data_checker_inst, Received: tid: 0xXX tdata: 0x2F2E2D2C2B2A29282726252423222120 tuser: 0x1 tdest: 0xX tkeep: 0xFFFF tstrb: 0xXXXX tlast: 0 Expected: tid: 0xXX tdata: 0x0F0E0D0C0B0A09080706050403020100 tuser: 0x1 tdest: 0xX tkeep: 0xFFFF tstrb: 0xXXXX tlast: 0 Item Number: 1 at 200 ns
Ideally, I could just replace the default report with my own.
While generalizing OSVVM's SortListPkg_int
to a more generic package, I found that the parameters Min
and Max
in procedure add
are integer typed. These parameters should use ElementType
.
Lines to change:
Shouldnt procedure IncAlertCount () exit with code 1?
The alert procedure exits with code 1.
This way CI can know if a test has failed without having to scrub the log?
Or maybe have a config item to set the exit code?
Hi Jim,
I made some tests with your new release 2022.02 and found a possible bug in the "OsvvmContext.vhd" File. There is no ScoreboardPkg included. Maybe this is your intention, but I don't think so.
Best regards,
Sebastian
Please look at MemoryPKG_user_guide.pdf
It looks that most of it is just copy&paste from AlertLogPKG documentation
Hi
I've encountered the following error message when using the coverage package with GHDL:
/usr/local/bin/ghdl:error: overflow detected
from: osvvm.coveragepkg.covptype.icoverindex at CoveragePkg.vhd:2072
As far as I understand the code, the overflow is intentionally?
However, I haven't found a way to tell GHDL that this is ok...
The tb below triggers this. It uses vunit, but should be easy to modify to run without.
library ieee;
context ieee.ieee_std_context;
library vunit_lib;
context vunit_lib.vunit_context;
library osvvm;
use osvvm.RandomPkg.all;
use osvvm.CoveragePkg.all;
entity tb_osvvm is
generic (
runner_cfg : string := runner_cfg_default
);
end entity tb_osvvm;
architecture tb of tb_osvvm is
shared variable cov_fill : CovPType;
begin
------------------------------------------------------------------------------------------------------------------------
-- Test process
------------------------------------------------------------------------------------------------------------------------
p_main : process
variable rnd : RandomPType;
begin
test_runner_setup(runner, runner_cfg);
show_all(display_handler);
while test_suite loop
if run("random") then
cov_fill.AddBins(GenBin(0, 3));
while true loop
cov_fill.ICover(rnd.RandInt(0, 3));
cov_fill.WriteBin;
end loop;
end if;
end loop;
info(to_string(get_checker_stat));
test_runner_cleanup(runner);
end process p_main;
end architecture tb;
Best regards,
emanuel
It would be nice, if we could set names for Bins.
Maybe we have a coverage model for a simple 3 state FSM:
type t_fsm_state is (IDLE, ADDR, DATA);
signal s_fsm_state, s_fsm_state_prev : t_fsm_state;
shared variable sv_fsm_cov : CovPType;
sv_fsm_cov.AddCross(GenBin(t_fsm_state'pos(IDLE)), GenBin(t_fsm_state'pos(ADDR));
sv_fsm_cov.AddCross(GenBin(t_fsm_state'pos(ADDR)), GenBin(t_fsm_state'pos(DATA));
sv_fsm_cov.AddCross(GenBin(t_fsm_state'pos(ADDR)), GenBin(t_fsm_state'pos(IDLE));
sv_fsm_cov.AddCross(GenBin(t_fsm_state'pos(DATA)), GenBin(t_fsm_state'pos(IDLE));
sv_fsm_cov.AddCross(ALL_ILLEGAL, ALL_ILLEGAL);
...
sv_fsm_cov.ICover(t_fsm_state'pos(s_fsm_state_prev), t_fsm_state'pos(s_fsm_state));
...
sv_fsm_cov.WriteBin;
At the moment, the integer values are shown in the report like this:
# %%WriteBin:
# %% Bin:(0) (1) Count = 1 AtLeast = 1
# %% Bin:(1) (0) Count = 1 AtLeast = 1
# %% Bin:(1) (2) Count = 1 AtLeast = 1
# %% Bin:(2) (0) Count = 1 AtLeast = 1
It would be nicer if we had names for Bins.
Maybe, the report could use them like this:
# %%WriteBin:
# %% Bin:(IDLE) (ADDR) Count = 1 AtLeast = 1
# %% Bin:(ADDR) (DATA) Count = 1 AtLeast = 1
# %% Bin:(ADDR) (IDLE) Count = 1 AtLeast = 1
# %% Bin:(DATA) (IDLE) Count = 1 AtLeast = 1
That could be realised with overloading maybe.
impure function GenBin(BinIndex : integer, name : string) return CovBinBaseType;
If you give a name with the Bin creation, we have such a new report,
if not, we have the old above with integers only.
Furthermore a name field of type string has to be added to the CovBinBaseType
and the CovMatrix* record types.
type CovBinBaseType is record
BinVal : RangeArrayType(1 to 1);
Action : integer;
Count : integer;
AtLeast : integer;
Name : string;
end record;
Xilinx and some other vendors provide a file called vhdl_analyze_order
per VHDL library, containing one source file per line. This file can be read by Tcl, Bash or what ever language to execute the compile commands for a VHDL library in the right order. Alternative names might be: analyze_order
or compile_order
.
This solution has several advantages:
Example:
NamePkg.vhd
OsvvmGlobalPkg.vhd
TextUtilPkg.vhd
TranscriptPkg.vhd
AlertLogPkg.vhd
MemoryPkg.vhd
MessagePkg.vhd
SortListGenericPkg.vhd
SortListPkg.vhd
SortListPkg_int.vhd
RandomBasePkg.vhd
RandomPkg.vhd
CoveragePkg.vhd
ScoreboardGenericPkg.vhd
ScoreboardPkg.vhd
OsvvmContext.vhd
Example Bash script to read such a file:
Library="xilinxcorelib"
# append absolute source path
SourceFiles=()
while IFS= read -r File; do
SourceFiles+=("$SourceDirectory/XilinxCoreLib/$File")
done < <(grep --no-filename -R '^[a-zA-Z]' "$SourceDirectory/XilinxCoreLib/vhdl_analyze_order")
GHDLCompilePackages
Source: https://github.com/tgingold/ghdl/blob/master/libraries/vendors/compile-xilinx-ise.sh?ts=2#L366-L376
I think there is a minor bug in ReportAlerts, where the hierarchy won't get printed unless the test failed even if ReportAll is true. I propose changing AlertLogPkg.vhd line 1338 from:
if (FoundReportHierVar and ReportHierarchyVar) and TestFailed then
to:
if (FoundReportHierVar and ReportHierarchyVar) and (TestFailed or ReportAll) then
Thank you!
Is there a typical approach for including alerts and logs (from AlertLogPkg) in synthesizable code? My favorite would be to not touch the production code -- let it call AlertIf and Log all it likes -- and put the synthesis translate off/on pragmas in the package. But that could be a significant amount of work.
What do you think? How are others handling this?
From an external user:
I am struggling with configuration procedure SetAlertLogOptions in conjunction with ReportAlerts. I am not sure, if there is a basic misunderstanding or a bug causing this observed behavior. In attached screenshot you will see the contradictions. My assumption was that “passed” and “affirmations” counts are skipped in report like “DisabledAlerts”:
With the settings:
ReportAlertLogOptions
-------------------------
. . .
PrintPassedVar: false
PrintAffirmationsVar: false
...
Report Alerts produces:
%% DONE FAILED Report Summary Total Error(s) = 3 Failures: 0 Errors: 3 Warnings: 0 Passed: 33 Affirmations Checked: 35 at 4355 ns
ScoreboardGenericPkg.vhd contains comments on how to modify the file for simulators not supporting package generics (latest binary/stable release of GHDL for example). I would prefer if such a modification is provided as a separate implementation in the same way that VendorCovApiPkg
has several implementations. This would remove need for users to create and maintain their own implementations.
When compiling Scoreboard with Riviera-PRO, I get this warning:
COMP96 Compile Package Body "ScoreboardGenericPkg"
COMP96 WARNING COMP96_0048: "This function may complete without return statement." ".../lib/OSVVM/ScoreboardGenericPkg.vhd" 1525 5
On line 2226 of the current AlertLogPkg.vhd, the base AffirmIf
procedure calls
AlertLogStruct.Alert(AlertLogID, ReceivedMessage & ExpectedMessage, ERROR) ;
which forces calling Alert
with a severity of ERROR
. However, AffirmIf
already has an AlertLevel
input. I am trying to signal a FAILURE
with an AffirmIf
call, but the severity that I request gets ignored.
AlertLogPkg.vhd: ASCII text, with CRLF line terminators
CoveragePkg.vhd: ASCII text, with CRLF line terminators
MemoryPkg.vhd: ASCII text
MessageListPkg.vhd: ASCII text
MessagePkg.vhd: ASCII text, with CRLF line terminators
NamePkg.vhd: ASCII text
NameStorePkg.vhd: ASCII text
OsvvmContext.vhd: ASCII text
OsvvmGlobalPkg.vhd: ASCII text
OsvvmTypesPkg.vhd: ASCII text
RandomBasePkg.vhd: ASCII text
RandomPkg.vhd: ASCII text
RandomProcedurePkg.vhd: ASCII text
ReportPkg.vhd: ASCII text
ResizePkg.vhd: ASCII text
ResolutionPkg.vhd: ASCII text, with CRLF line terminators
ScoreboardGenericPkg.vhd: ASCII text, with CRLF line terminators
ScoreboardPkg_int_c.vhd: ASCII text
ScoreboardPkg_int.vhd: ASCII text
ScoreboardPkg_slv_c.vhd: ASCII text
ScoreboardPkg_slv.vhd: ASCII text
SortListPkg_int.vhd: ASCII text
TbUtilPkg.vhd: ASCII text, with CRLF line terminators
TextUtilPkg.vhd: ASCII text
TranscriptPkg.vhd: ASCII text
VendorCovApiPkg_Aldec.vhd: ASCII text
VendorCovApiPkg.vhd: ASCII text
@JimLewis are you willing to use LF only everywhere? Current CRLF makes pure text parsing a little bit more cumbersome.
In AlertLogPkg.vhd
a some assignments of access values w/o .all.
. This causes a error using nvc
.
Example:
entity access_assignment is
end entity;
architecture test of access_assignment is
type rec_t is record
foo: integer;
end record rec_t;
type rec_ptr_t is access rec_t;
type rec_arr_t is array (integer range <>) of rec_ptr_t;type rec_arr_ptr_t is access rec_arr_t;
procedure ok_procedure is
variable rec_ptr: rec_arr_ptr_t;
begin
rec_ptr(0) := new rec_t'(foo => 42);
rec_ptr(0).all.foo := 2;
end;
procedure nok_procedure is
variable rec_ptr: rec_arr_ptr_t;
begin
rec_ptr(0) := new rec_t'(foo => 42);
rec_ptr(0).foo := 2; -- <- error here
end;
begin
end architecture;
nvc
error:
** Error: expected record type but found REC_PTR_T
File access_bug.vhd, Line 15
rec_ptr(0).foo := 2; -- <- error here
^^^^^^^^^^
According to my literature, The Designer's Guide to VHDL - Third Edition the .all.
is required and hence not a bug of nvc
[1].
[1] The Designer's Guide to VHDL Third Edition, section 15.1.2 Assignment and Equality of Access Values
Hello Jim,
I am a QuestaSim user and I have an issue regarding the position of the simulation time when doing logging.
The problem occurs is if I want to log a time value e.g.: "Pulse length = 20 ns at 123450000 ns".
The link between the Transcript window and the Wave window is then not working anymore (clicking with the mouse in Transcript window onto the simulation time normally sets the cursor in the Wave window). I made a support case at Mentor and they said that this link in looking for the first timing value in each line.
So if the simulation time would be printed out not at the end of the line this problem could be solved.
Best regards,
Sebastian
GHDL includes a script for building OSVVM that along with --std=08
uses the options -fexplicit -frelaxed-rules --no-vital-checks --warn-binding --mb-comments
. The -frelaxed-rules
option to "relax some LRM rules" was surprising, so after building OSVVM without it and running a simple testbench I get the following:
../src/osvvm/CoveragePkg.vhd:5249:12:error: pure function "to_boolean" cannot call (impure) procedure "alert"
../src/osvvm/CoveragePkg.vhd:5249:12:note: (you can use -frelaxed to turn this error into a warning)
../src/osvvm/AlertLogPkg.vhd:112:13:error: (procedure "alert" is defined here)
../src/osvvm/CoveragePkg.vhd:5286:12:error: pure function "to_std_logic" cannot call (impure) procedure "alert"
../src/osvvm/AlertLogPkg.vhd:112:13:error: (procedure "alert" is defined here)
../src/osvvm/CoveragePkg.vhd:5321:12:error: pure function "to_boolean_vector" cannot call (impure) procedure "alert"
../src/osvvm/AlertLogPkg.vhd:112:13:error: (procedure "alert" is defined here)
../src/osvvm/CoveragePkg.vhd:5356:12:error: pure function "to_std_logic_vector" cannot call (impure) procedure "alert"
../src/osvvm/AlertLogPkg.vhd:112:13:error: (procedure "alert" is defined here)
../src/osvvm/CoveragePkg.vhd:5245:12:error: pure subprogram body cannot call (impure) procedure "alert"
../src/osvvm/AlertLogPkg.vhd:112:13:error: (procedure "alert" is defined here)
../src/osvvm/CoveragePkg.vhd:5282:12:error: pure subprogram body cannot call (impure) procedure "alert"
../src/osvvm/AlertLogPkg.vhd:112:13:error: (procedure "alert" is defined here)
../src/osvvm/CoveragePkg.vhd:5308:12:error: pure subprogram body cannot call (impure) procedure "alert"
../src/osvvm/AlertLogPkg.vhd:112:13:error: (procedure "alert" is defined here)
../src/osvvm/CoveragePkg.vhd:5343:12:error: pure subprogram body cannot call (impure) procedure "alert"
../src/osvvm/AlertLogPkg.vhd:112:13:error: (procedure "alert" is defined here)
The comment on line 1085 "pure functions cannot use alert and/or print" seems to indicate this has been dealt with before. In that case it looks like report
was used instead, though making the functions impure fixes the error as well.
The final testbench reports all collected alerts in a testbench.
Should that report mark unused AlertLogIDs / LogNames in the report?
I have the following Bins, created as objects to give a simple reference:
constant BIN_RUNT_FRAMES : CovBinType := GenBin(16, 63, 1); -- Short frames
constant BIN_SHORT_FRAMES : CovBinType := GenBin(64, 79 ); -- Shortest frames, covering all word width positions (16 bytes per word)
constant BIN_STANDARD_FRAMES : CovBinType := GenBin(80, ETHERNET_FRAME_SIZE_MAX-16-1, 1); -- All standard Ethernet lengths
constant BIN_LARGE_FRAMES : CovBinType := GenBin(ETHERNET_FRAME_SIZE_MAX-16, ETHERNET_FRAME_SIZE_MAX ); -- Longest standard ethernet lengths, covering all word width positions (16 bytes per word)
constant BIN_JUMBO_FRAMES : CovBinType := GenBin(ETHERNET_FRAME_SIZE_MAX+1, 9000, 1); -- Jumbo Frames
...
-- add the coverage
cov.AddBins("Runt Frames ", G_N_HITS_PER_COV_PT, BIN_RUNT_FRAMES );
cov.AddBins("Short Frames ", G_N_HITS_PER_COV_PT, BIN_SHORT_FRAMES );
cov.AddBins("Standard Frames", G_N_HITS_PER_COV_PT, BIN_STANDARD_FRAMES);
cov.AddBins("Large Frames ", G_N_HITS_PER_COV_PT, BIN_LARGE_FRAMES );
cov.AddBins("Jumbo Frames ", G_N_HITS_PER_COV_PT, BIN_JUMBO_FRAMES );
When I get the coverage, I cant work out if there is a simple method to check if a value returned from cov.randCovPoint
is in a specific Bin, other than checking the ranges of all the bins. something like
testPoint := cov.randCovPoint;
if isInBin(testPoint, BIN_RUNT_FRAMES) then
-- Generate Runt Frame
elsif isInBin(testPoint, BIN_SHORT_FRAMES) then
-- generate short frame
--etc
Currently, I can work around this by matching a testPoint to a bin name.
Maybe the name labels could also be added to the CovBinType as an unconstrained string?
Please add the mirror of
function to_integer ( B : boolean ) return integer ;
and
function to_integer ( SL : std_logic ) return integer ;
something like:
function to_boolean ( I : integer ) return boolean;
and
function to_std_logic ( I : integer ) return std_logic;
regards,
Robert (Reuven) Paley
I am currently evaluating ghdl as vhdl simulation tool and OSVVM as verification methodolody tool. To carry out this evaluation I created a gitlab repository with a simple design with a particular multiplier.
In the simulation folder you can find a detailed info to cover all the simulation steps. Following verification plan and architecture, I designed a package that contains different procedures to carry out all the functionalities to validate the design. As you can see in the picture attached on readme file, I created a modular project, where different functionalities are declared in different files.
As far as I understood, a good way to cover functionality in that design is to analize all the possible input cross values, by using intelligent coverage. As you know I have to use a protected type to generate inputs, and to cover it. This protected type can't be shared in files (driver and monitor files). So the work-around I found was declare a protected type to generate input data, and declare another protected type to cover data. It seems to work but I think is a tricky solution.
Is there any other way to do this?
I have a test where I use randCovPoint to drive the input:
idx := cov.randCovPoint;
I have named each of my bins. But I now have a cover point but I cannot get the name of the bin for reporting, something like this:
log("Sending Input " & to_string(idx) & " contained in Bin: " & cov.getBinName(idx));
Unless I make 1 bin per cover point, I cannot get the correct name of the bin. And this seems wasteful if I have to make several bins with the same name, and more complicated if I want to set the "AtLeast" values for specific bins.
maybe the function could be called getBinNameFromCovPoint
I currently have testbenches that use a transcript file. But I also like specific messages to also display on std.textio.OUTPUT. I do this in the testbench by turning on/off the mirror around specific messages, but for alerts inside the scoreboard I have no control over this. When an error/failure occurs and Error count is reached, ReportAlert occurs inside the scoreboard and cannot be mirrored to console.
I use the log to log everything - all scoreboard matches as well as errors. It would be good to have only the errors pop out to console.
During tests with usage of RandomPType sometimes I receive following error:
%% Alert FAILURE RandomPkg.(RandIntV | RandRealV | RandTimeV): Unique > number of values available at 35 ns
%% Alert Stop Count on FAILURE reached at 35 ns
%% DONE FAILED AlertLogTop Total Error(s) = 1 Failures: 1 Errors: 0 Warnings: 0 at 35 ns
what does it mean?
In the hierarchical version of AffirmIf()
procedure, the AlertLevel
parameter isn't propagated to the called AlertLogStruct.Alert()
procedure. It is instead replaced by hard coded ERROR level. Which I assume is an bug, because in the not hierarchical version, the AlertLevel
is propagated.
The bug occurs in line 2081
AlertLogStruct.Alert(AlertLogID, Message, ERROR) ; -- signal failure
in line 2081 in the AffirmIf()
body should be replaced by
AlertLogStruct.Alert(AlertLogID, Message, AlertLevel) ; -- signal failure
This may be a shortage in my understanding of how things should work. Consider the following partial example.
shared variable cov : CovPType;
variable a,b : integer;
cov.AddCross(1, GenBin(1), GenBin(1)); -- AtLeast=1, point (1,1)
cov.AddCross(0, GenBin(2), GenBin(2)); -- ATleast=0, point (2,2)
(a,b) := cov.RandCovPoint; -- generating a=b=2 ?!
In a somewhat more complex example, I think I am seeing RandCovPoint generate a bin that has an AtLeast of 0 while other bins have AtLeast > 0 that haven't been covered yet. Is this expected?
sometimes it can be useful to get coverage points sequentially or randomly, depending on the test. Maybe it would be useful to add a function something like:
impure function nextCoverPoint(isRandom : boolean := true) return integer/integer_vector is
begin
if isRandom then return randCoverPoint;
else return getNextCoverPointSequence;
end if;
end function;
Thoughts?
There is a potential bug with: GetNextPoint(Mode => MIN);
For example, ModelSim reports :
# -- Compiling architecture behav of tb_ldpc_encoder
# ** Error (suppressible): testbench/tb_ldpc_encoder_osvvm.vhd(240): (vcom-1380) Identifier "MIN" is not directly visible.
#
# Potentially visible declarations are:
# std.STANDARD.min (physical unit)
# osvvm.CoveragePkg.MIN at testbench/osvvm_2020_05/CoveragePkg.vhd(161) (enumeration literal)
Fortunately, this can be easily fixed with calling “MIN” explicitly from Coverage package:
GetNextPoint(Mode => osvvm.CoveragePkg.MIN);
Maybe it is good idea to record this issue somewhere:
Thanks you and best regards,
Miroslav
Hi!
When compiling the latest osvvm using the ghdl/lib/ghdl/vendors/compile-osvvm.sh script I got the following error:
Analyzing package '/opt/osvvm/CoveragePkg.vhd'
/opt/osvvm/CoveragePkg.vhd:1477:33: operator ""&"" is overloaded
/opt/osvvm/CoveragePkg.vhd:1477:33: possible interpretations are:
*std_standard*:1:1: function "&" [string, character return string]
*std_standard*:1:1: function "&" [string, string return string]
The culprit is here:
------------------------------------------------------------ -- pt local for now -- file formal parameter not allowed with a public method procedure WriteBinName ( file f : text ; S : string ; Prefix : string := "%% " ) is ------------------------------------------------------------ variable MessageCount : integer ; variable MessageIndex : integer := 1 ; variable buf : line ; begin MessageCount := CovMessageVar.GetCount ; if MessageCount = 0 then write(buf, Prefix & S & GetCovModelName) ; -- Print name when no message writeline(f, buf) ; else if CovNameVar.IsSet then -- Print Name if set write(buf, Prefix & S & CovNameVar.Get) ; elsif AlertLogIDVar /= OSVVM_ALERTLOG_ID then -- otherwise Print AlertLogName if it is set write(buf, Prefix & S & GetAlertLogName(AlertLogIDVar)); else -- otherwise print the first line of the message MessageIndex := 2 ; write(buf, Prefix & S & string'(CovMessageVar.Get(1))) ; end if ; writeline(f, buf) ; for i in MessageIndex to MessageCount loop write(buf, Prefix & string'(CovMessageVar.Get(i))) ; writeline(f, buf) ; end loop ; end if ; end procedure WriteBinName ;
Changing the line to
write(buf, Prefix & S & string'(GetAlertLogName(AlertLogIDVar)));
solved the issue.
Best regards,
Michael Kiesenhofer
Hi Jim,
what do you think about adding these features to the CreateClock function?
1.) Add an enable port to be able to start and stop the clock signal
2.) Add the possibility to choose with which level the clock is starting. Now it always starts with '0', which is ok for a single clock, but when starting several related clocks (e.g. 50 MHz and 100 MHz) at the same time, they always share the falling edge.
3.) Add a Log message when starting or stopping the clock.
A possible declaration could be:
procedure CreateClock (
constant AlertLogID : AlertLogIDType;
signal Clk : inout std_logic;
signal ClkEn : in std_logic;
constant Period : time;
constant ClkName : string;
constant DutyCycle : real := 0.5;
constant StartHigh : boolean := false
);
Regards,
Sebastian
I have the following code:
cov.AddBins("Random Bins", 1, GenBin(0) );
cov.AddBins("Other Bins", 1, GenBin(0) );
while not cov.isCovered loop
iv := cov.randCovPoint;
log("iv= (" & to_string(iv(0)) & ")");
cov.ICover(iv);
end loop;
cov.writeBin;
And it gives the following output
KERNEL: %% Log ALWAYS in Default, iv= (0) at 0 ns
KERNEL: %% Log ALWAYS in Default, iv= (0) at 0 ns
KERNEL: %% WriteBin:
KERNEL: %% Random Bins Bin:(0) Count = 1 AtLeast = 1
KERNEL: %% Other Bins Bin:(0) Count = 1 AtLeast = 1
This implies even though both bins cover the same value, they do not get both get covered at the same time, and have priority in the order they were created. Should it be an error to create two identical bins? or should it cover both bins when ICover is called?
You get the same behaviour with crossed bins, where the crosses are identical.
cov.AddCross("Random Bins", 1, GenBin(0), GenBin(0,7));
cov.AddCross("Other Bins", 1, GenBin(0) , GenBin(0,7));
Hi Jim,
I often use the Scoreboard "only" as a FIFO. I can push values into it, and I can pop values from it. What I am missing is a function, which returns the current number of values stored in the FIFO, not the overall values ever have been stored (GetItemCount
).
Something like GetCurrentItemCount()
or GetStoredItemsCount()
.
What would you think about this?
Regards,
Sebastian
It would be useful to have a check function in the scoreboard that returns a boolean. This way you can easily connect a signal to the function to allow quick debugging on a waveform. I have the following current workaround:
err_cnt := GetAlertCount(sboard.GetAlertLogID);
sboard.check(act);
missmatch <= (GetAlertCount(sboard.GetAlertLogID) /= err_cnt), false after 1 ns;
I think it would be easier to simply write:
missmatch <= sboard.check(act), false after 1 ns;
It would also allow a testbench to take user controlled action on a missmatch.
I just cloned OSVVM and as part of getting started, I opened up RandomPkg_user_guide.pdf and jumped to section 14 for compile instructions. I tried a straightforward compile of said files but got an error because of the work library reference.
My suggestion to update instructions to reference running osvvm.do since that seamlessly replaces work with osvvm and is readily available as part of the git clone.
I have managed to create a generic version of SortListPkg_int
. So I started to test this new package in my testbench. A get an alert FAILURE, that my index is out of range when I use the Get
method.
I'm looping through an array and perform 64 add operations. The Counter is always 1 (the default value).
The following screenshot shows the behavior:
I'm testing three sorters
std_logic_vector
sorter derived from SortListGenericPkg
. The code is supplied in pull request #18.integer
sorter derived from SortListGenericPkg
.SortListPkg_int
implementation.All three version show always a count of 1.
I used QuestaSim 10.5c.
Addendum:
The source files for the complete testbench are available on branch VLSI-EDA/OSVVM/paebbels/osvvm-bitonicsort. The PoC command is: poc.ps1 -v vsim PoC.sort.sortnet.BitonicSort -g
It seems that Cadence Incisive 14.2 does not support the VHDL-2008 keyword tee
(see TranscriptPkg line 172), even with the -v200x -extv200x
options set. Could you add a workaround please?
Currently OSVVM offers a TbUtilPkg with an Increment
and WaitFOrToggle
procedures.
Currently no Decrement
is offered. Is it possible to add this missing feature for completeness?
Current API for integer value passing based on toggle events:
-- Integer type versions
procedure Increment ( signal Sig : InOut integer ; constant RollOverValue : in integer := 0) ;
procedure WaitForToggle ( signal Sig : In integer ) ;
Currently, if you call ReportAlerts, if no affirmations were checked then a test always passes. In a testbench where the UUT has locked up and the testbench has timed out, this may give a false sense of security in a CI environment.
Currently I have the following check in my generic OSVVM control entity:
if not G_ALLOW_VACUOUS_PASS then
AlertIf(G_ALERT_ID, GetAffirmCount = 0, "Test Ended with no affirmations checked", FAILURE);
end if;
ReportAlerts;
Would it be nicer to pass the required affirm count to the ReportAlerts method, or some machinism to turn a Vacuous pass into a failure within OSVVM itself?
Been getting the following errors with OSVVM
** Error: osvvm/AlertLogPkg.vhd(984): No feasible entries for subprogram "PrintTopAlerts".
** Error: osvvm/AlertLogPkg.vhd(991): No feasible entries for subprogram "PrintTopAlerts".
The procedure's is defined as
Lines 881 to 887 in 185a11d
Errors occur here
Lines 978 to 991 in 185a11d
The code is correct -- this seems to be a bug on ModelSim itself and it has been fixed at some point between 10.2c and 10.7c (versions I have available for testing)
I did a bit of digging and it seems ModelSim is making confusion with the AlertCount
identifier, which is used to name parameters in procedures/functions, constants, variables and record components. Either replacing the parameter for a different identifier (and adjusting uses) or calling PrintTopAlerts
with positional arguments (no named parameters) seems to fix the problem.
I know it's a ModelSim bug from an old version, but would be great if OSVVM could work around it!
Hi Jim,
I am wondering why there are 3 whitespace characters in procedure "LocalCheck" before printout of the word "Received:" (line 992).
This is only a visual issue, but in my opinion without this whitespace the logfile's output would be more consistent.
Best regards,
Sebastian
In a testbench with multiple checkers at different levels of heirarchy, it would be nice to see the AffirmCount per ID (if possible). I note you currently cannot fetch the Affirmation count per ID, only the total, getAffirmCount
has no arguments, although affirmations are done per ID (also, it appears affirmations are not stored per ID).
For example, my current testbench has the following Heirarchy:
%% Alert Stop Count on ERROR reached in CPU Packet Checker at 11780 ns
%% DONE FAILED 64bit Total Error(s) = 1 Failures: 0 Errors: 1 Warnings: 0 Affirmations Checked: 126 at 11780 ns
%% Default Failures: 0 Errors: 0 Warnings: 0
%% OSVVM Failures: 0 Errors: 0 Warnings: 0
%% testbench_tools_pkg Failures: 0 Errors: 0 Warnings: 0
%% ip_flow_control_top_tb Failures: 0 Errors: 1 Warnings: 0
%% AXI4L Filters and Decap Driver Failures: 0 Errors: 0 Warnings: 0
%% AWADDR Driver Failures: 0 Errors: 0 Warnings: 0
%% WDATA Driver Failures: 0 Errors: 0 Warnings: 0
%% BRESP Checker Failures: 0 Errors: 0 Warnings: 0
%% ARADDR Driver Failures: 0 Errors: 0 Warnings: 0
%% RDATA Checker Failures: 0 Errors: 0 Warnings: 0
%% AXI4L Table Driver Failures: 0 Errors: 0 Warnings: 0
%% AWADDR Driver Failures: 0 Errors: 0 Warnings: 0
%% WDATA Driver Failures: 0 Errors: 0 Warnings: 0
%% BRESP Checker Failures: 0 Errors: 0 Warnings: 0
%% ARADDR Driver Failures: 0 Errors: 0 Warnings: 0
%% RDATA Checker Failures: 0 Errors: 0 Warnings: 0
%% MAC Packet Driver Failures: 0 Errors: 0 Warnings: 0
%% CPU Packet Checker Failures: 0 Errors: 1 Warnings: 0
%% Media Packet Checker Failures: 0 Errors: 0 Warnings: 0
%% Register Scoreboard Failures: 0 Errors: 0 Warnings: 0
%% Flow Table Scoreboard Failures: 0 Errors: 0 Warnings: 0
%% Packet Coverage Failures: 0 Errors: 0 Warnings: 0
%% Stream Generator Failures: 0 Errors: 0 Warnings: 0
%% ipat_stats_store_inst Failures: 0 Errors: 0 Warnings: 0
%% Checking Failures: 0 Errors: 0 Warnings: 0
%% ipat_histograms_inst Failures: 0 Errors: 0 Warnings: 0
%% Checking Failures: 0 Errors: 0 Warnings: 0
It would be nice to see who was doing all the checking.
Thanks
Richard
I would like to empty all expected data from a scoreboard. For example, when a reset occurs in the middle of a test, it might be appropriate to just empty all queues in the scoreboard and start again.
I previously used this, but it is not appropriate because it destroys all the configured IDs and any other config:
queue_reset_proc : process(axi_reset)
begin
if axi_reset = '1' then
sboard.Deallocate;
sboard.Initialize;
end if;
end process;
You could use the following, but using the flush procedure seems more appropriate:
queue_reset_proc : process(axi_reset)
variable dump : axi_if'subtype;
begin
if axi_reset = '1' then
while not sboard.empty loop
dump := sboard.pop;
end loop;
end if;
end process;
I cant find if the following is possible - i would like to print multiple levels of the heirarchy name on and alert/log. Currently it only prints the name directly associated with the ID. Thats usually fine, but I have a verification component with multiple IDs inside that is instantiated twice in the testbench - so I cant easy tell which one is generating them:
KERNEL: %% Log ALWAYS in Default, Pushing write transaction to interface 0 at 750 ns
KERNEL: %% Log ALWAYS in Default, Pushing write transaction to interface 1 at 750 ns
KERNEL: %% Log PASSED in AWADDR Checker, Received: axid: 0x00 axaddr: 0x00000000 axlen: 0x06 axsize: 100 axburst: 01 Item Number: 1 at 780 ns
KERNEL: %% Log PASSED in WDATA Checker, Received: wdata: 0x00000006000000640000000026F2CDBF wstrb: 0xFFFF wlast: 0 Item Number: 1 at 780 ns
KERNEL: %% Alert FAILURE in AWADDR Checker, Valid transaction on Interface with no transaction expected at 780 ns
KERNEL:
KERNEL: %% Alert Stop Count on FAILURE reached in AWADDR Checker at 780 ns
KERNEL: %% DONE FAILED debug Total Error(s) = 1 Failures: 1 Errors: 0 Warnings: 0 Passed: 10 Affirmations Checked: 10 at 780 ns
KERNEL: %% Default Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% OSVVM Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% testbench_tools_pkg Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% axi_sim_utils_pkg Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% pcap_top_tb Failures: 1 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% AXI4L Regs Driver Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% AWADDR Driver Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% WDATA Driver Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% BRESP Checker Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% ARADDR Driver Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% RDATA Checker Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% RAM Interface 0 Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% AWADDR Checker Failures: 0 Errors: 0 Warnings: 0 Passed: 1
KERNEL: %% WDATA Checker Failures: 0 Errors: 0 Warnings: 0 Passed: 1
KERNEL: %% BRESP Driver Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% ARADDR Checker Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% RDATA Driver Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% RAM Interface 1 Failures: 1 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% AWADDR Checker Failures: 1 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% WDATA Checker Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% BRESP Driver Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% ARADDR Checker Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% RDATA Driver Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% Register Scoreboard Failures: 0 Errors: 0 Warnings: 0 Passed: 8
KERNEL: %% Packet Coverage 0 Failures: 0 Errors: 0 Warnings: 0 Passed: 0
KERNEL: %% Packet Coverage 1 Failures: 0 Errors: 0 Warnings: 0 Passed: 0
So with the messages coming from AWADDR/WDATA checker, I cant tell which RAM interface is reporting the messages until I get the report at the end. With a long log it would pretty impossible to tell where the messages were generated. Ideally I could just specify the number of layers of heirarchy to report rather than just all of it.
I recently discovered that RandSlv(16)
does not return the same as calling RandSlv(8)
twice and I wanted to ask if that's intended? I couldn't find anything regarding this in the documentation, probably I missed it?
Hi,
Using osvvm 2020.08 I get following error when using latest nighty (as for today) ghdl under archlinux. It compiles with no issue with 2020.07.
Not sure if this is an osvvm or a ghdl issue @tgingold, though.
Thanks,
Alright, attached is the list of errors I get with the Makefile from #6. This is with irun 15.10-s013: incisive.txt
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.