Check a type cast with an inline packed dimension and reject dimensions
following a type identifier in a cast target. Use a dimensioned typedef in
the reject test to distinguish dimensions in the type from dimensions after
the identifier.
Check that an error reported while elaborating a cast-target type is emitted
only once when width checking and expression elaboration reuse the cached
target information. Also check that each module instance resolves a
type-parameter cast target using its own parameter value.
Check that typed dynamic-array elaboration constructs the explicit cast
target rather than the enclosing expression type.
Run the tests through the native and vlog95 backends.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A SystemVerilog cast target can be either a type or a constant size
expression. Currently the parser commits to `PECastType` or `PECastSize`
based on how the target identifier is classified while parsing. This is too
early for identifiers whose meaning is only known after symbol lookup. As a
result, corner cases are handled incorrectly when parser-time classification
does not match the result of elaboration. For example, the parser can not
decide whether an identifier inherited from a base class is a type or a
constant size expression. Supporting the inherited lookup is separate, but
the cast target must remain unresolved until elaboration for that lookup to
be used.
Parse both forms through `expr_primary_or_typename` and represent them with
one `PECast`. Keep atomic types wrapped in `PETypename` and preserve named
targets as `PEIdent`.
Resolve the target during elaboration. First use `test_type()` to distinguish
a type target from a constant size expression. For a type target, use a
contextual `elaborate_type()` call to resolve the type. Diagnose dimensions
after a type identifier directly from `PEIdent::elaborate_type()` when it is
used as a cast target. A failed type elaboration returns `nullptr` and does
not fall back to interpreting the target as a size expression. Dimensions
contained in the named type remain valid.
Cache the resolved target information during width checking because ordinary
expression elaboration needs the same information. Tag the cache with the
`NetScope` and recompute it when the scope changes since type parameters can
give the same cast expression a different target type in each instance.
Typed elaboration can bypass width checking, so resolve into a local value
when no matching cache is available. This avoids modifying the parsed
expression from a const elaboration method while still avoiding repeated
diagnostics between the normal width checking and expression elaboration
phases.
Share the type and size conversion paths between width-based and typed
elaboration. Use the explicit cast target when constructing a dynamic array
instead of the enclosing expression type. Own the cast target and operand
with `std::unique_ptr`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that packed dimensions are preserved when local and
package-qualified identifiers resolve to types in type parameter values and
system function arguments. Verify that symbolic dimensions are evaluated in
the scope of each module instance.
Check the diagnostics for unsized and queue suffixes, indexed part selects,
and packed dimensions applied to an unpacked named type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that lookup chooses the nearest visible type or value when an
identifier can denote either. Cover lexical ordering, inherited properties,
and a bracket suffix that must remain a value select after lookup.
Check typed expression and l-value contexts where a type must be rejected
instead of binding an outer value. Check that a hierarchical type reference
is rejected with the type-specific diagnostic.
Check that probing an invalid hierarchical type parameter does not elaborate
its signal prefix and report a false circular dependency.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Named types in expression-like contexts are currently converted to
`PETypename` by the parser. This commits to the type interpretation before
symbol lookup, although the same syntax can represent an ordinary identifier.
Keep atomic types as `PETypename`, but parse local and package-qualified type
identifier candidates as `PEIdent`. Preserve any bracket suffixes so they can
be interpreted as packed dimensions for a type or as selects for a value.
Add `PExpr::test_type()` for non-elaborating type detection and
`PExpr::elaborate_type()` to return the elaborated type. Use these interfaces
for `$bits()`, `$sizeof()` and type parameters. Callers test the
interpretation before elaborating it, so a null type reports an elaboration
failure without incorrectly falling back to value elaboration.
Type testing is normally followed by elaboration, and both operations need
the same symbol lookup. Let `PEIdent::test_type()` cache the result and its
declaration scope, keyed by the lookup scope. Keep `elaborate_type()` const and
perform a local lookup when type testing was skipped or the cached result is
from another scope. This avoids repeated lookup without reusing a
scope-dependent result.
Search the complete identifier path before deciding whether it names a type.
Stop lookup at signal placeholders so they still hide matching types in outer
scopes without being elaborated by the type probe.
The LRM section 6.18 does not allow hierarchical references to type
identifiers, so reject a dotted type reference after lookup and report where
the type was declared. This distinguishes an invalid `test.T` type reference
from a path that does not name a type.
Use the unified symbol lookup result to choose the type or value
interpretation. Report an error when a type reaches an expression or l-value
context. This preserves normal lexical shadowing while deferring only the
syntactic decision.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`symbol_search()` currently uses a boolean argument to allow forward
references to the terminal name. Additional lookup options would require more
boolean arguments and make call sites difficult to read.
Replace the boolean with a bitmask and use a named flag at the existing
forward-reference call sites. Add a second flag that stops lookup at an
unelaborated signal instead of elaborating it. Stopping the lookup makes the
signal continue to hide matching symbols in outer scopes.
Forward-reference permission applies only to the terminal name, while signal
elaboration suppression applies to the complete path. This allows callers
that only need to classify a name to avoid triggering signal elaboration
during lookup.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a visible type prevents lookup from continuing to an outer value
for function and task calls and implicit `.name` and wildcard `.*` port
connections. Check that types are rejected as disable targets, named events,
procedural l-values, and expressions elaborated with a required type.
Also check the opposite lexical-order case where a typedef declared after a
reference does not hide an outer named event or variable. Use diagnostic gold
files for each negative case that emits the type-specific error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog places user-defined types and data identifiers in the same
namespace. Symbol lookup cannot currently return a type, so a value lookup can
skip a nearer typedef and incorrectly bind a value in an outer scope when an
ambiguous identifier is resolved during elaboration.
Add typedef results to `symbol_search()` and check visible typedefs before
continuing to enclosing scopes. Use the lexical visibility limit selected by
the caller. This is normally the reference position, while function and task
call lookup uses the end of the current scope as required by the LRM section
26.3.
Let callers that require a value or another non-type symbol diagnose the type
result and report its declaration location. This includes function and task
calls, expressions with and without a required type, procedural l-values,
named-event triggers, and disable targets. Callers that only probe for a
particular kind of symbol, including port-connection matching, ignore a type
result. Also ensure scope-only callers do not confuse the typedef's owning scope
with the resolved object.
This prepares expression elaboration to defer the type-versus-value decision
while preserving lexical shadowing.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check separately that a local variable, named event, and parameter hide a
compilation-unit task used as a disable target.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Disable targets currently use `Design::find_scope()`, which searches only
scope names. A task or named block from an outer scope is therefore selected
even when a variable, named event, or parameter in a closer scope has the
same name.
The LRM section 3.13 places tasks, named blocks, parameters, named events, and
variables in the same local name space. Use normal symbol lookup and require
the result to be a scope. This lets a closer non-scope object hide the outer
disable target and reports an error for the non-scope result.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a closer variable, named event, or parameter hides a task or
function used as a statement. Also check object method lookup and recursive
function calls used as statements.
Check that a later compilation-unit task or function takes precedence over a
matching subroutine in an enclosing instance. Check that different instances
of the same module resolve task calls through their respective enclosing
instances. Check ordinary lexical ordering for a task-call receiver declared
before or after the reference.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Task and function calls used as statements currently use
`Design::find_task()` and `Design::find_function()`, which only search for
scopes of the requested type. A closer variable, named event, or parameter is
skipped. This can call a hidden task or function, and can make the non-void
discarded-return path resolve a different symbol and abort.
Use one `symbol_search()` for both task lookup and the function fallback so
all declarations in the shared name space participate in lookup. Accept a
function scope or the return variable of a recursive function call, while
preserving the existing method fallback.
Allow the terminal task or function name to be declared later while resolving
a receiver prefix at the call position. Use the call position when the method
fallback searches for the receiver as well.
Remove the now unused `Design::find_task()` and `Design::find_function()`
helpers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that same-named scopes in the enclosing instance hierarchy do not
interfere with lookup of compilation-unit variables, parameters, named events,
and imported variables. Cover expressions, procedural l-values, implicit and
wildcard port connections, and lookup from module and nested function scopes.
Check task and function calls, including method receivers and chained calls.
Verify that receiver prefixes follow ordinary lexical ordering while direct,
imported, and chained compilation-unit function names can be declared after
their references. Check the enclosing-instance fallback when the compilation
unit has no match.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`symbol_search()` currently searches the enclosing instance hierarchy before
the compilation-unit scope for ordinary names. An enclosing instance scope can
therefore hide an earlier compilation-unit variable or object, including when
the object is the prefix of a dotted reference.
The LRM section 3.12.1 requires a common lookup order. First search the local
lexical scopes through the design unit. Next search the compilation-unit scope
up to the reference position. If there is no match, resume at the saved
instantiation parent and continue through the instance hierarchy. Disable data
object lookup when resuming so only enclosing scope names can match.
Task and function names follow the same traversal, but the LRM section 23.8.1
lets the terminal subroutine name search the complete compilation unit. Use a
separate terminal lexical limit for this. Resolve a prefix such as `object` in
`object.func()` at the reference position while allowing a forward declaration
of `func`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The scope traversal clears `start_scope` after switching to the compilation
unit and uses the null value to prevent a second compilation-unit search.
This gives the scope used for path evaluation two separate purposes.
Track whether the compilation-unit scope has been searched with a separate
flag. Keep the existing instance-before-compilation-unit traversal order.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The scope traversal tracks whether it has crossed a module boundary and
uses the inverse of that state to decide whether objects are visible.
Track object visibility directly instead. This keeps the existing behavior
while making the module-boundary rule and later traversal changes easier to
follow.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Child scopes and interface aliases are matched directly in the scope
traversal. This obscures the code that decides which scope to search next.
Move the child scope and interface alias lookup into a helper. Keep the
existing lookup order and error handling unchanged so the traversal can be
restructured separately.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The object lookup for each scope is embedded in the scope traversal. This
makes the traversal order and the module boundary handling difficult to
follow.
Move net, event, parameter, class property, and placeholder lookup into a
helper. Use separate found, not found, and failure results so the existing
lookup behavior is preserved. This prepares the scope traversal to be
changed independently.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a class property cannot share a name with another property, a
function, a task, a parameter, a type, or an enum named constant. Check
duplicate properties in both separate and comma-separated declarations. The
latter guards the shared declaration type ownership that previously caused a
crash.
Exercise properties in both declaration orders so both member registration
paths are covered.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LRM requires an identifier to name only one item within a scope. Class
properties are currently stored only in `class_type_t::properties`, outside
the common local symbol table. As a result, declarations such as:
class C;
int value;
function int value;
return 0;
endfunction
endclass
are accepted. A second property in a separate declaration silently replaces
the first property map entry. A repeated name in a comma-separated declaration
such as `int value, value` can crash because both declarators share the same raw
type.
Make `prop_info_t` a named item and register each property in the class local
symbol table. Check the declaration before taking ownership of its type or
initializer, since comma-separated properties share the raw declaration type.
Use `emplace()` for the property map so an accepted property cannot replace an
existing entry.
Properties now take part in the common symbol lookup. Give them a distinct
symbol type so duplicate declaration diagnostics identify them as class
properties, and remove the separate property check from type-identifier
classification.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Consolidating variable dimensions and hierarchy indices into a shared
grammar makes all index component forms parse in either context.
Check that `+:` and `-:` indexed part selects are rejected as dimensions,
and that `[]` and `[$:N]` are rejected as hierarchy indices. These forms
were previously excluded by the context-specific grammar rules.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Variable declaration dimensions and hierarchical identifier indices both
use bracketed components, but are parsed by separate grammar rules.
Consolidate them into a shared `index_component` rule and convert the
components once the surrounding context is known.
This prepares for accepting a `TYPE_IDENTIFIER` token as an ordinary name
in a hierarchical path. A path component can have the same spelling as a
typedef visible in the current scope. In the path it is an ordinary
identifier. The hierarchical reference does not override or replace the
typedef.
The shared rule parses component forms that are not valid in both contexts.
Preserve the previous restrictions by explicitly rejecting indexed part
selects in variable dimensions and empty or bounded-queue components in
hierarchical identifiers. Track the location of each component so these
errors point to the invalid suffix.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that source `null` expressions in `[null]` and `[null:N]` are
rejected rather than treated as the `$` marker for unbounded and bounded
queue dimensions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Queue dimensions use a `PENull` expression as an internal marker for `$`.
This also represents a source `null` expression, so declarations such as:
integer value[null:2];
are accepted and elaborated as bounded queues.
Use a dedicated `PEQueueDimension` marker for queue dimensions. This lets
source `null` expressions follow normal range expression validation while
preserving the existing representation of dynamic and fixed dimensions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a bare inherited non-void function call used as a statement emits
the required discarded-return warning and executes the function.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LRM section 13.4.1 permits a non-void function call to be used as a
statement and requires a warning when the return value is implicitly
discarded. A bare call to an inherited class function currently emits that
warning and then aborts.
Method lookup finds the inherited function through the implicit `this`
receiver. The discarded-result path then rebuilds a `PECallFunction` from the
original bare name, losing the receiver and leaving the expression without a
type.
Pass the resolved method path to the discarded-result path so the rebuilt call
remains qualified by `this`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a `const static` class property with a declaration
initializer is accepted and has the initialized value. Also check that
subsequent assignments through unqualified and object-member lookup are
rejected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Static property declaration initializers are elaborated as standalone
initialization processes instead of through a class constructor. The
const-property bookkeeping therefore does not see the initializer and
reports an initialized `const static` property as missing initialization.
Record whether each parsed property has a declaration initializer and
mark an initialized static const property when its signal is created.
Also mark the signal as const and its declaration assignment as an
initializer. This permits that initial assignment while rejecting later
writes. Uninitialized static const properties remain errors.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A named block inside a class constructor has its own scope. The const property
assignment check currently tests the name of this immediate scope and rejects
the assignment because it is not named `new` or `new@`.
Find the containing class method before deciding whether the assignment is in
the constructor. Assignments from nested blocks in other methods remain
invalid.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that an inherited property does not offset initialization bookkeeping
for a const property assigned in the derived class constructor.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Property indices include the properties inherited from base classes.
`netclass_t::get_prop_initialized()` currently uses this combined index
without removing the inherited property count when accessing the local
property table. This can read past the table and treat a derived const
property as already initialized.
Subtract the inherited property count, matching the other property accessors.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that an unqualified method call from a named block uses the implicit
`this` signal from the containing class method. The compiler currently looks
for the signal in the named-block scope and crashes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
An unqualified method call inside a named block is elaborated from the block
scope. When the call resolves to another method in the same class, receiver
construction looks for the implicit `this` signal directly in that scope:
function int call_method();
begin : nested
return get_value();
end
endfunction
The signal belongs to the containing method scope, so the lookup returns null
and the compiler dereferences it.
Find the containing method first and obtain the implicit `this` signal from
that scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check separately that `$unit::` references to a variable, named event, and
parameter declared later in the compilation unit are rejected.
Also check that preceding compilation-unit items remain visible and that a
later function name remains visible as permitted by the LRM section 3.12.1
exception.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LRM section 3.12.1 says that `$unit::` only disambiguates a name in
the compilation-unit scope and does not allow a reference to an item declared
later. Currently every bound scope is exempt from declaration-order checks, so
this incorrectly resolves `value`:
module test;
initial $display("%0d", $unit::value);
endmodule
integer value;
Apply the existing variable, named event, and parameter declaration-order
checks when lookup is bound to a compilation-unit scope. Other hierarchical,
package, and imported lookups remain bound without comparing unrelated lexical
positions. Task and function lookup remains unchanged, as required by the
exception in the same LRM section.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a reference before an inner enum declaration resolves to a
matching enum named constant in the outer scope, while a reference after the
declaration resolves to the inner constant.
Also check that `-gno-strict-parameter-declaration` continues to allow a
reference to a later enum named constant and identifies it correctly in the
declaration-after-use warning.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Enum named constants use the parameter lookup path, including its lexical
declaration-order check. Their declaration position is currently reported as
zero, however, so a later enum named constant can incorrectly hide a matching
constant from an outer scope.
Attach the parsed enum item's source location to the elaborated enum constant
and use its lexical position during lookup. Have the position lookup also
identify enum named constants so relaxed-mode warnings do not call them
parameters. Update the position after a warning to retain the existing warning
suppression behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a bare delay identifier before a wildcard package import resolves
an outer constant. Check that a following bare delay activates the import and
resolves the package constant.
Run the test through the native and vlog95 backends.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Bare identifiers used as unparenthesized delays construct `PEIdent` directly.
This bypasses wildcard package import activation, so a delay reference after
an import can resolve to an outer declaration instead of the imported name.
Create the identifier through `pform_new_ident()` so the import becomes
visible at the reference's lexical position.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that value parameters, `localparam` constants, scalar variables,
unpacked arrays, named events, and enum literals imported from a package in
another compilation unit are visible in the importing module. Exercise both
explicit and wildcard imports.
Give the package declarations larger unit-local lexical positions than the
references in the importing unit so that comparing these unrelated positions
exposes the bug.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Package imports already resolve names declared in packages from other
compilation units. After `NetScope::find_import()` finds such an import,
however, `symbol_search()` continues with an unbound lookup. It then compares
the declaration position in the package with the reference position in the
importing unit. Lexical positions are local to a compilation unit, so these
unrelated values can make a legal imported variable, named event, or parameter
appear to be used before its declaration.
Set `scope_is_bound` after `NetScope::find_import()` has checked that the
import is visible at the reference. The import already identifies the package
that declares the name, so binding the search avoids the invalid cross-unit
comparison and prevents lookup from continuing outside that package.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `prefix_scope` flag indicates that symbol lookup has been bound to a
specific scope. It controls whether lookup can continue outside that scope
and whether declaration ordering must be checked.
Rename it to `scope_is_bound` to describe the lookup state instead of how the
scope was selected. This allows other scope bindings to reuse it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that an implicit `.name` port connection before a wildcard import
resolves an outer declaration, while a connection after the import
resolves the declaration from the package.
Run the test through the native and vlog95 backends.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LRM section 23.3.2.4 says that an implicit `.name` port
connection is a reference that can make a name from a preceding wildcard
package import visible. Currently `.name` creates its `PEIdent` directly
and skips the package import reference bookkeeping, so the imported name
can not be resolved.
Allow `pform_new_ident()` to suppress implicit net creation and use it for
`.name`. This keeps import activation, `PEIdent` construction, and source
location handling in one place while preserving the existing behavior
that prevents `.name` from creating an implicit net.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check separately that a module-body specparam declaration following a
reference is rejected and that a specparam declared in a specify block
remains visible before its declaration.
Run both tests through the native and vlog95 backends.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LRM section 6.20.5 permits `specparam` declarations both in a
module body and in a `specify` block. It states:
A specify parameter declared outside a specify block shall be declared
before it is referenced.
Currently all specparams retain a declaration position of zero, making a
later module-body declaration visible to an earlier expression:
module test;
wire value;
assign value = delay;
specparam delay = 1;
endmodule
Record the source position for module-body specparams. Track when the
parser is inside a `specify` block so the outside-block restriction is
not applied there.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that class copy construction in a nested scope activates a wildcard
package import and resolves the imported source. Check that construction in
the enclosing scope still resolves the same-named local source.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The source expression of a class copy constructor currently bypasses
`pform_new_ident()`. An identifier made visible by a wildcard package import
is therefore not activated and can not be resolved during elaboration.
Create the source expression through `pform_new_ident()`, matching ordinary
identifier expressions and preserving the source location.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check separately that explicit and wildcard package imports only affect
following references. Use outer-scope declarations and package declarations
with the same names so references before and after each import resolve
differently.
Also cover implicit named port connections and repeated explicit imports.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Package imports become visible from the import declaration, or for wildcard
imports, from the reference that makes an identifier locally visible. For
example:
package p;
parameter X = 2;
endpackage
parameter X = 1;
module m;
localparam A = X;
import p::X;
localparam B = X;
endmodule
Currently both `A` and `B` resolve to `p::X`. `A` should resolve to the
compilation-unit `X`, while only `B` should resolve to `p::X`.
Record the lexical position where each imported name becomes locally visible.
Pass reference positions through ordinary symbol lookup and implicit named
port connections so imports introduced later are ignored.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a typedef reference in a nested scope keeps the package typedef
selected during parsing when another typedef with the same name is imported
later. Check that a reference following the import selects the new typedef.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Type names are resolved to `typedef_t` objects during parsing. During
elaboration `find_typedef_scope()` currently resolves the name again through
the completed import table. An import appearing after the original reference
can therefore redirect it to a different typedef with the same name.
Search the enclosing and package scopes for the exact `typedef_t` object
instead. This preserves the parsing-time binding and returns the scope that
owns the selected typedef.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check separately that a wildcard port connection ignores a declaration after
the module instance in strict mode and uses the port default.
Check the exact position of `.*`: an implicit net created by an explicit
connection before `.*` is connected, while one created after `.*` is not.
Check that `-gno-strict-net-var-declaration` preserves relaxed behavior and
binds a declaration introduced after `.*`.
Run all three tests through the native and vlog95 backends.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
IEEE 1800-2023 section 23.3.2.4 defines a `.*` connection as equivalent
to an implicit `.name` connection for every port not connected explicitly.
The existing `.name` path resolves the matching identifier at the
connection's lexical position. Wildcard port matching instead searches at
the end of the scope, making it find declarations after the connection:
child i_child(.*);
wire value;
Use the lexical position carried by the wildcard binding when looking up
and creating wildcard connections. The position of `.*` itself matters
because an earlier explicit port connection can create an implicit net
that the wildcard connection should see:
child i_child(.source(value), .*);
This also preserves the relaxed lookup provided by
`-gno-strict-net-var-declaration`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Several source and netlist objects inherit `LineInfo` while separately
storing the lexical position associated with the same source location. This
requires callers to copy the file, line, and lexical position independently.
Add the lexical position to `LineInfo`. Have `set_line()` initialize it when
it is unset, so new objects inherit the complete source location while later
diagnostic location updates preserve their established declaration order.
Initialize the field to `UINT_MAX` so zero remains available as a valid
scanner position and missing initialization is distinguishable. Have
`FILE_NAME()` preserve a more precise identifier position.
Remove constructor parameters that duplicate the position supplied through
`FILE_NAME()`. Use the shared field for identifiers, wires, events, event
triggers, nets, and elaborated events. Assign static class property nets
their declaration location since they previously relied on the standalone
`NetNet` position defaulting to zero.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Some elaboration paths copy the file and line from a LineInfo object
individually. Use set_line() instead. This keeps the copies together when
LineInfo is extended with additional source location information.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Combine the nearly identical dynamic-array and queue method blocks in
test_width_method_ and elaborate_expr_method_ (including class property
paths), keeping queue-only pop_front/pop_back gated on queue type.
Add ordering methods for queues and dynamic arrays. Update ivtest gold
files for always_*_warn, br1005, and br_gh710b LXT per review.
Split from steveicarus/iverilog#1330 (part 06/6).
Add integral sum() and product() reductions, including expression
forms, for queues, dynamic arrays, and class properties.
Split from steveicarus/iverilog#1330 (part 05/6).
Check the reproducer from GitHub issue #1321, which uses a prefix label on a
begin-end block inside an `always_comb` process.
Check prefix labels on sequential and parallel blocks. Place attributes between
the labels and block keywords, verify that the sequential label creates a named
scope, cover all fork join types, and use matching closing labels.
Check separately that visible type identifiers can be shadowed by prefix labels
on sequential and parallel blocks.
Check that matching and different block names after `begin` or `fork` are
rejected when a prefix label is already present.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog sequential and parallel blocks allow a block identifier before
the `begin` or `fork` keyword:
LABEL: begin
statement;
end
LABEL: fork
statement;
join
The parser currently only accepts the block identifier after `begin` and
`fork`. Add a prefix-label rule using `identifier_name`. This accepts labels
returned as either `IDENTIFIER` or `TYPE_IDENTIFIER` without duplicating the
label grammar. The mixed procedural item list lets the parser use the following
`:` to distinguish a visible type identifier used as a label from the start of
a variable declaration.
Use a shared optional prefix rule for sequential and parallel block forms.
Resolve the prefix and post-keyword names before starting the common block path,
and bind attributes placed between the label and block keyword. Require
SystemVerilog mode when a prefix label is present.
IEEE 1800-2023 section 9.3.5 does not allow a prefix label and a block name
after `begin` or `fork` at the same time. Report an error for this form while
keeping it in the grammar for error recovery. Keep the existing closing label
handling, which allows a matching name after `end` or a join keyword.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The sequential and parallel block grammar duplicates scope setup and teardown,
statement transfer, and closing label handling.
Move the common logic into `pform_start_block()` and
`pform_finish_block()`. This keeps the grammar actions focused on their
syntax-specific checks and makes both block forms use the same scope and
statement ownership paths without changing the accepted syntax.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Extend locator methods to class queue and dynamic-array properties,
including min/max, unique/min/max with-predicates, and VVP array-pattern
object handling. Built on the #1419 locator helpers.
Split from steveicarus/iverilog#1330 (part 04/6).
Check that a visible type identifier can be shadowed by labels on module
level assertion items. Cover both a concurrent assertion item and a
deferred immediate assertion item.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog assertion item labels use ordinary identifiers. A visible
type identifier should therefore be accepted as the label on a module
level assertion item:
typedef int CHECK;
module test;
CHECK: assert property (1);
endmodule
Procedural assertion statements already accept either identifier token in
their optional label rule. Reusing that rule for module level concurrent
and deferred assertion items exposes a declaration ambiguity: module items
can also start with a typedef name followed by a variable declaration.
Keep the grammar conflict-free by parsing typedef-start variable
declarations in a single production that includes the first declarator.
This lets the parser see `:` before reducing the typedef-start declaration
path, so module and procedural assertions can share the same label rule
while preserving the existing declaration handling for typedef data types.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a visible type identifier can be reused as a procedural assertion
label after a declaration in both task and block bodies. These are the contexts
where label and declaration parsing meet.
Also check that a null statement ends the declaration portion of a procedural
body and a following declaration is rejected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog procedural labels use ordinary identifiers. A visible type
identifier can therefore also be used as a label:
typedef int T;
module test;
initial begin
T value;
T: assert (1);
end
endmodule
The parser currently handles procedural declarations and statements as
separate lists. After `T value;`, it must decide whether the next
`TYPE_IDENTIFIER` starts another declaration before it can see that the
following `:` makes it an assertion label. Extending the label rule alone
therefore introduces parser conflicts.
Replace the separate lists with a mixed procedural item accumulator so the
parser can keep the declaration-or-statement decision open. Track whether
declarations have been seen, use allocation of the statement vector to record
whether a statement has been seen, collect concrete statements and old-style
task/function ports, and reject a declaration after a statement. A null
statement allocates an empty statement vector and therefore also starts the
statement section, preserving the existing declaration ordering rule. Own the
accumulated statement and port vectors with `unique_ptr` and release old-style
port vectors only when transferring them to a task or function.
Parse assertion labels as `identifier_name ':'` and use the accumulator for
constructors, functions, tasks, and sequential and parallel blocks. Keep the
temporary scope for an unnamed block until its body has been classified. If it
has no declarations, move nested named scopes into the enclosing scope and
reparent them before discarding the temporary scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`statement_or_null` currently reaches statements and null statements through
an optional attribute list. Reducing that empty prefix before the parser knows
which form follows makes the rule difficult to use in a mixed procedural item
list without conflicts.
Expand the rule into explicit attributed and unattributed statement and null
forms. This preserves attribute binding and null-statement behavior while
allowing the parser to distinguish the forms from their leading token.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Block variable declarations currently combine optional `const` and lifetime
qualifiers with the data type. This requires reducing empty qualifier rules
before the parser can determine which declaration form follows, making the
rule difficult to use in a mixed procedural item list without conflicts.
Split the declaration productions according to their leading syntax. Share
required and optional variable lifetime handling and add a rule for data types
following the historical leading `reg` extension. This keeps the declaration
behavior unchanged while allowing the parser to distinguish each form from
its leading token.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `statement` and null-statement rules start with an optional attribute
list. When it is empty, the reduced location starts at the previous token
instead of the statement. Diagnostics using that location can consequently
point to the beginning of the source file.
Use the statement or semicolon location when no attributes are present.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check separately that a visible interface name can be reused as a member,
modport, interface port, ordinary port, interface instance and procedural block
name.
Also check an attributed forward interface port type after another ANSI port
declaration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The lexer currently returns `INTERFACE_IDENTIFIER` for names of interfaces
that have already been parsed. There are two issues with this approach:
1. Once an interface has been parsed, its name can no longer be used in
grammar positions that accept an ordinary identifier.
2. The LRM allows an interface to be used before its declaration. Before the
declaration has been parsed, however, the name remains an ordinary
identifier and can not be accepted by productions requiring
`INTERFACE_IDENTIFIER`. Lexer lookahead tries to recognize forward
interface port types, but this depends on parser-managed port-list state
and does not cover all cases.
Parse interface port declarations from ordinary `IDENTIFIER` tokens instead.
An interface port can not simply be added to `port_declaration` using an
`IDENTIFIER` token. This creates a shift/reduce conflict on the identifier at
the start of the port list. Shifting starts an old-style `port_reference`,
while reducing the empty `attribute_list_opt` starts an interface
`port_declaration`. The parser has not yet seen the following identifier or
`.` that distinguishes the two forms.
Add leading interface port declarations as base cases of
`list_of_port_declarations`. Both the old-style and ANSI port-list rules can
then shift the common identifier and use the following identifier or `.` to
distinguish the interface port. Keep a separate base case for a non-empty
attribute list so no empty reduction is needed before the identifier. Handle
later interface ports in the recursive list rule and use
`interface_port_modport_opt` to share the forms with and without a modport.
Interface instances can use the existing module instantiation rules.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Collapse duplicated unique*/find* paths into parameterized helpers
and table-driven opcode emission so adding types does not require
copying whole method blocks. Align multi-line call arguments.
Add find*, unique*, min/max, and with-predicate locator methods for
queues and dynamic arrays, with VVP runtime support and ivtest.
Split from steveicarus/iverilog#1330 (part 03/6).
Add parsing and elaboration for chained calls on expression results,
with sv_call_chain_method1 regression.
Split from steveicarus/iverilog#1330 (part 02/6).
Check that nature and discipline declaration names can match visible type
identifiers. Also check `potential` and `flow` references to nature names that
are visible as type identifiers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Verilog-AMS nature and discipline declarations can use names that are also
visible as type identifiers. The `potential` and `flow` discipline items can
likewise reference a nature whose name is returned as `TYPE_IDENTIFIER` by the
lexer. These grammar positions currently only accept `IDENTIFIER`.
Use `identifier_name` for nature and discipline declaration names and for the
`potential` and `flow` nature references.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a for loop variable declaration can use the same name as a
visible typedef, including references from the loop condition and step
expressions.
Also check that procedural foreach can parse an array expression name that
is initially seen as a type identifier. Declare the array after the loop so
the parser sees the outer typedef while parsing the foreach header, then
elaboration resolves the array declaration as a module item.
Use unsigned variables and omit the foreach iterator because these tests do
not depend on signed values or iteration behavior. This lets both tests run
through the vlog95 backend as normal regressions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as
a type identifier from an outer scope. The lexer reports such names as
`TYPE_IDENTIFIER` until the new declaration has been installed.
The parser previously created the synthetic loop scope and declared the loop
variable only after parsing the complete `for` header. When the variable name
matches a visible typedef, this is too late: the lexer can continue returning
`TYPE_IDENTIFIER` for references to the variable in the initializer,
condition, and step expressions. Accept `identifier_name` for the declaration
name and create the loop scope and variable in a mid-rule action immediately
after it, so the declaration is visible while the rest of the header is
parsed.
The executable foreach grammar also used to require the array expression name
before the index list to be an `IDENTIFIER`. Use `identifier_name` there as
well, since this position is an expression name followed by `[` and not a type
name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a standard attribute name can match a visible typedef. Also check
that the global `$attribute` extension can target a primitive whose name is
visible as a type identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Standard attribute names and target names in both forms of the Icarus
`$attribute` extension are unambiguous identifier positions. When such a name
matches a visible typedef the lexer returns `TYPE_IDENTIFIER`, while the
grammar only accepts `IDENTIFIER`.
Use `identifier_name` for all of these positions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parameter_omit tests have different expectations depending on whether the
regression is run in the default Verilog mode or with force SystemVerilog.
The old list files modelled this by registering the same tests in both
regress-vlg.list and regress-fsv.list.
Move the tests to JSON descriptors. Use the existing force-sv override for the
forms that are valid SystemVerilog, and keep the implicit type cases as CE in
both modes. This also runs the tests through the additional configurations
supported by vvp_reg.py, providing better coverage in CI.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LRM allows omitting the `parameter` keyword in a module parameter port
list, but the optional type in that form is a data_type, not an implicit
data type. A parameter port list like this is therefore invalid:
module M #([3:0] P = 1);
The parameter declaration grammar was reusing the general
value_parameter_assign_with_type rule for the omitted-keyword form. That rule
also accepts implicit types so that ordinary `parameter signed P = 1`
declarations work, which made the omitted-keyword form accept implicit types
as well.
Add a separate rule for value parameter assignments without the `parameter`
keyword. The rule still accepts bare identifiers and explicit data types so a
parameter name can shadow a visible typedef name, but it rejects implicit
types.
Fixes: e56c93a2be ("Support shadowing type identifiers in parameter declarations")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The br_gh1385a, br_gh1385b, and br_gh1385c JSON descriptors mark the vlog95
variants as compile errors. The enum typedefs are translated correctly, so the
compile error expectation causes the tests to fail when compilation succeeds.
Remove the stale overrides and run the translated tests through vlog95.
Fixes: 10349287a0 ("Add regression tests for enum typedefs in nested scopes")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a named binding selector can have the same text as a visible typedef
name. Cover named module port connections, named parameter overrides, and named
task, function and constructor arguments.
Also check that a modport simple port selector can shadow a visible typedef
name. Modport simple port aliases share the same parser rule but declare the
modport-visible name rather than binding to an existing formal.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A named binding selector such as `.T(expr)` names an existing formal port,
parameter, task or function argument, or constructor argument. It is not a
declaration of a new identifier. If a visible typedef named `T` exists at the
use site the lexer returns `TYPE_IDENTIFIER`, which made the parser reject the
binding selector.
Modport simple port aliases use the same grammar, but are slightly different:
the selector is the modport-visible port name and can shadow a visible typedef
name in the interface scope.
Use `identifier_name` for the selector name in `named_expression` and
`named_expression_opt`. This covers named parameter overrides, named task and
function arguments, named constructor arguments, and modport simple port
aliases. Also use `identifier_name` in the named module port connection rules,
including implicit named port connections and error recovery.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Fold in Windows VPI routing for vpip_format_pretty, fix queue method
argument elaboration via elaborate_rval_expr, reject class tasks used as
expressions cleanly, and update br1005 now that class queues compile.
Review follow-up: move vpip_format_pretty to vpip_format.cc with
diagnostic return strings, restore NetNet-based queue method elaboration
with a separate property path, drop spurious /devel/ from .gitignore,
and bump copyright years on touched files.
Formatting pass per inline review: brace style for multi-line if bodies,
||/&& at end-of-line continuations, switch/case indentation, single-line
if returns, NetNet-based sys_task_method_ again, and aligned extern decls.
Check that event declarations can use visible type identifiers as event names.
Also check that the resulting named event can be triggered and waited on.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. This also applies to named event
declarations. The lexer reports such names as `TYPE_IDENTIFIER` before the
event has been installed, which made constructs such as:
typedef int T;
module test;
event T;
endmodule
fail in the event declaration grammar.
Event declarations do not have the local type/name ambiguity that exists for
variable, net, or parameter declarations. The name in `event_variable` is
always the event name. Use `identifier_name` so a `TYPE_IDENTIFIER` token can
be accepted as the event name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that visible type identifiers can be reused as named block labels. Cover
procedural `begin` blocks, fork blocks, and conditional generate blocks. Also
check matching end labels where the grammar consumes the shared `label_opt`
rule.
The generate test keeps the existing vlog95 compile-error expectation because
named generate scopes are not translated by the vlog95 target.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a named block label in an inner scope to use the same
name as a visible type identifier from an outer scope. The lexer reports such
names as `TYPE_IDENTIFIER` before the label has been installed, which made
constructs such as:
typedef int T;
module test;
initial begin
begin : T
end : T
end
endmodule
fail in the block label grammar.
The affected grammar positions are label names, not declarations with an
adjacent type/name ambiguity. Use `identifier_name` for `label_opt` and for the
anachronistic named generate begin form so a token returned as `TYPE_IDENTIFIER`
can still be accepted as the label name. With `label_opt` able to handle
`TYPE_IDENTIFIER`, the separate class end-label rule is no longer needed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a package declaration can use a visible type identifier as its
package name. Also check that the resulting package scope can be selected with
a scope-qualified reference.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a package declaration to use a name that is also visible
as a type identifier. The lexer reports such names as `TYPE_IDENTIFIER` before
the package has been installed, which made constructs such as:
package p;
typedef int T;
endpackage
import p::*;
package T;
endpackage
fail in the package declaration grammar.
Package declarations do not have the local type/name ambiguity that exists for
variable, net, or parameter declarations. After the optional lifetime the next
token is always the package name. Use `identifier_name` so a
`TYPE_IDENTIFIER` token can be accepted as the package name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Bison reports shift/reduce and reduce/reduce parser conflicts as warnings by
default. This allows parser changes to introduce new conflicts while the normal
build still succeeds.
Pass the conflict warning classes as errors to Bison when generating the
parsers. This makes the regular build fail if either parser has unresolved
conflicts.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parameter declaration grammar allows a visible type identifier to be used
as a parameter name. The assignment continuation rule still used
`identifier_name`, which made Bison reduce a `TYPE_IDENTIFIER` before it had
seen whether following dimensions belonged to the parameter name or to an
explicit type identifier.
Match ordinary and type identifiers directly in `parameter_assign` so the
parser can shift dimensions before deciding between a parameter name and an
explicit parameter type.
Fixes: e56c93a2be ("Support shadowing type identifiers in parameter declarations")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that UDP primitive and port names can shadow visible type identifiers.
Cover old-style UDP declarations, including input and output declarations and
the initial target, as well as ANSI-style UDP port declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a UDP primitive or UDP port declaration to use the same
name as a visible type identifier from another namespace or outer scope. The
lexer reports such names as `TYPE_IDENTIFIER` before the UDP name has been
installed, which made constructs such as:
typedef int T;
primitive T (Q, A);
output Q;
input A;
table
0 : 0;
endtable
endprimitive
fail in the UDP grammar.
UDP primitive and port names do not have the local type/name ambiguity that
exists for variable, net, or parameter declarations. Use `identifier_name` for
the primitive name, the UDP port list, UDP port declarations, and the UDP
initial target so a `TYPE_IDENTIFIER` token can be accepted as the UDP name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that UDP initial values on non-registered outputs generate compile
errors for both old-style and ANSI-style UDP declarations. Also check that
conflicting UDP port declarations generate an error and that a valid
ANSI-style `output reg` initializer is accepted.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Malformed UDP declarations can reach `pform_make_udp()` with conflicting
duplicate port declarations or with an initial value on an output that was not
declared as a register. These cases currently trigger internal assertions
instead of reporting normal compile errors.
The ANSI-style UDP output initializer path also treats the initializer
expression as if it was the old-style `initial out = value` assignment
statement. This makes a valid `output reg out = 1'b0` initializer assert as
well.
Report errors for the invalid declarations and read the ANSI-style initializer
value directly from the initializer expression.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that enum item names can shadow visible type identifiers. Cover plain enum
items as well as the counted and ranged enum item sequence forms.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. This also applies to enum item names. The
lexer reports such names as `TYPE_IDENTIFIER` before the enum item has been
installed, which made constructs such as:
typedef int T;
module test;
enum { T = 1 } e;
endmodule
fail in the enum item grammar.
Enum item declarations do not have the local type/name ambiguity that exists for
variable, net, or parameter declarations. The name in each `enum_name`
production is always the enum item name, including the sequence forms like
`T[2]` and `T[1:2]`. Use `identifier_name` for these names so they can shadow a
visible type identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that function and task declarations can use a visible type identifier as
the declaration name. Cover both ANSI declarations and the non-ANSI forms where
the name is parsed without a separate return type or port list.
Also check class method declarations where the method name is the same as the
enclosing class name. Add GitHub issue #670 coverage for the `function void`
case using the issue-based regression naming scheme.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. This also applies to task and function
names. The lexer reports such names as `TYPE_IDENTIFIER` before the new task or
function has been installed, which made constructs such as:
typedef int T;
module test;
function int T(input int value);
return value;
endfunction
task T;
endtask
endmodule
fail in the task and function declaration grammar. A class method with the same
name as the class itself hits the same problem because the class name is visible
as a type identifier in the class scope.
The task grammar can accept `identifier_name` directly, because a task has no
return type and the token after `task` and the optional lifetime is always the
task name.
Function declarations have a local return-type/name ambiguity. After
`function T` the parser does not know yet whether `T` is the function name with
no explicit return type, or whether a following identifier will make `T` the
explicit return type as in `function T f`. Parse the optional function return
type and function name together. This allows a `TYPE_IDENTIFIER` token to be
interpreted as the function name when no separate function name follows, while
still parsing typed forms and `void` return types correctly.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that visible type identifiers can be shadowed by value parameter names
and by type parameter names. Cover ordinary parameter declarations, typed
parameter declarations, and parameter port list declarations separately.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a visible type identifier to be shadowed by a
parameter declaration name. Parameter declarations still required the
parameter name to be an `IDENTIFIER` token and rejected declarations like:
typedef int P;
module test;
parameter int P = 1;
endmodule
The parameter grammar can not just accept `TYPE_IDENTIFIER` in every name
position. After `parameter P` the parser does not know yet whether `P` is
the parameter name, or whether a following identifier will make `P` the
parameter type.
Parse the optional value parameter type and the first parameter assignment
together. This allows a `TYPE_IDENTIFIER` token to be interpreted as the
parameter name when no explicit type is present, while still parsing a
following identifier as the parameter name for typed parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a class property can have the same name as a type declared in
an outer scope, or a type imported through a wildcard import. Also check
that a class property can have the same name as the class itself.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a class property to have the same name as a visible
type. The lexer reports the visible type name as `TYPE_IDENTIFIER` before
the property has been installed, which made constructs such as
`typedef int T; class C; int T; endclass` fail in the class item grammar.
A class property with the same name as the class itself hits the same
problem. Member references such as `obj.T` or `obj.C` can also hit the
same tokenization problem in hierarchical names.
Parse class properties through the same declaration helper used for
variables so the first type/name pair can be disambiguated. Also let
hierarchical member names use `identifier_name`.
Stop type lookup when a class scope already has a property with the same
name. This makes method body references resolve as properties instead of
visible types, including type names found through wildcard imports.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that automatic variables referenced through an assignment pattern in a
procedural `force` statement are rejected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Assignment patterns contain child expressions, but currently inherit
`PExpr::has_aa_term()` which always returns false. This means automatic
variables inside a pattern are not caught by checks for procedural `force`
and procedural continuous assignment statements.
Implement `has_aa_term()` for `PEAssignPattern` and recurse into all pattern
elements.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the repeat count expression of a non-blocking intra-assignment
event control can reference an automatic task argument. The repeat count is
evaluated when the assignment is scheduled, so the automatic variable is not
referenced after the task scope is freed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The repeat expression of an event controlled non-blocking assignment is
evaluated once when the assignment is scheduled. This means there is no
risk of it being referenced when its scope has already been freed. And
hence there is no need to require the repeat expression to only contain
static terms.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that variable and net declaration names can shadow a visible type
identifier. Check this for explicit data type declarations, `var` declarations,
and net declarations.
Check that task and function formal argument names can shadow a visible type
identifier, and that typed arguments still use the visible typedef when an
argument name follows.
Check ambiguous module port declarations where a type identifier can be either
the port name or the port type, with and without dimensions, and that
declaration lists continue to use the type selected by the first ambiguous
declarator. Cover both ANSI and non-ANSI module port declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. The lexer reports such names as
`TYPE_IDENTIFIER` before the new declaration has been installed, which made
constructs such as `int T;`, `wire T;`, and `input T` fail when `T` was a
visible typedef.
The affected declaration forms have a local type/name/dimension ambiguity. For
example, after `input T` or `wire T` the parser does not know whether `T` is the
declared name, or whether a following identifier will make `T` the declaration
type in `input T x` or `wire T x`. With dimensions, `input T [1:0]` and
`wire T [1:0]` can be either a declaration named `T` with unpacked dimensions or
a declaration using typedef `T` as a packed type followed by another name.
Parse these declaration forms with productions that decide the first declarator
and carry the selected declaration type across the rest of the list. This covers
variable declarations, net declarations, ANSI and non-ANSI module port
declarations, and task/function port declarations. Other identifier uses still
need separate grammar changes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a blocking intra-assignment delay on a real value preserves the
assigned value after the delay.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The vvp parser did not accept the local flag on `.var/real`
declarations. This can happen when elaboration creates a compiler-generated
real temporary, for example when a blocking intra-assignment delay is
rewritten from:
r = #1 1.25;
to assign the right hand side to a temporary before the delay and assign
the temporary to the target after the delay.
Add support for the local flag. Keep a VPI symbol for the variable so
`%load/real` can still resolve the label, but do not attach local real
variables to the current scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that visible type identifiers can be shadowed by declarations in
other namespaces or nested scopes. Keep each grammar category in a
separate regression so failures identify the affected rule.
Also check that package import and export items can name a type
identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows an identifier that is visible as a typedef to be
shadowed by a declaration in a nested scope or reused as a declaration
name in another namespace. The lexer can return `TYPE_IDENTIFIER` before
the new name has been installed, so these grammar positions reject
otherwise valid code.
This is not a complete conversion of all identifier grammar sites. Only
handle the trivial conflict-free cases where `IDENTIFIER` can be replaced
by `identifier_name` without any surrounding grammar changes.
Also stop type lookup when the current scope already has a local symbol
with the same name. This makes later references to a shadowing
declaration use the local symbol instead of an outer typedef.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The string substr() method reports an error if it is called with the wrong
number of arguments, but the error was not counted and elaboration continued
with missing function arguments. A call such as `s.substr(0)` could therefore
crash after printing the diagnostic.
Count the arity error and fill missing internal arguments with dummy constants
so elaboration can recover without building an incomplete system function call.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that unary real minus preserves the sign or bit pattern for zero,
NaN, and infinity. Each test starts with the positive value, negates it,
and then negates the result back to the positive value.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the vvp target emits unary real minus as `0.0 - value`.
This is not the same operation for all real values. It loses the
negative zero result for `-(+0.0)` and does not reliably flip the sign
bit for NaN values whose bits are visible through `$realtobits`.
Add `%neg/wr` and use it for unary real minus. This performs a direct
negation of the real stack value, so zero, NaN and infinity all use the
same operation as unary minus instead of a binary subtraction from zero.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the vvp code generator emits a -0.0 real constant with its
sign bit set, so the compiled value matches the runtime real value. The
sign used to be detected with (value < 0), which is false for IEEE 754
-0.0, and a -0.0 constant was turned into +0.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Check that bogus member access on a procedural l-value is rejected with a
normal compile error instead of aborting during elaboration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that an invalid indexed part select base on a procedural l-value is
reported as a normal compile error instead of crashing after the bind error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the procedural l-value path asserts if symbol lookup leaves a
member tail for a variable that is not a struct or class. For example,
`r.bad = 1'b1;` where `r` is a scalar variable aborts during elaboration
instead of reporting a normal error.
Report an error for the leftover member path before the assertion. This
matches the r-value path behavior for the same kind of invalid member access.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The l-value indexed part select path elaborates the base expression with
`elab_and_eval()`. If the base expression can not be bound this returns a
nullptr, but the l-value path dereferenced it while checking the expression
type. For example, `a[does_not_exist -: 2] = 2'b00;` reported the bind error
and then crashed.
Return early when base elaboration fails. This matches the r-value indexed
part select path and leaves the existing bind error as the reported
elaboration error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently vvp_reg.py uses `returncode >= 256` to distinguish execution
errors from ordinary compile or simulation failures. That matches the encoded
status returned by wait(), but subprocess.run() does not expose that value. Its
returncode is the decoded process exit status, or `-N` if the process was
terminated by signal N. Shell wrappers can also report signal termination as
`128 + N`.
As a result a compiler crash can be reported as `-11` or `139`. Both values
pass the old check and a CE test can be accepted as a normal compiler error.
Treat negative return codes and return codes greater than or equal to 128 as
execution errors before accepting CE and EF results. Also make sure that CE gold
mismatches are reported as failures.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The vlog95 backend currently emits `$unsigned()` when it needs to create a
self-determined unsigned expression context. `$unsigned()` is part of the
optional signed expression support in this backend and is only available when
the signed support flag is enabled.
Concatenation is part of the baseline Verilog-95 output and also creates a
self-determined unsigned expression context. Use `{expr}` for the unsigned case
and keep using `$signed()` when a signed context is needed.
Remove `-pallowsigned=1` from the existing vlog95 regression tests that now
pass without the optional signed support flag.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that synthesized case statement muxes can use array words as inputs.
This used to generate invalid VVP because .array/port statements were emitted
in the middle of .functor statements.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently draw_lpm_mux_nest() calls draw_net_input() while printing a
.functor statement. For array word inputs draw_net_input() emits an
.array/port statement as a side effect, which interleaves the .array/port
text into the middle of the .functor line and generates invalid VVP.
draw_lpm_substitute() has the same pattern. Collect the input labels before
starting to print the consuming statement so any side-effect output appears
as a separate statement first.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a class declared in a conditional generate block can be used.
Also check that classes declared in a generate loop get separate class scopes
for each generated instance.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows class declarations as module and generate items.
Currently a class declaration in a generate block triggers an assert because
`pform_push_class_scope()` only records classes in `PScopeExtra` scopes.
Add class storage to `PGenerate` and elaborate those classes like module and
package classes. When registering task, function or class declarations, only
use the current `PGenerate` object as the target if it is also the current
lexical scope. This distinction matters for generated classes because
`pform_cur_generate` remains set while the class body is parsed, but the
current lexical scope has changed to the `PClass`. This records the class
declaration in the generate block while leaving methods and constructors in
the class scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that using a class task through an object method call in expression
context reports a compile/elaboration error instead of triggering an assert.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Class object method calls in expression context call func_def() without first
checking that the resolved class method is a function. If the method is a task,
func_def() triggers an assert instead of reporting a normal elaboration error.
Check the method scope type before accessing the function definition and report
an error for tasks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently NetAssignNB::dump() prints a malformed fallback marker when
there is no rval expression. The leading '<' is missing, making it
inconsistent with the blocking assignment dump output.
Print the complete error marker.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The methods for handling up and down part select are nearly identical
and only differ in a hand full of lines.
Consolidate them into a single method to remove the duplicated code.
This makes it easier to maintain the code and add future changes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The methods for handling up and down part select are nearly identical
and only differ in a hand full of lines.
Consolidate them into a single method to remove the duplicated code.
This makes it easier to maintain the code and add future changes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that enum literals declared by enum typedefs in generate blocks, named
blocks, tasks and functions can be referenced from the same scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Enum types declared inside nested scopes are stored separately from typedefs.
The enum sets need to be elaborated when the `NetScope` is created so enum
literals are available for declarations and statements in the same scope.
Module, package and class scopes already do this. Generate, task, function and
named block scopes can also declare enum typedefs, but did not elaborate their
enum sets. Elaborate them while setting up these scopes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The VPI label resolver parses word and string labels into a 32 byte
temporary buffer. The scansets used by sscanf() did not specify a width,
so malformed labels could write past the end of the buffer.
Limit the scansets to the size of the buffer.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that an empty old-style UDP table reports the parser error and the
invalid primitive error instead of crashing.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
An empty old-style UDP table leaves the parsed table pointer unset after
the parser reports the table error. The old-style UDP creation path still
passed the null pointer to process_udp_table(), which crashes.
Report an invalid UDP table instead and do not register the primitive.
Also keep the new-style invalid-table diagnostic formatting consistent.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that variable selects of a packed array with negative bounds use the
correct index width and can read back assigned elements.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Variable select base normalization extends the base expression to cover
the packed array bounds. The current code compared min_wid against
num_bits() of each bound, but then assigned the bound value itself to
min_wid.
For positive bounds this can make the generated index expression much
wider than required. For negative bounds the effect is much worse since
min_wid is unsigned. Assigning a negative bound converts it to a huge
width, causing elaboration to try to pad the expression to that size and
abort or run out of memory for otherwise valid variable selects.
Use the bit width of the bound instead of the bound value.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that statements that are not allowed in functions or final procedures
are still rejected when they are placed in a named block scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently checks for statements that are not allowed in functions or final
procedures only inspect the immediate scope. If the statement is inside a
named block or a block with declarations, the current scope is the block and
the context is lost.
Make `NetScope::in_func()` and `NetScope::in_final()` preserve the context
through begin-end, fork-join and generate block scopes. Other scope types are
treated as context boundaries so function and final state does not leak across
subroutine or definition scopes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that queue push_back(), push_front() and insert() report errors when
called with too few or too many arguments.
These tests are expected to fail as compile/elaboration errors. They also make
sure the invalid calls do not crash during elaboration while reporting the
argument count error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When a method argument is missing, the error path stores a nullptr in the
argument vector for that missing slot. The vector was sized from the number of
arguments that were present in the source, so calls such as `q.push_back()` or
`q.insert(0)` wrote those nullptr placeholders past the end of the vector.
Size the vector from the number of arguments required by the queue method
instead. This gives the error path slots for the missing arguments while
leaving valid calls unchanged.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that multi-dimensional packed vector class properties can be emitted,
assigned, and read back through a class object.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently multi-dimensional packed vector class properties will cause an
assert and only single dimensional or scalar vectors will pass.
But just as for regular vectors there is nothing special about class
property multi-dimensional vectors as they will be represented in vector
form in vvp.
Removing the asserts allows multi-dimensional packed vectors to be used for
class properties. Indexed access to these properties is not supported yet;
that requires follow-up work to elaborate packed property selects and to
support partial stores to vector class properties.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that assignment patterns are evaluated in the queue element type
context when they are passed to the queue `push_front()`, `push_back()` and
`insert()` methods.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The arguments of the queue `push_front()`, `push_back()` and `insert()`
methods are passed to subroutine input ports. This makes them
assignment-like contexts with the declared argument type as target type.
Use `elaborate_rval_expr()` instead of `elab_and_eval()` for these
arguments. This evaluates the item argument with the queue element type and
the `insert()` index argument with `integer`, so target-type-dependent
expressions such as assignment patterns work and enum compatibility checks
use the queue element type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Extend the non-blocking event control assignment tests to check that a 0 or
negative repeat value is handled correctly. In this case the assignment
should be executed like a regular non-blocking assignment and the event
control should be ignored.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`NetEvWait` deletes the event that is assigned to it when itself
is deleted. But the event is not owned by the `NetEvWait`, it is shared among
all consumers of the event. Deleting it when the `NetEvWait` is deleted can
result in undefined behavior.
This is mainly a problem for non-blocking event control assignments with a
zero or negative immediate valued repeat. In this case the `NetEvWait` will
be deleted as it is not needed.
```
reg x;
event e;
x <= repeat(1) @e 1'b0;
x <= repeat(0) @e 1'b1; // Assert triggered since in-use event is freed
```
Remove the delete to fix this. Events that end up being unused will be
freed by the nodangle functor.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This test was added to verify the new options
in the `iverilog` program, which allow it to
be run from a build directory.
Since `iverilog` is not compatible with the MSYS2
runtime environment used in CI, the added test is
excluded on this platform.
Check that continuous assignments to unpacked net arrays preserve delay and
drive strength on the generated element drivers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Continuous assignments to unpacked arrays are expanded into per-element
BUFZ drivers. Currently this path drops the delay and drive strength from
the original continuous assignment, so `assign #5 a = b` updates the array
immediately and `assign (weak1, weak0) a = b` drives with the default
strength.
Pass the evaluated delay and strength values through the unpacked array
assignment helper and apply them to each generated element driver.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Drive strengths and delays are often handled as a pair of drive values
and a rise/fall/decay triple. Add small helper types to carry these
groups and use them in the continuous assignment and gate/UDP elaboration
paths.
Use the same helper types when propagating drive and delay values through
netlist links.
Also add helpers for dumping the values in debug output. This keeps the
behavior consistent and fixes one small bug where some of the debug
dumps printed the pointer value for the delays, rather than the actual
delay values.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that SystemVerilog net declarations can mix entries with and
without initialization.
Check that in SystemVerilog it is possible to do assignments within net array
declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`pform_set_data_type()` is now only called on wires that already have the
correct wire type set. There is no need to pass the same type to
`pform_set_data_type()` and set it again.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows initialized and uninitialized net declaration entries to
be mixed in the same declaration, e.g. `wire x, y = 1'b1`. In Verilog,
either all nets need to have an initializer or non can have one.
In addition SystemVerilog also allows assignments to arrays of wires during
declaration. E.g. `wire a[3:0] = b;`
Currently there are two different rules for net declarations, one for each
of the Verilog variants. Combine these into a single rule to support
SystemVerilog mixed declarations as well as the assignment to array nets.
When running in Verilog mode still reject mixed initialized and
uninitialized with a check after the parsing.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The assignment handling block uses space-based indentation that does not match
the surrounding code.
Fix the indentation before changing the block.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that continuous assignment of an assignment pattern to a single element
unpacked array is accepted. Check that assigning a scalar expression to the
whole unpacked array is rejected for both procedural and continuous
assignments.
Check that a selected element of a single element static unpacked array can be
used in a continuous l-value concatenation.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently single element static unpacked arrays are not always treated as
unpacked arrays when elaborating assignment l-values. The net only has one pin,
so checks using `pin_count() > 1` treat the array as a scalar value and skip
the unpacked array path.
Use `unpacked_dimensions() > 0` instead of `pin_count() > 1` when checking
whether a signal is an unpacked array. This lets single element arrays follow
the same l-value elaboration paths as other unpacked arrays.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that enum, struct, union and class restricted type parameters are
accepted. Check that mismatched default values and overrides are rejected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog 2023 allows type parameters to be restricted to a
specific kind of type, e.g. `parameter type struct T = T0`.
This is very similar to the type restrictions that can be applied to
forward typedefs.
Factor the support code from the typedefs into a standalone helper and
reuse it for both.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that soft packed unions can have members with different widths.
Check that the `soft` qualifier implies `packed` and that nested soft
packed unions use the same representation recursively.
Also check that member bits are right-justified and that assignments to
narrower members leave the MSBs beyond the member bits unchanged. Check
that soft packed unions reject default member values.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog 2023 adds soft packed unions. They are pretty much the same
as regular packed unions except they remove the restriction that all
elements have to have the same packed width.
The packed with of the union itself is the maximum packed width of any
element.
The bits of each member are right-justified towards the LSBs and this
representation is applied recursively to nested soft packed unions. The
existing packed union member offsets already use that layout. When
accessing a field that is smaller than the union itself upper bits are
ignored for both reading and writing.
The `soft` qualifier implies a packed union so both `union soft U { ... }`
and `union soft packed U { ... }` declare a soft packed union.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that each valid `begin_keywords` selector is accepted. Only check
that the selector itself is accepted, in these tests there is no check if
the correct keywords are actually accepted or rejected since that would get
pretty exhaustive.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Add flags to enable IEEE1800-2017 and IEEE1800-2023 languages generations
and also support them in the `begin_keywords macro. Since neither defines
new keywords they'll use the same keyword mask as 2012.
Update the driver, compiler, documentation and regression test harness so
-g2017 and -g2023 are recognized as language generation flags.
There are no specific features from these versions added yet, this is just
the necessary infrastructure to allow gating new features from those
generations when they are added later.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A few JSON regression test entries reference the wrong source or gold
files. There are also two regress-vvp list entries that reference each
other's JSON file.
Use the matching source and gold files for those entries.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The sv_mixed_assign2 JSON entry accidentally references
sv_mixed_assign1.v. Point it at sv_mixed_assign2.v instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that class objects, dynamic arrays, queues, strings and static
unpacked arrays can not be used as l-value concatenation operands. Check
procedural and continuous assignment concatenations, including single
operand concatenations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
L-value concatenation operands must be packed values. Using an unpacked
array, string, class object or other non-packed value as an operand can
reach later assignment code with an invalid l-value representation.
Check the operand type after l-value elaboration and report an
elaboration error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`%cmp/e` and `%cmp/u` are very similar with `%cmp/e` not setting the lt
flag and being a bit faster due to it. For case comparisons the flag is not
needed so switch to `%cmp/e`. This speeds up simulation time designs which
make use of case comparisons.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parser union still has a few fields that are not used by any
grammar rule. They do not have matching semantic type tags and no
action references them.
Remove the unused fields.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It uses a dedicated LIBVVP_SOVERSION specified in onfigure.ac
for the SONAME and full library version.
For linking, a pkg-config file is generated, and when building on
Windows, an import library is created that can be used with both
GCC and MSVC compilers.
On non-Windows platforms, all object files are compiled with -fPIC
to ensure compatibility with shared libraries.
On Windows use 'lib' prefix for library name with MinGW compiler
only. Other compiler like MSVC normally are not using any library
prefix.
With this commit the build rules for the vpp executable has been
cleaned too because the complex structure of the manually created
Makefile.in made it very difficult to extract specific parts of
them.
The `super` keyword refers to the parent class of the current class. If the
class has no parent the lookup still returned the current class handle and left
the `super` path component for l-value elaboration. This triggered the
`tail_path.empty()` assert.
Report an error during symbol lookup instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the compiler reports an error for `posedge`, `negedge` and `edge`
event controls on named events. Edge controls can not be used with named
events.
There is already an existing test that checks both `posedge` and `negedge`.
Split it into separate tests so that each invalid event control is checked
independently.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Using an edge control with a named event is invalid. The existing elaboration
code already reports an error for `posedge` and `negedge`, but the `edge` case
falls through to the default path and triggers an assert.
Handle `PEEvent::EDGE` like the other edge-control cases and report the same
kind of error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
- change documentation theme from `alabaster` to `shibuya`
- add pinned Documentation requirements for `sphinx` and `shibuya`
- update workflows to create `.venv` and install with `requirements.txt`
- ignore common virtual environment directories (`.conda` and `.venv`)
Since this file, just like 'config.h', is generated by autoconf,
it should only be deleted in the `distclean` target.
Also since the project does not currently use automake, manual
maintenance of the timestamp file for 'version_base.h' is required.
Fixup for commit 10b5f70e7 from #1331
Array indices must be integral expressions. Using a real valued expression
as an unpacked array index currently reaches the vvp real expression code
and triggers an assert.
Packed bit and part select indices already report an elaboration error for
real expressions since commit 2249d224de ("Bit/part selects cannot have
real index expressions"). Do the same for unpacked array indices.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
here are two separate paths `PENewArray::elaborate_expr()`, one for
assignment patterns and one for everything else.
But since since commit 5ca058bfb ("Add support for darray initialisation
from another darray"). The two paths have been effectively the same.
Both call `elaborate_expr()` on the init values with the same parameters.
The only difference is the regular path casts the type to `netarray_t`, but
that doesn't really do anything since it gets passed to a function that
takes a `ivl_type_t`, so is immediately cast back to the base type.
The comment on the regular path is also outdated since it still refers to
the tpre 5ca058bfb code.
Remove the branching and route it through the same path.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`PEIdent::test_width_parameter_()` has a special case for
`NetEConstEnum` that queries the enum base type directly. This was needed
when enum constants kept their enum type separately from the `NetExpr`
type.
Commit f63a162329 ("Provide data type for more NetExpr subclasses") made
`NetEConstEnum` attach the enum type to the `NetExpr`. The generic
parameter width path now gets the same type, width and signedness as the
special case.
Remove the redundant special case and use the common path for enum
constants as well.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that package variables can use explicit static lifetime. Check that
automatic lifetime is rejected for package variables.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LRM allows to add a lifetime specified for variables declared in
package scope. It is not particular useful since only static lifetime is
allowed. But it is legal syntax, so support it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The vvp reduction operators evaluate their input bit by bit. This is
expensive for wide vectors.
Add word wide reduction helpers to `vvp_vector4_t` and use them for both
reduction functors and vthread reduction opcodes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that string literals can be assigned to byte arrays. Check that
invalid target array types are reported as errors.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The logic functors combine their input vectors bit by bit.
Use the in-place `vvp_vector4_t` operators for the vector operation and
invert the result once for the inverted functors.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The vthread binary logic opcodes update vectors bit by bit.
Use the in-place `vvp_vector4_t` operators instead. This reuses the word
wide implementation and avoids per-bit `value()` and `set_bit()` calls.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`vvp_vector4_t` has word wide in-place operators for and and or, but not
for xor.
Add `operator ^=` using the same internal word representation.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog defines a special case that allows to assign string literals
to byte arrays. Each character of the string is copied to 1 element of the
byte array.
The size of string literal and the byte array does not have to match. If
the string literal is longer it is truncated. If it is shorter it will be
padded with null-bytes.
The assignment is done left aligned, the first character ends up in the
left most entry of the array. This means the order will differ whether the
array is declared with ascending or descending element order.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Output port expressions must support continuous assignment. Assignment
patterns for unpacked array output ports are currently elaborated as
temporary arrays and the connection is silently discarded.
Report an error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that drive strength can be specified between the net type and the
data type in a net declaration and that vector gate arrays resolve
strengths correctly.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The drive strength of a net must be declared between the net type and the data type. E.g.
wire (weak0, strong1) [7:0] x;
The current implementation expects the drive strength after the data type. Update the parser to fix this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This change standardizes the creation of iverilog-vpi-related
targets, which now follow the same pattern as the iverilog targets
in the 'driver' subdirectory.
Replace .github/test.sh with a unified set of targets installed
via `make check-*` in ivtest/, thereby removing CI-specific test
coordination. This avoids duplication in the regression logic and
ensures consistent execution between local and CI environments.
PLI1-dependent tests are now correctly controlled via
`configure --enable-libveriuser`.
Currently, the regression suite still depends on an iverilog package,
which must be installed manually at the location specified with
`configure --prefix=*`. Afterward, the complete regression suite
(VVP, VPI, and Python tests) can be run via `make check-installed`
and individual checks can be run with `check-installed-vpi`,
`check-installed-vvp` and `check-installed-vvp-py`.
When running `make check` on a UNIX-like operating system
with the specified `configure` option, `vvp` was unable to
find the required shared library.
This commit ensures that the runtime linker can locate the library.
This fixes issue #1313.
macro_start_args() inserts a null string for arg 0 at the start of def_buf.
This allows macro_finish_arg() to calculate the length of the first actual
argument (arg 1). But macro_start_args() relied on def_buf having already
been allocated, which isn't the case when all the macros are pre-defined.
This fixes issue #1323.
driver/main.c uses _NSGetExecutablePath in the __APPLE__ code path
but does not include the header that declares it, causing a build
failure on macOS.
Signed-off-by: Huang Rui <vowstar@gmail.com>
The new option allows parameter, net and events to be used before
declaration. With variants
-gno-strict-net-declaration for nets and events,
-gno-strict-parameter-declaration for parameters.
With `-ggno-strict-parameter-declaration` a warning is issued for
parameter use before declaration. This warning suppressed with
the new class `-Wno-declaration-after-use`, instead of `-Wno-anachronisms`.
The standards requires that parameters must be declared
before they are used. Using -gno-strict-parameter-declaration
will allow using a parameter before declaration, e.g., in a port
declaration, with the parameter declared in the body of the
module. Prior to version 13 this was allowed, so there is a large body
of existing code depending on the pre version 13 behaviour.
The vvp/ivl_dlfcn.h and cadpli/ivl_dlfcn.h files are essentially the
same, but have diverged a bit over the years. Merge them into a single
shared file at the top level. Use the static prefix for all inline
functins (currently only used in the cadpli version) as that will fix
issue #1301. We now require the compiler to support at least C99, so
can use "inline", not "__inline__".