Check that a class can derive from a forward declared base class that is
defined later, both directly and through a typedef alias. Cover a multi-level
hierarchy, base constructor chaining, and inherited property layout.
Check that a local forward declaration hides an outer class with the same name.
Check forward declared base classes in package scopes and in separate instances
of the same module. Check that inheritance cycles, undefined forward
declarations, and non-class base types are rejected.
Run the tests through the native and vlog95 backends.
Signed-off-by: Lars-Peter Clausen <[email protected]>
SystemVerilog allows a forward declared class to be used as the base of a
class that is declared before the base class definition.
typedef class B;
class C extends B;
endclass
class B;
endclass
The base type is currently elaborated while creating the derived class. At
that point the base class has not been added to the scope yet and the base
type does not resolve to a class.
Create all classes first and bind their base classes in a second pass. Reject
inheritance cycles before attaching the base class.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that `SCOPE.value` resolves to a forward-referenced generate block when
`SCOPE` also names an imported type. The lexer can only see the type at the
point of the reference, so this exercises parsing a `TYPE_IDENTIFIER` as the
first hierarchy component.
Check that a compilation-unit type does not prevent a same-named inherited
class property from being used as a procedural l-value or expression.
Check that empty and queue-bound indices on such hierarchy components are
rejected during parsing instead of reaching elaboration.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The lexer returns `TYPE_IDENTIFIER` when an identifier matches a visible
typedef. It does not know about hierarchy scopes declared later, so an
imported type can prevent a forward-referenced generate block with the same
name from being used as the first hierarchy component:
package p;
typedef int SCOPE;
endpackage
import p::*;
module test;
initial SCOPE.value = 1;
if (1) begin : SCOPE
int value;
end
endmodule
The same applies to inherited class properties, which are not visible to the
parser:
typedef int value;
class Base;
int value;
endclass
class Derived extends Base;
function int get;
return value;
endfunction
endclass
Accept `TYPE_IDENTIFIER` as the first hierarchy component and build it through
the same path as `IDENTIFIER`. This applies the existing hierarchy-index
validation before lookup and keeps malformed components out of elaboration.
Named types in expression-like contexts are already resolved through
identifier elaboration, so remove their separate `type_value` alternatives and
use the common hierarchy expression path. Keep atomic types in `type_value`.
This removes the grammar overlap without adding dedicated parameter and system
argument rules.
These identifiers can now reach continuous assignment l-value elaboration.
Use the common type diagnostic there. The implicit-net lookup checks typedefs,
so invalid type uses in continuous assignments, gate terminals, and module
port connections remain rejected rather than silently becoming nets.
This only permits hierarchy names to shadow visible type names. A hierarchical
path that resolves to a type remains rejected during elaboration.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that local, imported, and package-scoped typedefs resolve as declaration
types and as `$bits()` arguments, including attached dimensions and function
return and argument types.
Check lexical visibility before and after a local typedef declaration and an
explicit import. Earlier references resolve to outer typedefs and later
references resolve to the newly visible types.
Signed-off-by: Lars-Peter Clausen <[email protected]>
For-loop variable declarations currently match an optional `var` rule
before the data type. If `TYPE_IDENTIFIER` is also allowed to start a
hierarchy identifier, the parser can either shift it as an lvalue or
reduce the empty `K_var_opt` before a declaration.
Fold the optional keyword into `for_decl_data_type` with separate
alternatives for a data type with and without `var`. This keeps
declaration behavior unchanged and prepares for hierarchy identifiers
shadowing typedef names without introducing that shift/reduce conflict.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that a type identifier is rejected rather than declared as an implicit
net when used in a continuous assignment, primitive terminal, or ordered
module port connection. Cover local typedefs, explicit imports, and activated
wildcard imports.
These contexts are currently rejected by the grammar. Keep the tests in place
when type and hierarchy identifiers start using the same parser path.
Signed-off-by: Lars-Peter Clausen <[email protected]>
`PEIdent::declare_implicit_nets()` checks visible nets, parameters, genvars,
events, and enum constants before creating an implicit net, but does not check
typedefs. Type identifiers are currently filtered by the grammar before they
can reach this code, but this is not true when type and hierarchy identifier
parsing use the same path.
Check local and imported typedefs while searching the lexical scopes. Stop the
type search when another local declaration hides an outer typedef.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that package tasks can be called as statements both with and
without an argument list. Use a caller variable that shares its name
with a package typedef to verify that call arguments are parsed in the
caller context.
Also check package-scoped void functions and void casts of non-void
functions. Cover class and queue methods whose receiver is a package
member as well.
Signed-off-by: Lars-Peter Clausen <[email protected]>
SystemVerilog allows package tasks and functions to be called as
statements through package-qualified names, for example:
p::run();
`subroutine_call` currently accepts ordinary hierarchical and
class-qualified names, but not `package_scope`, so the parser rejects
these calls.
Accept a package scope before the hierarchical subroutine name. Leave
package lexer mode before parsing arguments so argument names are
classified in the caller context, then retain the package on `PCallTask`
for elaboration.
Also retain the package when a package member is used as a method
receiver. This allows calls such as `p::object.run()` to resolve the
object in the package rather than the caller scope.
Signed-off-by: Lars-Peter Clausen <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
`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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
`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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
`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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
Check that automatic variables referenced through an assignment pattern in a
procedural `force` statement are rejected.
Signed-off-by: Lars-Peter Clausen <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
Check that a blocking intra-assignment delay on a real value preserves the
assigned value after the delay.
Signed-off-by: Lars-Peter Clausen <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
Check that a string substr() call with too few arguments is rejected with a
normal compile error.
Signed-off-by: Lars-Peter Clausen <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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) <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
`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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
`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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
`%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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
- 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 <[email protected]>
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 <[email protected]>
`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 <[email protected]>
Check that package variables can use explicit static lifetime. Check that
automatic lifetime is rejected for package variables.
Signed-off-by: Lars-Peter Clausen <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
`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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
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__".
Currently, when a constant bit/part select is found in the implicit
sensitivity list for an always_* construct, it is replaced by the
entire signal. If there is more than one bit/part select from the
same signal, that signal gets added to the list multiple times. This
breaks the algorithm used to detect duplicate events in the nodangle
functor, causing it to erroneously merge non-identical events in some
cases.
The proper fix is to support sensitivity at the bit/part level, as
required by IEEE 1800. But for now, just make sure we only include
the entire signal once, regardless of how many different bit/part
selects we find. Enhance the "sorry" message to report which signals
are contributing excessively to the process sensitivity.
Also allow extra configuration options to be passed via the
IVL_CONFIG_OPTIONS environment variable and add some missing
dependencies. Don't include --enable-libveriuser by default.
Update the README accordingly, with sensible line wrapping.
This version works with the native Windows (mingw64 and clang64)
versions of Perl in MSYS2.
Note that warnings are disabled in the Environment.pm module because
Perl fails to notice that OLDOUT and OLDERR are used when restoring
the STDOUT and STDERR file handles.
When the argument is a literal string, tf_getp returns a pointer to
the string. But the return type is a PLI_INT32, so on machines where
pointers are larger than 32 bits, the pointer value may get truncated.
Check for this at run time, and if it occurs, print a warning and
return 0.
PLI 1 was deprecated in 1364-2005, so disable by default and note that
it is deprecated in the help text.
This works round the problem that the clang linker (lld) in MSYS2 does
not support the -r option, so cannot be used to build libveriuser.a.
The clang dlltool is not compatible with the binutils dlltool. However
both the clang and binutils linkers support reading the .def file and
creating the import library directly, so we no longer need to perform
the link in two stages.
When redirection operators are included in a command string passed to
the system() subroutine, it spawns an intermediate shell to handle the
redirection. This is particularly inefficient when running the tests
in MSYS2. Creating our own version of system() based on fork() and
exec() allows us to handle the redirection directly.
We need to build libvvp with a suffix from the outset to ensure that
the vvp binary searches for the correct library file name once it is
installed.
Also Windows DLLs need to be stored in the same directory as the main
program, not in a separate lib directory.
Commit 95810b2f61 mistakenly added the suffix to the output file name
when linking the final vvp.exe binary. 'make check' and 'make install'
assume the suffix is only added when installing.
The tgt-vvp code generatpr outputs identifiers as quoted strings, and
because of this, escapes any " and \ characters (which may appear in
escaped indentifiers). We need to undo this when reading them into
vvp, so that the original name is seen by the VPI routines.
These were implemented as returning nothing (void), and passing an
invalid operation value would trigger an assertion failure. The IEEE
standards define them as returning 1 on success and 0 on failure.
vpi_sim_control() is the name used in Verilog-AMS. Strictly speaking
it should return a bool, but to avoid polluting the namespace by
including stdbool.h, we return a PLI_INT32. As C is a weakly typed
language, this should make no practical difference.
The existing elaboration code only allowed assignments from/to individual
elements and either failed an assertion (when assigning the entire array)
or failed to compile (when assigning an array slice).
Improve path search between nets, so that paths containing
concats as well as part selects can be found.
Signed-off-by: Michael Kupfer <[email protected]>
Only vector types can be cast to real. Report an error when trying to cast
a different type instead of triggering an assert later on.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently nested lvalues are only supported for vector typed properties.
Refactor the code to also support other types.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently assignment operators on queues and dynamic elements trigger an
assert.
Add support for handling this properly. Since the operation for loading an
element for an queue or dynamic array is identical most of the code can be
shared, only writing back the value has to be handled separately.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently assignment operators on object properties are silently
ignored. Make sure that they are handled.
To enable this refactor the code a bit so that the assignment
operator handling can be shared between object property assignments
and scalar value assignments.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Logic type class properties use the wrong constructor resulting in a
default value of a vector with 0 width. Switch to the right constructor to
fix this.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Then temporarily add the resulting configure and lexor_keywords.cc
files to the repository so they will be included in the snapshot and
release tarballs that are automatically generated by GitHub. Remove
these files in the post-snapshot/post-release cleanup.
The old MAKE_SNAPSHOT.sh and MAKE_RELEASE.sh scripts created tarballs
that could be uploaded to icarus.com and SourceForge. Now we release
on GitHub, we need to make all the necessary changes in the git
repository, temporarily creating a release_tag.h file and deleting it
after we have created the snapshot or release tag. This allows GitHub
to automatically generate the tarballs for us.
Now we publish releases on GitHub, we need to commit the file to the
repository when making a snapshot or release, so we need to use a
different filename to the one that is automatically generated by
'git describe' (which we still want git to ignore).
Remove implicit casts between vector and real in tgt-vvp. These are not
required since any implicit cast in the source will be converted to an
explicit cast in the elaboration stage.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The code doesn't currently handle the case of different bits within
the vector needing different delays (e.g. when the rise and fall
delays are different and some bits are rising as other bits are
falling) and aborts with an assertion failure. For now, output a
suitable "sorry" message and exit gracefully.
Although the introductory paragraph seems clear enough, add a reminder
at the start of the section on extended arguments that they must appear
after the input file name.
This adds a "-q" option on the vvp command line and a vvp_set_quiet_flag()
function in the VVP library API. Setting this flag will cause all output
to standard output via MCD bit 0 to be suppressed. It will not prevent the
output being sent to a log file if the vvp "-l" option has been used, and
it will not affect output to the STDOUT file descriptor.
Newer version of the linker on MacOS provide a deprecation warning when
using the `-undefined` flag with the `suppress` value. This is cause CI to
fail to do logs not matching when building VPI modules.
Switch to using the `dynamic_lookup` value for the flag instead, which
resolves the warning and is the behavior we want when loading the module.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The vlog95 code generator collects all the constant assignments to a net
within each scope and then emits them. The old code only recorded the
ivl_signal_t for each constant assignment, which meant it had to iterate
through the nexus pointers in the assicated nexus to find the constant.
When there were multiple constant assignments to the same net, it needed
to record which assignments had already been emitted, which it did by
keeping a count in the nexus private data and skipping that many constants
on each successive assignment. However the count did not get reset after
emitting all the assignments in that scope, so if there were assignments
to the same net made in another scope, the count would already be positive
and those assignments would also be skipped.
This could probably have been fixed by clearing the nexus private data
after processing the constant assignment list for each scope, but it is
more efficient to record the ivl_nexus_ptr_t for each constant along with
the ivl_signal_t, eliminating the need to search for the associated nexus
pointer.
Internally, the maximum address space of a vector is 31 bits + a sign bit
to signal invalid addresses (out of bounds or has one or more x or z bits).
This commit ensures that unsigned part-select bit addresses which would
otherwise overflow and wrap around within this address space are correctly
handled as out of bounds.
The for loop initialisation statement, termination condition, and step
statement were only made optional in IEEE 1800-2012. Commit 0695c1fe
enforced this. So we need to compile with -g2012. The vlog95 code
generator doesn't currently translate this, so the tests will fail
when compiling the translated code.
Early editions of the SystemVerilog standard did not specify the return
type for $bits, so we made it 32 bit unsigned 2-state. Later editions
state the return type is integer (32 bit signed 4-state), so make it so.
When multiple words in one array were connected to the same nexus as a
single word array, the code generator was sometimes failing to generate
all the necessary aliases. This was highly dependent on the elaboration
order.
This fix should be more robust, but there are currently no tests in the
test suite that cause the compiler to generate whole-array aliases, and
I can't think of a way to make it do so as we don't yet support unpacked
arrays in module ports, so that branch of the code is currently untested.
Add a regression test to check that the right-hand side of a shift
operation is always treated as unsigned, even if it is a signed registers
or a variation thereof.
Signed-off-by: Lars-Peter Clausen <[email protected]>
When loading a signal into into an index register currently the signedness
of the signal is used when deciding whether sign-extension should be
performed or not. But this can lead to incorrect results, instead the
signedness of the expression must be used as that might be different from
the signal. E.g.
```
reg signed [1:0] = 2'b10;
$display(1 << x[1:0]);
```
gives the wrong result without this.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that assignments with undefined intra-assignment delay get executed
with zero delay. The assignment should not be skipped.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Assignments with an undefined intra-assignment delay should be treated like
assignments with zero delay. For the most part this is implemented
correctly, except for assignments to a part of a vector where the offset
inside the vector is an immediate value. E.g.
```
reg [1:0] x;
integer d = 'x;
...
x[0] <= #d 1'b1
```
Here when loading the delay into the index register flag 4 is updated, but
never cleared afterwards. As a result, if the delay is undefined, the vector
assignment will be skipped. Fix this by making sure flag 4 is always
cleared before the vector assignment instruction.
Signed-off-by: Lars-Peter Clausen <[email protected]>
For sequences where the tgt-vvp backend generates `%pushi` followed by one
of the operations that have an immediate version replace it with the
immediate version. This is slightly more efficient.
Signed-off-by: Lars-Peter Clausen <[email protected]>
As discussed in issue #1143, the for loop initialisation statement,
termination condition, and step statement were only made optional in
IEEE 1800-2012. So check all three are present when compiling for
ealier generations.
SystemVerilog makes all of the initialisation, condition, and step
components of a for loop optional. We already support this for the
initialisation and step components.
A constant function call may be inside a named block, so we need to
search upwards to find the enclosing module before checking that the
called function is local to that module.
SystemVerilog allows constant function calls to reference functions
in (other) packages or in the $unit scope, so extend the checks to
permit that.
Update the versions of called Actions to prevent warnings.hi and add
"workflow_dispatch" to allow testing.
Unrelated: add "*.so" to .gitignore to hide built libvvp.so.
The tran island resolution tests and caches the state of all branch
enable inputs before resolving the branch endpoint values. If a
branch enable is connected directly to a branch endpoint, we need
to update the cached stete and rerun the island resolution if any
enable state changed.
This fixes issue #1122.
If a net or variable is referenced in another net or variable declaration
or in a value parameter definition (e.g. when using the $bits function)
and hasn't already been elaborated, we need to elaborate it early. So
during the scope elaboration phase, add placeholders in each NetScope
object to record the PWire objects that are yet to be elaborated. This
allows the symbol_search() function to find the unelaborated objects
and to trigger early elaboration.
Add a flag in the PWire object to indicate when we are elaborating it.
This allows us to detect circular references and avoid an infinite loop.
This fixes issue #483, issue #575, and issue #1097.
If a signal has been cast to a different type, synthesis needs to
reflect the expression type, not the base signal type.
If a part select selects the entire signal, unless otherwise cast,
the expression is unsigned, regardless of the base signal type.
This fixes the additional issues reported in issue #1099.
Most pre-processor errors are flagged to the main compiler by a comment
at the end of the pre-processed output. But certain errors, such as
failing to find or open an include file, cause the pre-processor to
exit immediately, which bypassed the generation of that comment. So
we need to also generate that comment for all early-exit cases.
This fixes issue #1104.
When there is only one operand, we elide the concatenation during
expression synthesis. But if that operand is signed, we need to
insert an intermediate local signel to cast it to unsigned.
This fixes issue #1099.
This only applies to simple identifiers. Only return a match if the
lexical position of the identifier being searched is later in the
source text than the lexical position of a matching symbol.
Enhance the lists of identifiers and declaration assignments generated
by the parser to associate each identifier with its lexical_pos. Also do
this for single items in complex parser rules where the location passed
to the pform is not the location of the identifier.
This is needed for detecting use before declaration. The lexical scanner
is the only place where we process the source text in strict lexical
order, so do it there.
As Verilog allows modules to span multiple source files, don't reset
the counter when we reset the lexor.
cb_data.obj must be set to a valid handle when requesting vpiScaledRealTime.
Check the returned time value as well as the actual callback time. Zero
the requested cb_data after registering the callbacks to make sure it
is not used during the callback execution.
NOTE: This removes the ability to request vpiSuppressTime for the
simulation time callbacks (other than cbNextSimTime). Requesting
this is clearly stated to be an error in IEEE 1364-2001 onwards.
IEEE 1364-1995 has different wording to later versions of the standard,
stating "For reason cbNextSimTime, the time structure is ignored." So
it's possible old VPI code might not pass a valid time pointer or time
structure. So remove the checks that the time pointer is non-null and
that the time type is not vpiSuppressTime.
To allow a user to select the time type, we have to assume that if
the time pointer is non-null, it is a valid pointer and not just an
uninitialised field.
When registering a cbReadWriteSynch or cbReadOnlySynch callback,
the time type must be either vpiSimTime or vpiScaledRealTime.
vpiSuppressTime is illegal. The required behaviour is a delay of
zero, so use vpiSimTime with the high and low fields set to 0.
The old code only worked for VPI objects that represented variables
and nets. For simulation time callbacks, the user might pass an
object that represents a scope.
This adds support for vpiScaledRealTime in various callbacks where it
wasn't previously supported. However this doesn't work properly when
the cb_data.obj field references a scope handle.
Previously they were reusing the pointer supplied when the callback
was registered, which is not guaranteed to still be valid.
Note that the IEEE standard states:
The only fields in the s_cb_data structure that shall need to
be set up for simulation action or feature callbacks are the
reason, cb_rtn, and user_data (if desired) fields.
so for cbEndOfSimulation callbacks we cannot rely on the time pointer
being either valid or null. The standard does not require that the
time structure should be filled in when the callback occurs, but for
backwards compatibility continue to do so, returning a vpiSimTime
value.
Fill out cb_data.time and require it is non-NULL.
Record the last NextSimTime CB so we don't call CBs added during this timestep.
(cherry picked from PR #740)
If we have a variable which is part driven by a continuous assignment,
the parts that are not driven by that assignment can be the target of
more than one procedural assignment. So we need to only test the cassign
mask, not test and set it, when elaborating the procedural assignments.
This is legal if the procedural and continuous assignments target
different words.
NOTE: This is not fully compliant with the standard, because vvp
does not know that the nets were originally declared as variables,
so initialises to 'bz instead of 'bx and does not handle release
correctly.
We have already eliminated procedural assignments to uwires, so if
we find a l-value of type UNRESOLVED_WIRE, it must be a variable
that has a continuous assignment. Report it as such.
A uwire is never a valid l-value for a procedural assignment (other
than a force/release), so catch that error as soon as we can. We
then know that any remaining l-values with type UNRESOLVED_WIRE must
be variables which have been coerced by a continuous assignment.
Internally we convert SystemVerilog variables that have a continuous
assignment into unresolved wires. But from a user's perspective they
are still variables, so we should refer to them as such in error
messages. This new flag lets us distinguish between such variables
and nets that were declared as uwires.
SystemVerilog allows variables to be driven by continuous assignments,
including port connections. Internally we handle this by converting
the NetNet from a REG to an UNRESOLVED_WIRE. Here we handle the case
of an unpacked array variable connected to a module output port.
This fixes issue #1001.
This test uses 'wire real' but specified the '-gno-xtypes' option.
This is because it named a variable 'wreal' which is a keyword when
that option is enabled.
When using the Icarus extension for wire types, only logic (4-state)
wires may have multiple drivers (as documented in extensions.rst).
Other types of wire should be treated as unresolved wires.
When the Icarus extension is disabled, only 4-state wires are
allowed (IEEE 1800-2017 section 6.7.1).
Whilst the wording in the IEEE standards is ambiguous, discussions on
the standards committee mailing lists clarify that an unsized literal is
supposed to be the same size as an integer (as shown in IEEE 1364-2005
table 5-22). The token following the base format character is specified
to be an unsized number. So to maintain compatibility with the standards
and with other tools, if the unsigned number part of an unsized signed
based literal can be represented in less than integer_width bits and the
MSB is a '1', we need to add a leading zero to ensure it is zero-extended
when used in an expression.
This fixes issue #1082.
Arguably this should be done in the target code generator, as the code
generator can infer the value for undriven bits from the net type. But
in practice it is quite hard to do this in the vvp code generator. So
adapt the cprop functor that concatenates part selects to do this as
well.
This fixes issue #1047 and issue #1083.
When driving a 2-state net, any undriven bits in the concatenation
of part selects should be driven to '0', not 'z'. This saves having
to cast the result.
This removes the regress-msys2.list file, fixes the output from the
pr2509349a.v test to not be different on different systems, and
documents the $readmempath task.
This file contained some SystemVerilog tests that are not yet supported.
Move the tests to the regress-vvp.list format, and mark them as NI so
that we know what's going on.
A concat typically has multiple inputs. Whenever one of the input values
change the output value of the concat is updated and propagated to its
downstream consumers.
When multiple inputs change within the same cycle each input will cause a
update propagation. Depending of the overall structure of the design this
can cause a significant performance penalty.
E.g. the following synthetic structure has a exponential runtime increase
based on the value of N.
```
reg [N-1:0] x;
generate for (genvar i = 0; i < N - 1; i++)
assign x[i+1] = ^{x[i],x[i]};
endgenerate
```
To improve this defer the value propagation of the concat to the end of the
current cycle, this allows multiple input updates to be included in a
single output update.
For the example in report #1052 this reduced the runtime from 2 minutes to
essentially 0.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The concat functors use individual bit access to initialize and copy
values.
For initialization pass the initial bit value to the constructor and for
coping use set_vec() instead. Both can be a fair bit faster since data is
copied word by word rather than bit by bit.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The implementation for partial receive for concat only differs from the
regular receive in that it takes an additional offset.
The regular receive can easily be implemented by calling the partial
receive with an offset of 0. This allows to remove some duplicated code.
The overhead of this is negligible, but to help the compiler to optimize this
a bit better mark the `recv_vec()` and `recv_vec_pv()` functions as final.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The pr1002 test has a always block with the `dataout` in its sensitivity
list. It compares `dataout` to `expected_dataout`.
Both `dataout` and `expected_dataout` depend on `datain` and are updated in
the same cycle. This means there is no guarantee in which order they are
updated and the always block might get scheduled before `expected_dataout`
has been updated. This can lead to a test failure.
To avoid this slightly change the test to use a task to perform the
comparison and add an explicit delay before the task is executed so that
all updates have a chance to be fully resolved
Signed-off-by: Lars-Peter Clausen <[email protected]>
The first evaluation of an `assign` statement is scheduled at the same time as
`initial` statements.
There are some test cases that evaluate the result of an `assign` statement
in an `initial` statement. This is an inherent race condition and might
fail depending on the exact order of evaluation.
To fix this add an additional delay in the `initial` block. This will make
sure that all `assign` statements get fully resolved first.
Signed-off-by: Lars-Peter Clausen <[email protected]>
`IVCXX` which contains the C++ compiler that will be invoked when building
an vpi module might contain additional arguments that get passed to the
compiler. E.g. such as the C++ version (`-std=c++11`). For this to work
properly `IVCXX` needs to be put in quotes.
This fixes intermittent CI failures for the MacOS target.
Signed-off-by: Lars-Peter Clausen <[email protected]>
To escape the `.` in the regex it needs to be prefixed with a `\`. But
since the `\` is a escape character in python strings it needs to be
escaped as well.
Without this some versions of python print the following warning:
run_ivl.py:36: SyntaxWarning: invalid escape sequence '\.'
match= re.search(b'Icarus Verilog version ([0-9]+)\.([0-9]+)', text)
Signed-off-by: Lars-Peter Clausen <[email protected]>
Before the start of simulation, functor update events resulting from
initial value propagation are added to the initialisation event queue
(schedule_init_list). Once simulation has started, they are added to
the main event queue (sched_list). The cbStartOfSimulation callbacks
are executed after the initialisation event queue has been emptied.
Currently, if these callbacks generate further functor update events,
those events are added to the initialisation event queue, but that
queue is not looked at again. Instead, make sure any new events are
added to the main event queue.
This issue and proposed fix was reported by gatk555 in PR #1065.
Starting with commit 96df251c95 ("Suppress unnecessary VCD/LXT/LXT2
warnings about packages.") there is no longer a warning printed that the
unit scope can't be printed if it is empty.
Remove the special SystemVerilog mode gold file for the pr1963962 test that
expects this warning.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The part functor has no real typed state and the bitsr field of the state
struct is unused. Remove it.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Only output a warning if a package contains dumpable items. This is
mainly to avoid the warning about the $unit scope when a design has
been compiled for a SV generation (issue #710).
The condition expression may require the loop variable width to be
expanded. The compiler wraps the NetESignal with a NetESelect to
do this, so we need to handle that when checking that the condition
expression uses the loop variable.
Fixes issue #687 and issue #1004.
This causes tgt-vvp to use a lower case 'c' instead of an upper case
'C' as the prefix for constant values used to initialise undriven nets.
For use by the following commit.
vvp_net_ptr_t uses vvp_sub_pointer_t to implement a tagged pointer with the
tag containing the port number.
The size of the tagged pointer is that of a normal pointer and could easily
be passed in a register when passing it as an argument to a function.
But since the vvp_sub_pointer_t type has a non-standard destructor it is
instead passed on the stack with the register containing a pointer to the
stack location where the value is stored.
This creates extra boiler plate code when passing a vvp_net_ptr_t to a
function writing and reading the value to and from the stack.
Use the default destructor for vvp_sub_pointer_t to avoid this and have the
value passed in a register.
There isn't much of a performance gain but the change is simple enough to
do anyway.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently replication in a concatenation is implemented by simply
concatenating the input signals multiple times by the replication amount.
Replace this to use NetReplicate on the concatenation instead. In case
there is only one input vector to the concatenation the replication will directly
connect to the input vector.
This is slightly more efficient in vvp since the replication functor has
only one input while the concatenation has multiple inputs connected to the
same wire. When an update of the input occurs the replication functor will
only receive a single update, while the concatenation will receive multiple
update events, one for each replication.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The repeat functor can receive a partial vector. Make sure this is handled.
Since the expectation is that will only happen if the input wire is driven
by a single partial selection the default recv_vec4_pv_() can be used which
replaces the missing bits by `z`.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The current `PEIdent::test_width()` method is only able to calculate width
of a path with up to two elements.
For more complex paths it will not be able to calculate the width. E.g.
* Nested struct member access
* function call of a enum member in a struct
To make nested structures work properly walk the whole path tail element
by element updating the type along the way. Also take the indices into
account and update the type if an arrays dimensions have been fully
consumed.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that reversed part selects result in an error. Check this for both
right-hand and left-hand side expressions as well as for inner and outer
dimensions.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The order of the indices of a part select need to match the order in which
the dimension of a packed array has been declared. E.g. if the msb is less
than the lsb in the declaration it also has to be for the part select.
If the order of the part select is the opposite of the declaration this is
an error. This works as expected for part selects on the most outer
dimensions.
But for inner dimensions the current implementation just swaps the msb and
lsb of the part select if they are in the wrong order.
Refactor this so that an error is reported for both the outer and inner
dimensions.
Signed-off-by: Lars-Peter Clausen <[email protected]>
An initial value propagation should only be scheduled for variable array
ports, but not for net array port since those do not contain any values.
This got accidentally broken when fixing support for 2-state variable
array ports.
Add a check that only does the initial value propagation if the port is for
a variable array.
Fixes: 0eb01fff1e ("vvp: Fix initial value propagation for 2-state non-automatic arrays")
Signed-off-by: Lars-Peter Clausen <[email protected]>
The elaboration of the base expression of a vector slice index can fail and
return a nullptr. Currently this results in a nullptr deref. Handle that
case by exiting the function early.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Commit 56c5bf1da1 ("ivtest: Remove regress v11, v12, and v13") removed the
`expected_fail` argument from the `check_run_outputs()` function, but did
not remove all references. This causes the run_ivl.py script to fail. The
script is part of the CI pipeline and causes all PRs to fail.
Remove the remaining references to `expected_fail` to make it work again.
Signed-off-by: Lars-Peter Clausen <[email protected]>
find_scope() requires the hierarchical path to use escaped identifiers;
without the leading '\' and trailing ' ', if there are any '.' characters,
the path will be broken up at the wrong point(s).
vvp is missing a parser rule for unsigned 2-state net arrays. E.g.
```
bit a[0:1];
assign a[0] = 1'b0;
```
will synthesize fine, but when running it with vvp cause a syntax error.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Now that out-of-bounds access on 2-state queues and dynamic arrays yields
the right value move the tests from the "Not Implemented" list to the list
of tests that get run.
Signed-off-by: Lars-Peter Clausen <[email protected]>
vvp does not track whether the values stored in a dynamic array or queue
are 2-state or 4-state. Internally the data is always stored as 4-state.
To make sure that the read value is actually 2-state do a cast for 2-state
reads.
E.g. performing an out-of-bounds access on a 2-state dynamic array or queue
will yield a undefined value.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The sv_queue_vec test uses queues of 2-state vectors, but also checks if
certain operations on the queue yield 'X.
2-state queues should never yield 'X and the test only passes because of a
bug. In preparation for fixing the bug change the test to use a 4-state
base type instead.
Signed-off-by: Lars-Peter Clausen <[email protected]>
For 2-state non-automatic arrays currently real 0.0 value is propagated as
the initial value. This will cause an assert at the downstream receivers
which expect a vector.
Make sure that the vector value 0 is propagated instead for 2-state
vectors.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Most places in the code use a std::vector for array dimensions.
The only exception is the constructor of NetNet, which uses
a `std::list` to pass the unpacked dimensions. But to store the
unpacked dimensions it also uses a `std::vector`.
There does not seem to be a good reason why the constructor
has to take a `std::list`, so switch it also to `std::vector`.
This allows to simplify the code and remove some special handling
for `std::list<netrange_t>`.
Signed-off-by: Lars-Peter Clausen <[email protected]>
`std::vector<netrange_t>` is used for signal array dimensions. As such it is
used in quite a few places.
Add a typedef that can be used as a shorthand to refer to it. This helps to
keep lines where this is used from growing to overly long.
The new type is called `netranges_t`.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are two `NetNet` constructors, one for arrays and one for non-arrays.
There are a few places where the array constructor is used for non-arrays,
but with an empty unpacked dimensions list. Switch this over to using the
non-array constructor.
This slightly reduces boiler-plate code.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The `netrange_width()` helper function computes the total width of a set of
ranges. There are a few places where this is currently open-coded and
`netrange_width()` can be used. This removes a bit of duplicated code.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are sometimes cases where calculating the total width of a
`vector<netrange_t>` has to take into account an existing base width. E.g.
when chaining multiple `vector<netrange_t>`. Add support to the
`netrange_width()` function to be able to handle this case.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The templatized version of `calculate_count()` that is used on a data type
is not used. Remove it.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that binding task and function arguments by name works as expected.
Also check that is works for the various variations of invoking a class
constructor.
Signed-off-by: Lars-Peter Clausen <[email protected]>
In addition to providing positional arguments for task and functions
SystemVerilog allows to bind arguments by name. This is similar to how
module ports can be bound by name.
```
task t(int a, int b); ... endtask
...
t(.b(1), .a(2));
```
Extend the parser and elaboration stage to be able to handle this. During
elaboration the named argument list is transformed into a purely positional
list so that later stages like synthesis do not have to care about the
names.
For system functions and tasks all arguments must be unnamed, otherwise an
error will be reported.
In addition to functions and tasks arguments can also be bound by name for
the various different ways of invoking a class constructor.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Attach line information to named items. This allows to provide better
location information for messages involving named items. The location of
item itself can't always be used, since the item itself might be empty.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are a few different places in the parser that all parse named
expressions in the same way. Consolidate them into a single rule.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are a few places in the code where a std::list is copied to a
std::vector by iterating through the list and copying each element over to
the vector. The std::vector type has a iterator based constructor that can
do the same.
Update the code to use it instead. This removes a bit of boilerplate code
and also makes it easier to update the code.
Signed-off-by: Lars-Peter Clausen <[email protected]>
`named_pexpr_t` is a typedef for `named<PExpr*>`. There are a few places
where `named<PExpr*>` is used directly. Replace those with `named_pexpr_t`
for consistency.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are a few places where some sort of expression list is printed. Add
helper functions to consolidate this in a single place and reduce the
amount of code.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The last user of the named_number_t type was removed in commit 2f474358d9
("2f474358d99929ec625a46690d1be6939ed67064"). Remove the type as well.
Signed-off-by: Lars-Peter Clausen <[email protected]>
When vvp parses a command which it thinks is a system call it tries to
match the symbols to values in the scope. The typo uses the wrong index
variable to access the vpi table. This results in a failed dynamic cast
which goes unchecked until the value is dereferenced, resulting in a
segfault.
Check that constructor chaining for various corner cases of mixing implicit
and explicit constructors are handled correctly.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently when neither an explicit constructor is specified nor any
properties are present in the class that will create an implicit
constructor there will be no constructor for the class.
As a result a class that specifies the arguments for the base class
constructor as part of the `extends` clause will not have the base
constructor called with the right arguments.
E.g.
```
class C;
function new(int a);
endfunction
endclass
class D extends C(10);
endclass
```
To avoid this make sure that an implicit constructor is created when
passing arguments through the `extends` clause.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are some corner cases around class constructor chaining that can
result in chained constructors not being called, or being called multiple
times.
This is primarily related to that a class can have either an explicit
constructor called `new` and an implicit constructor called `new@` and how
the lookup of them is done.
Lookup is currently done independently for the implicit and explicit
constructor using the `method_from_name()` method. `method_from_name()`
will search the whole class hierarchy for a class method. If a class
doesn't have a method by that name it will look in the parent class and so
on.
As a result the lookup for the explicit constructor can return the explicit
constructor of a parent class if the class itself only has an implicit
constructor and vice versa.
E.g. in the following example the constructor of D will not be called
because the implicit constructor for C is found when looking for a implicit
constructor in D.
```
class C;
int x = 10;
endclass
class D extends C;
function new;
$display("D");
endfunction
endclass
class E extends D;
int y;
function new;
y = 20;
endfunction
endclass
E e = new;
```
There is a similar case where the constructor of a base class can be called
multiple times if the base class has an explicit constructor and the
derived class has an implicit constructor. In that case the derived class
constructor will call the base class constructor, but the code that is
emitted for the `new` statement will call both of them.
To mitigate this introduce a new method to lookup the constructor that will
search for either the explicit or implicit constructor in the current class
and only continue to search in the base class if neither is found.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Commit 3daa2982ac ("Add support for `const` variables") added support for
constant variables, but had a small mistake and did propagate the constant
flag from the parser if the variable is declared with the `var` keyword.
Still allowing to modify those variables. Fix this.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Automatic 2-state vectors currently get initialized to 'hx, while their
default value should be 0.
Make sure the vector is initialized to 0 at the beginning of the automatic
context.
Signed-off-by: Lars-Peter Clausen <[email protected]>
SystemVerilog allows to declare const variables. These variables are
read-only and can not be assigned a value after their declaration. It is
only possible to assign an initial value as an initializer.
E.g.
```
const int x = 10;
x = 20; // Error
```
The LRM requires that for variable declarations with static storage the
initializer is a constant expression with the extension that other const
variables are also allowed. const variables with automatic storage can
be initialized by any expression.
Checking if an expression contains only const variables requires a bit more
work to implement. So for now be more lenient that what the standard
requires and allow arbitrary expressions to initialize const variables even
for those with static storage.
Signed-off-by: Lars-Peter Clausen <[email protected]>
arith_expr_type() queries the expression type of its two child nodes up to two
times. Since the child nodes might also need to query their child nodes
expression type to determine their own this can lead to an exponential runtime.
For complex expressions this can easily result in very long elaboration time.
Avoid this by querying the expression type only once for each child node.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that it is possible to declare module ports with only partial
attributes. Other attributes should be inherited from the previous port in
the list or use the default.
Signed-off-by: Lars-Peter Clausen <[email protected]>
In Verilog it is possible to declare multiple ports as part of the same
port declaration. Ports declared this way all have same direction, signal
kind and data type. E.g.
```
module M (input [3:0] a, b, c) ...
```
SystemVerilog extends this and allows to override on a per port basis
certain port attributes. E.g. redefine just the data type
```
module test (input [3:0] a, [1:0] b, int c) ...
```
Or to just redefine the port kind
```
module test(input [3:0] a, var b, wire c) ...
```
It is even possible to leave out the direction for the very first port. As
long as at least one other property of the port is specified. In that case
the direction will default to `inout`. E.g.
```
module test(integer a, b, c) ...
```
Furthermore it is possible to specify unpacked dimensions for each of the
ports. E.g.
```
module test(input integer a, b[1:0], c[3:0][1:0]) ...
```
If all port properties are omitted for the first port this indicates the
start of a non-ANSI port list.
Extend the parser to handle this.
If all three direction, port kind and data type are omitted they are
inherited from the previous port. Otherwise
* If the direction is omitted it is inherited from the previous port.
* If the data type is omitted it defaults to logic.
* If the port kind is omitted the behavior depends on the direction.
For output ports with an explicit data type it is a variable, for
all others it is a net.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Add a helper function to the parser that handles module port declaration.
This allows to reduce a bit of duplicated code.
Signed-off-by: Lars-Peter Clausen <[email protected]>
`$bits()` for array types is supposed to return the full size of the array
in bits. This currently works for data types that are passed to `$bits()`,
but not for array typed identifiers.
E.g.
```
typedef int T[1:0];
T x;
$display($bits(T)); // -> 64
$display(x); // -> 32
```
Since the `$bits()` implementation uses the expr_width of an expression
include the size of the unpacked dimensions in that for array identifiers
and array slices. Strictly speaking an array identifier does not have an
expression width, but this would be its expression with if it were for
example bitstream cast to a vector.
Special care needs to be take to not trying to pad array identifier
expressions.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Bit selects on packed arrays are always unsigned and have a width of 1.
Element selects on a multi-dimensional packed array are always unsigned and
have the width of the element.
At the moment a element or bit select on the last level element of a
multi-dimensional signed array will incorrectly yield a signed expression.
Commit 40b36337e2 ("Fix some bugs with packed array dimensions") added
some special checks to fix the width on multi-dimensional array element
selects. But this removed the unsigned attribute from bit selects.
Commit 81947edaa5 ("A bit select is not the same as selecting part of a
packed array") fixed this for single dimensional packed array, but left it
broken for multi-dimensional arrays.
Commit 7c024d6cab ("Fix width calculation for bit/part selects of
multi-dimensioned packed arrays.") added some additional fixes for the
width calculation, which make the special checks in the first commit
unnecessary.
We can now remove those checks which will give us the correct behavior in
terms of the signedness of bit and element selects on both single- and
multi-dimensional packed arrays.
Signed-off-by: Lars-Peter Clausen <[email protected]>
At the moment there are two rules for port declarations. One that allows
the port to be declared as an unpacked array, the other that allows to
specify an initializer expression.
SystemVerilog allows both to be specified in the same port declaration. Add
support for this to the parser.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The module_output_port_list_def declares a output port with an implicit
data type and assigns an initial value to it. Since output ports with an
implicit data type are nets this test is not standard compliant.
This only works because at the moment the parser incorrectly flags all
output ports with an initial value as variables rather than following the
method defined by the standard to decide whether the port should be a net
or variable.
Make the test standard compliant by using an explicit data type for the
output port, in which case it will be a variable.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The currently used checkout@v2 CI action shows the following deprecation
warning
```
Node.js 12 actions are deprecated. Please update the following actions to
use Node.js 16: actions/checkout@v2. For more information see:
https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/.
```
Github has announced that this will eventually stop working somewhen in mid
2023.
Switch to checkout@v3 which uses Node.js 16 to avoid the ci from breaking
in the near future.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that basic assignment patterns are supported for unpacked arrays.
Check that all of packed types, reals and string arrays are supported.
Signed-off-by: Lars-Peter Clausen <[email protected]>
SystemVerilog allows to use assignment patterns to assign values to an
array. E.g. `int a[4] = '{1, 2, 3, 4}`.
Each value is evaluated in the context of the element type of the array.
Nested assignment patterns are supported. E.g. `int a[2][2] = '{'{1, 2},
'{1, 2}};`
Add initial support for array assignment patterns for both continuous as
well as procedural assignments.
For continuous assignments the assignment pattern is synthesized into an
array of nets. Each pin is connected to one of the assignment pattern
values and then the whole net array is connected to target array.
For procedural assignments it is unrolled in the vvp backend. E.g
effectively turning `a = '{1, 2};` into `a[0] = 1; a[1] = 2;`.
Not yet supported are indexed initializers or `default`.
E.g. `int a[10] = '{1:10, default: 20};`
Signed-off-by: Lars-Peter Clausen <[email protected]>
Types for array signals are currently handled as a special case. The type
that is associated with the signal is not the array type itself but rather
the element type.
There is a fair amount of existing code that depends on this behavior so it
is not trivial to change this.
But there are certain constructs such as assignment patterns or array
concatenation where the array type itself is required.
Add a new `NetNet::array_type()` method that will return the array type if
the signal is an array. This will allow to query the array type when
needed.
`NetAssign_::net_type()` is updated to use this new method to return the
array type if the assigned signal is an array.
Long term the special handling of arrays for signals should be removed.
This will for example allow to unify the handling of arrays for signals,
class properties and struct members.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The are many binary operations where if the two operands are 2-state the
result is guaranteed to be 2-state.
This is true for all arithmetic operation with the exception of division
where division by 0 will always result in 'x even if the inputs are both
2-state.
The same is true for all binary bitwise operators as well as the binary
logical operators.
Having the expression type be 2-state avoids some unnecessary %cast2
instructions that would otherwise get inserted when assigning the result to
a 2-state variable.
E.g without this change the following will result in
```
int a, b, c;
b = a + b;
```
will result in
```
%load/vec4 ...;
%load/vec4 ...;
%add;
%cast2;
%store/vec4 ...;
```
For binary comparison operators this is already handled.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are some cases where during an assignment the elaboration step can
generate constructs with the right-hand-side expression being wider than
the left-hand-side expression.
To handle this the tgt-vvp backend inserts a %pad operation when necessary.
One place where this is missing is when writing to an string element. Here
instead an assert is triggered requiring the right-hand-side expression to
be 8 bits wide.
E.g.
```
bit [7:0] x;
bit [8:0] y;
string s;
x = y; // tgt-vvp inserts %pad
s[0] = y; // tgt-vvp triggers assert
```
Long term this should be fixed at the elaboration stage and insert the
proper width cast. But for now solve this the same way as other places in
tgt-vvp and insert the %pad operation for string element assignments if the
width does not match.
Signed-off-by: Lars-Peter Clausen <[email protected]>
`ivl_assert()` is similar to `assert()` except that it will also include
source file and line information about the expression for which the assert
was triggered.
Use `ivl_assert()` instead of `assert()` where the line information is
available. This will generate better bug reports and make it easier to
diagnose why an assert is triggered.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that the file and line location is correct for errors
related to implicit named port connections.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Some tests require a specific compiler error, rather than just failing. Add
support for this by allowing to check for gold files for CE tests.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Implicit named port connections are only supported by SystemVerilog. Add a
check to generate an error when trying to use it in Verilog mode.
Regression test br_gh315 is modified to run in SystemVerilog mode since it
makes use of implicit named port connections.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The implicitly generated identifier for implicit named port connections
gets its file and line information from the optional attributes. If no
attribute list is specified this will just point to the beginning of the
file resulting in incorrect line information.
Use the file and line information from the identifier token instead to fix
this.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that implicit import of functions and tasks is supported if the
wildcard import statement is in the unit scope.
Signed-off-by: Lars-Peter Clausen <[email protected]>
SystemVerilog requires that functions and tasks are not implicitly imported
if a symbol with the same name appears in the scope, even if it the symbol
is declared after its usage.
To support this a list of potential imports is collected while parsing a
scope and only when the end of the scope is reached it is evaluated whether
the symbol should be imported or not based on whether it already exists in
the scope.
This currently works fine for all scopes except for the unit scope. Since
the unit scope might span multiple files it is never explicitly closed and
the potential imports are never checked.
Make sure that after parsing all files is done the potential imports for
the unit scope are checked.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Add support for `continue` and `break` in constant functions. This is done
in a similar way to how `disable` is implemented for constant functions.
Two new global flags are introduced `loop_break` and `loop_continue` that
get set when evaluating the corresponding statement. If either of these
flags are set all other statements are ignored until the end of a loop is
reached. At the end of the loop both `loop_break` and `loop_continue` get
cleared. If `loop_break` was set before clearing it the loop is exited.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that it is possible to omit trailing ports in a module ordered list
connection list.
Also check that an error is generated if too many ports are specified in a
ordered list connection.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The current implementation expects that for a module instantiation with a
ordered list connection all ports are supplied.
But there doesn't seem to be such a requirement in the LRMs. The Verilog
LRM doesn't mention anything in this regard and the SystemVerilog LRM
mentions in section 23.3.2.1 that a blank or omitted port connection is
either left unconnected or uses the default value of the port.
Update the implementation so that it allows to omit trailing ports and only
generates an error message if too many ports are specified in the ordered
port list.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently continue and break are supported in most loops. But not in
do-while loops. Add support for them in do-while loops as well.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that partial and fully out-of-bound writes to a function's return
value are handled correctly. Check this for both 4-state and 2-state
vectors.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Partial out-of-bounds write to a function's return value will trigger an
assert, even though the operation is valid.
The assert checks that the truncated value has the expected width, but
instead it should check that the non-truncated value has the expected with.
Move the assert before the truncation to fix this.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Directly casting a negative double to a unsigned integer type is undefined
behavior and has different results on x86 and ARM based platforms.
On x86 the behavior is similar to casting a signed int to an unsigned
integer, i.e. the sign bit will end up in the MSB. But on ARM the result
will be 0.
To get consistent behavior, first cast to signed integer and then cast the
signed integer value to an unsigned integer value.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The current check to decide whether a port is an array or a scalar signal
uses the number of pins on the NetNet. If it is larger than one the code
assumes that it is an array.
But for arrays with on a single element the number of pins will be 1 and
the port is incorrectly treated as a scalar signal which results in an
error.
Instead of using the number of pins check for the number of unpacked
dimensions to decide whether the port is an array.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check support for using the return statement in a task.
* That it is possible to exit form a task using the `return` statement
without affecting other concurrently running instances of the same task
* That it is possible to use return in a named block in a task
* That using a return value in a task results in a elaboration error
* Returning from inside a parallel block in a task results in a
elaboration error
Signed-off-by: Lars-Peter Clausen <[email protected]>
SystemVerilog allows to use the `return` statement in a task to exit the
task before it reaches the end of its execution. This is defined in section
13.3 ("Tasks") of the LRM (1800-2017).
This is similar to using `disable` to stop a task from within itself with
the difference that `disable` will affect all concurrently running
executions of a task, while `return` will only affect the task from which
it has been called.
The `%disable/flow` vvp instruction allows to implement the required
behavior for task return.
There is one complication in that it is not allowed to call return from
inside a parallel block (fork-join). If a parallel block is unnamed and has
no variable declarations there won't be a NetScope for it. So it is not
possible to detect whether the return is inside a parallel block by
walking up the scope chain.
To solve this add a design global counter that gets incremented when
entering a fork block and decremented when exiting a parallel block. The
return implementation then checks if the counter is non 0 to determine
whether it is in a parallel block.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that assigning array that have opposite left-to-righto order for
their dimensions have their elements assigned in reversed order.
Signed-off-by: Lars-Peter Clausen <[email protected]>
In SystemVerilog arrays assignments are supposed to be connected left to
right. This means if the left to right direction differs between the two
arrays they will be connected in reverse order.
E.g.
```
logic a[1:0];
logic b[0:1];
assign b = a;
```
should connect a[0] to b[1] and a[1] to b[0]. Things get a bit more tricky
for multi-dimensional arrays where some dimensions have a matching
direction and some do not.
The current implementation always connects them low to high, which results
in incorrect behavior.
Signed-off-by: Lars-Peter Clausen <[email protected]>
In the current implementation a `%fork` instruction in a final block will
get scheduled, but never executed.
And while SystemVerilog requires a `final` procedure to execute in 0 time
and so no SystemVerilog `fork` is allowed inside of it, there are some
other scenarios where iverilog generates `%fork` statements.
For example when declaring variables in a sub-block a sub-scope with its
own thread is is used to allocate the storage for those variables and
`%fork` is used to execute the child thread.
E.g. the following, while being valid SystemVerilog, will never execute the
loop because the generated code will implement the loop as a child thread
being executed by a `%fork` statement.
```
final for (int i = 0; i < 10; i++) $display(i);
```
To mitigate this treat final statements the same as functions and rather
than scheduling a child thread, execute it immediately when using the
`%fork` statement.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The port_index_ member of the NetNet is not initialized which can lead to
undefined behavior. Make sure to initialize to -1 to indicate that the net
is not associated with any port.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that foreach counts counts from $left to $right. This means it should
count up if $left is less than $right and count down otherwise.
Signed-off-by: Lars-Peter Clausen <[email protected]>
foreach loops are supposed to iterate arrays $left to $right. E.g. `reg
x[3:0]` should be iterated from 3 to 0 and `y[1:4]` from 1 to 4.
The current implementation iterates them from $low to $high. Modify this to
either count up or down depending on whether $left or $right is the larger
of the two values.
Note that the same applies for dynamic arrays. But since for dynamic arrays
$left is always 0 and $right is always $high they always count up and we do
not need to differentiate between two different cases.
Signed-off-by: Lars-Peter Clausen <[email protected]>
vvp_reg.py requires 4 gold files. One for each of stdout and stderr of both
iverilog and vvp. Most of these log files will be empty for most test
cases. This will result in a lot of empty files being added to the
repository.
If a gold file for a specific output stream can not be found assume that
the output stream is supposed to empty. This allows to omit the empty gold
files.
Also remove all the existing empty gold files.
Signed-off-by: Lars-Peter Clausen <[email protected]>
This adds the "normal-vlog95" test type, because we need to run a different
set of commands for this to work so a new test type makes sense. This also
moves a few of the existing tests to the new format in order to test the
new test rig.
Check that packed array assignment patterns and struct assignment patterns
are supported for continuous assignments.
Check for both assignment to variables as well as array elements.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently when creating the NetNet for a continuous assignment to an array
element the type of the element is flattened into a canonical 1 dimensional
form. This works for most cases because packed types are compatible if
their total packed with is the same.
But there are some contexts such as if the right-hand-side is an assignment
pattern where the actual type matters and flattening the type will result
in incorrect behavior.
Retain the original type of the array element when creating the NetNet for
the array element assignment.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Add a regression test to show that the proper dumpfile is selected, by
noting in the output from the vvp command what file name it is creating.
To make this work, I also needed to add some capabilities to the vvp_reg.py
regression test rig.
The -dumpfile=<path> vvp extended argument sets the default nanme to use
for the various dumpers. If this flag is not given, the default is "dump".
The $dumpfile system task overrides the default or this command line flag.
This commit also factors out all the dumpfile selection code for the various
dumper implementations.
This generates a fresh copy of config.sub.
The existing config.sub calls 64-bit ARM targets `aarch64`, which is
the official name for the target. However, Apple targets go by the
name `arm64-apple`. As a result, this platform was not recognized.
This gets iverilog building on Apple targets with 64-bit ARM processors.
Signed-off-by: Sean Cross <[email protected]>
This creates a new test suite driver and infrastructure for going
forward. This cleans up the descriptions for tests, and is more
extensible.
Include documentation for the new engine, so that new tests can go
here instead of the old test suite.
Check that struct assignment patterns with only positional arguments are
supported. Also check that invalid assignment patterns for structs report
an error.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that positional and nested positional assignment patterns are
supported for packed arrays. Also check that invalid assignment patterns
for packed arrays result in an error.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Structs can be initialized by an assignment pattern. E.g.
```
struct packed {
int x;
shortint y;
} S = '{ 1, 2};
```
is the same as
```
struct packed {
int x;
shortint y;
} S;
s.x = 1;
s.y = 2;
```
Add initial support for unnamed struct assignment patterns. Named struct
assignment patterns like
```
struct packed {
int x;
shortint y;
} S = '{x: 1, y: 2};
```
are still unsupported.
Signed-off-by: Lars-Peter Clausen <[email protected]>
SystemVerilog allows to use assignment patterns to assign a value to a
packed array.
This is similar to using a concatenation, with the difference that for
concatenations the values are evaluated in a self-determined context and
for assignment patterns they are evaluated in a context defined by the
element type of the packed array. This means that the value is for example
automatically width expanded or truncated if it does not have the same size
as the element type. Automatic type conversion is also done when allowed. E.g.
```
bit [3:0][3:0] x = '{1'b1, 32'h2, 3.0, "TEST"};
$display("%x", x); // -> 1234
```
Nested assignment patterns are also supported. E.g.
```
bit [1:0][3:0][3:0] x = '{'{1, 2, 3, 4.0}, '{5, 6, 7, 8}};
$display("%x", x); // -> 12345678
```
Add support for using assignment patterns as the right hand side value.
Since the complete type of the target variable is required to correctly
evaluate the assignment pattern it is handled as a special case in
`elab_rval_expression()`. For other types of expressions for packed values
only the total width of the target value is provided to the rvalue
elaboration function.
SystemVerilog also supports assignment patterns for the left hand side in
assignments. This is not yet supported.
Also not yet supported is specifying array elements by index, including
`default`.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that package exports are supported. Also check for various scenarios
where package exports should fail.
Signed-off-by: Lars-Peter Clausen <[email protected]>
By default an identifier that has been imported into a package is not
available for imports by other packages. Only imports that have been
exported can be imported again. E.g.
```
package P1;
int x;
endpackage
package P2;
import P1::x;
export P1::x;
endpackage
module test;
import P2::x; // This will only work if x has been exported.
endmodule
```
Exports follow the same syntax as imports and allow both export of specific
identifiers or wildcard export. Export supports the special `*::*` target,
which will export all imported items.
Add support for handling package exports.
There is one special cases that needs to be considered. Usually when using
wildcard imports from multiple packages it is an error if there multiple
import candidates for an identifier. With exports it is possible that there
are multiple candidates through different packets, but they all refer to
the same identifier. In this case it does not create a conflict. E.g.
```
package P1;
int x;
endpackage
package P2;
import P1::x;
export P1::x;
endpackage
package P3;
import P1::*;
import P2::*;
int y = x; // No import conflict
endpackage
```
Signed-off-by: Lars-Peter Clausen <[email protected]>
This is a test for github issue#800. This should work on all platforms,
but Windows seems weird. The issue seems to be with Windows comparing
gold files with CR-LF weirdly, so make all the tests internal.
Add additional enum compatibility tests that check for compatibility in
different contexts.
* Array element
* Function return value
* Function and task argument
* struct member
* class property
Signed-off-by: Lars-Peter Clausen <[email protected]>
In SystemVerilog it is not allowed to assign a value to a enum variable
that is not of the same time as the enum variable.
This is currently enforced for assignment and continuous assignment. But
ignored in other places such as function parameter passing.
Move the enum type check into `elab_rval_expr()` to cover more cases.
Signed-off-by: Lars-Peter Clausen <[email protected]>
In most cases the type of an lvalue part select is the base type of the
lvalue with the width of the part select. But there are some exceptions.
1) An index into a `string` type is of type `byte`.
2) Packed structs are implemented as packed arrays under the hood. A lvalue
struct member is elaborated as a normal part select on a packed array. The
type of that select should be the type of the member.
For the case 1 there is some special handling for strings that accounts for
this. But for case 2 the type information of the member is lost.
This works fine for most things but there are a few constructs where the
type information is required.
* Enum type compatibility check
* Assignment pattern behavior depends on the type of the lvalue
Allow to attach a specific type to a lvalue part select to allow correct
behavior for constructs where the type is required.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The NetAssign_:net_type() function return the type of lvalue expression.
But it only does so for a limited amount of cases.
Refactor the function so that it works for the general case and always
returns the data type, if the data type of the lvalue expression is known.
This will allow to implement better type checking and other constructs such
as pattern assignments that require to know the type of the lvalue.
It also allows to remove some duplicated code in other methods of
NetAssign_ that want to lookup the type.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that an error is reported when accessing a hierarchical identifier
through a package scoped identifier.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Package scoped identifiers should only be able to access identifiers that
are declared in the package, but not identifiers that are visible in the
package, but declared outside of it.
```
int x;
package P;
int y;
endpackage
module test;
initial begin
$display(P::x); // Should fail
$display(P::y); // OK
end
endmodule
```
Make sure that the symbol search will not attempt to cross the package
boundary during identifier lookup.
Signed-off-by: Lars-Peter Clausen <[email protected]>
In SystemVerilog identifiers can usually have an additional package scope
in which they should be resolved. At the moment there are many places in
the code base that handle the resolution of the package scope.
Add a common data type for package scoped paths as well as a
symbol_search() variant that works on package scoped identifiers. This
allows to handle package scope resolution in a central place.
Having the code in a central place makes it easier to ensure consistent and
correct behavior. E.g. there are currently some corner case bugs that are
common to all implementations. With the common implementation it only has
to be fixed in one place.
It will also make it easier to eventually implement class scoped
identifiers.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are a few NetExpr subclasses where the data type of the expression
is known, but it not attached to the NetExpr and only kept as a private
member in the subclass.
Attaching the type directly to the NetExpr allows to query it externally
and implement better type checking.
It also allows to remove a bit of duplicated code in the subclasses and
rely on the default implementation in the NetExpr base class.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The current NetExpr::enumeration() always returns a nullptr.
The NetExpr class has a ivl_type_t member that represents
the type of the expression.
Provide a default implementation of NetExpr::enumeration() that
casts this type to the netenum_t type. This will allow
to share this implementation between subclasses and remove
a bit of duplicated code.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that function calls with empty arguments are supported. Check the
general case and special cases such as calling a function with empty
arguments as part of a module port binding or force statements in automatic
contexts.
Also check that calling a function with too many trailing empty arguments
as well as passing an empty argument for a port without a default value is
an error.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that class properties can be shadowed by local symbols in class
methods and also check that a package scoped identifier with the same name
as class property can be accessed in a class method.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are currently two mechanisms for handling class properties. One that
is used when a class property is accessed through an object and other when
a class property is used freestanding in a class method.
Both are very similar, but there are some small differences. E.g. one
supports arrays, the other supports nested properties.
```
class B;
int x;
endclass
class C;
B b;
B ba[2];
task t;
ba[0] = new; // Does work
this.ba[0] = new; // Does not work
b.x = 10; // Does not work
this.b.x = 10; // Does work
endtask
```
There is another problem where free standing properties take precedence
over local variables. E.g.
```
class C;
int x = 1;
task t();
int x = 2;
$display(x); // Should print 2, will print 1
endtask
endclass
```
The class property elaboration also ignores the package scope of the
identifier resulting in access to a class property being elaborated if
there is a property of the same name as the scoped identifier. E.g.
```
package P;
int x = 2;
endpackage
class C;
int x = 1;
task t;
$display(P::x); // Should print 2, will print 1
endtask
endclass
```
Consolidate the two implementation to use the same code path. This is
mainly done by letting the symbol search return a result for free standing
properties as if the property had been specified on the `this` object. I.e.
`prop` and `this.prop` will return the same result from the symbol search.
Signed-off-by: Lars-Peter Clausen <[email protected]>
As a quirk of the (System)Verilog grammar a function or task argument list
with no arguments can not be distinguished from a argument list with a
single empty argument. The iverilog parses it as the latter. There are
currently many places in the code base where this is fixed up in slightly
different ways.
Fix this up in the parser in a central way before passing the arguments to
the elaboration stage.
The existing implementation in some cases removes all empty trailing
arguments. While this works to handle the case for zero arguments it also
hides some errors that should be detected. E.g. in the following 3
arguments are passed to a function which only takes two arguments. But no
error is reported since the explicitly specified empty arguments are
removed.
```
function f(integer a, integer b = 2); ... endfunction
f(1,,);
```
In the new implementation the empty argument will only be removed if there
is exactly one empty argument in the argument list.
Signed-off-by: Lars-Peter Clausen <[email protected]>
A function parameter can be an empty value, in which case its expression is
a nullptr and can not be dereferenced. Make sure this case is handled in
the has_aa_term() and declare_implicit_nets() methods.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The default value for a function or task argument is elaborated once and
then used for each function invocation where no actual value is provided.
This means if a function or task is called multiple times the same NetExpr
is passed as a sub-expression to multiple statements or expressions such as
the function call.
This is causing problems because each expression or statement expects to
have exclusive ownership over its sub-expressions. It can for example
result in a double free or other undefined behavior.
To mitigate this duplicate the default argument expression before it is
given as a sub-expression to another expression or statement.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are no users of the old symbol_search that need the cls_val result.
Remove it as a output parameter of the function.
Signed-off-by: Lars-Peter Clausen <[email protected]>
This includes support at the parser (pform) through enaboration
and the netlist format for the break and continue statements.
Elaboration actually already worked for for-loops, but since the code
generators need more information, this is a rewire of that support to
be explicit about for-loops. This means they are not rewritten as fancy
while loops. The code generators will have to handle that.
Given the elaboration of for-loops now work, write the vvp code generator
support needed to implement it.
Now that for-loops are presented as for-loops to the code generator, the
vlog95 code generator doesn't need to infer them anymore. Generate the code
more directly.
Also update the tests list so that the vlog95_reg tests all pass.
Check that it is possible to call a method on a package scoped identifier.
Both for built-in types as well as class objects.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently package scoped function calls are supported. Update the parser
and elaboration to also allow method calls on packaged scoped variables.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that an error is reported when trying to access an imported
identifier through a hierarchical name.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Imported identifiers should only be visible in the scope they have been
imported too. They should not be accessible through hierarchical names into
that scope. This is defined in section 26.3 ("Referencing data in
packages") of the LRM (1800-2017).
Modify the symbol search to not look at imports if the name is part of a
hierarchical path.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The github CI VM has multiple CPUs. 2 for Linux and Windows, 3 for macOS.
Make use of parallel build to speed up the CI tests a bit.
For Windows the `makepkg-mingw` command already schedules a parallel
build, so no changes are made to the Windows build.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that null-bytes get removed when reading a value through the VPI API
as a vpiStringVal. Also check that null-bytes are not removed from string
literals when string literals are read through the VPI API as a non
vpiStringVal.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The vlog95 backend currently strips null-bytes from strings in structural
elements. E.g. `assign y = "a\000b"` gets translated to `assign y = "ab"`.
This changes the behavior of the generated output compared to the input.
Don't ignore the null-bytes to make sure the behavior stays the same.
Signed-off-by: Lars-Peter Clausen <[email protected]>
When a string literal is used in a context where it needs to be wider than
it is it will get left-padded with null-bytes. When the vlog95 backend
emits the string literal it will strip the leading null-bytes as it results
in much more legible code.
Unfortunately there are some corner cases where this results in a change of
behavior of the generated code compared to the original. E.g. if the
context that caused the width expansion has been removed by optimization.
`$display(0 ? "Yes" : "No")` should print " No" due to width expansion, but
when running through the vlog95 backend it will print "No".
Another scenario where there is a change in behavior is when a null byte
was explicitly added at the front of a string literal. E.g. $bits("\000ab")
should print 24, but will print 16 when running through the vlog95 backend.
To mitigate this remove the stripping of the leading null-bytes from the
vlog95 backend. This results in slightly less legible code being generated
in some cases, but makes sure that the code is always correct.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently when reading a number literal through the VPI API as a
vpiStringVal all null-bytes in the literal get ignored. This behavior is
different from when reading a signal through the VPI API as a vpiStringVal.
The latter will only ignore leading null-bytes and replace other null-bytes
with a space. E.g. the following two will print different values.
```
$display("%s", "a\000b"); // -> " ab"
reg [23:0] x = "a\000b";
$display("%s", x); // -> "a b"
```
For consistency modify the number literal formatting code so that it has
the same behavior as the signal value formatting code and only replaces
leading null-bytes.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The VPI API for string literals does not correctly handle the case where a
null-byte ('\0') appears in the string literal. It uses strlen() to
calculate the length of the literal, which will give the wrong result if
there is a null-byte in the string literal. Instead of using strlen() use
the stored length to fix this.
In addition when formatting a string literal as a string ignore any
null-bytes. The LRM is not entirely clear what should happen to null-bytes
when formatting a value as a string. But the behavior of ignoring the
null-bytes is consistent with the rules of SystemVerilog for converting a
string literal to a SV string.
This problem can occur when a string literal gets null-byte left-padded due
to width of its context of its expression, but then optimization removes
part of the expression and only leaves the padded string literal.
E.g.
```
$display(0 ? "Yes" : "No");
```
will be transformed into
```
$display("\000No");
```
There is also one subtle change in behavior associated with this. The empty
string ("") is supposed to be equivalent to 8'h00. So e.g.
`$display(":%s:", "")` should print ": :" since the width of the empty
string is 1 byte and the %s modifier prints a string with the width of the
value, left-padding with spaces if necessary. The current implementation
will print "::" though. This change requires to update the marco_with_args
gold file.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that when assigning or casting a string literal or vector to a SV
string type that null-bytes are removed.
Also check that writing a null-byte to an element of a string variable is
ignored.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The `%pushi/str` and `%concati/str` instructions should remove null-bytes
from the string literal when converting it to a string. This is defined in
section 6.16 ("String data type") of the LRM (1800-2017).
This is already handled correctly when converting a vector from the stack
to a SV string, just not when converting a string literal to SV string.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Make sure the package scope is considered when elaborating identifiers for
continuous unpacked array assignments.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Classes are allowed to access properties of the base class. This also
includes static properties. Currently when looking up a static property
only those of the class itself are considered. Extend this to also consider
properties of the base classes.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that an error is reported, rather than crashing, when trying to do a
package scoped function call when the function does not exist in the
package or is not a function.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently a package scoped function call will result in an assert if the
function does not exist in the package scope.
For non-package scoped function calls instead a proper error is reported.
Refactor the code to share the same code paths between package scoped and
non-package scoped function calls. This makes sure that errors are reported
in both cases. It also makes the code slightly smaller.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that indices to package scoped identifiers are evaluated in the scope
where the identifier is accessed and not in the scope where the identifier
is declared.
Signed-off-by: Lars-Peter Clausen <[email protected]>
There are a few cases where a member select on a package scoped identifier
is evaluated in the scope of the package rather than the scope where the
identifier is referenced.
This leads to incorrect behavior if a local symbol is used as an index in a
part select of the referenced member select. E.g.
```
package P;
localparam N = 1;
struct packed {
logic [3:0] x;
} s = 4'b0101;
endpackage
module test;
localparam N = 2;
initial $display(P::s.x[N]); // Will print 0, should print 1
endmodule
```
Use the scope where the member select is used, rather than the scope where
the identifier is defined, to fix this.
Signed-off-by: Lars-Peter Clausen <[email protected]>
`PECallFunction::test_width()` does not consider the package scope and will
not return any information for package scoped function calls.
As a result in contexts where the width or sign of a expression must be
known produces the wrong result when using a package scoped function.
Make sure to search for the function name in the package scope if a package
is specified.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The vlog95 backend currently ignores the sign of a function return value.
Check for it and if `-pallowsigned=1` was specified emit the `signed`
keyword. Otherwise report an error.
Signed-off-by: Lars-Peter Clausen <[email protected]>
The parameter_no_default test is expected to pass in SystemVerilog mode.
Make sure the expected result is correctly annotated in the results file.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Default member values are not allowed in packed structs. Check that an
error is reported for them.
Signed-off-by: Lars-Peter Clausen <[email protected]>
SystemVerilog allows struct members to have default values specified as
part of the struct declaration. But this is only allowed for unpacked
structs. For packed structs an error should be reported. This is defined in
section 7.2.2 ("Assigning to structures") of the LRM (1800-2017).
Currently default member values are just silently discarded if specified
for a packed struct. Make sure to report an error instead.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Make sure that comments spanning multiple lines are supported in multi-line
macros. Since the lexer parses line by line we need a flag to track whether
a multi-line comment is currently active.
Signed-off-by: Lars-Peter Clausen <[email protected]>
A '*' or '/' directly following a C-style comment in a macro currently
triggers the detection of the start of another comment. Fix this by first
looking for a '/' that should start the comment.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that variables used in void functions contribute to the sensitivity
list in a always_comb block.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Internally void function calls are modeled as task calls. But unlike task
calls, access to a signal inside a void function is supposed to contribute
to the sensitivity list of an always_comb block.
Make sure that the same logic applied for non-void functions is also
applied for void functions.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Check that an error is reported for size casts with either a value of 0, a
negative value or an undefined value.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Size casts are only allowed if the value is positive. For cases where it is
0 negative or undefined an error should be reported. Currently the negative
case is not handled. Extend the test to also check for negative values.
Signed-off-by: Lars-Peter Clausen <[email protected]>
Currently the Windows build generates a warning
=> WARNING: MINGW_INSTALLS is deprecated, use MINGW_ARCH instead
Make this change to the CI workflow file.
Signed-off-by: Lars-Peter Clausen <[email protected]>
With the development version bumped to v13 the regression tests runner
expects a `regress-v13.list`. Provide one, which is just a copy of the
`regress-v12.list` for now.
Signed-off-by: Lars-Peter Clausen <[email protected]>
* The only known breaking change is that wires must now be declared before use; which is required in the standard (see `gh1287 <https://github.com/steveicarus/iverilog/issues/1287>`__).
----
🙏 Acknowledgments
------------------
We thank all contributors who reported issues, submitted patches, expanded regression coverage, and
improved documentation. Release 13 reflects continued community effort toward improving correctness,
The sizer target does not generate any code. Instead it will print statistics about the Verilog code.
It is important to synthesize the Verilog code before invoking the sizer. This can be done with the `-S` flag passed to iverilog. Note, that behavioral code can not be synthesized and will generate a warning when passed to the sizer.
# The file index is used to find the file name in the following table.
:file_names 3;
"N/A";
"<interactive>";
"hello_world.v";
The first line contains the shebang. If this file is executed, the shebang tells the shell to use vvp for the execution of this file.
To run the simulation, execute::
% ./top.vvp
Or you can call vvp directly::
% vvp top.vvp
Next are some directives. The first one, `:ivl_version` specifies which version of iverilog this file was created with. Next is the delay selection with "min:typical:max" values and the time precision, which we did not set specifically, so the default value is used. The next lines tell vvp which VPI modules to load and in which order. The next lines tell vvp which VPI modules to load and in what order. Next, a new scope is created with the `.scope` directive and the timescale is set with `.timescale`. A thread `T_0` is created that contains two instructions: `%vpi_call` executes the VPI function `$display` with the specified arguments, and `%end` terminates the simulation.
Opcodes
-------
The various available opcodes can be seen in :doc:`Opcodes <../developer/guide/vvp/opcodes>`
Ensure that `iverilog` is on your search path, and the vpi library
@@ -322,16 +365,16 @@ is available.
To compile the program:
```
```bash
iverilog hello.vl
```
(The above presumes that /usr/local/include and /usr/local/lib are
part of the compiler search path, which is usually the case for gcc.)
(The above presumes that `/usr/local/include` and `/usr/local/lib` are
part of the compiler search path, which is usually the case for `gcc`.)
To run the program:
To run the generated program:
```
```bash
./a.out
```
@@ -348,165 +391,30 @@ Verilog web page for the current state of support for Verilog, and in
particular, browse the bug report database for reported unsupported
constructs.
- System functions are supported, but the return value is a little
tricky. See SYSTEM FUNCTION TABLE FILES in the iverilog man page.
- Specify blocks are parsed but ignored in general.
- Specify blocks are parsed but ignored by default. When enabled
by the `-gspecify` compiler option, a subset of specify block
constructs are supported.
- `trireg` is not supported. `tri0` and `tri1` are supported.
- tran primitives, i.e. `tran`, `tranif1`, `tranif0`, `rtran`, `rtranif1`
and `rtranif0` are not supported.
- Net delays, of the form `wire #N foo;` do not work. Delays in
every other context do work properly, including the V2001 form
`wire #5 foo = bar;`
- Event controls inside non-blocking assignments are not supported.
i.e.: `a <= @(posedge clk) b;`
The list of unsupported SystemVerilog constructs is too large to
enumerate here.
- Macro arguments are not supported. `` `define `` macros are supported,
but they cannot take arguments.
## Nonstandard Constructs and Behaviors
## Nonstandard Constructs or Behaviors
Icarus Verilog includes some features that are not part of the IEEE 1364
standard, but have well-defined meaning, and also sometimes gives nonstandard
(but extended) meanings to some features of the language that are defined.
See the "Icarus Verilog Extensions" and "Icarus Verilog Quirks" sections at
https://steveicarus.github.io/iverilog/ for more details.
Icarus Verilog includes some features that are not part of the
IEEE1364 standard, but have well-defined meaning, and also sometimes
gives nonstandard (but extended) meanings to some features of the
language that are defined. See the "extensions.txt" documentation for
more details.
## Credits
* `$is_signed(<expr>)`
This system function returns 1 if the expression contained is
signed, or 0 otherwise. This is mostly of use for compiler
regression tests.
* `$sizeof(<expr>)`, `$bits(<expr>)`
The `$bits` system function returns the size in bits of the
expression that is its argument. The result of this
function is undefined if the argument doesn't have a
self-determined size.
The `$sizeof` function is deprecated in favour of `$bits`, which is
the same thing, but included in the SystemVerilog definition.
* `$simtime`
The `$simtime` system function returns as a 64bit value the
simulation time, unscaled by the time units of local
scope. This is different from the $time and $stime functions
which return the scaled times. This function is added for
regression testing of the compiler and run time, but can be
used by applications who really want the simulation time.
Note that the simulation time can be confusing if there are
lots of different `` `timescales`` within a design. It is not in
general possible to predict what the simulation precision will
turn out to be.
* `$mti_random()`, `$mti_dist_uniform`
These functions are similar to the IEEE1364 standard $random
functions, but they use the Mersenne Twister (MT19937)
algorithm. This is considered an excellent random number
generator, but does not generate the same sequence as the
standardized $random.
### Builtin system functions
Certain of the system functions have well-defined meanings, so
can theoretically be evaluated at compile-time, instead of
using runtime VPI code. Doing so means that VPI cannot
override the definitions of functions handled in this
manner. On the other hand, this makes them synthesizable, and
also allows for more aggressive constant propagation. The
functions handled in this manner are:
* `$bits`
* `$signed`
* `$sizeof`
* `$unsigned`
Implementations of these system functions in VPI modules will be ignored.
### Preprocessing Library Modules
Icarus Verilog does preprocess modules that are loaded from
libraries via the -y mechanism. However, the only macros
defined during the compilation of that file are those that it
defines itself (or includes) or that are defined in the
command line or command file.
Specifically, macros defined in the non-library source files
are not remembered when the library module is loaded. This is
intentional. If it were otherwise, then compilation results
might vary depending on the order that libraries are loaded,
and that is too unpredictable.
It is said that some commercial compilers do allow macro
definitions to span library modules. That's just plain weird.
### Width in `%t` Time Formats
Standard Verilog does not allow width fields in the %t formats
of display strings. For example, this is illegal:
```
$display("Time is %0t", $time);
```
Standard Verilog instead relies on the $timeformat to
completely specify the format.
Icarus Verilog allows the programmer to specify the field
width. The `%t` format in Icarus Verilog works exactly as it
does in standard Verilog. However, if the programmer chooses
to specify a minimum width (i.e., `%5t`), then for that display
Icarus Verilog will override the `$timeformat` minimum width and
use the explicit minimum width.
### vpiScope iterator on vpiScope objects.
In the VPI, the normal way to iterate over vpiScope objects
contained within a vpiScope object, is the vpiInternalScope
iterator. Icarus Verilog adds support for the vpiScope
iterator of a vpiScope object, that iterates over *everything*
the is contained in the current scope. This is useful in cases
where one wants to iterate over all the objects in a scope
without iterating over all the contained types explicitly.
### time 0 race resolution.
Combinational logic is routinely modelled using always
blocks. However, this can lead to race conditions if the
inputs to the combinational block are initialized in initial
statements. Icarus Verilog slightly modifies time 0 scheduling
by arranging for always statements with ANYEDGE sensitivity
lists to be scheduled before any other threads. This causes
combinational always blocks to be triggered when the values in
the sensitivity list are initialized by initial threads.
### Nets with Types
Icarus Verilog supports an extended syntax that allows nets
and regs to be explicitly typed. The currently supported types
are logic, bool and real. This implies that `logic` and `bool`
are new keywords. Typical syntax is:
```
wire real foo = 1.0;
reg logic bar, bat;
```
... and so forth. The syntax can be turned off by using the
-g2 flag to iverilog, and turned on explicitly with the -g2x
flag to iverilog.
## CREDITS
Except where otherwise noted, Icarus Verilog, ivl and ivlpp are
Except where otherwise noted, Icarus Verilog, ivl, and ivlpp are
Copyright Stephen Williams. The proper notices are in the head of each
file. However, I have early on received aid in the form of fixes,
Verilog guidance, and especially testing from many people. Testers, in
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.