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>