Repository navigation
Conversation
This was referenced Oct 20, 2026
A package instantiated in an architecture is made visible with a use clause naming the instance, such as use my_inst.all. The dependency scanner read my_inst as a library and warned "failed to find library 'my_inst'". Skip use clauses that name a package instantiated in the same file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
reflection_check_pkg has generic check_equal and check_equal_with_checker
procedures with the parameters of check_pkg's check_equal. They check
with the predefined "=" of the type, and on a mismatch walk the
reflection mirrors of both values and list every element that differs,
one per row:
Equality check failed (tb_packet.vhd:21)
hdr.addr: got 6, expected 5
data(0): got '1', expected '0'
reflection_check_generic_pkg instantiates both for one type, so one
package instantiation gives the same call shape as check_pkg:
package packet_checks is new vunit_lib.reflection_check_generic_pkg
generic map (t => packet_t);
The packages are opt-in through vu.add_reflection(), which fails early
when the standard is older than VHDL-2019 or the simulator lacks
reflection. A new supports_vhdl_reflection() simulator capability is True
for NVC and Riviera-PRO. Riviera-PRO needs -dbg for the call path
locations the tests check.
The default of msg is written as the value of check_result_tag, since
NVC can't call an instance of a generic subprogram that leaves out a
parameter with a string constant default (nickg/nvc#1695).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ru551n
force-pushed
the
reflection-check-equal
branch
from
October 20, 2026 20:56
03f7958 to
719c5e0
Compare
Physical values print with the unit in lower case on all simulators, since NVC gives it in upper case. An array of records crashes NVC when it reflects an element, so that test is skipped on NVC and the limitation is documented. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This adds
check_equalfor values of any type: records, arrays, enumerations and so on. It uses VHDL-2019 reflection to name every element that differs when the check fails. It is opt-in throughvu.add_reflection(). This PR now also brings the reflection plumbing from #1239, which is closed. Itsto_dictwas one-way, since reflection can't create values.Motivation
Comparing records is the most common check in a transaction-level testbench.
got = expectedworks for any record, but on a mismatch it only says that something differs. The usual fix is a hand-writtento_stringper record type, which goes stale when a field is added. Reflection can walk both values and report exactly which fields differ, for any type, without per-type code.Why opt-in
std.reflection. NVC has had'reflectsince 1.11.0 (2023-12), and Riviera-PRO 2026.04 supports it. GHDL 7.0.0-dev and Questa FSE 26.1 don't providestd.reflection(checked locally).add_vhdl_builtins().add_reflection()fails early, with a clear message, when the standard is older than 2019 or the simulator lacks reflection.supports_vhdl_reflection()capability on the simulator interface,Falseby default andTruefor NVC and Riviera-PRO. Other simulators only need to flip the flag when they gain support.API
reflection_check_generic_pkg: one instantiation per type gives bothcheck_equal(got, expected, msg, level, path_offset, line_num, file_name)andcheck_equal(checker, got, expected, ...), with the same parameters ascheck_pkg. Instances for different types overload on the type.reflection_check_pkg: the same two procedures as plain generic procedures,check_equalandcheck_equal_with_checker. The generic package is just these two instantiated.The generic procedures are for when a package instance doesn't fit. A procedure instance can be declared in a process, a subprogram or a block, as well as in an architecture or a package. NVC only accepts a package instance in an architecture or a package. Each procedure is instantiated on its own, so a process can take only the variant it uses:
To share the instances between testbenches, instantiate them in the package that declares the types, and
use work.types_pkg.packet_checks.allin each testbench. This works on NVC and Riviera-PRO and is documented.The checker variant needs its own name in the package,
check_equal_with_checker. Both uninstantiated procedures take the generic typet, so their signatures can't tell them apart, andprocedure check_equal is new check_equalwould be ambiguous. The instance can still be namedcheck_equal, so the call sites look like check_pkg's in both forms.One line per type is the minimum the language allows. A mirror can only be passed as a variable, so
packet'reflectcan't be an argument, and VHDL has no implicit instantiation of generic subprograms.Possible follow-up: a package with several type generics, such as
reflection_check_3_pkg generic map (t1 => packet_t, t2 => config_t, t3 => state_t), would cover all types of a testbench in one instantiation. Generic types can't have defaults, so this needs one package per number of types. Prototyped on NVC and Riviera-PRO: it works with named association. With positional association, NVC counts the implicit"="generic after each type as a slot and rejects the map, while Riviera-PRO accepts it.Behaviour
"="of the type. The mirrors are only built when the check fails.msgreplaces "Equality check failed", as incheck_pkg. Paths use.elementfor record elements and(index)for array elements, with the declared index for both ascending and descending ranges. Arrays of different lengths report'lengthinstead of their elements.timeis printed withtime'image, scaled from the resolution limit, since Riviera-PRO gives the value in units of the resolution limit and NVC in fs.path_offsetchain matchescheck_pkg, so with VHDL-2019 call paths the log item points at the caller'scheck_equalline.check_pkgalready covers, such asinteger: the calls become ambiguous. This is documented.Other changes
reflection_util_pkg, for further reflection packages to share.use my_inst.allfor a package instantiated in the same file producedfailed to find library 'my_inst'. That affects any testbench with a local package instance, not only this feature. Use clauses that name a local package instance are now skipped. There is a new unit test.Simulator notes
stringconstant default fails at runtime withmissing body for ...$default_MSG, reported as Instance of a generic subprogram fails with "missing body for ...$default_MSG" when a string constant default is used nickg/nvc#1695. So themsgdefault is written as the literal value ofcheck_result_tag,"<+/->", with a comment linking the issue.package packet_checks is new vunit_lib.reflection_check_generic_pkg ...at library level) doesn't work.check_equalthrough it silently does nothing: nothing is logged and the check isn't counted. In a minimal reproduction without VUnit, with the generic package in another library, the simulator crashes at startup ("The simulator process terminated unexpectedly"). With both in the same library it works. NVC handles both. The docs say to instantiate it inside a package or an architecture instead. I'll report it to Aldec.-dbg(rivierapro.vcom_flags) to record the caller's location in VHDL-2019 call paths. The reflectionrun.pysets it.unhandled type HEADER_T in type_bit_widthinget_value_mirror(src/type.c:1025). Riviera-PRO handles it. Since the mirrors are only built when the check fails, a passing check is unaffected. The test is skipped on NVC through conditional analysis, and the docs mention it.2000 MM), Riviera-PRO in lower case. The message lower-cases it, as for enumeration values."="is not supported. I tried afunction "=" ... is <>generic. NVC rejects passing it on from the generic package ("=" => "="), and without the association Riviera-PRO uses the predefined"="instead. It can be added once the simulators agree.Testing
vunit/vhdl/reflection/run.pywith VHDL-2019: 11/11 on NVC 1.23-devel and on Riviera-PRO 2026.04. They cover an array of records (skipped on NVC, see below), user integer and physical types, and: element paths, all-differences messages, scalar types, arrays (ascending, descending, other element types, length mismatch), a scalart, a custom checker with message and level, procedures instantiated in a process.std.reflection(checked with a direct compile).add_reflection()refuses them with its clear error, andtest_reflection_vhdl_2019is skipped for them.tests/unit: 643 passed.tests/acceptance/test_artificial.pyandtest_dependencies.pypass on GHDL and NVC, as a check of the scanner change.This PR was written with the help of an AI assistant (Claude).
🤖 Generated with Claude Code