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>