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>