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>
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>
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>
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 `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>
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>
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>
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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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 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.
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.