Add parsing and elaboration for chained calls on expression results,
with sv_call_chain_method1 regression.
Split from steveicarus/iverilog#1330 (part 02/6).
Check that nature and discipline declaration names can match visible type
identifiers. Also check `potential` and `flow` references to nature names that
are visible as type identifiers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Verilog-AMS nature and discipline declarations can use names that are also
visible as type identifiers. The `potential` and `flow` discipline items can
likewise reference a nature whose name is returned as `TYPE_IDENTIFIER` by the
lexer. These grammar positions currently only accept `IDENTIFIER`.
Use `identifier_name` for nature and discipline declaration names and for the
`potential` and `flow` nature references.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a for loop variable declaration can use the same name as a
visible typedef, including references from the loop condition and step
expressions.
Also check that procedural foreach can parse an array expression name that
is initially seen as a type identifier. Declare the array after the loop so
the parser sees the outer typedef while parsing the foreach header, then
elaboration resolves the array declaration as a module item.
Use unsigned variables and omit the foreach iterator because these tests do
not depend on signed values or iteration behavior. This lets both tests run
through the vlog95 backend as normal regressions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as
a type identifier from an outer scope. The lexer reports such names as
`TYPE_IDENTIFIER` until the new declaration has been installed.
The parser previously created the synthetic loop scope and declared the loop
variable only after parsing the complete `for` header. When the variable name
matches a visible typedef, this is too late: the lexer can continue returning
`TYPE_IDENTIFIER` for references to the variable in the initializer,
condition, and step expressions. Accept `identifier_name` for the declaration
name and create the loop scope and variable in a mid-rule action immediately
after it, so the declaration is visible while the rest of the header is
parsed.
The executable foreach grammar also used to require the array expression name
before the index list to be an `IDENTIFIER`. Use `identifier_name` there as
well, since this position is an expression name followed by `[` and not a type
name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a standard attribute name can match a visible typedef. Also check
that the global `$attribute` extension can target a primitive whose name is
visible as a type identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Standard attribute names and target names in both forms of the Icarus
`$attribute` extension are unambiguous identifier positions. When such a name
matches a visible typedef the lexer returns `TYPE_IDENTIFIER`, while the
grammar only accepts `IDENTIFIER`.
Use `identifier_name` for all of these positions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parameter_omit tests have different expectations depending on whether the
regression is run in the default Verilog mode or with force SystemVerilog.
The old list files modelled this by registering the same tests in both
regress-vlg.list and regress-fsv.list.
Move the tests to JSON descriptors. Use the existing force-sv override for the
forms that are valid SystemVerilog, and keep the implicit type cases as CE in
both modes. This also runs the tests through the additional configurations
supported by vvp_reg.py, providing better coverage in CI.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LRM allows omitting the `parameter` keyword in a module parameter port
list, but the optional type in that form is a data_type, not an implicit
data type. A parameter port list like this is therefore invalid:
module M #([3:0] P = 1);
The parameter declaration grammar was reusing the general
value_parameter_assign_with_type rule for the omitted-keyword form. That rule
also accepts implicit types so that ordinary `parameter signed P = 1`
declarations work, which made the omitted-keyword form accept implicit types
as well.
Add a separate rule for value parameter assignments without the `parameter`
keyword. The rule still accepts bare identifiers and explicit data types so a
parameter name can shadow a visible typedef name, but it rejects implicit
types.
Fixes: e56c93a2be ("Support shadowing type identifiers in parameter declarations")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The br_gh1385a, br_gh1385b, and br_gh1385c JSON descriptors mark the vlog95
variants as compile errors. The enum typedefs are translated correctly, so the
compile error expectation causes the tests to fail when compilation succeeds.
Remove the stale overrides and run the translated tests through vlog95.
Fixes: 10349287a0 ("Add regression tests for enum typedefs in nested scopes")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a named binding selector can have the same text as a visible typedef
name. Cover named module port connections, named parameter overrides, and named
task, function and constructor arguments.
Also check that a modport simple port selector can shadow a visible typedef
name. Modport simple port aliases share the same parser rule but declare the
modport-visible name rather than binding to an existing formal.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A named binding selector such as `.T(expr)` names an existing formal port,
parameter, task or function argument, or constructor argument. It is not a
declaration of a new identifier. If a visible typedef named `T` exists at the
use site the lexer returns `TYPE_IDENTIFIER`, which made the parser reject the
binding selector.
Modport simple port aliases use the same grammar, but are slightly different:
the selector is the modport-visible port name and can shadow a visible typedef
name in the interface scope.
Use `identifier_name` for the selector name in `named_expression` and
`named_expression_opt`. This covers named parameter overrides, named task and
function arguments, named constructor arguments, and modport simple port
aliases. Also use `identifier_name` in the named module port connection rules,
including implicit named port connections and error recovery.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Fold in Windows VPI routing for vpip_format_pretty, fix queue method
argument elaboration via elaborate_rval_expr, reject class tasks used as
expressions cleanly, and update br1005 now that class queues compile.
Review follow-up: move vpip_format_pretty to vpip_format.cc with
diagnostic return strings, restore NetNet-based queue method elaboration
with a separate property path, drop spurious /devel/ from .gitignore,
and bump copyright years on touched files.
Formatting pass per inline review: brace style for multi-line if bodies,
||/&& at end-of-line continuations, switch/case indentation, single-line
if returns, NetNet-based sys_task_method_ again, and aligned extern decls.
Check that event declarations can use visible type identifiers as event names.
Also check that the resulting named event can be triggered and waited on.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. This also applies to named event
declarations. The lexer reports such names as `TYPE_IDENTIFIER` before the
event has been installed, which made constructs such as:
typedef int T;
module test;
event T;
endmodule
fail in the event declaration grammar.
Event declarations do not have the local type/name ambiguity that exists for
variable, net, or parameter declarations. The name in `event_variable` is
always the event name. Use `identifier_name` so a `TYPE_IDENTIFIER` token can
be accepted as the event name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that visible type identifiers can be reused as named block labels. Cover
procedural `begin` blocks, fork blocks, and conditional generate blocks. Also
check matching end labels where the grammar consumes the shared `label_opt`
rule.
The generate test keeps the existing vlog95 compile-error expectation because
named generate scopes are not translated by the vlog95 target.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a named block label in an inner scope to use the same
name as a visible type identifier from an outer scope. The lexer reports such
names as `TYPE_IDENTIFIER` before the label has been installed, which made
constructs such as:
typedef int T;
module test;
initial begin
begin : T
end : T
end
endmodule
fail in the block label grammar.
The affected grammar positions are label names, not declarations with an
adjacent type/name ambiguity. Use `identifier_name` for `label_opt` and for the
anachronistic named generate begin form so a token returned as `TYPE_IDENTIFIER`
can still be accepted as the label name. With `label_opt` able to handle
`TYPE_IDENTIFIER`, the separate class end-label rule is no longer needed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a package declaration can use a visible type identifier as its
package name. Also check that the resulting package scope can be selected with
a scope-qualified reference.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a package declaration to use a name that is also visible
as a type identifier. The lexer reports such names as `TYPE_IDENTIFIER` before
the package has been installed, which made constructs such as:
package p;
typedef int T;
endpackage
import p::*;
package T;
endpackage
fail in the package declaration grammar.
Package declarations do not have the local type/name ambiguity that exists for
variable, net, or parameter declarations. After the optional lifetime the next
token is always the package name. Use `identifier_name` so a
`TYPE_IDENTIFIER` token can be accepted as the package name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Bison reports shift/reduce and reduce/reduce parser conflicts as warnings by
default. This allows parser changes to introduce new conflicts while the normal
build still succeeds.
Pass the conflict warning classes as errors to Bison when generating the
parsers. This makes the regular build fail if either parser has unresolved
conflicts.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parameter declaration grammar allows a visible type identifier to be used
as a parameter name. The assignment continuation rule still used
`identifier_name`, which made Bison reduce a `TYPE_IDENTIFIER` before it had
seen whether following dimensions belonged to the parameter name or to an
explicit type identifier.
Match ordinary and type identifiers directly in `parameter_assign` so the
parser can shift dimensions before deciding between a parameter name and an
explicit parameter type.
Fixes: e56c93a2be ("Support shadowing type identifiers in parameter declarations")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that UDP primitive and port names can shadow visible type identifiers.
Cover old-style UDP declarations, including input and output declarations and
the initial target, as well as ANSI-style UDP port declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a UDP primitive or UDP port declaration to use the same
name as a visible type identifier from another namespace or outer scope. The
lexer reports such names as `TYPE_IDENTIFIER` before the UDP name has been
installed, which made constructs such as:
typedef int T;
primitive T (Q, A);
output Q;
input A;
table
0 : 0;
endtable
endprimitive
fail in the UDP grammar.
UDP primitive and port names do not have the local type/name ambiguity that
exists for variable, net, or parameter declarations. Use `identifier_name` for
the primitive name, the UDP port list, UDP port declarations, and the UDP
initial target so a `TYPE_IDENTIFIER` token can be accepted as the UDP name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that UDP initial values on non-registered outputs generate compile
errors for both old-style and ANSI-style UDP declarations. Also check that
conflicting UDP port declarations generate an error and that a valid
ANSI-style `output reg` initializer is accepted.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Malformed UDP declarations can reach `pform_make_udp()` with conflicting
duplicate port declarations or with an initial value on an output that was not
declared as a register. These cases currently trigger internal assertions
instead of reporting normal compile errors.
The ANSI-style UDP output initializer path also treats the initializer
expression as if it was the old-style `initial out = value` assignment
statement. This makes a valid `output reg out = 1'b0` initializer assert as
well.
Report errors for the invalid declarations and read the ANSI-style initializer
value directly from the initializer expression.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that enum item names can shadow visible type identifiers. Cover plain enum
items as well as the counted and ranged enum item sequence forms.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. This also applies to enum item names. The
lexer reports such names as `TYPE_IDENTIFIER` before the enum item has been
installed, which made constructs such as:
typedef int T;
module test;
enum { T = 1 } e;
endmodule
fail in the enum item grammar.
Enum item declarations do not have the local type/name ambiguity that exists for
variable, net, or parameter declarations. The name in each `enum_name`
production is always the enum item name, including the sequence forms like
`T[2]` and `T[1:2]`. Use `identifier_name` for these names so they can shadow a
visible type identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that function and task declarations can use a visible type identifier as
the declaration name. Cover both ANSI declarations and the non-ANSI forms where
the name is parsed without a separate return type or port list.
Also check class method declarations where the method name is the same as the
enclosing class name. Add GitHub issue #670 coverage for the `function void`
case using the issue-based regression naming scheme.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. This also applies to task and function
names. The lexer reports such names as `TYPE_IDENTIFIER` before the new task or
function has been installed, which made constructs such as:
typedef int T;
module test;
function int T(input int value);
return value;
endfunction
task T;
endtask
endmodule
fail in the task and function declaration grammar. A class method with the same
name as the class itself hits the same problem because the class name is visible
as a type identifier in the class scope.
The task grammar can accept `identifier_name` directly, because a task has no
return type and the token after `task` and the optional lifetime is always the
task name.
Function declarations have a local return-type/name ambiguity. After
`function T` the parser does not know yet whether `T` is the function name with
no explicit return type, or whether a following identifier will make `T` the
explicit return type as in `function T f`. Parse the optional function return
type and function name together. This allows a `TYPE_IDENTIFIER` token to be
interpreted as the function name when no separate function name follows, while
still parsing typed forms and `void` return types correctly.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that visible type identifiers can be shadowed by value parameter names
and by type parameter names. Cover ordinary parameter declarations, typed
parameter declarations, and parameter port list declarations separately.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a visible type identifier to be shadowed by a
parameter declaration name. Parameter declarations still required the
parameter name to be an `IDENTIFIER` token and rejected declarations like:
typedef int P;
module test;
parameter int P = 1;
endmodule
The parameter grammar can not just accept `TYPE_IDENTIFIER` in every name
position. After `parameter P` the parser does not know yet whether `P` is
the parameter name, or whether a following identifier will make `P` the
parameter type.
Parse the optional value parameter type and the first parameter assignment
together. This allows a `TYPE_IDENTIFIER` token to be interpreted as the
parameter name when no explicit type is present, while still parsing a
following identifier as the parameter name for typed parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a class property can have the same name as a type declared in
an outer scope, or a type imported through a wildcard import. Also check
that a class property can have the same name as the class itself.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a class property to have the same name as a visible
type. The lexer reports the visible type name as `TYPE_IDENTIFIER` before
the property has been installed, which made constructs such as
`typedef int T; class C; int T; endclass` fail in the class item grammar.
A class property with the same name as the class itself hits the same
problem. Member references such as `obj.T` or `obj.C` can also hit the
same tokenization problem in hierarchical names.
Parse class properties through the same declaration helper used for
variables so the first type/name pair can be disambiguated. Also let
hierarchical member names use `identifier_name`.
Stop type lookup when a class scope already has a property with the same
name. This makes method body references resolve as properties instead of
visible types, including type names found through wildcard imports.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that automatic variables referenced through an assignment pattern in a
procedural `force` statement are rejected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Assignment patterns contain child expressions, but currently inherit
`PExpr::has_aa_term()` which always returns false. This means automatic
variables inside a pattern are not caught by checks for procedural `force`
and procedural continuous assignment statements.
Implement `has_aa_term()` for `PEAssignPattern` and recurse into all pattern
elements.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the repeat count expression of a non-blocking intra-assignment
event control can reference an automatic task argument. The repeat count is
evaluated when the assignment is scheduled, so the automatic variable is not
referenced after the task scope is freed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The repeat expression of an event controlled non-blocking assignment is
evaluated once when the assignment is scheduled. This means there is no
risk of it being referenced when its scope has already been freed. And
hence there is no need to require the repeat expression to only contain
static terms.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that variable and net declaration names can shadow a visible type
identifier. Check this for explicit data type declarations, `var` declarations,
and net declarations.
Check that task and function formal argument names can shadow a visible type
identifier, and that typed arguments still use the visible typedef when an
argument name follows.
Check ambiguous module port declarations where a type identifier can be either
the port name or the port type, with and without dimensions, and that
declaration lists continue to use the type selected by the first ambiguous
declarator. Cover both ANSI and non-ANSI module port declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows a declaration in an inner scope to use the same name as a
type identifier from an outer scope. The lexer reports such names as
`TYPE_IDENTIFIER` before the new declaration has been installed, which made
constructs such as `int T;`, `wire T;`, and `input T` fail when `T` was a
visible typedef.
The affected declaration forms have a local type/name/dimension ambiguity. For
example, after `input T` or `wire T` the parser does not know whether `T` is the
declared name, or whether a following identifier will make `T` the declaration
type in `input T x` or `wire T x`. With dimensions, `input T [1:0]` and
`wire T [1:0]` can be either a declaration named `T` with unpacked dimensions or
a declaration using typedef `T` as a packed type followed by another name.
Parse these declaration forms with productions that decide the first declarator
and carry the selected declaration type across the rest of the list. This covers
variable declarations, net declarations, ANSI and non-ANSI module port
declarations, and task/function port declarations. Other identifier uses still
need separate grammar changes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a blocking intra-assignment delay on a real value preserves the
assigned value after the delay.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The vvp parser did not accept the local flag on `.var/real`
declarations. This can happen when elaboration creates a compiler-generated
real temporary, for example when a blocking intra-assignment delay is
rewritten from:
r = #1 1.25;
to assign the right hand side to a temporary before the delay and assign
the temporary to the target after the delay.
Add support for the local flag. Keep a VPI symbol for the variable so
`%load/real` can still resolve the label, but do not attach local real
variables to the current scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that visible type identifiers can be shadowed by declarations in
other namespaces or nested scopes. Keep each grammar category in a
separate regression so failures identify the affected rule.
Also check that package import and export items can name a type
identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows an identifier that is visible as a typedef to be
shadowed by a declaration in a nested scope or reused as a declaration
name in another namespace. The lexer can return `TYPE_IDENTIFIER` before
the new name has been installed, so these grammar positions reject
otherwise valid code.
This is not a complete conversion of all identifier grammar sites. Only
handle the trivial conflict-free cases where `IDENTIFIER` can be replaced
by `identifier_name` without any surrounding grammar changes.
Also stop type lookup when the current scope already has a local symbol
with the same name. This makes later references to a shadowing
declaration use the local symbol instead of an outer typedef.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The string substr() method reports an error if it is called with the wrong
number of arguments, but the error was not counted and elaboration continued
with missing function arguments. A call such as `s.substr(0)` could therefore
crash after printing the diagnostic.
Count the arity error and fill missing internal arguments with dummy constants
so elaboration can recover without building an incomplete system function call.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that unary real minus preserves the sign or bit pattern for zero,
NaN, and infinity. Each test starts with the positive value, negates it,
and then negates the result back to the positive value.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the vvp target emits unary real minus as `0.0 - value`.
This is not the same operation for all real values. It loses the
negative zero result for `-(+0.0)` and does not reliably flip the sign
bit for NaN values whose bits are visible through `$realtobits`.
Add `%neg/wr` and use it for unary real minus. This performs a direct
negation of the real stack value, so zero, NaN and infinity all use the
same operation as unary minus instead of a binary subtraction from zero.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the vvp code generator emits a -0.0 real constant with its
sign bit set, so the compiled value matches the runtime real value. The
sign used to be detected with (value < 0), which is false for IEEE 754
-0.0, and a -0.0 constant was turned into +0.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Check that bogus member access on a procedural l-value is rejected with a
normal compile error instead of aborting during elaboration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that an invalid indexed part select base on a procedural l-value is
reported as a normal compile error instead of crashing after the bind error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the procedural l-value path asserts if symbol lookup leaves a
member tail for a variable that is not a struct or class. For example,
`r.bad = 1'b1;` where `r` is a scalar variable aborts during elaboration
instead of reporting a normal error.
Report an error for the leftover member path before the assertion. This
matches the r-value path behavior for the same kind of invalid member access.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The l-value indexed part select path elaborates the base expression with
`elab_and_eval()`. If the base expression can not be bound this returns a
nullptr, but the l-value path dereferenced it while checking the expression
type. For example, `a[does_not_exist -: 2] = 2'b00;` reported the bind error
and then crashed.
Return early when base elaboration fails. This matches the r-value indexed
part select path and leaves the existing bind error as the reported
elaboration error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently vvp_reg.py uses `returncode >= 256` to distinguish execution
errors from ordinary compile or simulation failures. That matches the encoded
status returned by wait(), but subprocess.run() does not expose that value. Its
returncode is the decoded process exit status, or `-N` if the process was
terminated by signal N. Shell wrappers can also report signal termination as
`128 + N`.
As a result a compiler crash can be reported as `-11` or `139`. Both values
pass the old check and a CE test can be accepted as a normal compiler error.
Treat negative return codes and return codes greater than or equal to 128 as
execution errors before accepting CE and EF results. Also make sure that CE gold
mismatches are reported as failures.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The vlog95 backend currently emits `$unsigned()` when it needs to create a
self-determined unsigned expression context. `$unsigned()` is part of the
optional signed expression support in this backend and is only available when
the signed support flag is enabled.
Concatenation is part of the baseline Verilog-95 output and also creates a
self-determined unsigned expression context. Use `{expr}` for the unsigned case
and keep using `$signed()` when a signed context is needed.
Remove `-pallowsigned=1` from the existing vlog95 regression tests that now
pass without the optional signed support flag.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that synthesized case statement muxes can use array words as inputs.
This used to generate invalid VVP because .array/port statements were emitted
in the middle of .functor statements.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently draw_lpm_mux_nest() calls draw_net_input() while printing a
.functor statement. For array word inputs draw_net_input() emits an
.array/port statement as a side effect, which interleaves the .array/port
text into the middle of the .functor line and generates invalid VVP.
draw_lpm_substitute() has the same pattern. Collect the input labels before
starting to print the consuming statement so any side-effect output appears
as a separate statement first.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a class declared in a conditional generate block can be used.
Also check that classes declared in a generate loop get separate class scopes
for each generated instance.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows class declarations as module and generate items.
Currently a class declaration in a generate block triggers an assert because
`pform_push_class_scope()` only records classes in `PScopeExtra` scopes.
Add class storage to `PGenerate` and elaborate those classes like module and
package classes. When registering task, function or class declarations, only
use the current `PGenerate` object as the target if it is also the current
lexical scope. This distinction matters for generated classes because
`pform_cur_generate` remains set while the class body is parsed, but the
current lexical scope has changed to the `PClass`. This records the class
declaration in the generate block while leaving methods and constructors in
the class scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that using a class task through an object method call in expression
context reports a compile/elaboration error instead of triggering an assert.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Class object method calls in expression context call func_def() without first
checking that the resolved class method is a function. If the method is a task,
func_def() triggers an assert instead of reporting a normal elaboration error.
Check the method scope type before accessing the function definition and report
an error for tasks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently NetAssignNB::dump() prints a malformed fallback marker when
there is no rval expression. The leading '<' is missing, making it
inconsistent with the blocking assignment dump output.
Print the complete error marker.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The methods for handling up and down part select are nearly identical
and only differ in a hand full of lines.
Consolidate them into a single method to remove the duplicated code.
This makes it easier to maintain the code and add future changes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The methods for handling up and down part select are nearly identical
and only differ in a hand full of lines.
Consolidate them into a single method to remove the duplicated code.
This makes it easier to maintain the code and add future changes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that enum literals declared by enum typedefs in generate blocks, named
blocks, tasks and functions can be referenced from the same scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Enum types declared inside nested scopes are stored separately from typedefs.
The enum sets need to be elaborated when the `NetScope` is created so enum
literals are available for declarations and statements in the same scope.
Module, package and class scopes already do this. Generate, task, function and
named block scopes can also declare enum typedefs, but did not elaborate their
enum sets. Elaborate them while setting up these scopes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The VPI label resolver parses word and string labels into a 32 byte
temporary buffer. The scansets used by sscanf() did not specify a width,
so malformed labels could write past the end of the buffer.
Limit the scansets to the size of the buffer.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that an empty old-style UDP table reports the parser error and the
invalid primitive error instead of crashing.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
An empty old-style UDP table leaves the parsed table pointer unset after
the parser reports the table error. The old-style UDP creation path still
passed the null pointer to process_udp_table(), which crashes.
Report an invalid UDP table instead and do not register the primitive.
Also keep the new-style invalid-table diagnostic formatting consistent.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that variable selects of a packed array with negative bounds use the
correct index width and can read back assigned elements.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Variable select base normalization extends the base expression to cover
the packed array bounds. The current code compared min_wid against
num_bits() of each bound, but then assigned the bound value itself to
min_wid.
For positive bounds this can make the generated index expression much
wider than required. For negative bounds the effect is much worse since
min_wid is unsigned. Assigning a negative bound converts it to a huge
width, causing elaboration to try to pad the expression to that size and
abort or run out of memory for otherwise valid variable selects.
Use the bit width of the bound instead of the bound value.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that statements that are not allowed in functions or final procedures
are still rejected when they are placed in a named block scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently checks for statements that are not allowed in functions or final
procedures only inspect the immediate scope. If the statement is inside a
named block or a block with declarations, the current scope is the block and
the context is lost.
Make `NetScope::in_func()` and `NetScope::in_final()` preserve the context
through begin-end, fork-join and generate block scopes. Other scope types are
treated as context boundaries so function and final state does not leak across
subroutine or definition scopes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that queue push_back(), push_front() and insert() report errors when
called with too few or too many arguments.
These tests are expected to fail as compile/elaboration errors. They also make
sure the invalid calls do not crash during elaboration while reporting the
argument count error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When a method argument is missing, the error path stores a nullptr in the
argument vector for that missing slot. The vector was sized from the number of
arguments that were present in the source, so calls such as `q.push_back()` or
`q.insert(0)` wrote those nullptr placeholders past the end of the vector.
Size the vector from the number of arguments required by the queue method
instead. This gives the error path slots for the missing arguments while
leaving valid calls unchanged.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that multi-dimensional packed vector class properties can be emitted,
assigned, and read back through a class object.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently multi-dimensional packed vector class properties will cause an
assert and only single dimensional or scalar vectors will pass.
But just as for regular vectors there is nothing special about class
property multi-dimensional vectors as they will be represented in vector
form in vvp.
Removing the asserts allows multi-dimensional packed vectors to be used for
class properties. Indexed access to these properties is not supported yet;
that requires follow-up work to elaborate packed property selects and to
support partial stores to vector class properties.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that assignment patterns are evaluated in the queue element type
context when they are passed to the queue `push_front()`, `push_back()` and
`insert()` methods.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The arguments of the queue `push_front()`, `push_back()` and `insert()`
methods are passed to subroutine input ports. This makes them
assignment-like contexts with the declared argument type as target type.
Use `elaborate_rval_expr()` instead of `elab_and_eval()` for these
arguments. This evaluates the item argument with the queue element type and
the `insert()` index argument with `integer`, so target-type-dependent
expressions such as assignment patterns work and enum compatibility checks
use the queue element type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Extend the non-blocking event control assignment tests to check that a 0 or
negative repeat value is handled correctly. In this case the assignment
should be executed like a regular non-blocking assignment and the event
control should be ignored.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`NetEvWait` deletes the event that is assigned to it when itself
is deleted. But the event is not owned by the `NetEvWait`, it is shared among
all consumers of the event. Deleting it when the `NetEvWait` is deleted can
result in undefined behavior.
This is mainly a problem for non-blocking event control assignments with a
zero or negative immediate valued repeat. In this case the `NetEvWait` will
be deleted as it is not needed.
```
reg x;
event e;
x <= repeat(1) @e 1'b0;
x <= repeat(0) @e 1'b1; // Assert triggered since in-use event is freed
```
Remove the delete to fix this. Events that end up being unused will be
freed by the nodangle functor.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This test was added to verify the new options
in the `iverilog` program, which allow it to
be run from a build directory.
Since `iverilog` is not compatible with the MSYS2
runtime environment used in CI, the added test is
excluded on this platform.
Check that continuous assignments to unpacked net arrays preserve delay and
drive strength on the generated element drivers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Continuous assignments to unpacked arrays are expanded into per-element
BUFZ drivers. Currently this path drops the delay and drive strength from
the original continuous assignment, so `assign #5 a = b` updates the array
immediately and `assign (weak1, weak0) a = b` drives with the default
strength.
Pass the evaluated delay and strength values through the unpacked array
assignment helper and apply them to each generated element driver.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Drive strengths and delays are often handled as a pair of drive values
and a rise/fall/decay triple. Add small helper types to carry these
groups and use them in the continuous assignment and gate/UDP elaboration
paths.
Use the same helper types when propagating drive and delay values through
netlist links.
Also add helpers for dumping the values in debug output. This keeps the
behavior consistent and fixes one small bug where some of the debug
dumps printed the pointer value for the delays, rather than the actual
delay values.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that SystemVerilog net declarations can mix entries with and
without initialization.
Check that in SystemVerilog it is possible to do assignments within net array
declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`pform_set_data_type()` is now only called on wires that already have the
correct wire type set. There is no need to pass the same type to
`pform_set_data_type()` and set it again.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows initialized and uninitialized net declaration entries to
be mixed in the same declaration, e.g. `wire x, y = 1'b1`. In Verilog,
either all nets need to have an initializer or non can have one.
In addition SystemVerilog also allows assignments to arrays of wires during
declaration. E.g. `wire a[3:0] = b;`
Currently there are two different rules for net declarations, one for each
of the Verilog variants. Combine these into a single rule to support
SystemVerilog mixed declarations as well as the assignment to array nets.
When running in Verilog mode still reject mixed initialized and
uninitialized with a check after the parsing.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The assignment handling block uses space-based indentation that does not match
the surrounding code.
Fix the indentation before changing the block.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that continuous assignment of an assignment pattern to a single element
unpacked array is accepted. Check that assigning a scalar expression to the
whole unpacked array is rejected for both procedural and continuous
assignments.
Check that a selected element of a single element static unpacked array can be
used in a continuous l-value concatenation.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently single element static unpacked arrays are not always treated as
unpacked arrays when elaborating assignment l-values. The net only has one pin,
so checks using `pin_count() > 1` treat the array as a scalar value and skip
the unpacked array path.
Use `unpacked_dimensions() > 0` instead of `pin_count() > 1` when checking
whether a signal is an unpacked array. This lets single element arrays follow
the same l-value elaboration paths as other unpacked arrays.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that enum, struct, union and class restricted type parameters are
accepted. Check that mismatched default values and overrides are rejected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog 2023 allows type parameters to be restricted to a
specific kind of type, e.g. `parameter type struct T = T0`.
This is very similar to the type restrictions that can be applied to
forward typedefs.
Factor the support code from the typedefs into a standalone helper and
reuse it for both.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that soft packed unions can have members with different widths.
Check that the `soft` qualifier implies `packed` and that nested soft
packed unions use the same representation recursively.
Also check that member bits are right-justified and that assignments to
narrower members leave the MSBs beyond the member bits unchanged. Check
that soft packed unions reject default member values.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog 2023 adds soft packed unions. They are pretty much the same
as regular packed unions except they remove the restriction that all
elements have to have the same packed width.
The packed with of the union itself is the maximum packed width of any
element.
The bits of each member are right-justified towards the LSBs and this
representation is applied recursively to nested soft packed unions. The
existing packed union member offsets already use that layout. When
accessing a field that is smaller than the union itself upper bits are
ignored for both reading and writing.
The `soft` qualifier implies a packed union so both `union soft U { ... }`
and `union soft packed U { ... }` declare a soft packed union.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that each valid `begin_keywords` selector is accepted. Only check
that the selector itself is accepted, in these tests there is no check if
the correct keywords are actually accepted or rejected since that would get
pretty exhaustive.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Add flags to enable IEEE1800-2017 and IEEE1800-2023 languages generations
and also support them in the `begin_keywords macro. Since neither defines
new keywords they'll use the same keyword mask as 2012.
Update the driver, compiler, documentation and regression test harness so
-g2017 and -g2023 are recognized as language generation flags.
There are no specific features from these versions added yet, this is just
the necessary infrastructure to allow gating new features from those
generations when they are added later.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A few JSON regression test entries reference the wrong source or gold
files. There are also two regress-vvp list entries that reference each
other's JSON file.
Use the matching source and gold files for those entries.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The sv_mixed_assign2 JSON entry accidentally references
sv_mixed_assign1.v. Point it at sv_mixed_assign2.v instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that class objects, dynamic arrays, queues, strings and static
unpacked arrays can not be used as l-value concatenation operands. Check
procedural and continuous assignment concatenations, including single
operand concatenations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
L-value concatenation operands must be packed values. Using an unpacked
array, string, class object or other non-packed value as an operand can
reach later assignment code with an invalid l-value representation.
Check the operand type after l-value elaboration and report an
elaboration error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`%cmp/e` and `%cmp/u` are very similar with `%cmp/e` not setting the lt
flag and being a bit faster due to it. For case comparisons the flag is not
needed so switch to `%cmp/e`. This speeds up simulation time designs which
make use of case comparisons.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parser union still has a few fields that are not used by any
grammar rule. They do not have matching semantic type tags and no
action references them.
Remove the unused fields.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It uses a dedicated LIBVVP_SOVERSION specified in onfigure.ac
for the SONAME and full library version.
For linking, a pkg-config file is generated, and when building on
Windows, an import library is created that can be used with both
GCC and MSVC compilers.
On non-Windows platforms, all object files are compiled with -fPIC
to ensure compatibility with shared libraries.
On Windows use 'lib' prefix for library name with MinGW compiler
only. Other compiler like MSVC normally are not using any library
prefix.
With this commit the build rules for the vpp executable has been
cleaned too because the complex structure of the manually created
Makefile.in made it very difficult to extract specific parts of
them.
The `super` keyword refers to the parent class of the current class. If the
class has no parent the lookup still returned the current class handle and left
the `super` path component for l-value elaboration. This triggered the
`tail_path.empty()` assert.
Report an error during symbol lookup instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the compiler reports an error for `posedge`, `negedge` and `edge`
event controls on named events. Edge controls can not be used with named
events.
There is already an existing test that checks both `posedge` and `negedge`.
Split it into separate tests so that each invalid event control is checked
independently.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Using an edge control with a named event is invalid. The existing elaboration
code already reports an error for `posedge` and `negedge`, but the `edge` case
falls through to the default path and triggers an assert.
Handle `PEEvent::EDGE` like the other edge-control cases and report the same
kind of error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
- change documentation theme from `alabaster` to `shibuya`
- add pinned Documentation requirements for `sphinx` and `shibuya`
- update workflows to create `.venv` and install with `requirements.txt`
- ignore common virtual environment directories (`.conda` and `.venv`)
Since this file, just like 'config.h', is generated by autoconf,
it should only be deleted in the `distclean` target.
Also since the project does not currently use automake, manual
maintenance of the timestamp file for 'version_base.h' is required.
Fixup for commit 10b5f70e7 from #1331
Array indices must be integral expressions. Using a real valued expression
as an unpacked array index currently reaches the vvp real expression code
and triggers an assert.
Packed bit and part select indices already report an elaboration error for
real expressions since commit 2249d224de ("Bit/part selects cannot have
real index expressions"). Do the same for unpacked array indices.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
here are two separate paths `PENewArray::elaborate_expr()`, one for
assignment patterns and one for everything else.
But since since commit 5ca058bfb ("Add support for darray initialisation
from another darray"). The two paths have been effectively the same.
Both call `elaborate_expr()` on the init values with the same parameters.
The only difference is the regular path casts the type to `netarray_t`, but
that doesn't really do anything since it gets passed to a function that
takes a `ivl_type_t`, so is immediately cast back to the base type.
The comment on the regular path is also outdated since it still refers to
the tpre 5ca058bfb code.
Remove the branching and route it through the same path.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`PEIdent::test_width_parameter_()` has a special case for
`NetEConstEnum` that queries the enum base type directly. This was needed
when enum constants kept their enum type separately from the `NetExpr`
type.
Commit f63a162329 ("Provide data type for more NetExpr subclasses") made
`NetEConstEnum` attach the enum type to the `NetExpr`. The generic
parameter width path now gets the same type, width and signedness as the
special case.
Remove the redundant special case and use the common path for enum
constants as well.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that package variables can use explicit static lifetime. Check that
automatic lifetime is rejected for package variables.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LRM allows to add a lifetime specified for variables declared in
package scope. It is not particular useful since only static lifetime is
allowed. But it is legal syntax, so support it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The vvp reduction operators evaluate their input bit by bit. This is
expensive for wide vectors.
Add word wide reduction helpers to `vvp_vector4_t` and use them for both
reduction functors and vthread reduction opcodes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that string literals can be assigned to byte arrays. Check that
invalid target array types are reported as errors.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The logic functors combine their input vectors bit by bit.
Use the in-place `vvp_vector4_t` operators for the vector operation and
invert the result once for the inverted functors.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The vthread binary logic opcodes update vectors bit by bit.
Use the in-place `vvp_vector4_t` operators instead. This reuses the word
wide implementation and avoids per-bit `value()` and `set_bit()` calls.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`vvp_vector4_t` has word wide in-place operators for and and or, but not
for xor.
Add `operator ^=` using the same internal word representation.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog defines a special case that allows to assign string literals
to byte arrays. Each character of the string is copied to 1 element of the
byte array.
The size of string literal and the byte array does not have to match. If
the string literal is longer it is truncated. If it is shorter it will be
padded with null-bytes.
The assignment is done left aligned, the first character ends up in the
left most entry of the array. This means the order will differ whether the
array is declared with ascending or descending element order.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Output port expressions must support continuous assignment. Assignment
patterns for unpacked array output ports are currently elaborated as
temporary arrays and the connection is silently discarded.
Report an error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that drive strength can be specified between the net type and the
data type in a net declaration and that vector gate arrays resolve
strengths correctly.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The drive strength of a net must be declared between the net type and the data type. E.g.
wire (weak0, strong1) [7:0] x;
The current implementation expects the drive strength after the data type. Update the parser to fix this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This change standardizes the creation of iverilog-vpi-related
targets, which now follow the same pattern as the iverilog targets
in the 'driver' subdirectory.
Replace .github/test.sh with a unified set of targets installed
via `make check-*` in ivtest/, thereby removing CI-specific test
coordination. This avoids duplication in the regression logic and
ensures consistent execution between local and CI environments.
PLI1-dependent tests are now correctly controlled via
`configure --enable-libveriuser`.
Currently, the regression suite still depends on an iverilog package,
which must be installed manually at the location specified with
`configure --prefix=*`. Afterward, the complete regression suite
(VVP, VPI, and Python tests) can be run via `make check-installed`
and individual checks can be run with `check-installed-vpi`,
`check-installed-vvp` and `check-installed-vvp-py`.
When running `make check` on a UNIX-like operating system
with the specified `configure` option, `vvp` was unable to
find the required shared library.
This commit ensures that the runtime linker can locate the library.
This fixes issue #1313.
macro_start_args() inserts a null string for arg 0 at the start of def_buf.
This allows macro_finish_arg() to calculate the length of the first actual
argument (arg 1). But macro_start_args() relied on def_buf having already
been allocated, which isn't the case when all the macros are pre-defined.
This fixes issue #1323.
driver/main.c uses _NSGetExecutablePath in the __APPLE__ code path
but does not include the header that declares it, causing a build
failure on macOS.
Signed-off-by: Huang Rui <vowstar@gmail.com>
The new option allows parameter, net and events to be used before
declaration. With variants
-gno-strict-net-declaration for nets and events,
-gno-strict-parameter-declaration for parameters.
With `-ggno-strict-parameter-declaration` a warning is issued for
parameter use before declaration. This warning suppressed with
the new class `-Wno-declaration-after-use`, instead of `-Wno-anachronisms`.
The standards requires that parameters must be declared
before they are used. Using -gno-strict-parameter-declaration
will allow using a parameter before declaration, e.g., in a port
declaration, with the parameter declared in the body of the
module. Prior to version 13 this was allowed, so there is a large body
of existing code depending on the pre version 13 behaviour.
The vvp/ivl_dlfcn.h and cadpli/ivl_dlfcn.h files are essentially the
same, but have diverged a bit over the years. Merge them into a single
shared file at the top level. Use the static prefix for all inline
functins (currently only used in the cadpli version) as that will fix
issue #1301. We now require the compiler to support at least C99, so
can use "inline", not "__inline__".
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 <michael.kupfer@fau.de>
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 <lars@metafoo.de>
Currently nested lvalues are only supported for vector typed properties.
Refactor the code to also support other types.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
`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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
`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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
`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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
`$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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
`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 <lars@metafoo.de>
Check that the file and line location is correct for errors
related to implicit named port connections.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <sean@xobs.io>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
Check that package exports are supported. Also check for various scenarios
where package exports should fail.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
Check that an error is reported when accessing a hierarchical identifier
through a package scoped identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
Check that an error is reported when trying to access an imported
identifier through a hierarchical name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
Make sure the package scope is considered when elaborating identifiers for
continuous unpacked array assignments.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
`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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
Check that variables used in void functions contribute to the sensitivity
list in a always_comb block.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
msys2 removed the gperf package from the base-devel package collection[1].
Add gperf explicitly to the dependency list, without this the Windows
CI will fail.
[1] 085698dce3
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
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 <lars@metafoo.de>
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 <lars@metafoo.de>
Check that it is possible to use the `super` keyword to access properties
and methods of the base class that exist with the same name in current
class.
Also check that `this.super` is supported as an alternative to `super` and
has the same behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to use either `super` or `this.super` to access the
base class. Both have the same behavior. Currently only `super` is
supported, also add support for `this.super`.
To support it the parser has to be changed slightly and move the trailing
`.` after the `this` or `super` keywords into the `implicit_class_handle`
parser rule. This is necessary to avoid reduce conflicts in the grammar.
As a side effect `super` can no longer be used as a standalone identifier.
E.g. `return super;` But that's not legal SystemVerilog anyway, so that is
OK.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to use the `super` keyword to access properties and
methods of a base class. This is useful if there is for example an
identifier with the same name in the current class as in the base class and
the code wants to access the base class identifier.
To support this a bit of refactoring is required. Currently properties are
internally referenced by name, this does not work if there are multiple
properties of the same. Instead reference properties always by index.
In addition when looking up an identifier that resolves to an object return
both the type and the object itself. This is necessary since both `this`
and `super` resolve to the same object, but each with a different type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Internally the special THIS_TOKEN("@") and SUPER_TOKEN("#") are used
to represent the special `this` and `super` keywords in a component
name.
When printing an identifier replace the tokens with their keywords.
This generates nicer error and debug messages.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The PEIdent elaborate_expr() and elaborate_lval() are sort of open-coding
the path traversal implemented by the new symbol_search() using the old
symbol_search().
Switch them over to use the new symbol search as it is better at handling
the corner cases and is also less code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
One variant did, the other variant didn't. As well as being a trap for
the unwary, this gets in the way of using yywarn/VLwarn for non-fatal
"sorry" messages.
The function prototypes both use the name VLwarn, with a macro definition
providing the alias to yywarn. But one of the variant implementations was
named yywarn. Make it consistent with the function prototype.
Always prefix with "error: ". Capitalise the first word of the main
message unless it's a Verilog keyword. Use VLerror() in preference
to direct output to cerr.
Check that typed constructors calls are supported. Also check various
invalid usages of typed constructor calls and check that an error is
reported.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
By default when creating a new class object the type of the object is
determined by the type of the target.
SystemVerilog also allows to explicitly specify the type of the object to
be created. The specified class still needs to be assignment compatible
with the target. This is e.g. useful to construct an object of a derived
class of the target. E.g.
```
class B; ... endclass
class C extends B; ... endclass
B b;
b = C::new;
```
Add support for this to the parser as well as handling it during
elaboration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Class methods with static lifetime are not allowed in SystemVerilog. Report
an error when such a method is declared.
Note that this is different from static class methods
E.g.
```
class C;
task static t; endtask // Class method with static lifetime, forbidden
static task t; endtask // Static class method, allowed
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Up to 1800-2017 the grammar in the LRM allowed an optional lifetime
qualifier for class declarations. Icarus supports this and uses this as the
default lifetime for methods of the class. But the LRM never specified what
this qualifier should do actually actually. Starting with 1800-2023 the
qualifier will be removed from the grammar[1].
Furthermore the LRM states that methods of a class are supposed to have
automatic storage and static storage is forbidden.
This currently works in Icarus for the most part since the liftime attached
to class methods is ignored during elaboration in most places. Where it
does not work is for variable initializers where it results in broken code
being generated and vvp crashes at runtime. E.g.
```
class C;
task t;
int x = 10;
endtask
endclass
```
Keep the optional lifetime qualifier for classes in the grammar for now, to
ensure backwards compatibility in case somebody is actually using it. But
ignore it and print a warning if it is specified.
In addition set the default lifetime for all classes to automatic. This
makes sure that variable initialization in classes works as expected.
[1] https://accellera.mantishub.io/view.php?id=3561
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Normally the preprocessor will catch these and report them as undefined
macros. But in case the compiler is run without the preprocessor, also
catch them in the compiler scanner. This will ensure the scanner properly
rejects directives that have additional garbage characters tacked on the
end.
Verilog compiler directives are free-form and, subject to semantic rules,
can appear anywhere in the source code. Whilst it is common practice to
write them on a separate line, we should handle all legal syntax.
Clean up warnings that show up on newer compilers. Many of these warnings
are related to obsolete c library features or language features. This does
not clear up warnings in code generated by bison or flex.
It was common practice in the past to just declare a port direction
and declare it as a vector in a subsequent type declaration. Versions
of the standard up to and including 1364-2005 include an example that
does this (e.g. 1364-2005 section 12.3.7). Users may have old or
third-party code that they can't or don't want to modify, so allow
the warning to be suppressed by including it in the anachronisms
category.
Check various different scenarios for array compatibility in continuous
array assign. Both testing cases that should work and cases that should
fail.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently there is no error checking for continuous assignments to unpacked
arrays. If the lvalue and rvalue net are not compatible undefined behavior
occurs. For some types of incompatibility it will crash during elaboration,
for others it will crash during simulation, and for some it will just work,
even though the assignment is not allowed by the standard.
Implement checking to ensure the two nets are compatible as required by the
standard and report an error otherwise.
Two arrays are considered to be compatible if their element types are
equivalent, they have the same number of ranges and each range has the same
number of elements.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to assign an object to another object that is of
a type of any of its base classes. Also check that an error is reported if
this is not the case.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows objects to be assigned to a variable that is a base
type of the objects type.
E.g.
```
class B; endclass
Class C extends B; endclass
C c = new
B b = c;
```
Add a type_compatibility() method for netclass_t that allows these kinds of
assignments.
This already works fine in vvp since, as SystemVerilog does not support
multiple inheritance, properties will always be at the same offset in the
base class and the inheriting class.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to use a function with a return type as a
statement by using a void cast.
Also check that trying to void cast a void function, a task or an
expression results in an error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog has explicit support for calling a function
as a statement. This is allowed when the function call is encapsulated in
`void'(...)`. E.g. `void'(f(1, 2, 3));`
We already support calling function calls as statements without the void
cast and emit a warning when doing so.
Adding support for void casts only requires to update the parser to handle
the void cast and then do not emit the warning if a function is called as
a statement as part of a void cast.
Void casting a task or void function call is not allowed and will generate
an elaboration error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When calling non-void functions or non-void methods of built-in types as a
task a warning is issued. But when calling a non-void method of a user
defined class as a task an error is generated.
Be consistent here and generate a warning in both cases.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Unpacked array dimensions that are specified with only a single size value
(C-style unpacked arrays) have a $left of 0 and a $right of size - 1. E.g.
`x[10]` is equivalent to `x[0:9]`. This is defined in the LRM (1800-2017)
section 7.4.2 ("Unpacked arrays").
Currently it is implemented the other way around. There are a few contexts
where this distinction matters. For example array to array assignments,
which are supposed to be done left-to-right.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that an error is reported when either calling a task or a void
function as part of an expression.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Calling a task as part of an expression should report an error. The current
implementation uses `func_def()` and if that returns nullptr will report
the error. But `func_def()` will trigger an assert if the underlying scope
is not a function.
Make sure to first check that the scope is actually a function before
trying to call `func_def()`. If the scope is not a function report an
error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Unlike normal functions void functions can not be called as part of an
expression. Trying so will currently hit an internal assert.
Make sure an error is reported instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is not allowed to create objects of virtual classes. Currently the
virtual keyword is accepted by the parser, but otherwise ignored.
Keep track of whether a class is virtual and generate an error when the
class new operator is used for a virtual type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a sign, width or type cast expression that contains an automatic
term is detected as such and can not be used as the left-hand side in a
procedural continuous assignment.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
If the base expression of a cast expression has an automatic term then the
cast expression itself has an automatic term.
Make sure this is implemented so that an error is properly reported when
using such an expression in a context where automatic variables are not
allowed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
With the recent refactorings pform_make_task_ports_vec() and
do_make_task_ports() are now very similar.
Consolidate them into a single function.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The ivl_variable_type_t in PWire is now only used for passing the base type
for vector types to the elaboration stage. But we can query the base the
from the vector_type_t itself. If the there is no data_type_t set for the
PWire the base type will default to IVL_VT_LOGIC.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For loops may have empty initialization statements. In that case some things
can't be done, such as loop unrolling or synthesis, but otherwise it is a
valid thing to do. So generate the correct code in this case.
Check that it is possible to use a packed scope type identifier for the
type of a class property when the class is defined in the unit scope. This
makes sure that the elaboration is done in an order so that the type is
available when the class property is elaborated.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to use a forward declared class type as the type
of a property in another class.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Elaborating uses a multi stage approach. Currently non-static class
properties are elaborated during the scope elaboration phase. This can
cause problems if the type of a property is declared in a different scope.
In that case it is possible that the scope in which the type is defined has
not been elaborated yet and the type is not available. E.g.
```
package P;
typedef int T;
endpackage
class C;
P::T x;
endclass
```
Another area where this is problematic is when a class has a property of a
another class that has a forward declaration. In this case the type of the
forward declared class, which is created when the scope is elaborated, is
not available when the scope of the class that is using it is elaborated.
E.g.
```
typedef class B;
class A;
B b;
endclass
class B;
endclass
```
To avoid this elaborate the properties during the signal elaboration phase.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to skip dimensions in a foreach loop by not specifying
an identifier name for the dimensions. E.g. the following will iterate over
the first and last dimensions, but skip the middle dimension.
```
int x[1][2][3];
foreach(x[a,,b]) ...
```
Add support for this to the parser as well as elaboration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently when the number of loop variables in a foreach loop is larger
than the number of array dimensions an assertion is triggered.
Turn this into a error message instead for graceful error reporting.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog supports type parameters. These are similar to value
parameters, but they allow to pass a type to a module or similar when
instantiating it.
E.g.
```
module A #(parameter type T = int);
endmodule
module B;
A #(.T(real)) i_a;
endmodule
```
Add support for handling type parameters.
For the vlog95 and vhdl backends type parameters, similar to typedefs, get
replaced with their actual value. For modules with non-local type
parameters for each module instance a unique module or architecture is
generated with the actual type.
Querying type parameters through VPI is not yet supported.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Rather than moving one item at a time form the elaboration_work_list to the
temporary queue use std::swap to exchange them all at once. This is a bit
more efficient.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that all sorts of forward typedefs are supported.
Also check that any recursive use of a type results in an error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog supports forward type declarations. This allows to declare a
type identifier and use it, e.g. in a signal declaration, before declaring
what the actual type is. The type still needs to be fully defined
eventually in the same scope as its forward type declaration. E.g.
```
typedef T;
T x;
typedef int T;
```
The forward type definition can also contain the kind of the type it is
going to be. E.g struct, union, class, etc. The LRM calls this the basic
type. If the actual type is not of the basic type specified in the forward
type declaration this is an error. E.g.
```
typedef struct T;
typedef int T; // Error, int is not a struct
```
It is legal to have more than one forward type declaration for the same
type name, as long as the basic type is the compatible. It is even legal to
have a forward type declaration after the actual type has already been
declared. E.g.
```
typedef T;
typedef int T;
typedef T;
```
Implement support for forward type definitions as part of the new
typedef_t. The basic type will be attached to the typedef_t.
The compatibility of the basic type for multiple forward type declarations
will be checked in the parser. The compatibility of the basic type to the
actual type will be checked during elaboration, once the actual type is
known.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Enum types are currently elaborated in lexical declaration order. With forward
typedefs it is possible that a type is referenced before it is declared.
To support this elaborate the enum type on demand when it is used. This is
similar to what is being done for other types.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
With forward type declarations it is possible to create a circular type
definition where a type resolves to itself. E.g.
```
typedef T1;
typedef T1 T2;
typedef T2 T1;
```
Flag a type as elaborating when elaboration of the type is started and
clear it when elaboration finishes. If the elaboration function is entered
again while the flag is still set a circular type has been detected and an
error is reported.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently typedefs are just a pointer to a data_type_t.
Currently typedefs are implemented by setting the name field of a
data_type_t when a typedef of the type is declared. This works mostly, but
there are some corner cases that can't be supported.
E.g. a typedef of a typedef does not work as it overwrites the name field
of the same data_type_t multiple times.
Forward typedefs can also not be supported since forward typedefs allow to
reference a type before it has been declared.
There are also some problems with type identifier references from a
higher-level scope if there is a type identifier in the current scope with
the same name, but it is declared after the type identifier has been
referenced. E.g. in the following x should be a vector fo width 8, but it
will be a vector of width 4, because while the right type is used it is
elaborated in the wrong scope.
```
localparam A = 8;
typedef logic [A-1:0] T;
module M;
localparam A = 4;
T x;
typedef int T;
endmodule
```
Furthermore typedefs used for the type of ports are elaborated in the wrong
scope.
To handle these corner case issues introduce a data_type_t for typedefs.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that compressed assignment statements are supported for genvar loops.
This is supported in SystemVerilog, but not in Verilog.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog supports using compressed assignment operators for the genvar
for loop variable update.
Add support for this in a similar way as increment/decrement operators by
transforming the statement to its uncompressed equivalent. E.g. `x += y`
gets transformed to `x = x + y`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that $signed/$unsigned works when being combinatorially assigned with a
delay and the target of the function is a net without any drivers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Trying to add a drive strength or delay to a undriven net will result in an
assertion. Make sure that a driver is added to undriven nets.
A driver is already added for all NetESignals, which covers most expression that
can produce a raw net rvalue. But there are other ways we can end up with just a
net as the rvalue, e.g. when applying a sign cast to a net. The following
example triggers the issue
```
wire [7:0] a;
wire [7:0] b = $signed(a);
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
macro_start_args truncates def_buf, but does not check to ensure that
someone has allocated def_buf first. This will cause a null pointer
dereference if the first access to def_buf while parsing a file is a
macro invocation. Fix this by avoiding truncating def_buf if it is NULL,
as it is effectively already truncated.
Fixes: 680196953 ("Add support for text macros with arguments.")
Signed-off-by: Sean Anderson <seanga2@gmail.com>
Check that it is possible to have scoped reference to a type identifier in
a package.
* As part of variable declarations
* As an argument to a system function
* As the type in a type cast
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that for a module port with a vector type identifier the type is
elaborated in the scope where it is declared rather than the scope of the
module port.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently when referencing a typedef this gets replaced with the
`data_type_t` that the typedef points to. This works for most cases, but
there are some corner cases where it breaks down.
E.g. it is possible to have a scoped type identifier which references a
type defined in a package. For such type identifiers, only the data_type_t
itself is remembered, but not the package scope. This will cause the type
identifier to be elaborated in the wrong scope.
Furthermore type identifiers of vector types used for module or task port
might not be elaborated in the correct scope.
Introduce a new `typeref_t` which has `data_type_t` as a base type and can
be used as the data type for a signal. A new instance of a `typeref_t` is
created when referencing a type identifier. The `typeref_t` remembers both
the data type and the scope of the type identifier.
When elaborating the `typeref_t` the elaboration is passed through to the
referenced `data_type_t`. But special care is taken to lookup the right
scope first.
With the new approach also typedefs of typedefs are supported. This
previously did not work because chained typedefs all reference the same
`data_type_t`, but each typedef sets the `name` field of the `data_type_t`.
So the second typedef overwrites the first typedef and a lookup of the
scope of the first typedef by name will fail as it will return the scope of
the second typedef.
This refactoring also allows to define clear ownership of a data_type_t
instance. This e.g. means that an array type owns its base type and the
base type can be freed when the array type itself is freed. The same is
true for signals and class properties, they now own their data type and the
data type can be freed when the signal or property is freed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The current class end label parser rule gets the data type from the
TYPE_IDENTIFIER, casts that to a class_type_t and gets the name from that.
This code was written when the TYPE_IDENTIFIER only provided the data type.
But these days it provides both the data type and the name. Simplify the
code to get the name directly from the TYPE_IDENTIIFER.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There is compatibility code that defines unique_ptr as auto_ptr if the C++
version is before C++11.
But there are already other parts of the codebase that do require C++11 and
the minimum required version to build the project is C++11. So remove the
compat code as it is no longer needed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are C++11 constructs in Icarus at the moment and the plan is to
retain C++11 compatibility until more modern versions are widely available
in the default installation of systems.
Pass `-std=c++11` to the compile to enforce building with C++11, this will
make sure that neither an older nor a newer version is used. E.g. compilers
on some platforms still default to an earlier version of C++11.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to call a void function from a class method.
Check this for both functions defined in the global scope as well as
functions that are methods of the class or a base class.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Calling a void function (or a regular function and ignoring the result)
from within a class method will currently result in an error unless the
void function itself is a method of the same class.
This is because we add the implicit `this` as an object on which to search
for the function and if we do not find it print an error. Change this to
only print an error if the implicit this was not added and it was a method
call on an object identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check for various dynamic array and queue types that their type
compatibility is handled correctly.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Icarus allows to pass a value of the element type as an argument to the
dynamic new operator. To allow this the type compatibility check for
dynamic arrays allows both the dynamic array type itself and also the
element type.
This currently leads to a confusing error message if neither type matches.
The error message will say that the passed value is not compatible with the
element type. E.g.
```
real d1[];
int d2[];
d1 = d2;
```
results in
```
error: the type of the variable 'd2' doesn't match the context type.
: variable type=dynamic array of netvector_t:bool signed[31:0]
: context type=real
```
This is slightly confusing. Change the way the error message is reported so
that the context type is the type of the dynamic array and not the element.
With the change the above results in
```
error: the type of the variable 'd2' doesn't match the context type.
: variable type=dynamic array of netvector_t:bool signed[31:0]
: context type=dynamic array of real
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog defines different levels of type compatibility.
* Matching
* Equivalent
* Assignment compatible
* Cast compatible
At the moment the `nettype_t` has only one type compatibility test. It is
used to check assignment compatibility when assigning to a dynamic array,
queue or class.
The current implementation rejects a few cases that should allowed and
allows a few cases that should be rejected.
Dynamic arrays and queues are assignment compatible if their element types
are compatible. And two packed types are equivalent if they are both
2-state or 4-state, both signed or unsigned and have the same packed with.
In the current implementation the sign is not considered and instead of
checking if the packed width is the same it checks that the dimensions are
identical.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `netdarray_t` type implements the `packed_width()` method by returning
the packed width of the element type. It is the only non-packed type that
implements the method.
This triggers an assert in the vlog95 backend for tasks with dynamic array
typed parameters. And while the vlog95 backend does not support dynamic
array types it should not result in a crash, just an error message.
The only place that relies on the behavior that the packed width of the
element type is returned is in the vvp backend where variable declarations
are generated. Update that code to query the packed width of the element
type instead and then remove the `packed_width()` implementation for the
`netdarray_t` type.
This fixes the assert in the vlog95 backend. But it is also nicer from an
architectural perspective as this brings the type in line with the other
types in terms of behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The C++ API for `ivl_type_t` has a method to query the total width of a
packed type. This is currently not exported to the C API and the tgt-vvp
backend implements similar functionality by querying the individual
dimensions of a type.
Export the `packed_width()` method to the C API. This allows to remove the
custom implementation from the tgt-vvp backend.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Current regression tests only cover checking for invalid non-blocking
writes to constructs that are valid in Verilog. Add two tests to
additionally cover some SystemVerilog constructs.
* Non-blocking writes to members of a struct typed variable with automatic
lifetime
* Non-blocking writes to class typed variables with automatic lifetime
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `PEIdent::has_aa_term()` method still uses the old `symbol_search()`
and will fail to find the variable if part of the identifier path is a
member select of a variable.
As a result such writes to fields of automatic structs can be classified as
static and it is possible to do non-blocking assignments to them. E.g.
```
task automatic t;
struct packed {
logic x;
} s;
s <= ...; // This fails
s.x <= ...; // This works, but should fail
endtask
```
Switch to the new symbol search to make sure this case is handled
correctly. The new symbol search will correctly handle identifier paths
that have a trailing item after the variable, while the old symbol search
will always return an error in that case.
Note that while it is not allowed to do a non-blocking write to a class
object automatic variable, it is allowed to do a non-blocking write to a
property of a class object that is stored in an automatic variable, as the
non-blocking write is supposed to capture a reference to the object and not
reference the variable. E.g.
```
class C;
int x;
endclass
task automatic t;
C c;
c <= ...; // Not allowed
c.x <= ...; // Allowed
endtask
```
Non-blocking access to class properties is not yet support in
Icarus in general, but the error handling for that needs to be done
somewhere else.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that default values for class methods are handled correctly and it is
possible to omit any argument. Check it for both functions and tasks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For class function method calls currently only as many arguments as have
been supplied are elaborated. Any trailing arguments that might have default
values are skipped. This will trigger an assertion later on in the vvp code
generator backend.
Fix this by making sure that all arguments of the function are evaluated.
Note that this already works correctly for class task method calls.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to reference a package scoped identifier that has
the same name as a local identifier, but is a different kind of identifier.
* A variable or function identifier from a package scope if it is a
type identifier in the current scope
* A type identifier from a package scope if it is a non-type identifier
in the current scope
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In order to avoid conflicts in the grammar the lexer distinguishes between
identifiers and type identifiers. To correctly classify an identifier the
lexer needs to know in which scope a token is parsed. E.g. when the parser
encounters a package scope operator it calls `lex_in_package_scope()` to tell
the lexer which scope the following identifier should be classified in.
Currently the `lex_in_package_scope()` is only used when a type identifiers
is parsed, but on for normal identifiers. As a result it is not possible to
reference variables or function from a package scope that have the same
name as a type identifier in the current scope. E.g.
```
package P;
int T;
endpackage
module test;
typedef int T;
initial $display(P::T);
endmodule
```
Another problem is that in expressions both type identifiers and signal
identifiers can be referenced. As a result there are two rules in an
expression that can be reduced
* <PACKAGE_TYPE> :: <TYPE_IDENTIFIER>
* <PACKAGE_TYPE> :: <IDENTIFIER>
The way the rules are formulated at the moment the parser has to use token
lookahead to decide which rule to follow before it can reduce the package
scope operator. As a result the lexer detects the token before
lex_in_package_scope() is called and the identifier does not get evaluated
in the package scope, but in the current scope. Which can cause the
identifier to be misclassified. E.g.
```
package P;
typedef int T;
shortint X;
endpackage
module test;
typedef byte X;
initial $display($bits(P::T));
initial $display($bits(P::X));
endmodule
```
Here `P::T` gets classified as a signal identifier and `P::X` gets
classified as a type identifier.
To solve this introduce a common rule for the package scope operator. Using
the same rule everywhere allows the parser to reduce it unconditionally
without using lookahead.
Note that there are additional problems with resolving the type of a scoped
type identifiers in expressions, but this is a prerequisite to solve that.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to declare an unpacked array type with an
unpacked array type as the base type.
Also check that it is possible to declare an signal with an unpacked array
dimension with an unpacked array base type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is currently possible to declare an unpacked array with multiple
dimensions. But trying to declare an unpacked array that has another
unpacked array as a base type will result in undefined behavior. E.g.
```
typedef int T1[1:0];
typedef T1 T2[3:0];
T2 x[7:0];
```
To support this recursively unwrap the data type and add the unpacked
dimensions to the signal until the base type no longer is a unpacked array
type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that for a module port with an array type identifier the type is
elaborated in the right scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
elab_anet.cc was removed from the build in commit 4a8be3db9c ("Implement
bi-directional part selects."). But the file itself was never removed,
remove it now.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that package scope function calls work with and without arguments as
well as empty positional arguments.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parser currently only allows package scoped functions to be called if
there is at least one argument. But package scoped functions are the same
as normal functions and it is allowed to call them with no arguments. It is
even possible to pass no value for a positional argument, if the positional
argument has a default value.
Update the parser to handle this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For function calls when calling the PECallFunction() constructor a copy is
made of the argument expression list. This means the original list should
be deleted within the rule.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
If the type of a port is an array type it currently always gets evaluated
in the scope where the port is declared.
But if the type is a typedef it might be declared in a different scope and
must be evaluated in that scope. E.g. the following will declare an array
port with 10 entries and an element type of a 5 bit vector, while it should
declare one with 4 entries and an element type of a 2 bit vector.
```
localparam A = 2;
localparam B = 4;
typedef [A-1:0] T[B];
module test (
T x
);
localparam A = 5;
localparam B = 10;
endmodule
```
This is in part due to array types being given special handling. This was
necessary before because each base type required slightly different
handling and so the base type had to be extracted from the array type.
This has now been consolidated and all data types are treated the same.
The only exception is the vector type which still needs special handling to
support separate definition of port direction and type.
As a result it is possible to remove the special handling of the array
type. This solves the problem of evaluating the type in the wrong scope.
Some special handling needs to be retained though to be able to
differentiate between array dimensions that are part of a type and array
dimensions that are part of port declaration. This is again necessary to
correctly support separate definition of port direction and type. E.g. in
the example below port `x` and `y` get treated slightly differently, even
though the resulting signals will be identical.
```
typedef logic [7:0] T[1:0];
...
input T x;
input [7:0] y[1:0];
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to copy empty dynamic arrays and queues.
If the target is a dynamic arrays there are two ways of copying. Through
direct assignment as well as the array new operator.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
An empty dynamic array or queue is represented by a null object in vvp.
Currently when trying to copy such an object results in undefined behavior
in various places. Either hitting an assert or causing a nullptr
dereference.
Make sure that the empty object is handled correctly by treating it as a
special case.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There is nothing special to do for return class objects from a function.
They can be handled the same as other objects such as dynamic arrays and
queues.
But there currently is an assert in the code that handles function calls
assigned to objects that will trigger if the target type is not an queue or
dynamic array.
This is because Icarus allows dynamic arrays to be initialized with a
single value and for that the element with of the dynamic array needs to be
known, so the single value expression can be evaluated correctly.
Since classes can not be initialized from vector expressions the width does
not matter in that case.
Update the code to only query the element width if the target type is an
dynamic array or queue and pass a placeholder value of 1 for the width
otherwise.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For modules with parameters the vlog95 backend generates one module
declaration for each module instance. This is done so that different values
for the module parameters can be supported.
Local parameters are guaranteed to have the same value for all module
instances though. Add support for detecting the case that all module
parameters are local parameters and in that case only create one shared
module declaration. This is similar to what the vhdl backend does.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
We differentiate between local and non-overridable parameters
in the frontend to be able to generate better error messages.
For the backend they should both be considered local parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a packed struct or union with an unpacked array, dynamic array
or queue as a member is detected as an error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Unpacked dimensions for struct or union members are currently silently
discarded. E.g.
```
struct packed { int x[2]; } s;
```
will elaborate successfully as a struct with a non-array int typed field.
This should instead elaborate to an unpacked array of ints typed field. And
subsequently, since unpacked arrays are not allowed in a packed struct or
union, result in an error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The figure_packed_base_type() method can be used to check whether a type is
2-state or 4-state at parse time. The parser no longer cares about the
specific type of a data type. The figure_packed_base_type() function is
no longer used, so remove it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Packed arrays are only allowed of packed base types. Currently whether the
base type is packed is checked before elaborating the base type.
This works as long as the actual type is known before elaboration. But for
example with type parameters the actual type is only known after
elaboration. In order to be able to support type parameters move the check
for whether the type is packed after elaboration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parser used to have behavior that was dependent on the
`ivl_variable_type_t` of a signal. It also used the `ivl_variable_type_t`
of a signal to decide whether a signal can be re-declared as part of a
non-ANSI port declaration.
Neither of these is done anymore and most of the reference to
`ivl_variable_type_t` can be removed from the parser. The only thing it is
still needed for is to decide whether a vector type is 4-state or 2-state.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`pform_make_task_ports()` has code very similar to `pform_set_net_range()`.
Use that helper function instead of duplicating the code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
pform_module_define_port() has code very similar to `pform_set_net_range()`.
Use that helper function instead of duplicating the code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Now that pform_set_range() is only used for vector types pass the
vector_type_t as an argument rather than deconstructing the type into range
and signedness.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that all kinds of invalid repeated task port declarations are
detected as errors. They should not crash the application nor should they
result in successful elaboration.
The tests are created for corner cases that previously resulted in
incorrect behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that all kinds of invalid module port declarations, where the
declaration conflicts with previous declarations, are detected as errors.
They should not crash the application nor should they result in successful
elaboration.
The tests are created for corner cases that previously resulted in
incorrect behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that when port direction and data type are declared separately that
an error is reported if the port direction has an explicit range
specification, but the data type has not. This should even be the case if
the data type has an implicit range, e.g `int` or a struct type.
For vector types also check that it is an error if the ranges are not
identical.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that when port direction and data type are declared separately that
an error is reported if the port direction has an explicit range
specification, but the data type has not. This should even be the case if
the data type has an implicit range, e.g `int` or a struct type.
For vector types also check that it is an error if the ranges are not
identical.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
(System)Verilog allows to declare the port direction separate from the
signal declaration. E.g.
```
output x;
integer x;
```
But this is only allowed if the port declaration
* does not have an explicit net type
* does not have an explicit data type
* is a non-ANSI style declaration
For all other cases of port declarations the signal is considered fully
defined and it is not allowed to have a separate signal declaration.
In addition the declared packed dimensions need to match between the port
and signal declaration.
In the current implementation there are a few cases where this is not
handled correctly.
1) It is possible to declare non-ANSI task ports with the same name over
and over again, if it was declared as a signal before the port.
```
task t;
string x;
input logic x;
output real x;
endtask
```
2) It is possible to re-declare non-ANSI input ports of a module that have
a data type, but no explicit net type.
```
module M;
input integer x;
wire integer x;
endmodule
```
3) It is possible to re-declare a ANSI port if it has an implicit data type.
```
module M(output [1:0] x);
reg [1:0] x;
endmodule
```
4) It is possible to declare a vector signal for a scalar non-ANSI task
port.
```
task t;
input x;
reg [7:0] x;
```
To handle all of these correctly refactor signal declaration and lookup a
bit.
The PWire class that represents a signal already has two flags `port_set_`
and `net_set_`. These flags indicate whether a signal has already been used
in a port or signal declaration. A port declaration that includes an
explicit data type is considered both a port and signal declaration.
Use these flags to decide whether it is possible to extend an existing
declaration. E.g. when creating a port without an explicit data type and a
PWire by that name already exists and the `port_set_` flag is not set
extend the existing PWire. On the other hand if the `port_set_` flag is
already set report an error.
Similar for signals but with the `net_set_` flag.
For port declarations with an explicit data type or ANSI style port
declarations it is always an error if a PWire by that name already exists.
This is for both module and task/function ports.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are some tests that use non-ANSI style task port declarations where
the port direction has no packed range specification, but the corresponding
signal declaration has as range specification.
This is not valid, the standard requires the range specification for both
to match.
These tests are currently passing because this error is not detected if the
port direction declaration is scalar.
In preparation for eventually detecting this error set the
`no-io-range-error` flag for these tests. When this flag is set the error
is downgraded to a warning.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The br_ml20150606 regression test uses ANSI style port declarations, but
also re-declares the ports inside module as signals.
This is not valid (System)Verilog, even though the data type in the port
declaration is an implicit type. An ANSI-style port is always fully
defined. This defined section 23.2.2.2 ("ANSI style list of port
declarations") of the SystemVerilog LRM (1800-2017) and section 12.3.4
("List of ports declarations") of the Verilog LRM (1364-2005).
The test was originally added in response to a similarly non-compliant test
in the Yosys test suite, but that test has subsequently been updated to
conform to the standard[2].
Remove the non-compliant test in preparation for adding strict standard
compliance checking on ANSI port redeclarations.
[1] https://sourceforge.net/p/iverilog/mailman/message/34182256/
[2] https://github.com/YosysHQ/yosys/issues/1570
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The default implementation of the virtual method `NetExpr::has_width()`
returns true. There are a few classes that directly inherit from NetExpr
that override the method with the exact same implementation. Remove these.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are no users for the `NetScope::find_enumeration_for_name()` and
`Definitons::enumeration_for_name()` methods. Remove both of them.
The last user was removed in commit 61a088fa78 ("Use elaborate_type()
infrastructure to elaborate signal types").
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The last user of the `make_range_from_width()` was removed in commit
f6042033d0 ("Correctly handle separate port type declaration for
`integer` and `time`").
Remove the function itself as well.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The last user of the `PExpr::is_the_same()` method was removed in commit
37b60a4c52 ("Clean up interface of the PWire class").
Remove the method.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that default values are support for module port lists.
* For output ports it is supported in both Verilog and SystemVerilog.
* For input ports it is only supported in SystemVerilog.
* For inout ports it is never supported
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Both Verilog (2005) and SystemVerilog support default port values for
variable output ports. SystemVerilog also supports default port values for
input ports. For port declaration lists it is possible to specify the
default value for port identifier.
E.g.
```
module M (
input integer x, y = 1,
output integer z, w = 2
) ...
```
Currently the parser only supports specifying the default value for the
first identifier in the list. Extend the parser to also allow to specify
the default value for identifiers in the list.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few places where it is possible to provide an optional
initializer in the form of `[ = <expression> ]`.
There are currently multiple rules that implement this behavior as well as
few places with duplicated rules, one with and one without the initializer.
Introduce a common helper rule for optional initializers. This allows to
remove some duplicated code from the parser.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For output port lists with a default value for the first port declaration
all subsequent port declarations are declared as inout ports. This is due
to a small typo when setting the `port_declaration_context` port direction.
Fix this to make sure all ports in the port declaration list are declared
as output ports.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that SystemVerilog sign cast are supported correctly. The regression
tests are modeled after the existing tests for $unsigned/$signed.
They check that
* Width extension is done correctly on the cast expression
* Expressions in the sign cast are evaluated as self-determined
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog supports sign cast where it is possible to change the
signedness of an expression. Syntactical it is similar to width or type
casting, except that the keywords 'signed' or 'unsigned' are used in front
of the cast operator. E.g.
```
logic [3:0] a = 4'b1000;
logic [7:0] b = signed'(a); // b is 8'b11111000;
logic signed [3:0] c = 4'b1000;
logic signed [7:0] d = unsigned'(c); // d is 8'b00001000;
```
As noted by the LRM section 6.24.1 ("Cast operator") applying a sign cast
to an expression is equivalent to calling the $signed() and $unsigned()
system functions on the expression.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the var keyword is supported in the following contexts
* Module ports (both ANSI and non-ANSI)
* Module variable declarations
* Package variable declarations
* Task and function ports
* block variable declarations
* for loop variable declarations
Also check that it is an error to use the var keyword in a for loop without
an explicit data type, as that is not allowed by the standard.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog adds the `var` keyword that can be used to declare a signal
as a variable.
In contexts where a signal is always a variable it is purely optional and
it makes no difference whether it is specified or not. This is in
* for loop variable declarations
* task and function port declarations
For variable declarations as block items when `var` is used it is possible
to omit the explicit data type and use a implicit data type instead. E.g.
all of the following are valid.
```
var x;
var signed y;
var [1:0] z;
```
For module input and output ports the `var` keyword can be used in place of
the net type. It can be combined with either an implicit or explicit data
type.
E.g.
```
input var x
output var [1:0] y
```
inout ports can not be variables and will be reported as an error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Refactor the variable lifetime parser rules so that instead of having too
rules, one with lifetime and one without, there is a single rule where the
lifetime is an optional element.
This helps to avoid a combinatorial explosion of parser rules once we
add `var` support.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the parser can recover from `integer` or `time` variable
declarations, but not for variables of other types. Refector the parser
rules so that it can recover for all variable types as well as events.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows input ports to be variables. If something is connected
to the input port it will be converted to an unresolved wire.
This is handled the same as having a continuous assignment on a
SystemVerilog varibale.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
If the parameter has no explicit type, the type is inferred from the RHS
expression. The first time the parameter is evaluated, the RHS hasn't yet
been elaborated, so the type is unknown. This causes the evaluation to be
performed by NetScope::evaluate_parameter_logic_, which correctly handles
both logic and real types. However, on subsequent evaluations of the
parameter, the expression type is now known, so the evaluation was being
performed by NetScope::evaluate_parameter_real_. This function requires
the parameter to have an explicit type.
For now, rather than add more code to NetScope::evaluate_parameter_real_
to handle an implicit type, force NetScope::evaluate_parameter_logic_ to
be used whenever we have an implicit type. This should probably be reworked
if support for more complex types is added.
Without this fix, ivlh_textio was failing at step 11 where the time is read from the file. This was because clang happens to put period directly after the units buffer on the stack. sscanf writes the terminating NUL overwriting the low byte of period, which is 100, so it returns 0.
Example clang warning fixed:
warning: 'sscanf' may overflow; destination buffer in argument 4 has size 2, but the corresponding specifier may require size 3 [-Wfortify-source]
Both the `vvp_fun_signal_real` and `vvp_fun_signal_string` classes
implement a `size()` method that returns 1. There are no users of these
methods, remove them.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Add regression tests for the following types partial writes for both
2-state and 4-state vectors.
* Non-blocking
* Blocking
* Blocking event control
Check that all in-bounds partial writes, partial out-of-bounds and
full out-of-bounds all works as expected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Writes to 2-state arrays currently only support full writes. If the write
is a partial write it will trigger an assert. E.g.
```
int a[3:0]
int i = -1;
a[i+:8] = 8'h0; // Triggers assert
```
Add support for partial writes by doing a read-modify-write in the same way
as for 4-state arrays.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%store/vec4a` instruction does not handle partial of full
out-of-bounds writes to a vector array element. Trying to do so will
trigger an assert. E.g.
```
integer a[3:0];
integer i = -10;
a[0][i+:8] = 8'h0; // Triggers assert
```
For fully out-of-bounds writes the write should be skipped, for partial
out-of-bounds writes the value needs to be resized to be within the bounds
of the vector. Use the `resize_rval_vec()` helper function to implement
this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few functions that handle implement different kinds of vector
writes that have to handle that the assigned value partially or completely
out-of-bounds.
Each function has similar, but not identical, code for this, sometimes with
small bugs for corner cases.
Add a helper function that takes care of handling of updating the width and
offset of the assigned value if necessary.
This ensure consistent and correct behavior and allow to remove some
duplicated code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%assign/vec4/a/{d,e}` instructions, when checking for a full
out-of-bounds write on the low side, uses the target signal width, while it
should use the assigned value width.
This can lead to a fully out-of-bounds write to be assumed to be a partial
out-of-bounds access, which will trigger an assert later on.
E.g.
```
integer a[1:0];
integer i = -4;
a[0][i+:4] <= 4'h0; // Triggers assert
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that multiple events can be used in a non-blocking event control
assignment. The assignment should happen if either of the events trigger.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When multiple events are used in a non-blocking event control they need to
be combined into a single event using `event/or`.
The generated `event/or` statement is missing the trailing semicolon and
newline, which results in parser error when vvp tries to run.
E.g.
```
event e, f;
integer x;
x <= @(e or f) 10;
```
Add the missing semicolon and newline to fix this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a non-blocking event control assignment works as expected to a
lvalue concatenation. All values that are part of the concatenation should
only be assigned after the event triggers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that non-blocking event control assignments works on an array part
select if the part select index is not an immediate value.
This is a copy of the nb_ec_array_pv test, but using variable indices
instead of immediate values.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A non-blocking event controlled assignment consists of 3 steps.
* Setup event
* Perform assignment
* Clear event
This works fine if the lvalue is a singular value. If the lvalue is a
concatenation multiple assignments are generated and the event is cleared
after each assignment. As a result only the first assignment is event
controlled. All other assignments will be regular non-blocking assignments.
E.g.
```
reg x, y;
event e;
{x,y} <= @e 2'b11;
$display(x, y); // x will be 1'b1, y will be 1'bx
```
To resolve this the event needs to be cleared after all assignments have
been done. This requires changes to both tgt-vvp and the vvp runtime.
tgt-vvp is updated to only insert a single `%evctl/c` instruction for each
event controlled non-blocking assignment.
The vvp runtime is not updated to implicitly clear the event in the
`%assign/vec4/e` instruction and instead rely on the explicit `%evctl/c`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
VVP array assignment operations expect the array element index to be in
index register 3.
For array element assignments with a dynamic part select the array index
gets moved into a temporary index register and has to be moved into
register 3 after evaluating the dynamic part select. This is currently not
done non-blocking event control assignments. This causes the write to go to
the wrong array element. It will go to whatever value is in the register 3
from previous operations.
```
reg [3:0] a[1:0];
integer i = 0;
event e;
a[1][i+:2] <= @e 2'b10; // Will write to the wrong array element
->e;
```
Make sure to move the temporary register to register 3.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Both the `%concati/vec4` and `%pushi/vec4` instructions need to construct a
vector from the immediate value encoded in the instruction. Currently both
these instructions have a custom implementation for that.
Remove the custom implementations from those functions and use the
`get_immediate_rval()` helper function. This removes a bit of duplicated
code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%cmp/ws` and `%cmp/wu` instructions compare two index registers. They
are currently unused. Since the index registers are not used for data there
is not really a need to compare them. Values can be compared before loading
them into an index register.
So remove these two instructions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%mov/wu` instruction moves data from one index register to another.
The instruction is not used. It also does the same as `%ix/mov`. So remove
it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `recv_vec{4,8}_pv()` functions are used to implement a partial write to
a vector. As parameters they take both the value and the width of the
value.
All callers of of these functions pass `val.size()` or a variation thereof
as the width of the value. And all implementations that do anything with
the data have an assert that `val.size() == wid`.
Remove the `wid` parameter from these functions and just use `val.size()`
directly where needed. This allows to simplify the interface and also
to remove the asserts.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that assignment operators on real array entries are supported.
Also check that
* out-of-bounds indices work as expected
* it works after a comparison that set vvp flag 4 to 0
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The basic structure for supporting assignment operators on real arrays
exists in the tgt-vvp backend. But there are a few problems, most
importantly it generates the wrong instruction for loading data from the
real array.
The instruction it uses is `%load/reala`, but that instruction does not
exist, the correct name is `%load/ar`.
In addition to this there are a few minor problems.
* Out-of-bounds access on the array triggers an assert
* Missing `%pop/real` instruction when skipping a write due to
out-of-bounds access
Address these so assignment operators are supported on real array entries.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the signedness of a struct member is properly handled when being
passed to a system function.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Access to members in packed struct fields is internally implemented using a
part select.
vvp has a special syntax for passing a part select of a vector to a system
function. This special syntax assumes that the part select is unsigned like
it is for normal Verilog part selects.
As a result passing a signed struct member to a system function will
interpret it as unsigned.
Add a check to make sure that the expression is actually unsigned. If it is
not fall back to evaluating the expression on the vector stack and pass the
value on the stack to the system function.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that an assignment operator on an out-of-bounds array element works
as expected. The out-of-bounds access should leave the array unmodified,
but the right-hand side must be evaluated regardless.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For an out-of-bounds assignment operator on an array element an assert is
hit if the element width is great than 32.
Remove the assert and make sure that this case is handled correctly by
using the `%pad/s` instruction to extended the X value to the correct
width.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
If the index of an array access is known to be out-of-bounds during
elaboration it is replaced with 'x. In the tgt-vvp backend that is handling
compressed array assignments there is an assert() that triggers if the
index is an undefined immediate.
There is already an existing code path that is capable of handling
out-of-bounds access. Remove the assert and set the index to ULONG_MAX to
trigger taking the out-of-bound access path.
On this out-of-bounds path the write to the array is skipped. But this
leaves the result on the vector stack. Insert the `%pop/vec4` instruction
to make sure it is removed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Parameters with real values are possible in Verilog, but not in the VCD
format, so lie a little and call them "real" objects. Otherwise, we can
treat them like constants and it works out, at least for gtkwave.
Check that for the following operations the load or store is not skipped
after a operation that sets vvp flag 4.
* Assignment to immediate indexed real array entry
* Assignment operator on immediate indexed vector array entry
* Assignment operator on dynamic vector part select
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The operator assignment on dynamic part selects uses the `%store/vec4`
instruction to store the value. This instruction will skip the assignment
if flag 4 is set. This is for handling the case where the index is
undefined.
Since the left hand side of the assignment is an arbitrary expression it
can change the flag. The implementation handles this by making a copy of
the flag and restoring it before executing the `%store/vec4` instruction.
The flag is set by the `%ix/vec4` instruction when loading the index
register. But the copy of the flag is made before that and just picks
up the flag that was stored by previous expressions. This can cause
the store to be skipped when it shouldn't.
E.g. in the following code the increment will be skipped. Flag 4 is used
from the `a == 0` comparison, rather than from computing the part select
index.
```
int a = 0;
if (a == 0) begin
a[a+:2] += 1;
end
$display(a); // Will print 0, should print 1
```
Fix this by moving the copy of the flag after the `%ix/vec4` instruction.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The vvp `%load/vec4a` instruction will skip the load if vvp flag 4 is set
and return 'x. This is meant for handling the case where the index is
undefined.
For assignment operators on array entries, when the index is an immediate
value, vvp flag 4 is not cleared before the load instruction. If a previous
instruction set flag 4 it load yield 'x.
E.g. for the following sequence `x[0]` should be `11`, but will be `'x`.
```
integer x[10];
logic a = 1'b0;
x[0] = 10;
if (a == 0) begin
x[0] += 1;
end
```
Properly clear the flag before the load instruction to handle this
correctly.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When assigning a value to a real typed array entry the vvp `%store/reala`
instruction. This instruction will skip the store if the vvp flag 4 is set.
This is to handle the case where the index is undefined.
When the index into the array is an immediate value the flag 4 is not
cleared. If a previous instruction set flag 4 the store will be skipped.
E.g. for the following r[0] will remain 0.0 since the assignment to it is
skipped.
```
integer a = 0;
real r[1:0];
if (a == 0) begin
r[0] = 1.23;
end
```
Fix this by using the `draw_eval_expr_into_integer()` helper function to
evaluate the index into a word register. The function correctly handles all
the special cases.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Writing parameters into VCD files makes the values available to waveform
tools. This can be done easily enough by writing out a $dumpadd section
at the beginning of the file that sets the parameter values. We don't need
to track the values over change, because by definition they do not change.
This changes the typical vcd output as well, so a few of the regression tests
need to be adjusted to account for this.
Also, while tracking this down, found and fixed the vvp/README.txt documention
for the .param/x records.
Check that out-of-bounds access on a dynamic array or queue works and
returns the correct value.
* 2-state vectors: '0 with the element width
* 4-state vectors: 'x with the element width
* reals: 0.0
* strings: ""
Note that the 2-state test currently still fails as out-of-bounds access on
a 2-state vector incorrectly returns 'x.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Commit e1870acfac ("Return the correct value when a queue or darray
references an undefined element") added support for specifying the width of
the vector elements stored in a queue or dynamic array, so that an
out-of-bounds access can create a word with the right width.
To get the element width of a queue or dynamic array it uses the
`packed_width()` method. But this method is only implemented for
`netqueue_t` and returns always 1 for dynamic arrays. As a result
out-of-bounds access on a dynamic array will push a vector of the wrong
width onto the stack if the vector element is wider than 1 bit. This will
usually trigger an assert in vvp.
Fix this by moving the `packed_width()` method implementation from
`netqueue_t` to its base class `netdarray_t` so that it works for all types
of dynamic arrays.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The custom `svector` class is essentially a subset of `std::vector`. There
is no inherent advantage to using `svector`. Both have the same memory
footprint.
`svector` was designed to be of static size, but there are a few places in
the parser where it has to grow at runtime. Handling this becomes a bit
easier by switching to `std::vector` since it is possible to use its
methods which take care of resizing the vector.
This also allows to remove the unused parameter of the `lgate` struct
constructor, which was only needed for compatibility with `svector`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The get_signed() method for the netqueue_t class is identical to that of
its base class netdarray_t.
Remove the redundant re-implementation of the method.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Ever since the conversion to use a stack for vectors `draw_eval_bool64()`
has been unused. The last caller of `draw_eval_bool64()` was removed in
commit e4b862f3d1 ("Clean up vector handling dead code.").
Remove `draw_eval_bool64()` and related functions as well.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that scalar typed parameters are handled correctly. Make sure the
width of the parameter only depends on the type and not on the value
assigned to the parameter.
Same for parameters with a 1-bit range specification.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Parameters without any type or range specification inherit the type from
the value that has been assigned to it. Similarly a parameter with just an
`signed` or `unsigned` keyword will inherit its range from the value
assigned to it.
In the current implementation any vector type parameter that does not have
a range specification inherits the type form the assigned value. That
includes parameters with an explicit scalar vector type. E.g.
```
parameter bit X = 10
```
Make sure that a parameter only uses the width from the assigned value if
the parameter does not have an explicit data type.
To support this we need to remember whether a `netvector_t` was declared as
an explicit or implicit data type. Currently this information is only
available on the unelaborated `vector_type_t`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There is currently a restriction in the vvp code generator backend that
throws an assertion when generating wire access for a multi-dimensional
real array.
But there is nothing special about multi-dimensional arrays. In vvp arrays
are in canonical form. Meaning they only have a single dimension and the
conversion form multi to single dimension is done in the higher layers.
Remove the assert to allow multi-dimensional real arrays.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that using a class new operator on a variable that is not of a class
type results in an error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Using a class new operator on a non-class variable should result in an
error. At the moment when using a class new operator on a dynamic array or
queue will result in an segmentation fault. This is because the
implementation assumes that the left hand side is of a class type.
Add a check in the class new operator implementation that the type of the
left hand side is a class. Report an error if it is not.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The lgate struct has its own fields for tracking file and line number,
while everything else that has this information attached inherits from the
LineInfo class.
Make lgate also inherit from LineInfo for consistency.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are some cases where the r-value for an assignment just can't
be elaborated. Instead of segfaulting on the error, handle it by
assuming that the nullptr came from an error message, and ignore it
going forward.
PECastType currently uses the unelaborated data type to make the decision
how to implement the cast. The unelaborated data type is provided by the
parser and this works as long as the parser knows the data type.
But for example with type parameters the actual data type is not known
until elaboration. In preparation for supporting type parameters make sure
to only use the elaborated type in the PECastType implementation.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that module ports can have the shortreal data type.
Note that SystemVerilog does not allow nets to be of shortreal type.
Supporting net ports with a shortreal type is a Icarus extension.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently there is a restriction in the parser that rejects `shortreal`
typed module ports. And while at the moment `shortreal` signals are
implemented as `real` typed signals, which is not standard compliant, there
is nothing special about module ports in this regard.
Note that support for `shortreal` (and `real`) nets is an Icarus extension,
but ports can also be variables, in which case a shortreal port is allowed
by the LRM.
`shortreal` variables and nets are allowed everywhere else. There is no
good reason to not allow them for module ports, so remove the restriction.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `pform_attach_discipline()` function creates a signal using
`pform_makewire()` and then looks it up by name.
`pform_makewire()` now returns the signal, so use that directly and skip
the look-up by name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `pform_set_data_type()` function is used to set the data type as well
as attributes on a list of signals. Currently the signals are passed as a
list of signal names and then the function looks up the actual signals from
the names.
Refactor the code to directly pass a list of signals. This will allow to
skip the look-up by name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `pform_set_net_range()` function currently looks up a signal by name.
But in all places where it is called the reference to the signal is already
available.
Refactor the code to pass the signal itself, rather than the signal name, to
`pform_set_net_range()`. This allows to skip the look-up by name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`pform_make_var_init()` calls `pform_get_wire_in_scope()` but never uses
the result other than checking that the signal exists. But we already know
that the signal exists since we only call `pform_make_var_init()` for a freshly
created signal.
Remove the unnecessary signal look-up by name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to declare signals of nested unpacked types. E.g. a
queue of dynamic arrays.
This is currently not supported by Icarus. Add regression test nevertheless
to check that this is reported as a non-supported construct and does not
result in random crashes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the maximum size of a bounded queue is properly handled when
being used as the return type for a function.
Elements beyond the maximum size should be ignored.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are currently two implementations for elaborating unpacked array
types. One that is used when elaborating a signal with an unpacked array
type and one that is used everywhere else using the elaborate_type()
infrastructure.
The elaborate_type() implementation is less complete and for example does
not support bounded queue types.
Consolidate both into a single implementation to reduce duplicated code and
get consistent behavior. This for example makes sure that the maximum queue
size is respected when used as a function return type.
Nested data structures of arrays, dynamic arrays or queues are not yet
supported. In the current implementation when encountering such a type an
assert will be triggered and the application crashes. In the new
implementation an error message will be printed without crashing the
application.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that expressions within assignment patterns are evaluated as if they
were assigned to a variable with the same type as the base type of the
assignment pattern target.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The expressions within an array assignment pattern should be evaluated in a
context that is equivalent to an assignment to a variable of the element
type of the l-value array.
This is defined in section 10.9.1 ("Array assignment patterns") of the LRM
(1800-2017).
At the moment the values in an assignment pattern are evaluated in a self
determined context, which can lead to incorrect behavior.
Use the existing `elaborate_rval_expr()` function, which is meant for
elaborating assignments, to elaborate the assignment pattern values.
This solves the following issues:
* implicit width conversion (including sign extension)
* implicit type conversion (e.g. real to vector)
* math operators that depend on the target width (e.g. addition)
* use of expressions that require `test_width()` to be called. (e.g.
unary operator)
* use of concatenations
* use of named constants (e.g. parameters or enums)
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `elaborate_rval_expr()` function takes a `data_type_t`, a
`ivl_variable_type_t` and a `width` parameter. In most places the
ivl_variable_type_t and width are directly derived from the data_type_t.
This slightly simplifies the code.
The only place where this is currently not possible is when assigning to a
compound expression like a concatenation, e.g. `{a,b} = c;`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`pform_set_reg_idx()` is always called right after `pform_makewire()`. Move
it into the function. This avoids the extra lookup that
`pform_set_reg_idx()` does to get the PWire from the name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few parameters for `pform_makewire()` and related functions
that always get passed the same value.
* port_type is always NetNet::NOT_A_PORT
* attr is always 0
Remove these parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a queue type is supported for the return type of a function.
Make sure that the queue is not cleared in between invocations for
non-automatic functions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the elaboration function for unpacked array types prints an error
for queues that they are not allowed inside classes. And while this error
gets triggered when declaring a property with a queue type, it also gets
triggered for other places that uses a queue type, e.g. a function return
type. The only exception is signals which uses a different internal code
path when elaborating queue types.
Move the error message, that is class property specific, to the class
property elaboration. This also makes sure that the error messages
references the line where the property is declared and not the line where
the type is declared.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Dynamic arrays and queues can be implicitly cast between each other. At the
moment this only works if the right hand side is a signal or assignment
pattern.
But this should be possible for other r-value expression that returns a
queue or dynamic array type. E.g. function calls or class properties.
Since the expr_type() method is defined for all NetExpr objects we can use
that and do not have to cast to NetESignal.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This will allow to generate error messages that point to the right line if
there is something wrong or not supported in a class property declaration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The LineInfo class defines a copy-constructor, but relies on the default
copy-assignment operator.
In newer versions of C++ this deprecated and modern compilers generate a
warning about this. A class must either use the default copy-constructor
and default copy-assignment operator or provide a user defined version of
both.
Since the current user-defined copy-constructor for LineInfo does the same
as the default copy-constructor, remove the custom one and rely on the
default constructor.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%store/dar/...` and `%store/qdar/...` instructions are used to load a
value into an entry in dynamic array or queue. These instructions will skip
the load if VVP flag 4 is 1.
For assignment pattern initialization these instructions are used to load
the value of the individual assignment pattern expressions into the dynamic
array.
For queues flag 4 is never cleared when generating the code for the
assignment pattern. This means the initialization might be skipped
depending on what value the flag had before.
```
int a = 1;
int q[$];
a = a == 1;
q = {1, 2, 3, 4};
```
For dynamic arrays it is cleared once in the beginning. But each item in
the assignment pattern can be an arbitrary expression. Evaluating the
expression can cause the flag to get overwritten. E.g. the following code
will skip the assignments.
```
int a = 1;
int d[];
d = {a ? 1 : 1, 2, 3, 4};
```
To fix these issues make sure that the flag is cleared after evaluating
each initialization expression and before executing the `%store/...`
instruction.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `pform_set_param_from_type()` function is not used. The last user was
removed in commit 16646c547c ("Rework parsing of parameter types").
Remove the function itself.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the signedness of class properties is handled correctly
* When sign extending
* When passing as a value to a system function
Check this for both when accessing the property from within a class method
as well as accessing it on a class object.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the signedness of the return value of methods is handled
correctly.
* When sign extending
* When passing as a value to a system function
Check this for both methods on user defined class as well as built-in
methods on SystemVerilog types.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The signedness of an expression can change depending on its context. E.g.
for an arithmetic operation with one unsigned operand all operands are
treated as unsigned.
This is currently not considered when accessing class properties. This can
lead to incorrect behavior with regards to sign extension.
E.g. the following will print 4294967295 rather than 65535.
```
class C;
shortint x = -1;
endclass
...
C c = new;
$display(c.x + 32'h0);
```
Furthermore the return value is not expanded to the width of its context.
This can cause vvp to crash with an exception when it expects a vector on
the stack to have a certain width. E.g.
```
class C;
shortint x = -1;
endclass
...
C c = new;
int x;
bit a = 1'b1;
x = a ? c.x : 64'h0;
```
Solve both of this by using `pad_to_width()` on the property expression if
it is a vectorable type. Since any identifier, not just class properties,
need to have this done insert this on the common path and remove the
`pad_to_width()` call on individual paths.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The signedness of an expression can change depending on its context. E.g.
for an arithmetic operation with one unsigned operand all operands are
treated as unsigned.
For methods, both on built-in SystemVerilog types as well as user defined
classes, this is currently not considered. This can lead to incorrect behavior
if the value is sign extended.
E.g. the following will print 4294967295 rather than 65535.
```
shortint q[$];
q.push_back(-1);
$display(q.pop_front() + 32'h0);
```
Furthermore the return value is not expanded to the width of its context.
This can cause vvp to crash with an exception when it expects a vector on
the stack to have a certain width.
E.g.
```
int d[];
longint x;
bit a = 1'b1;
x = a ? d.size() : 64'h0;
```
Solve both of this by using `pad_to_width()` on the method return value if
it is a vectorable type. Since any function call, not just methods, needs
to have this done to its return value insert this on the common path.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When calling a queue method without parenthesis it gets elaborated through
the PEIdent path. On this path the type, width and signdess are not
reported for the method call. This leads to incorrect behavior in contexts
where those are important.
Correctly report the type, the same as when the method is called with
parenthesis.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The result for the built-in methods for the SystemVerilog types is
currently always unsigned. This can lead to incorrect behavior if the value
is sign extended or passed as an argument to a system function (e.g.
$display).
For most built-in methods this does not matter, since even though they have
a signed return type, they will not return a negative value. E.g. the
string `len()` or queue `size()` functions.
It does make a difference though for the queue `pop_front()` and
`pop_back()` methods. Their return type is the element type of the queue.
If the element type is signed and the value in queue is negative is will be
handled incorrectly.
E.g. the following will print `4294967295` rather than `-1`.
```
int q[$];
q.push_back(-1);
$display(q.pop_front());
```
To correctly support this consistently assign the actual data type of the
built-in method's return value to the `NetESFunc`, rather than just the width
and base type. The width, base type and also the signedness can be derived
from the data type.
Note that this only fixes the default signedness, but not the case where
the signedness of the expression is changed by its context (e.g. in
arithmetic expression). Handling this will require some additional work.
Also note that assigning the actual data type is also required to support type
checking on the return value, e.g. as needed for enum types.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a couple of different NetNet constructors for different data
types. They are all very similar, consolidate them into a single
constructor taking a ivl_type_t.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the behavior of the Verilog AMS `abs()` function is correct when
its argument is a function call. Check this for both vector as well as real
types.
This test is largely a copy of the existing vams_abs2 test, just replacing
the identifier argument with a function call argument.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently a `vector_type_t` with the base type set to `IVL_VT_REAL` is used as
the data type for real type signals. But there is also the `real_type_t` data
type, which is used as the data type for function return types and class
properties.
Move signals also over to using `real_type_t`. This ensures consistent
behavior between all sorts of constructs with a data type, makes sure that
`vector_type_t` is only used for vector types.
It also allows to eventually differentiate between `real` and `shortreal`
at the elaboration stage. Currently this information is discarded by the
parser.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
reals are both signed and scalar. But the real_type_t currently reports as
neither.
This isn't much of a problem because most real signals are implemented
using netvector_t with the base type set to IVL_VT_REAL, for which the
signedness is correctly reported. Function return values and class
properties use the netreal_t as their data type, but most places that work
with reals check the base type and assume that the value is signed when the
base type is real.
The only place where this really makes a difference at the moment is the
Verilog-AMS function when being passed a function call as its argument. In
that case the `abs()` function will be optimized away and a negative value
will be passed through as negative.
But going forward netreal_t is also going to be used for the data type of
real type signals.
To fix the `abs()` issue and to be ready to switch real signals over to
using netreal_t as their type implement the appropriate methods on
netreal_t.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently only the netvector_t type implements the get_scalar() method. To
check whether a type is scalar it is first cast to netvector_t and then the
method is called.
But there are other types, such as areal that can also be scalar. To
support indicating that a real type is scalar add a virtual get_scalar()
method to ivl_type_s, which is the base class for all types.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The compiler normally optimises away the enclosing block statement
if a block only contains one statement. But this is not valid for
a fork/join_none block.
Check that static class properties can be accessed for read and write and
that they are shared between all instances of a class type.
Check that this works for the following 3 cases
* accessing the static property in a class function or task
* accessing the static property in a class function or task using `this`
* accessing the static property on a class object instance
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Assigning a value to a static class property in a class task or function
will currently not write to the static signal, but instead to an otherwise
invisible per instance property. E.g. the example below will print 0 when
the task `t` is called.
```
class C;
static int i;
task t;
i = 10;
$display(i);
end
endclass
```
Since static class properties are implemented as normal signals just
fallback to the default signal handling when an assignment to a static
class property is detected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that constant recursive functions are supported. Check both Verilog
style using assignments to the implicit function return signal and
SystemVerilog style using `return`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Add a regression test that checks that recursive functions using a `return`
statement work correctly.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A `return` statement in a function gets translated into a vvp `%disable`
instruction. This works fine as long as no recursion is involved. The
`%disable` instruction will stop execution of all active threads of a
particular scope. For recursive functions this means as soon as the inner
most function returns all containing outer function calls get disabled as
well. This results in incorrect behavior.
To make recursive functions using the `return` statement work use the new
vvp `%disable/parent` instruction. This instruction will only disable the
closest thread in the thread hierarchy that matches the target scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%disable` instruction will stop the execution of all active
threads of a specific scope. This is what is required to implement
the semantics of the Verilog `disable` statement.
But it is not suited to implement the SystemVerilog flow control
statements such as `return`, `continue` and `break`. These only
affect the thread hierarchy from which it is called, but not other
concurrently running threads from the same scope.
Add a new `%disable/flow` instruction that will only disable the thread
closest to the current thread in the thread hierarchy. This can either be
the thread itself or one of its parents. This will leave other concurrent
threads of the same scope untouched and also allows function recursion
since only the closest parent thread is disabled.
Note that it is not possible to implement this using `%jmp` instructions
since a block in a function with variable declarations will be its own
sub-thread, but using flow control instructions it is possible to exit from
that thread to the parent scope, which is not possible with `%jmp`
instructions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Embed the Icarus Verilog documentation, and format it so that the
Sphinx tools can process it into html or other formats. This will
make the documentation easier to keep up to date with the actual
software.
Check that it is not possible to declare a variable in a package without an
explicit data type for the variable.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Variable declarations in packages need an explicit data type. Omitting the
data type or using just packed dimensions is not valid syntax. E.g. the
following should not work.
```
package P;
x;
[1:0] y;
endpackage
```
The current implementation does accept this tough. To fix this update the
parser to only allow explicit data types for package variable declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This simplifies the code by making it independent of the size of 'long', and
fixes the behaviour of urandom_range when the upper limit is > 0x7fffffff.
Check that it is possible to declare the type separately from the direction
for non-ANSI integer, time and atom2 ports. Check that it is possible to
both declare the type before and after the direction.
For integer, time and atom2 types the range specification on the port
direction declaration should be empty, rather than the implicit packed
dimension of the integer type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When using non-ANSI style port declarations it is possible to declare the
port direction and the data type for the port in separate statements. E.g.
```
input x;
reg x;
```
When using packed array dimensions they must match for both declarations.
E.g.
```
input [3:0] x;
reg [3:0] x;
```
But this only applies for vector types, i.e. the packed dimension is
explicitly declared. It does not apply to the `integer` and `time` types,
which have an implicit packed dimension.
The current implementation requires that even for `integer` and `time`
types the implicit dimension needs to be explicitly declared in the port
direction. E.g. the following will result in a elaboration error
complaining about a packed dimension mismatch.
```
module test;
output x;
integer x;
endmodule
```
Currently the parser creates a vector_type_t for `time` and `integer`. This
means that e.g. `time` and `reg [63:0]` are indistinguishable during
elaboration, even though they require different behavior.
To fix let the atom2_type_t handle `integer` and `time`. Since it no longer
exclusively handles 2-state types, rename it to atom_type_t.
This also fixes a problem with the vlog95 target unit tests. The vlog95
target translates
```
module test(output integer x);
endmodule
```
to
```
module test(x);
output x;
integer x;
endmodule
```
which then fails when being elaborated again. There were some regression
tests that were failing because of this that will now pass.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When using non-ANSI style port declarations it is possible to declare the
port direction and the data type for the port in separate statements. E.g.
```
input x;
reg x;
```
When using packed array dimensions they must match for both declarations.
E.g.
```
input [3:0] x;
reg [3:0] x;
```
But this only applies to vector types, i.e. the packed dimension is
explicitly declared. It does not apply to the atom2 types which have an
implicit packed dimension.
The current implementation requires that even for atom2 types the implicit
dimension needs to be explicitly declared in the port direction. E.g. the
following will result in a elaboration error complaining about a packed
dimension mismatch.
```
module test;
output x;
byte x;
endmodule
```
Currently atom2_type_t's are deconstructed into base type, range and
signdness in the parser. That data is then passed to the signal
elaboration, which will then construct a netvector_t from it. This makes it
impossible to e.g. differentiate between `bit signed [31:0]` and `int`
during elaboration.
Instead of breaking the data type apart pass it as the data_type_t of the
signal and use the elaborate_type() method in the signal elaboration to
generate the netvector_t.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to both declare and call class constructors
without using parenthesis after the `new` keyword.
Check that a non-ANSI port for a class constructor results in an error.
Check that it is possible to invoke a class task through a implicit class
handle (`this` or `super`) without using parenthesis after the task name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is possible to call a class method without parenthesis if no arguments
are specified.
At the moment this works when calling a class method by name. But when
using the implicit class handle `this` or `super` it does not work.
Add support for this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Class constructors can be declared without parenthesis after the `new` when
no arguments are required. Just like for normal function.
In a similar way the base class constructor can also be invoked without
parenthesis after the `new`.
```
class C extends D;
function new;
super.new;
endfunction
endclass
```
Add support for this by making the parenthesis optional in the parser.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Class constructors don't allow for non-ANSI ports. E.g. the following is
not valid.
```
class C;
function new();
input int i;
endfunction
endclass
```
The parser will currently accept this, but otherwise ignore the non-ANSI
port. Modify the parser rules so that this is a syntax error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few places in the grammar that follow the pattern of
`implicit_class_handle '.' hierarchy_identifier` and then splice the two
identifier paths into a single one. Factor this into a common helper rule
to avoid duplicated code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few places in the grammar where it is possible to specify a
argument list in parenthesis or nothing. E.g. a task invocation.
```
task t(int a = 10);
endtask
initial begin
// All 3 are valid syntax
t(1);
t();
t;
end
```
Factor this out into a common rule to be able to remove some duplicated
code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few places in the grammar where it is possible to specify a
task/function port list in parenthesis or nothing. E.g. task and function
prototypes. Factor this out into a common rule to be able to remove some
duplicated code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that for typedefs of array, dynamic array and queue types the base
type is elaborated in the right scope. There are separate tests for vector
base type and other base types since these take different paths internally.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The base type of an array type needs to be elaborated in the scope where
the array type is declared. At the moment it is elaborated in the scope
where the signal is declared, which can cause incorrect results.
E.g. in the example below the width of the array base type would be 4
instead of 8.
```
localparam A = 8;
typedef reg [A-1:0] T[1:0];
module test;
localparam A = 4;
T x;
endmodule
```
If an unpacked array type is specified use the scope of the array type as
the default scope for the base type. Note that the base type can still be a
typedef in a different scope than the array scope, but we need to start
searching for it in the array scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Use the string containing the current source file path to derive the
object file name, not the string containing the space-separated list
of source files.
(thanks to DavidC-75 for pointing out the error)
Previously both ':' and ';' were recognised as path separators on all
platforms, but ':' can't be used in Windows. So now we only recognise
';' when running in Windows and ':' when running in any other OS.
Check that the behavior for all sorts of base types for enums is correctly
implemented. Both for valid as well as invalid base types.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The base type for an enum type can be a type identifier for a typedef as
long as it resolves to a vector or integer type with at most one packed
dimension. This is described in section 6.19 ("Enumerations") of the LRM
(1800-2017). E.g.
```
typedef bit [3:0] T;
enum T {
A
} e;
```
Add support for this by allowing to specify a type identifier as the base
type for an enum in the parser. During elaboration it is checked whether
the type identifier resolves to a valid enum base type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to create a typedef of an array type that shadows
an existing typedef in a higher level scope.
Also check that it is possible to create a typedef in a class scope that
shadows an exiting typedef in a higher level scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is possible to declare a new typedef that shadows an existing typedef in
a higher level scope. E.g.
```
typedef int T;
class C;
typedef real T;
endclass
```
In the current implementation this works for scopes that are not class
scopes.
Update the parser to also support this in class scopes by re-using the
existing parser rule that is used for the other scopes.
Reusing the existing rule also adds support for class forward typedes
inside classes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is possible to declare a new typedef that shadows an existing typedef in
a higher level scope. E.g.
```
typedef int T;
module M;
typedef real T;
endmodule
```
In the current implementation this only works as long as the new type is
a not an array type.
Update the parser to allow to specify unpacked dimension when overwriting
a typedef from a different scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to have multiple instances of a module
that declares a class and that the class in each module instance
is a unique type that can have dependencies on module parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For classes declared inside a module each module instance creates a new
unique class type. These types are not compatible to each other. This is
necessary since module parameters can change the class implementation.
This is defined in section 6.22 ("Type compatibility") of the LRM (1800-2017).
In the current implementation when a class is elaborated the elaborated
type is stored in the class_type_t so it is possible to look up the
elaborated class type. But this class_type_t is shared among elaborated
class types. As a result when creating multiple instances of a module with
a class definition an internal assert is triggered.
To support multiple module instances with class definitions instead of
storing the elaborated type in the type definition look up the type in the
scope in which the type definition is references.
This is similar to how the same problem is solved for enum types.
For packages we still need to remember the elaborated type otherwise scoped
class type references wont work. Since there is only one instance of a
package this doesn't have the same problem as classes in modules.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The base class type is not owned by a class and is shared. For this reason
it must not be modified. To ensure this mark the base class pointer as
const.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Array ports are created via a resolve list. We need to detect and
record whether they need to be created in an automatic context at
the point they are declared, not at the time they are created.
Check that the compatibility of signals of enum data type across module
boundaries.
If the enum data type is declared at a higher level scope or imported from
a package the signals are compatible between different module instances. If
the enum data type is declared within the module itself though the signals
are not compatible.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
An enum data type declared in a module is not compatible between different
instances of the module. The type is unique in each hierarchical instance
scope. The type can for example depend on module parameters which would
result in conflicting definitions. This is defined in section 6.22 ("Type
compatibility") of the LRM (1800-2017).
At the moment enum compatibility is checked by comparing the enum_type_t.
But the enum_type_t is shared among the netenum_t that are created for each
module instance and gives the wrong result.
Since there is exactly one netenum_t created for each enum and each
instantiated scope use this to check if the data type of two enum type
signals is compatible.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to declare a registered output of a user defined
primitive using the `output reg` syntax.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parser currently expects `reg output` for UDP registered output. But
the correct syntax is `output reg`. Fix this to accept the correct syntax.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `net_type` and `dt` parameter of `pform_set_net_range()` always get
passed the same value, NetNet::NONE and IVL_VT_NO_TYPE respectively. Both
these values are ignore by the function. So these parameters don't do
anything useful, remove them.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a couple of different functions for the different data types that
are called when the type of a signal is set. But they all effectively do
the same.
Consolidate this code by moving the common code into the main
pform_set_data_type() function.
This allows to remove most of the type specific functions and eliminates
some duplicated code. It ensures consistent and data type independent
behavior at the parser level. Something that will be required to eventually
support type parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When creating a PWire for a enum type the signedness as well as whether
the base type is an integer is assigned to the wire.
But this information is never queried again. When creating the netenum_t
this information is directly taken from the enum_type_t.
The signedness and integer information of the PWire is only used when
elaborating a netvector_t.
Removing this makes the pfrom_set_enum() function similar to those for
other types and will allow us to consolidate them in follow up patches.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to define the data type of a non-ANSI task port
in a separate declaration from the port direction. Add tests for both the
type declared before the port direction and for the type declared after the
port direction.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to define the data type of a non-ANSI module port
in a separate declaration from the port direction. Add tests for both the
type declared before the port direction and for the type declared after the
port direction.
Note that this doesn't work yet correctly for integer type module ports
yet, so there are no tests for this. This will be addressed in follow up
work.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When using non-ANSI ports (System)Verilog allows to have separate
declarations for the port direction and data type. E.g.
```
input x;
reg x;
```
It is also allowed to first declare the data type and then the port type.
E.g.
```
reg x;
input x;
```
Currently this fails with an error message. Add support for handling this
by allowing to change the port type of a signal from `NOT_A_PORT` to port
direction.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For some data types the value returned by the `elaborate_type()` method is
shared among different signals of that type. E.g. all string or real types
get elaborated to the same ivl_type_s. This means the returned value must
not be modified, otherwise the data type for unrelated signals might get
changed.
To enforce this and protect against accidental breakage make the return
type of the `elaborate_type()` and the related `elaborate_type_raw()`
methods const.
Note that `ivl_type_t` is used for the new return type which is a typedef
for `const ivl_type_s*`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a range mismatch is detected for non-ANSI task ports when
port direction and data type are declared separately.
An error should be reported and no crash should occur.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a range mismatch is detected for non-ANSI module ports when port
direction and data type are declared separately.
An error should be reported and no crash should occur.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When using non-ANSI style port declarations it is possible to have both a
port and net or variable declaration for the same signal. In this case the
range specification for the two declarations have to match.
In the current implementation if the range specifications do not match an
error is reported and no signal is created. This generates follow up errors
about the signal not being declared when it is used.
In some cases it even causes the application to crash. E.g. the task
elaboration expects the port signal to exist. If it does not it will crash.
To avoid this still create the signal, even when an error is detected. Use
the range specification of the net or variable in this case. Overall
elaboration will still fail due to the error, but the application will not
crash.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently there is a mix of passing line information either as `struct
vlltype` or as a separate `const char *file` and `unsigned lineno`.
For consistency always use the struct vlltype variant.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There is a function prototype for `pform_make_reals()`, but the function
is never declared nor used. Remove it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that queues of packed arrays are supported. These tests are identical
to the existing queue tests for other data type, just that the data type
is a packed array.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to declare a dynamic array of a packed array
type. The test is identical to the tests for the other supported dynamic
array types.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently only dynamic arrays and queues of atom2 and vector types are
supported. Add support for packed arrays. Since these three types are
essentially handled the same internally supporting this only requires to
allow to elaborate a packed array base type.
Factor out type elaboration into a helper function that can be shared
between the elaboration of the base type of a dynamic array or queue and
the type for other signals. This gives consistent behavior and will also
make it easier to support additional base types for dynamic arrays or
queues.
Note that it is not yet possible to index elements of packed array dynamic
arrays or queues. But neither is it possible to do a bit select for vector
or atom2 type dynamic arrays or queues yet. Supporting this needs some
additional work.
There is one test that declares a queue of a struct type, but doesn't use
it since it is not supported. With this change a error will generated when
trying to declare a queue of a struct. So update that test to not declare
the variable so it does not fail.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Each data_type_t has a elaborate_type() method that returns the
corresponding ivl_data_t for that type.
Make use of that in PWire::elaborate_sig(). This removes duplicated code
and ensures consistent behavior between the different places where types
are elaborated.
This will also make it easier to add new data type that are going to be
elaborated this way.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In the vvp all vector signals are in canonical form. This means a single
dimension and the lsb starts at 0.
This means that there is no need to restrict new operations for dynamic
arrays of vectors to vectors with 0 or 1 packed dimensions. Multiple packed
dimensions will work just fine. All that is needed is the total packed
width for the signal.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The SystemVerilog grammar explicitly allows an empty class item
declaration. The empty class item declaration is just a semicolon and has
no effect.
E.g. the following is legal
```
class C
int x;;;
endclass
```
Add support to the parser to accept empty class item declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
String literals may have escaped special characters in them. Make sure
we are processing all the special characters that the standard supports,
and also fix the handling of the assignment to strings. Note that the
vvp input has string literals sanitized so that the parser can handle
the various binary values. desanitize the strings when pushing string
literals into the string stack. This fixes string assignments, and other
string operations.
The logic that decides whether a vector is scalar or not incorrectly flags
all variables that are declared in packages as scalar. As a result it is
not possible to do a part select on a vector declared in a package.
Rather than having an independent scalar flag consider a vector as scalar
if it does not have any packed dimensions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
While a package can not have logic defined in it. It can have
variables with initializers. These initializers currently get
ignored when converting the package to a module in the
vlog95 backend.
Make sure packages are treated the same as modules here and
that the initializers are turned into initial blocks in the
generate vlog95 code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Using Verilog data types on module input and inout ports is an error in
Verilog. But in SystemVerilog it is allowed and the port should be a net
with the specified data type.
Check that this is supported.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Add regression tests that check that declaring a net of type class, dynamic
array, queue or string result in an error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In Verilog module input ports can only have a packed dimensions and a
signed flag, but no explicit data type.
In SystemVerilog an explicit data type can be specified for module input
ports. Such a port is a net, regardless of the data type, unless
explicitly made a variable using the `var` keyword.
This works for the most part in the current implementation, but for some
data types such as `reg` and `integer` the input port is turned into a
variable. And since input port's can't be variables in the current
implementation this results in an error.
Fix this by completely removing the `reg_flag` that is used to indicate
that a certain data type is always a variable. There is no such restriction
on data types for SystemVerilog and for Verilog there are already checks in
place that a input port can only have an implicit (or real) data type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
While a variable can have any data type the data type for nets is quite
restricted.
The SystemVerilog LRM section 6.7.1 ("Net declarations with built-in net
types") requires that the data type of a wire is either a 4-state packed or
a unpacked struct or unpacked array of 4-state packed types.
As an extension to this iverilog allows real data type for wires as well as
2-state packed types.
Add a check that reports an error if a net with any other type is declared.
In addition in Verilog a net can not have an explicit data type at all. It
can only have a packed dimension and a signed flag. As an extension to this
Icarus also allows wires to be of `real` data type.
Note that in Verilog mode the data type is checked in the parser since only
the parser knows whether the data type is an implicit type (`input reg
[7:0]` and `input [7:0] x` elaborate the same). But for SystemVerilog the
type is checked during elaboration since due to forward typedefs and type
parameters the type is not necessarily known in the parser.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Consistently use ivl_assert() instead of assert() in the eval_tree()
implementations. ivl_assert() includes information about which expression
triggered the assert and it makes debugging easier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There is now an implicit $unit package that needs to be ignored by
the blif target. Take this opportunity to make the root module checking
for the blif target a bit more robust.
Void functions can be used in always_comb, but since the compiler
uses the check_synth() method to generate some warnings, make sure
that function is implemented for functions as well as tasks.
Check that a output port that has a explicit data type, but no explicit
net type is elaborated as a variable type port.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In SystemVerilog output ports are a variable if either:
* They are explicitly declared a variable (with the `var` keyword)
* There is no explicit net type, but a explicit data type
This is in detail described in section 23.2.2.3 ("Rules for determining port
kind, data type, and direction") of the LRM (1800-2017).
E.g.
```
output x // Net
output [1:0] x // Net
output signed x // Net
output wire x // Net
output wire logic x // Net
output var x // Variable
output logic x // Variable
output var logic x // Variable
output int x // Variable
output real x // Variable
output string x // Variable
output some_typedef x // Variable
```
At the moment the code checks for certain data types and only makes the
output port a variable for those. And it is even different data types
depending on whether the port is declared ANSI or non-ANSI style.
Change this so that if a data type is specified and it is not a implicit
data type (i.e. only ranges or `signed`) then the output is of type
variable.
This ensures consistent and correct behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently module ports only support vectors, atom2, enum and struct packed
types, but not packed arrays.
Generalize the code so that any packed type is supported.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Task and function item rules are identical. Consolidate them into a single
set of rules to remove some duplicated code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
NetNet::get_isint() is never used anywhere, remove it. The information
whether a signal is an integer is always directly queried from the signal
data type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For signals that are declared in a block string_type_t is already used to
pass the type information to the signal elaboration.
But for task ports it is passed as IVL_VT_STRING. Switch this over to also
passing the type information as a data_type_t.
This allows to remove the special handling for IVL_VT_STRING in the signal
elaboration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to declare task ports with SystemVerilog types.
Both ANSI style and one for non-ANSI style.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows unpacked array dimensions on non-ANSI style task and
function ports.
To support this refactor pform_make_task_ports() to accept a of
pform_port_t, which in addition to the identifier name also allows to
specify per port unpacked dimensions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Tasks and functions support two types of port declarations. Either ANSI
style, in parenthesis after the task name, or non-ANSI style, as
declaration statements in the task body.
In the current implementation SystemVerilog types are only accept for ANSI
style port declarations, while non-ANSI style only accept Verilog types
(reg, integer, time, real).
Add support for SystemVerilog data types for non-ansi style ports.
This also makes the parsing rules simpler since we can use `data_type` to
match all data types and don't need a explicit rule for each supported data
type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows `parameter` and `localparam` to declare constants
within a class scope. E.g.
```SystemVerilog
class C;
localparam A = 10;
endclass
```
In this context both declare a local parameter that can not be overwritten.
Supporting this can be achieved for the most part by adding a parser
sub-rule in class declaration rule. In addition some extra support code is
needed to mark the parameter as non-overridable.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is allowed to access a constant declared in a class scope, such as a
enum value or parameter, on an object of that class type. This is described
in section 8.5 ("Object properties and object parameter data") of the LRM
(1800-2017).
E.g.
```
class C
enum { A } e;
endclass
C c = new;
c.e = c.A;
```
Support this by in addition of searching for class properties on the object
also search for constants in the class scope.
A bit of refactoring is needed around the parameter elaboration functions
since they expect a non-const NetScope, but for classes we only have a
const scope available.
The non-const scope is needed to be able to mark specparams as
non-annotatable. Since classes can't have specparams this part is factored
out into a separate function the NetScope parameter for the shared
functions is made const.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Parameter expressions need to remember the scope they have been declared in
so that the code generator backends can insert the right parameter
reference, rather than a constant value.
Currently the scope is stored as a non-const reference. But that is not
needed. Mark the scope reference as const so NetEConstParam and
NetECRealParam can be created when only a const scope reference is
available.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The NetScope class has a method called find_parameter() that looks up the
parameter and returns a iterator to it. This is only ever used to get the
line information of the parameter.
Refactor the function so that it only returns the line info. This will
allow to call this function on a const NetScope object.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The has_parameter_port_list member of the LexicalScope class is not
initialized, which means its default value is undefined. This leads to
random failures where a parameter is marked as non-overridable when it
shouldn't.
Make sure has_parameter_port_list is properly initialized to false.
Fixes: 673b40b78c ("Elaborate `parameter` as non-overridable where required")
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to use a class new as
an initializer for a variable or property declaration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are currently two rules for parsing variable declarations.
One that is used when declaring variables in as a block declaration item
and another that is use everywhere else.
Consolidate those into a single set of rules. This removes a fair bit of
duplicated code in the parser.
A side effect of this refactoring is that class new statements can be used
as variable initializers as allowed by the standard. E.g.
```
module test;
class C;
endlcass
C c = new C;
endmodule
```
This previously was not supported for block item variable declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Variables don't have a delay or strength and the NetNet::Type is known. Add
a small wrapper around pform_makewire() that can be used to create
variables. This will allow to reduce the boilerplate code for variable
declarations.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few places where pform_makewire() is used and attributes can be
attached to the created net or variable. At the moment pform_makewire()
doesn't allow to specify the attributes, and they either get dropped
silently or with a warning.
Add support for passing the attributes to pform_makewire() which will then
pass it on to pform_set_data_type() to attach it to the declared net or
variable.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are currently two very similar implementations of pform_makewire().
One that takes a `net_decl_assign_t`, the other a `std::list<decl_assignment_t*>`.
The one that takes a `std::list<decl_assignment_t*>` is a superset of the
other. It can handle both wires and variables, while the other can only
handle wires.
Update the parser to generate a `std::list<decl_assignment_t*>` for wire
declarations. This allows to remove one of the two functions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the following declarations inside a generate block generate an
error:
* module, program or interface
* specparam
* specify block
* timeunit
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Most things that can be declared in a module can also be declared in a
generate block.
But there are a few exceptions that can not be declared in generate block
* module, program or interface declaration
* specify block or specparam
* timeunit
Some of these currently work while some of them trigger an assertion and
cause and application crash.
Add checks to make sure that all of them these are reported as an error and
do not cause a crash.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Split the test into multiple tests that each check one type of invalid
override rather than having one big tests that checks for everything.
This allow to check whether the test passes or fails by seeing if it
compiles or not. The one big test on the other hand relies on seeing the
exact error messages as recorded in the gold file.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For modules, programs and interfaces that have a parameter port list, a
parameter declared inside the scope's body is supposed to be elaborated as
a local parameter.
TThis is described in the Verilog LRM (1364-2005) section 4.10.1 ("Module
parameters") and the SystemVerilog LRM (1800-2017) section 6.20.1
("Parameter declaration syntax").
Implement this by marking a parameter declared in such a way as
non-overridable.
Note that a parameter declared within a named block, function or task can
still be overridden, even if the module has a parameter port list.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The "->" operator is rarely used, but exists. Unfortunately, the syntax
is tied up in a horrible mess with the System Verilog constraint list
syntax. Do some flex magic to make it all work.
SystemVerilog supports parameters without default values in parameter port
list. Add regression tests to check this feature.
Also add a regression test to check that modules without a default
parameter are not automatically picked as a toplevel module.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to omit the default value of a parameter declared in a
parameter port list. In this case the parameter must be overridden for
every module instance. This is defined in section 6.20.1 ("Parameter
declaration syntax") of the LRM (1800-2017).
In addition a module that has a parameter without a default value does not
qualify for automatic toplevel module selection.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For unpacked statically sized array types $bits() is supposed to return the
total size of the array. Accumulated the number of unpacked dimensions and
multiply it by the packed with of the base type to get the right result.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few system functions that take either an expression or a data
type. This is implemented in the parser by allowing a type identifier as a
primary expression.
But those functions allow any data type, not just typedefs. E.g.
```
$bits(int);
$bits(reg [1:0]);
$bits(struct packed { int x; });
```
Support this by changing the parser rule from TYPE_IDENTIFIER to data_type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are currently two different systems to evaluate constant expressions
in iverilog.
The PExpr based system using the eval_const() method and the NetExpr based
system using the eval_tree() method. The latter is more complete while the
former only implements the bare minimum and also has some minor bugs.
The PExpr based system is only used to evaluate expressions within
attributes.
Switch attribute expression evaluation over to elab_and_eval(). This
enables to use the full set of constant expressions for attributes, maybe
most importantly constant functions and system math functions.
It also allows to remove the PExpr based system since there are no more
users.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to completely omit the `parameter` or `localparam`
keyword in the parameter list. Both at the beginning and before redefining
the parameter data type. This is not support in Verilog.
Add regression tests that check that this is supported when in
SystemVerilog mode.
It is not valid to use an implicit data type e.g. just `signed` when
`parameter` was omitted, add regression tests to check for this as well.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to completely omit the `parameter` keyword in a
module parameter port list. This is described in section 6.20.1 ("Parameter
declaration syntax") of the LRM (1800-2017).
E.g.
```
module a #(X = 10) ...
module b #(int Y = 20) ...
```
It also allows to redefine the parameter type without having to have a
parameter or localparam before the type.
E.g.
```
module a #(parameter int A = 1, real B = 2.0) ...
module b #(int X = 3, real Y = 4.0) ...
```
Extend the parser to support this.
Note that it is not possible to declare a parameter with an implicit data
type this way.
E.g. the following is not legal SystemVerilog
```
module a #([3:0] A = 1) ...
module b #(int X = 2, signed Y = 3.0) ...
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When encountering a construct that requires SystemVerilog in most cases an
error message is generated when SystemVerilog is not enabled and parsing
simply continues.
Factor the checking and generating of the error message into a helper
function. This slightly reduces boiler plate code and gives consistent
error messages.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In Verilog a parameter in a generate block is invalid and should
result in a compile error.
In SystemVerilog on the other hand it is valid, but it is equivalent
to a localparam and can't be overridden.
Add regression tests that check for this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows to use the `parameter` keyword in a generate
block. If used in a generate block it behaves like a `localparam` and
cannot be overridden.
This is described in section 27.2 ("Generate constructs - Overview") of the
LRM (1800-2017).
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Parameters declared in certain scopes behave like local parameters and can
not be overridden. Rather than making those parameters a localparam track
whether a parameter can be overridden.
This allows to generate better error messages when trying to override the
parameter.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
During parsing parameters and localparams are kept in a separate list only
to be collected into the same list during elaboration.
Store them in the same list during parsing as well, this allows to remove
some duplicated code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A base class can be referenced by scope. E.g. if the base class is in a
package.
```
package P;
class B;
endclass
endpackage
module test;
class C extends P::B;
endlcass
endmodule
```
To support this let the parser accept a scope identifier for the base
class.
A small change is also necessary to how the base class lockup is done
during elaboration. At the moment the code will search for the base class
by name in the current scope. This doesn't work with scoped identifiers.
But we already have a reference to the base class data type, so we don't
have to search for it by name.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are multiple places in the grammar where either a type identifier or
scoped type identifier is accepted.
Factor this into a common parser rule. This removes some duplicated code.
But it will also be required to avoid reduce-reduce conflicts for future
grammar extensions, e.g. to support type parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently when encountering an end label on a unnamed block
a 'syntax error' will be generated and the parser will give up.
Slightly refactor the parser so that this case is detected, a more specific
error message is generated and the parser can recover and continue.
This also slightly reduces the parser since it allows to merge the almost
identical rules for handling named and unnamed blocks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Most named constructs support a end label in SystemVerilog. The handling of
this end label is always the same.
* Generate an error if the end label does not match the name of the block
* Generate an error if not in SystemVerilog mode
* Delete the end label
Factor this into a common helper function. This reduces code size a bit and
results in consistent error messages.
The latter requires refreshing of some gold files to match the slightly
different error messages.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog supports variable declarations in unnamed forks, while
Verilog does not.
Add a regression test that checks for this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
While it is not a particular useful construct it is legal to have a
parallel block with just variable declarations and no statements. E.g.
```
fork
int x;
join
```
At the moment there is a special rule for completely empty parallel
blocks. Remove that rule and change the statement_or_null_list in the
fork/join parser section to a statement_or_null_list_opt. This way it
covers both completely empty parallel blocks as well as parallel blocks
with only variable declarations.
Note that this already works as expected for named parallel blocks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that invalid parameter overrides generate an error.
There are some cases that are not handled correctly today. The test will be
updated once they are addressed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Overriding a parameter that does not exist will only generate a warning at
the moment. This can hide programming mistakes such as an typo in a
parameter override.
There is nothing in the LRMs to support that this should only be warning,
so elevate this to an error. This is consistent with how an error is
generated when trying to reference a non-existing port or variable.
The generated error message differentiates between whether the parameter
does not exist at all, or whether it is a localparam.
There are two regression tests that rely on that only a warning is
generated, these have been updated to expect an error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that all parameters in a parameter port list after a `localparam` get
elaborated as localparams, until the next `parameter`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When declaring module parameters in the ANSI style parameter list it is
possible to omit the `parameter` or `localparam` keyword. In this case
whether the parameter is local or non-local is inherited from the previous
parameter.
In the current implementation when the type of the parameter is not
specified it will always use parameter. E.g. the following will create a
localparam A and a parameter B, while it should be localparam A and B.
```
module #(localparam A = 1, B = 2);
```
Fix this by remembering whether the previous entry was a parameter or
localparam. This is similar to how the parameter data type is already
remembered.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Verilog-AMS defines parameter value ranges which can restrict the value
that can be assigned to a parameter. It defines this for both `parameter`
and `localparam`. Currently it is only implemented for `parameter`. Support
it for `localparam` as well for consistency.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The code for handling parameter and localparameter declarations is very
similar. Consolidate this into a single helper function.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
struct members are currently always treated as unsigned. This leads to
incorrect behavior in contexts where the sign makes a difference. E.g.
```
struct packed {
int x;
} s;
s.x = -1;
if (s.x > 0) $display("FAILED");
```
Query the signedness of the struct member form the type of the member.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that when an error message for a enum or struct data type is
generated it points to the location of the declaration of the type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
enum_type_t inherits from LineInfo, but also has a LineInfo field called
`li`.
When a enum_type_t is created the LineInfo of the object itself is set to
the location where the type is declared.
The `li` field gets set when a signal of the enum_type_t is created to the
location where the signal is created. The `li` field is then used when
elaborating a netenum_t to set the line information on the netenum_t.
This works fine when the enum is directly used to declare a signal, since
the location of the type and signal declaration are the same and there is
only one signal of that type.
But when using a typedef and declaring multiple signals with the same type
the `li` field will be repeatedly set and eventually point to the last
signal declaration of that type.
On the other hand when using or declaring an enum as part of an aggregate
type such as an array, struct or class the line info will never be
set.
This can cause misleading error messages. E.g.
```
typedef enum {
A, B = A
} e_t;
struct packed {
e_t e;
} s;
```
will generate
```
:0: error: Enumeration name B and A have the same value: 32'sd0
```
To fix this use the LineInfo that was assigned to the enum_type_t itself
when it was declared and remove the `li` field.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
netstruct_t inherits from LineInfo. But the file and line information is
never set leading to messages like
:0: error: Member r of packed struct/union must be packed.
When elaborating a netstruct_t set the line info from the struct_type_t it
is elaborated from. This makes sure that error messages for the struct type
have the proper file and line information when printed.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Test that enums are elaborated in declaration order and a enum declaration
can reference a item of an enum that was declared before it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog supports variable declarations in unnamed blocks, while
Verilog does not.
Add a regression test that checks for this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
While it is not a particular useful construct it is legal to have a
begin/end block with just variable declarations and no statements. E.g.
```
begin
int x;
end
```
At the moment there is a special rule for completely empty begin/end
blocks. Remove that rule and change the statement_or_null_list in the
begin/end block parser section to a statement_or_null_list_opt. This way it
covers both completely empty blocks as well as blocks with only variable
declarations.
Note that this already works as expected for named begin/end blocks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
enums for a scope are stored in a std::set. This means when iterating over
the enums during elaboration it is possible that they are elaborated in a
different order than they have been declared in. This causes problems if
one enum references items of the other enum. E.g.
```
enum {
A
} a;
enum {
B = A
} b;
```
In the current implementation whether this works or not depends on the
pointer values of the enum_type_t for `a` and `b`, which can change between
environments.
To make sure that enums are elaborated in the same order use a std::vector
instead of a std::set.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
These test verify that explicit cast to packed array and packed struct
types are supported and executed correctly.
The tests are based on the test for integer casts. Just the type of the
variables was changed to packed array and packed struct respectively.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Update the enum cast test to reflect that enum casts are now supported.
Also add a small check to verify that the right value got assigned to the
enum after the cast.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Assigning a value to an enum signal that is not of the same type as the
enum requires an explicit cast.
To support this attach the type of a type cast to the resulting expression.
This allows the assignment elaboration to confirm that value has been
explicitly cast to the right type.
Also handle the case where the value is a constant. In this case create a
NetEConstEnum instead of a NetEConst as the resulting expression.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The scope_ field of the NetEConstEnum class is initialized in the
constructor, but never used anywhere again. Remove it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently explicit cast is supported to atom2 and vector types. packed
struct, packed array and enum are not supported.
An explicit cast to packed type works the same for all packed types though.
Add support for handling also packed structs, packed arrays and enums by
make the code more generic and querying the packed base type from the
ivl_type_t.
To correctly handle enums a bit more work is necessary, which will be done
in a follow up patch.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Mark them as NI so that in the fugure they might be turned back
on if they can be made to work. Keep the tests around as reference.
Also, remove reports that are no longer tested in CI. This is because
they are no longer tested by a previous patch that relies on the
change vvp_reg.pl behavior around failed tests.
Remove now obsolete update_msys2_report.pl, and simplify the test.sh
script, since diff commands and Windows specific trickery are no
longer needed.
If there are any failures, return a non-zero exit status so that
invoking scripts can detect that failures happen. This eliminates
the need to use regression report reference outputs, and should
make it easier to merge PRs that add or impact tests.
Add a test that checks that signing annotations on structs are supported
and that signed structs are properly evaluated as a signed value.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
packed structs and packed unions as a whole can either be signed or
unsigned. This information is used when it is used as a primary in an
expression, i.e. without accessing any of the members.
Add support for parsing and elaborating signed structs.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Extend the array_packed test to check declaring a packed array of a type
from another scope that is addressed via a scoped identifier.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is possible to directly declare a packed array of a struct or enum
without having to create a typedef first.
Add a check to the array_packed test that this is supported and works as
expected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Allow scoped identifiers to be used as the base type for packed array
types. Scoped type identifiers can be used the same way as unscoped type
identifiers.
E.g.
```
package p;
typedef logic [1:0] vector;
endpackage
module test;
p::vector [1:0] pa;
endmodule
```
is a valid construct.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is possible to directly declare a packed array of a struct or enum,
without having to typedef the struct or enum first. E.g.
```
struct packed {
int x;
} [1:0] pa;
```
Add support to the parser for handling this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
These tests check that a enum that is declared in a struct or class are
correctly elaborated and also name collisions with the enum names are
detected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When creating an enum type it must be added to the scope where it is
declared so it can later be elaborated and the enum and its names can be
referenced in expressions.
In addition the names of the enum must be added to the lexor scope so that
name collisions are detected and can be reported as errors.
This is done with pform_put_enum_type_in_scope() function.
At the moment the function is called from two different places
* When adding a typedef of a enum type
* When creating a signal of a enum type
In addition the enum_type_t is added to a class scope `enum_sets` when
declaring a enum property in a class. But this only makes sure that the
enum gets elaborated, its names are not added to the lexor scope.
This works fine for the most part, but breaks for a few corner cases.
E.g. it is possible to declare a enum type as part of the subtype of
another packed type such as structs or packed arrays. E.g.
```
struct packed {
enum {
A
} e;
} s;
```
This is not covered by either of the cases above and neither do the names
of the enum get added to the lexor scope, nor is the enum type elaborated.
Another corner case that is currently not working is declaring a class
property where the type is a typedef of a enum that is declared outside of
the class. In this case the enum is elaborated again inside the class
scope. E.g. the below is supposed to work, but fails with an already
declared symbol error.
```
typedef enum {
A
} e_t;
class C;
typedef enum {
A
} e1;
e_t e2;
endclass
```
In addition since for enums declared in classes they are only added to
`enum_sets`, but names are not added to the lexor scope, it is possible to
declare a different symbol in the class scope with the same name.
E.g. the following elaborates fine
```
class C;
enum {
A
} e;
typedef int A;
endclass
```
To fix this call pform_put_enum_type_in_scope() when the enum_type_t is
created in the parser. This makes sure that it is handled the same
regardless where the type is declared or used.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Refactor the enum rule by adding a enum_base_type rule which handles the
type specific initialization. This allows to keep the non-type specific
parts in a common rule, which makes it easier to modify in future changes.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The test checks that all invalid declarations produce an error and also do
not crash the application.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When something goes wrong when parsing a struct member, e.g. the type does
not exist, a nullptr is added to the struct member list. This will cause a
crash when iterating over the list.
E.g.
```
struct packed {
logc x;
} s;
```
Add a check so that nullptr members are not added to the list.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
By adding ivtest to the iverilog source tree, it is easier to keep
the regression test synchronized with the source that is being tested.
This should be especially helpful for PRs that add a new feature, and
have a matching ivtest PR with the regression test for that feature.
Currently it is only possible to declare packed array variables with a
struct type as the element type.
Add support for packed arrays of other packed types. This includes packed
arrays of enums and vectors as well as packed arrays of packed arrays.
Since packed arrays of packed types are already supported for class members
the infrastructure for elaborating all types of packed arrays exists.
It just needs to be called when elaborating a signal.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When creating a signal of a packed array it is checked that the base-type
of the packed array is a packed type.
But this check is only done if the packed array itself is the type of the
signal. Placing the packed array in a struct or class will elaborate fine,
but then crash during simulation.
E.g.
```
typedef real myreal;
struct packed {
myreal [1:0] p;
} s;
```
Move the check from signal creation to type elaboration, so that it is not
possible to create a packed type with a non-packed base-type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Use netrange_t, which is meant for storing ranges, for storing the range of
a netenum_t.
This makes the integration with the rest of the codebase a bit more
seamlessly and also allow to reuse methods defined for netrange_t such as
the width() method rather than having to reimplement it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Specifying and enum with an invalid dimension range results in an assert or
segfault. E.g. `enum [$] E { ... }`.
Use the `evaluate_ranges()` function to elaborate the enum dimensions. This
functions has proper error checking and recovery built-in.
In addition verify that there is at most one packed dimension.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Having an enum with a lsb > msb base type, e.g. `enum logic [0:9]` is a
legal construct.
It is handled correctly for the most part already, there is just an assert
that triggers on it. Remove that assert.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
To determine the base type structs and packed arrays call the
figure_packed_base_type() for their sub-types.
This method is not defined for enum or atom2 types and the default
implementation returns IVL_VT_NO_TYPE.
As a result packed arrays of enum or atom2 types and packed structs with
members of enum or atom2 types get elaborated with IVL_VT_NO_TYPE
as the base type.
For example
```
struct packed {
bit signed [31:0] x;
} s1;
```
gets elaborated with a base type of IVL_VT_BOOL, while
```
struct packed {
int x;
} s2;
```
gets elaborated with a base type of IVL_VT_NONE.
To fix this define the figure_packed_base_type() for enum_type_t and
atom2_type_t.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Trying to elaborate a type with invalid packed dimensions currently results
in a crash. E.g. `typedef logic [] T;`
The issue is in the `elaborate_array_ranges()` function which
does not verify that the range specification is valid.
Replace the `elaborate_array_ranges()` with `evaluate_ranges()`, which does
the same thing, but properly checks the range specification and
reports an error if it is invalid.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
If the left-hand side of a logical operator is a constant that causes the
right-hand side to be short-circuited the right-hand side can be discarded
even if it is not constant.
In this case replace the expression by a constant.
E.g.
* `0 && expr` will be replaced by a constant 0.
* `1 || expr` will be replaced by a constant 1.
* `0 -> expr` will be replaced by a constant 1.
Note that it is not possible to replace the expression by a constant if
only the right-hand side is a constant, even when the value of the
expression is constant. The left side still has to be evaluated for side
effects.
E.g. it is known at elaboration that `a++ && 0` will yield 0, but the
increment on `a` has to be executed regardless.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Section 11.4.7 of the SystemVerilog LRM states
```
The && and || operators shall use short circuit evaluation as follows:
- The first operand expression shall always be evaluated.
- For &&, if the first operand value is logically false then the second operand shall not be evaluated.
- For ||, if the first operand value is logically true then the second operand shall not be evaluated.
```
vvp currently evaluates both operands of a logical operator. This works
fine as long as the right-hand side does not have a side effect. But if it
has the result might be incorrect.
E.g. for `a && b++` `b` must not be incremented if `a` evaluates to false.
The Verilog LRM mentions that it is allowed to short circuit any expression
"if the final result of an expression can be determined early". But there
is no requirement to do so.
So the new and the old behavior are both correct implementations in
Verilog.
Use the new behavior in both Verilog and SystemVerilog mode to make sure
the behavior is consistent when an expression has side effects.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The code for generating the logical `and` and `or` operators is identical
except for the final opcode to combine the two results.
Consolidate this into a single function to reduce the code a bit.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
If this assert fires, the "this" pointer we pass to it will be a
null pointer, so will cause a null pointer dereference. We've
tested it is not null earlier, so we don't need the assertion.
When using the latest mingw64 header files, rpcndr.h (which is indiretly
included by windows.h) defines a type named "byte" which collides with a
definition in cpp_type_traits.h (included indirectly by the STL). This is
only a problem if "using namespace std" is declared prior to including
windows.h.
For non-ANSI port declarations that have both a port declaration and
a corresponding variable declaration, the signed attribute may be
attached to either the port declaration or the variable declaration,
or both declarations.
This also ensures the same genvar cannot be used in two nested loops
(issue #533), because the implicit localparam with the same name
shadows the genvar declaration.
This requires us to make a copy of the typedefs map when adding it to
a NetScope object, because the pform data is deleted before we are
finished with it.
The IEEE standard specifies that the numbering of generate blocks
restarts at 1 in each new scope, and that the 'else' part of an 'if'
construct is part of the same constuct, so has the same number.
This eliminates some indeterminism in the error messages, which was
causing occasional failures in CI. We don't expect this list to be
very large, so the O(n) insertion time should not be a problem.
A module port list may contain unnamed entries, e.g.
module dut(a,);
When performing a wildcard connection, these entries should be skipped,
as there is no name to match.
The old implementation connected all inputs to the same vvp_net_t port,
on the basis that we don't care about the data values or what port they
arrived on. But if one or more of the inputs fans out to multiple nets,
the chains get tangled, which either results in connections being lost
or inappropriate connections being made, depending on the order that
the inputs are linked.
This could have been fixed by using a standard wide functor. But as we
don't care about the data values, that would be unnecessary overhead.
We just need separate vvp_net_t objects to handle the input connectivity
and can keep using a single shared functor.
This is needed for the waveform dumpers now that vpi_iterate(vpiModule, NULL)
has been ficed to only return modules.
This includes recognising vpiProgram and vpiInterface, although the compiler
and vvp currently incorrectly classify them as modules.
(replacing assertions)
The IEEE standard either requires out-of-bounds bits to be ignored on
write, returned as 1'bx on read, or requires a compile-time error message.
The latter is easier to implement.
If we have a bit/part select that is selecting one or more sub-arrays, e.g.
wire [3:0][3:0] foo;
assign foo[1] = 4'd1;
we need to take into account the bit width of the sub-array when calculating
the bit width of the select.
The code assumed all handles stored in vpip_root_table were modules. This
is true for traditional Verilog, but not so for SystemVerilog.
Whilst here, also add support for iterating over packages.
To correctly restore the file name and line number after including a
file or expanding a macro, the preprocessor needs to be aware of the
changes introduced by `line directives. The `line directive still
needs to be passed on to the main compiler so it can track the
changes too.
To avoid duplicate error messages, the preprocessor silently ignores
invalid `line directives, relying on the main compiler to report the
errors.
This might come to pass for example when calling the function
$ivl_string_method$len(<expression>) where the expression is
calculated, and not simply a variable name.
There are too many ad hoc handlers of symbol_search partial results.
Rewrite symbol_search to clean up things like partial results and
member/method detections. Use this reworked symbol_search function
to rewrite expression elaborate for the PECallFunction expressions.
When elaborating a subclass, the base class scope needs to be elaborated
before the subclass scope. If the base class and subclass are defined in
different packages, this requires the package scopes to be elaborated in
the correct order. SystemVerilog reqires packages to be defined before
they are used, so that is the order we should elaborate them in.
Parameters can have string type and do the usual string stuff,
and also implement some of the string methods on string parameters
so that they evaluate down to constants.
Use the common data_type_or_implicit rules to support type
definitions for parameters. This eliminates a bunch of special
rules in parse.y, and opens the door for parameters having
more complex types.
In the rare cases where DARRAY signals are in the network, handle
them by creating the proper ivl_nexus_t node. This also implements
the receive of vvp_object_t objects bu vvp_fun_anyedge_sa. This
together makes it possible for IVL_VT_DQUEUE objects to be in
wait lists.
This fixes#412
Depending on the order of elaboration, a function may not have been
elaborated before a call to it is elaborated, so don't assert that it
has been. As an optimisation, try to elaborate it on the fly, so we can
elide the call if the function body is empty.
Use the new cur_instance variable to get the call handle instead of calling
vpi_handle(vpiSysTfCall, 0).
This completes a proper fix for issue #141, to replace the problematic fix
that was reverted in commit 8da8261f.
PLI 1.0 callbacks are directly associated with the instance of the system
task/function that initiated them, allowing them to access the task/function
arguments. However, we implement them using VPI callbacks, which are not so
associated. So we need to pass the VPI handle for the associated task/function
instance to the callback routine via the VPI callback user_data pointer,
because vpi_handle(vpiSysTfCall, 0) will return null when called from the
callback function.
This is the first step to a proper fix for issue #141, to replace the
problematic fix that was reverted in commit 8da8261f.
sync_cb::run_run() attempts to cast the obj field of the callback data to a
__vpiSysTaskCall pointer. But a sync_cb object is only used for simulation
time callbacks, where the obj field is (mostly) not used, so I can't see
that would ever succeed. As the obj field is not required to be set by the
user, the dynamic cast results in undefined behaviour, so mingw32 is not to
blame.
This code was introduced by Johann Klammer in commit c79df7c44, but the user
klammerj and all trace of that pull request have vanished from GitHub, and
there is no associated regression test, so I can't establish the rationale
for it.
When doing continuous assignment of packed structs, support the case
where the value being assigned is a member of a member, etc. Procedural
assignments already support this.
See issue#307
IEEE Std 1800-2017 Section 7.6 Array assignments
Assignment of a dynamic array creates a duplicate of the source,
so that assignments to the copy don't impact the original. Handle
all sorts of dynamic array base types.
This.new is not allowed.
super.new beyond the first statement is not allowed.
And while I'm at it, clean up the use of "@" and "#" in
the code as tokens for this and super.
A NetESelect is used for accessing packed struct members and also for
accessing dynamic array elements. In these cases the expr_type() and
enumeration() methods should reflect the member/element type.
The IEEE standard does not clearly state whether the `` directive is applied
before or after embedded macros are expanded. Other simulators vary in their
behaviour. For maximum compatibility, this fix adopts the behaviour found in
Verilator, where `prefix``suffix expands to <prefix>suffix if prefix is a
defined macro, otherwise it expands to <prefixsuffix> (where <...> is the
expanded macro text). Other simulators show this behaviour in at least some
circumstances.
Unless explicitly declared a wire an enum output port is of variable type
and should be marked as IMPLICT_REG.
Currently this is only done when the base type of the enum is `logic`. But
it should be done for all enums regardless of their base type.
Without this change for example the following snippet
```
typedef enum {
A,
B
} E;
module M (
input E ei,
output E eo
);
always_comb eo = ei;
endmodule
```
fails with the following error message
test_enum.sv:11: error: eo is not a valid l-value in M.
test_enum.sv:8: : eo is declared here as wire.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Since commit 62fce50f8c ("Remove dead code for allocate_vec handling.")
vector.c only contains the license header and some include directives
but no actual code.
Remove the file.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Since commit 15cda5fe, forked threads are never embedded in the parent
thread, so we no longer need the special case code that ensured that
task/function calls were reaped before a join.
This also fixes GitHub issue #368.
Given a macro definition like this:
`define name `macro``text
the preprocessor should expand `macro, not `macrotext, when it expands
`name. This also ensures that
`define name(p,s) p``_``s
`define PREFIX my_prefix
`define SUFFIX my_suffix
`name(`PREFIX, `SUFFIX)
expands to
my_prefix_my_suffix
as the user would expect.
When -pfileline=1 is used the queue procedural warnings have file
and line information added to the messages. Also switch the trace
debugging to be off by default.
Also, Add some preliminary missing darray functionality.
When connecting module inout ports, an island is created. If there
is no other driver on one of the island ports, a tie-off is added.
In the case of a tri0 or tri1 net, this must have the correct (pull)
drive strength.
With a pattern rule, the recipe will only be executed once, even when
the rule has multiple targets. Using this to handle the output from
bison is included as an example in the GNU make manual.
This fixes the makefiles so that bison-generated header files will be
regenerated if they are deleted.
The current bison (3.7) generates a *.cc file that includes the header
it generated. For parse.cc this would be parse.hh. Right now, we rename
this header to have a common name used in other files, but this results
in a compile error for the parse.cc file:
parse.cc:462:10: fatal error: parse.hh: No such file or directory
462 | #include "parse.hh"
| ^~~~~~~~~~
Fix this by telling bison to output the header file to the correct
filename in the first place so that we don't have to rename it.
(using the --defines instead of -d option).
This looks like a bison specific option not available in Posix yacc;
but looks like we're requiring bison anyway.
Signed-off-by: Henner Zeller <h.zeller@acm.org>
* Update README to reflect that bison fails to generate correct code
on newer MacOS as well and bison 3.6+ works fine as well
* macos.txt removed because it contains outdated instructions
For functions without a port list in parantheses, declarations are optional in SystemVerilog.
This is true even in IEEE1800-2005, but not in IEEE1364-2005
__CYGWIN32__ is not defined when building with the 64-bit Cygwin
toolchain. According to the Cygwin FAQ, __CYGWIN__ has been defined
since 1998, so this should still work for users on 32-bit systems.
When module ports are collapsed, we can't tell which of the nexus drivers
are associated with a given module port and should be routed through an
associated modpath delay. Work round this by inserting a transparent
buffer or tran_vp if an output or inout port has a modpath delay. The
target code generator can elide this once it has handled the modpath
delays.
In PR #300, @xdch47 pointed out a stable way to fix parallel
installation problems.
This fix applied the method, thanks!
Signed-off-by: Huang Rui <vowstar@gmail.com>
When installing tgt-stub and tgt-vhdl, due to the wrong target
path, the install scripts can't find the file to be installed.
The missing file is: stub.conf, stub-s.conf, vhdl.conf, vhdl-s.conf
Changed to right path fixed this problem.
Thanks @minux help to fix.
Signed-off-by: Huang Rui <vowstar@gmail.com>
As for parentheses, we need to ignore commas within a pair of braces
when parsing a macro argument, e.g. `MACRO({a,b}) has one argument.
This fix is a little crude in that it doesn't distinguish between
parentheses and braces, e.g. it will accept {a,b). But any errors
like that will be caught by the compiler proper.
See also: https://bugs.gentoo.org/706366
gcc-10 and above flipped a default from -fcommon to -fno-common:
https://gcc.gnu.org/PR85678
Usually all it takes is to add a few 'extern' declarations and
move definitions from header files to modules. I've port iverilog
to gcc-10 accroding to this guide:
https://wiki.gentoo.org/wiki/Gcc_10_porting_notes/fno_common
To fix this, I analyzed the code, and found ``pli_trace`` has been
defined at here:
https://github.com/steveicarus/iverilog/blob/v10_3/libveriuser/priv.c#L24
So I changed ``FILE* pli_trace;`` to ``extern FILE* pli_trace;``.
The var ``current_file`` only in ``cfparse_misc.h``, I changed it
from ``char *current_file;`` to ``extern char *current_file;`` and
declaring it in cflexor.lex
And then it works.
Signed-off-by: Huang Rui <vowstar@gmail.com>
The compiler elaborates types on the fly as they are used. For user-
defined types (typedefs) we must do the elaboration in the scope where
the type was declared, not in the scope where it is used.
If the condition expression is 2-state, the result won't be blended, so
the result will be a valid enum value if both true and false expressions
return the same enum type.
When strings are arguments to functions/tasks, that doesn't suddenly
make them implicitly scalar. Strings are vectors and should be treated
that was, even if they are IMPLICIT_REG.
The fix for the compiler hang when calculating the sensitivity list
for an always_comb construct containing recursive function calls
could cause the compiler to ignore sequential calls to the same
function, and thus not add the arguments of those calls to the
sensitivity list.
The old scheme of linking the VPI modules with the vvp exports meant they
did not work when loaded by the compiler. Instead, let each client create
a jump table for the VPI routines and pass that to each VPI module as it
is loaded.
We don't support evaluating user-defined system functions at compile
time. If possible, defer evaluation until run time. If used in a
constant expression, output a "sorry" message.
Casting from signed to unsigned types and vice versa is legal in SV,
as is casting from a larger to a smaller size. Obey Verilog rules
for expression bit width and signedness.
The unique, unique0, and priority keywords can decorate case statements
to tell the run time (or synthesis) to do extra tests (or make extra
assumptions). These tests are not implemented in the vvp run time, but
now the decorations make it to the code generators.
bison 3.4.2 complains when encountering '%pure-parser':
"warning: deprecated directive, use ‘%define api.pure’"
A quick google suggests this option has been around since at least
2012, maybe longer, so probably safe to replace.
Signed-off-by: Nicholas Sielicki <sielicki@yandex.com>
Explicit imports should always conflict with local declarations using
the same name. Wildcard imports only conflict if they are referenced
before a local declaration with the same name.
This also unifies the detection of identifier conflicts.
The '-i' option is there to allow the compiler to be used to check an
incomplete design for errors. With no top-level modules, nothing will
be elaborated, but at least will be checked for syntax errors.
As reported on iverilog-devel on 2018-10-12, a dimension size of zero
could case the compiler to go into an infinite loop. Further tests
showed that unsized or queue dimensions entered as packed dimensions
would cause the compiler to crash.
As discussed on iverilog-devel (2018-03-09), the existing implementation
(using Icarus-specific vpi functions) only worked with assignments to
simple variables, and could not be easily modified to work more generally.
So use the new vvp instructions added in the previous two commits.
This allows any always processes that are sensitive to the UDP output
to start first. This fixes a time 0 race that was found in a Lattice
Semiconductor simulation library (reported on iverilog-devel).
If the initial value is 'x', propagate the value to the UDP output
before the start of simulation, to avoid unwanted update events on
the z -> x transition on downstream nets.
In 64-bit Windows, an unsigned long is 32 bits, so initialising the num
member of the union did not properly initialise the ptr member. The num
member isn't actually needed, so eliminate it.
cfparse.h defines the YYLTYPE struct in case it has not been defined, and
also declares an extern YYLTYPE cflloc which is used in cflexor.
As cfparse_misc.h defines an extended YYLTYPE, the cflloc instance in
cfparse.c has this extended type, i.e. there is a type mismatch.
Changing the include order in cflexor causes both cflexor.c and
cfparse.c to use the definition from cfparse_misc.h.
This has been uncovered by GCC when using LTO:
---
gcc -flto=8 main.o substit.o cflexor.o cfparse.o -o iverilog
cfparse.h:105:16: warning: type of 'cflloc' does not match original declaration [-Wlto-type-mismatch]
105 | extern YYLTYPE cflloc;
| ^
cfparse.c:1162:9: note: type 'struct cfltype' should match type 'struct YYLTYPE'
1162 | YYLTYPE yylloc
| ^
cfparse.c:1162:9: note: 'cflloc' was previously declared here
cfparse.c:1162:9: note: code may be misoptimized unless '-fno-strict-aliasing' is used
---
- type is vpiPartSelect, not vpiMemoryWord
- left/right range is for part, not full word
- index is not valid for a part select
The user will now get a sensible error message if they pass part of an
array word to $dumpvars (GitHub issue #230).
This fixes the problem reported in GitHub issue #254, where if the
parser aborted on one compilation unit, spurious errors were reported
for the next compilation unit.
- make primitive redefinition a warning, not an error
- make edge-sensitive ifnone a warning, not an error
This allows Icarus to be used to simulate designs using third-party
cell libraries that contain such things.
bison 3.4.1 writes the header file before the c++ file. Our makefile
rules make the header files depend on the c++ files, so we need to
fix the timestamps accordingly.
The signed version of the power operation in vvp should only be used
if the exponent is signed. Both signed and unsigned versions will
produce the correct result regardless of the type of the base operand,
provided it has been appropriately extended to the result size.
When vpi_handle_by_name() iterates over the VPI objects in a scope, handle
the case that vpi_get_str() returns a null value. This currently occurs if
the scope contains an enum type definition, as vpi_get_str() is not
implemented for __vpiEnumTypespec.
Note we only want these enabled when building the compiler and runtime
binaries. If we included the ICARUS_VPI_CONST definition in the global
CPP_FLAGS, that would propagate to the flags used by iverilog-vpi, so
would affect compilation of user VPI code.
Currently $display et al. output nothing when the expression
corresponding to a %c format specification has the value 0. As
Verilog provides no other way to write raw bytes to a file, we
should allow 0 values to be written. Other simulators allow this.
- allow ICARUS_VPI_CONST to be pre-defined by the user
- use it for sizetf as well as for compiletf and calltf
- fix remaining warnings when it is defined as 'const'
When performing a signed division or modulus operation using native
arithmetic, trap the special case that the numerator is the minimum
integer value and the denominator is -1, as this gives an undefined
result in C++.
In traditional Verilog, each task_port_item must have an explicit port
direction.
In SystemVerilog, if the port direction is not specified, it should be
inherited from the preceding task_port_item for that task/function, and
only the first task_port_item should infer the direction to be 'input'.
Predefined macros get stored in the precompiled macro file that gets
read back in when processing library files. This means the predefined
macros get processed twice. We need to skip the check in this case.
A common use case (prior to the introduction of localparam) was to
use macros to define constant values, and to put global constant
values in an include file that gets included by each source file.
This will generate a lot of spurious warnings if we warn about all
redefinitions. Make this new option the default for -Wall.
In vvp, the __vpiSignal object holds a pointer to the scope containing
the signal. This was getting set to the current scope when the net was
finally resolved, rather than to the scope where the net was declared.
This implements and enforces the full set of rules for determining
timescales in SystemVerilog. The previous relaxation of the rules
that allowed timescales to be redefined within the compilation unit
scope has been removed. Time unit and precision redeclarations are
now recognised after a nested module declaration.
This relies on using the automatically generated name for the unit scope.
This could collide with an escaped identifier, so it would be better to
identify the scope by a reference to the PPackage object, but for now,
do it the easy way.
The compilation unit scope is now treated as a specialised form of
package (with an automatically generated name). All items declared
outside a design element are added to the current compilation unit
package. Apart from when searching for a symbol, once we get into
elaboration we can treat these just like any other package.
This adds a -u option to the driver to allow the user to specify that
they want each source file to be treated as a separate compilation
unit, and modifies the compiler to accept a list of files (either on
the command line or via a file specified by a new -F option). This
list of files is then preprocessed and parsed separately, causing all
compiler directives (including macro definitions) to only apply to the
file containing them, as required by the SystemVerilog standard.
Two fixes needed:
- when searching for a base class, we need to look in the root scope
if the base class isn't found in the scope hierarchy
- the classes in the root scope need to be stored in an ordered
list, not a map, to ensure they are elaborated in the order they
were declared. Without this, the compiler may try elaborating an
extended class before its base class is known about.
Verilog spec has a very nasty system of macros jumping from
file to file, resulting in a global macro scope. We abosolutely
MUST track macro redefinitions and warn user about them.
Signed-off-by: Andrew Andrianov <andrew@ncrmnt.org>
If a thread becomes detached due to a join_any statement, that
thread must not attempt to join its parent, even if the parent
is waiting on a subsequent join statement.
This occurs when tgt-vvp attempts to generate a C4<..> constant
value with a bit width >= 65536. The actual failure occurs in the
StringHeap class, which originally supported a maximum string length
of 65535. This fix enables the StringHeap class to support any size
string (provided the system has sufficient memory).
Normally there is at most one signal attached to a vvp functor, but
due to port collapsing, there can be more than one. If these signals
are array words, we need to trigger vpi callbacks on all the associated
arrays when the functor value changes.
If there is a syntax error in the source code, pform_makegate may be
passed a null list of port connections. The error is already reported,
so we just need to ignore it.
Return and print an error if iverilog is unable to open dependencies
file. User can pass e.g path to existing directory in '-M' option,
which makes fopen to return NULL followed by crash in fclose.
(* my_fancy_attribute *)
foobar1 foobar (clk(clk), rst(rst) ...);
- Modifies PGModule to hold the attribute map (can be verified with pform_dump)
- pform_make_modgate(s) bind the attributes from the parser to the above map
- The attributes from PGModule are inserted into the NetScope of that module
PGModule::elaborate_scope_mod_instances_
- Currently these attributes automatically make it into netlist
- These attributes are accessible via ivl_scope_attr_cnt and ivl_scope_attr_val
from ivl_target.h
This was already supported in command files, using the '-v' flag.
'-v' is already in use on the command line, so use '-l' instead,
and make that an alias for '-v' in command files.
Change cbReadWriteSynch and cbReadOnlySynch to interpret the passed
time value as a relative delay, not an absolute time. This matches
the behaviour of other simulators.
Replace explicit comparisons against generation_flag with calls to
the gn_system_verilog helper function, both for code clarity and
to fix a couple of bugs. Also simplify the implementation of the
function, as we already rely on the generation_flag enumeration
being an ordered list.
Arrays type match if they have a common parent, instead of the
element type. Now (un)signed & std_logic_vector types do not match,
as it should be in VHDL.
Pull request #116 added the ability for the iverilog driver to determine
ivl_root from the location of the iverilog executable (this is needed to
support relocation at the time iverilog is installed). However, the code
did not support the possible variations in the library path name.
An out-of-range constant bit select on the LHS of an assignment was being
treated as an error, whereas an out-of range constant part select would
only result in a warning. In any other context, either case would result
in a warning, so convert the error to a warning.
In addition, all warnings for out-of-range or undefined constant bit/part
selects should be controlled by -Wselect-range.
When emitting a design, all scopes must be emitted before emitting any
top level task/function/method definitions, otherwise hierarchical
references can't always be resolved.
SystemVerilog allows tasks, functions, and classes to be defined at the
root level or inside packages, so we can't rely on an enclosing module
being present to provide the timescale.
This just enables the compiler to parse path declarations that
contain part selects. As for bit selects, the part select is
discarded, and if elaboration of specify blocks is enabled,
the path declaration will be applied to the entire vector. If
elaboration is enabled, a warning message will now be output
when a bit or part select is discarded.
This does a better job of setting the intermediate expression types
and widths when calculating the canonical index into a packed array.
It still doesn't properly handle out-of-bound indices (br953).
The existing support for ``, `", and `\`" did not work in nested macro
definitions. Note that the new implementation only detects and replaces
these sequences inside the macro text (as required by the IEEE standard),
whereas the old implementation would detect and replace them anywhere in
the source files.
SystemVerilog allows a mixture of procedural and continuous assignments
to be applied to different parts of the same vector. The previous attempt
to make this work for non-blocking assignments was flawed (see preceding
fix for vvp_fun_part_pv::recv_vec4_pv). Instead, handle this case by
converting the non-blocking assignment into a delayed force statement,
which matches the way mixed continuous and blocking assignments are
handled.
Most vvp functors need to support recv_vec4_pv. Any that are strength-aware
also need to support recv_vec8_pv. Note the simplifying assumption that is
documented in the base class recv_vec4_pv_ implementation.
If all three rise/fall/decay delay values are constant, we can use
the vvp .delay statement variant that takes three literal numbers.
If not, we have to use the variant that takes three net inputs. If
some of the delay values are constant, we need to create constant
drivers for those delay inputs.
If a static variable declared in a task, function, or block has an
initialisation expression, SystemVerilog requires the declaration to
have an explicit static lifetime. This is supposed to be a compile
error, but for now just output a warning.
Implementing this required adding support in the parser for explicit
lifetimes in variable declarations. For now, just output an error if
the user asks for a lifetime that isn't the default for that scope.
A conditional clause that doesn't drive any bits of a particular nexus
should not affect the bitmask generated for that nexus. The completely
undriven case is handled by the enable signal.
Currently limited-length strings (e.g. string(1 to 4)) are
emulated using 2D array of bits (e.g. bit [1:4][7:0]).
Because of that, ivl treats them as standard vectors and
$display() does not show them as strings. Now, they are
wrapped with $sformatf("%s", ..) to fix it.
A compressed assignment statement should give exactly the same
result as the equivalent uncompressed statement. This means
that the type (signed/unsigned) of the LHS affects the type of
the RHS expression (unlike in normal assignments). We need to
take care that bit/part selects and concatenations are correctly
identified as unsigned values, even in the cases where they
reduce to a single whole signal.
The type of extension (zero/sign) is determined by the expression
type, not the operand type, so we need to cast to the expression
type before extending the value.
Added the ability to coalesce set/reset values to different parts
of the same vector. Also added a check that all bits of the vector
are assigned a value.
Enabled coalescence of asynchronous set/reset part-vectors
The destructor needs to delete the stored NetEvent objects. Failure
to do this was causing a compiler crash after synthesis if the
nodangle functor was disabled.
Synthesis could only handle relatively simple conditional constructs.
This rework aims to make it handle anything the user can throw at it
(or output a sensible message as to why it can't).
Flip-flops are generally modelled in behavioural code using non-blocking
assignments. This change makes the synthesised code behave the same as
the behavioural code. It's a more realistic model of a real flip-flop
too, which will always have some clock-to-output delay.
In case of a vhdlpp-specific () call, the timeformat suffix string was overridden,
therefore it has to be restored to the previous value after the call.
The .scope needs to be aware of return types so that the %call/vec4
function knows how to intialize the return value. We also need to
extend the %ret/vec4 to support writing parts of the return value.
Synthesis does not currently support some commonly used styles for
representing flip-flops, e.g.
q <= 0;
if (en) q <= 1;
or
if (clr) q <= 0;
if (set) q <= 1;
For now, output a "sorry" message.
The elaborator allows the RHS of assignment to be wider than the
LHS. When using an if statement to represent a mux, this meant the
mux inputs could be different widths, resulting in an assertion
failure during synthesis. The fix is to prune the RHS to match the
LHS for each assignment. This has the benefit of minimising the
mux width.
When a binary (in)equality comparison has a constant left operand,
the tgt-vvp code generator swaps the left and right operands to
allow the cmpi instruction to be used. The code for swapping the
operands was incorrect.
Create The %callf/* opcodes to invoke user defined functions in a
more specialized way. This allows for some sanity checking on the
way, and also is a step towards keeping return values on stacks.
Otherwise it is not possible to modify their values in subprograms.
Argument elaboration has been moved to a separate function, so now it is
common for procedure and function calls.
This way it is possible to have limited size strings. Previously they
were translated to unpacked array of bytes, which cannot be assigned as
it was a string.
Since glibc version 2.20, _SVID_SOURCE is deprecated, see
'man 7 feature_test_macros'. To be able to compile this code without compiler
warnings in new and old glibc versions, both _DEFAULT_SOURCE and _SVID_SOURCE
must be defined.
Before this patch, only literals on the right side of a < compare
(or left side of a > compare) would be blended into a %cmpi instruction.
This patch broadends the cases where the %cmpi can be used.
In generate blocks such as for loops, there may be many generated
scopes that have the same generated name. But in these cases, there
is an index number in the hname that can be used. So do so.
The bug report was for an assertion failure when a number contained only
a lowline (e.g. 'b_), but the standard says that a number can't start
with a lowline (e.g. 'b_1). The parser already rejected these cases for
decimal numbers, but allowed them through for binary/octal/hex numbers.
parse.y has been updated to allow declarations outside a module (legal
in SystemVerilog), but not all types of declaration are supported yet.
Output a sorry or error message as appropriate.
The reported problem was caused by a null statement in a case statement,
which caused the check for an infinite loop to fail. Further testing
exposed more problems with null statements in loop statements - these
caused crashes earlier in elaboration.
This is syntax permitted in 1364-2001 but removed in 1364-2005.
Also update the iverilog man page to document the anachronisms warning
class that warns about use of this feature when a later generation is
selected.
The compiler was emitting a "sorry" message and aborting compilation when
it encountered attributes on a wire declaration/assignment. Change this
to a warning, as most attributes are ignored anyway.
"# include <string>" was added so "Microsoft Visual Studio Express 2015 RC Web" could compile it without error. "static void operator delete[](void*); was preprocessed so "Microsoft Visual Studio Express 2015 RC Web" could link it without error for a function not yet implemented.
"child->delay_delete = 1;" was added, for when building with "Microsoft Visual Studio Express 2015 RC Web" in DEBUG mode, so that pr2909555.v would pass with -strict, otherwise it would cause memory access error will trying to access the previously deleted "child" variable.
First and second areas were changed for "Microsoft Visual Studio Express 2015 RC Web" so that gold files would match. For the third area of change, "Microsoft Visual Studio Express 2015 RC Web" wanted to print 6 zeros after the decimals for the values of 0.0 and -0.0, and then the gold files wouldn't match.
Changes so "Microsoft Visual Studio Express 2015 RC Web" could build it without a bunch of runtime errors and crashes during regression testing. When declaring an bitfield variable of type enum in a struct, the enum has to have an underlying integer type for MSVC++ when compiling a C++ file, and for these cases, it had to be unsigned integer for everything to work okay during regression testing.
Changes so "Microsoft Visual Studio Express 2015 RC Web" could build it without a bunch of runtime errors and crashes during regression testing. When declaring an bitfield variable of type enum in a struct, the enum has to have an underlying integer type for MSVC++ when compiling a C++ file, and for these cases, it had to be unsigned integer for everything to work okay during regression testing.
First area of Change for "Microsoft Visual Studio Express 2015 RC Web" was for compiling with error when NDEBUG defined. The second and third areas of change for "Microsoft Visual Studio Express 2015 RC Web", the dynamic_cast has to come first so parpkg_test.v, parpkg_test1.v, parpkg_test2.v would pass.
Changes for "Microsoft Visual Studio Express 2015 RC Web" to first check for a dereferencable iterator so pr1741212.v, and many others, will pass with a DEBUG build.
Implicit ports may be unnamed, either because the port expression
is not a simple/escaped identifier, or because there is no port
expression. To handle these cases, error messages should report
the port position as well as the port name.
In the special case that a net is attached to an island port, values
driven onto the net via the VPI must go to the functor, not the filter,
so that they propagate through the island.
When putting a value onto a wire, the value needs to be sent to the
filter, not the functor (the functor may be part of the expression
that drives the wire).
Force and release weren't implemented properly (or at all in the
case of real values). They need to behave the same as the force
and release operations in vthread.cc.
vvp_net_t::force_vec4 propagates all bits of the forced value passed
to it, regardless of the mask value. I can't see any way to fix this
directly, so instead make sure anything that calls force_vec4 sets
the unforced bits of the passed value to the correct value.
Conditions to detect rising/falling edges were incorrect.
VHDL standard specifies it has to detect the current value,
rather than compare against the previous one.
* 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>`