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