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 for various dynamic array and queue types that their type
compatibility is handled correctly.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Icarus allows to pass a value of the element type as an argument to the
dynamic new operator. To allow this the type compatibility check for
dynamic arrays allows both the dynamic array type itself and also the
element type.
This currently leads to a confusing error message if neither type matches.
The error message will say that the passed value is not compatible with the
element type. E.g.
```
real d1[];
int d2[];
d1 = d2;
```
results in
```
error: the type of the variable 'd2' doesn't match the context type.
: variable type=dynamic array of netvector_t:bool signed[31:0]
: context type=real
```
This is slightly confusing. Change the way the error message is reported so
that the context type is the type of the dynamic array and not the element.
With the change the above results in
```
error: the type of the variable 'd2' doesn't match the context type.
: variable type=dynamic array of netvector_t:bool signed[31:0]
: context type=dynamic array of real
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog defines different levels of type compatibility.
* Matching
* Equivalent
* Assignment compatible
* Cast compatible
At the moment the `nettype_t` has only one type compatibility test. It is
used to check assignment compatibility when assigning to a dynamic array,
queue or class.
The current implementation rejects a few cases that should allowed and
allows a few cases that should be rejected.
Dynamic arrays and queues are assignment compatible if their element types
are compatible. And two packed types are equivalent if they are both
2-state or 4-state, both signed or unsigned and have the same packed with.
In the current implementation the sign is not considered and instead of
checking if the packed width is the same it checks that the dimensions are
identical.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `netdarray_t` type implements the `packed_width()` method by returning
the packed width of the element type. It is the only non-packed type that
implements the method.
This triggers an assert in the vlog95 backend for tasks with dynamic array
typed parameters. And while the vlog95 backend does not support dynamic
array types it should not result in a crash, just an error message.
The only place that relies on the behavior that the packed width of the
element type is returned is in the vvp backend where variable declarations
are generated. Update that code to query the packed width of the element
type instead and then remove the `packed_width()` implementation for the
`netdarray_t` type.
This fixes the assert in the vlog95 backend. But it is also nicer from an
architectural perspective as this brings the type in line with the other
types in terms of behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The C++ API for `ivl_type_t` has a method to query the total width of a
packed type. This is currently not exported to the C API and the tgt-vvp
backend implements similar functionality by querying the individual
dimensions of a type.
Export the `packed_width()` method to the C API. This allows to remove the
custom implementation from the tgt-vvp backend.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Current regression tests only cover checking for invalid non-blocking
writes to constructs that are valid in Verilog. Add two tests to
additionally cover some SystemVerilog constructs.
* Non-blocking writes to members of a struct typed variable with automatic
lifetime
* Non-blocking writes to class typed variables with automatic lifetime
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `PEIdent::has_aa_term()` method still uses the old `symbol_search()`
and will fail to find the variable if part of the identifier path is a
member select of a variable.
As a result such writes to fields of automatic structs can be classified as
static and it is possible to do non-blocking assignments to them. E.g.
```
task automatic t;
struct packed {
logic x;
} s;
s <= ...; // This fails
s.x <= ...; // This works, but should fail
endtask
```
Switch to the new symbol search to make sure this case is handled
correctly. The new symbol search will correctly handle identifier paths
that have a trailing item after the variable, while the old symbol search
will always return an error in that case.
Note that while it is not allowed to do a non-blocking write to a class
object automatic variable, it is allowed to do a non-blocking write to a
property of a class object that is stored in an automatic variable, as the
non-blocking write is supposed to capture a reference to the object and not
reference the variable. E.g.
```
class C;
int x;
endclass
task automatic t;
C c;
c <= ...; // Not allowed
c.x <= ...; // Allowed
endtask
```
Non-blocking access to class properties is not yet support in
Icarus in general, but the error handling for that needs to be done
somewhere else.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that default values for class methods are handled correctly and it is
possible to omit any argument. Check it for both functions and tasks.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For class function method calls currently only as many arguments as have
been supplied are elaborated. Any trailing arguments that might have default
values are skipped. This will trigger an assertion later on in the vvp code
generator backend.
Fix this by making sure that all arguments of the function are evaluated.
Note that this already works correctly for class task method calls.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to reference a package scoped identifier that has
the same name as a local identifier, but is a different kind of identifier.
* A variable or function identifier from a package scope if it is a
type identifier in the current scope
* A type identifier from a package scope if it is a non-type identifier
in the current scope
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
In order to avoid conflicts in the grammar the lexer distinguishes between
identifiers and type identifiers. To correctly classify an identifier the
lexer needs to know in which scope a token is parsed. E.g. when the parser
encounters a package scope operator it calls `lex_in_package_scope()` to tell
the lexer which scope the following identifier should be classified in.
Currently the `lex_in_package_scope()` is only used when a type identifiers
is parsed, but on for normal identifiers. As a result it is not possible to
reference variables or function from a package scope that have the same
name as a type identifier in the current scope. E.g.
```
package P;
int T;
endpackage
module test;
typedef int T;
initial $display(P::T);
endmodule
```
Another problem is that in expressions both type identifiers and signal
identifiers can be referenced. As a result there are two rules in an
expression that can be reduced
* <PACKAGE_TYPE> :: <TYPE_IDENTIFIER>
* <PACKAGE_TYPE> :: <IDENTIFIER>
The way the rules are formulated at the moment the parser has to use token
lookahead to decide which rule to follow before it can reduce the package
scope operator. As a result the lexer detects the token before
lex_in_package_scope() is called and the identifier does not get evaluated
in the package scope, but in the current scope. Which can cause the
identifier to be misclassified. E.g.
```
package P;
typedef int T;
shortint X;
endpackage
module test;
typedef byte X;
initial $display($bits(P::T));
initial $display($bits(P::X));
endmodule
```
Here `P::T` gets classified as a signal identifier and `P::X` gets
classified as a type identifier.
To solve this introduce a common rule for the package scope operator. Using
the same rule everywhere allows the parser to reduce it unconditionally
without using lookahead.
Note that there are additional problems with resolving the type of a scoped
type identifiers in expressions, but this is a prerequisite to solve that.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to declare an unpacked array type with an
unpacked array type as the base type.
Also check that it is possible to declare an signal with an unpacked array
dimension with an unpacked array base type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
It is currently possible to declare an unpacked array with multiple
dimensions. But trying to declare an unpacked array that has another
unpacked array as a base type will result in undefined behavior. E.g.
```
typedef int T1[1:0];
typedef T1 T2[3:0];
T2 x[7:0];
```
To support this recursively unwrap the data type and add the unpacked
dimensions to the signal until the base type no longer is a unpacked array
type.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that for a module port with an array type identifier the type is
elaborated in the right scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
elab_anet.cc was removed from the build in commit 4a8be3db9c ("Implement
bi-directional part selects."). But the file itself was never removed,
remove it now.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that package scope function calls work with and without arguments as
well as empty positional arguments.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parser currently only allows package scoped functions to be called if
there is at least one argument. But package scoped functions are the same
as normal functions and it is allowed to call them with no arguments. It is
even possible to pass no value for a positional argument, if the positional
argument has a default value.
Update the parser to handle this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For function calls when calling the PECallFunction() constructor a copy is
made of the argument expression list. This means the original list should
be deleted within the rule.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
If the type of a port is an array type it currently always gets evaluated
in the scope where the port is declared.
But if the type is a typedef it might be declared in a different scope and
must be evaluated in that scope. E.g. the following will declare an array
port with 10 entries and an element type of a 5 bit vector, while it should
declare one with 4 entries and an element type of a 2 bit vector.
```
localparam A = 2;
localparam B = 4;
typedef [A-1:0] T[B];
module test (
T x
);
localparam A = 5;
localparam B = 10;
endmodule
```
This is in part due to array types being given special handling. This was
necessary before because each base type required slightly different
handling and so the base type had to be extracted from the array type.
This has now been consolidated and all data types are treated the same.
The only exception is the vector type which still needs special handling to
support separate definition of port direction and type.
As a result it is possible to remove the special handling of the array
type. This solves the problem of evaluating the type in the wrong scope.
Some special handling needs to be retained though to be able to
differentiate between array dimensions that are part of a type and array
dimensions that are part of port declaration. This is again necessary to
correctly support separate definition of port direction and type. E.g. in
the example below port `x` and `y` get treated slightly differently, even
though the resulting signals will be identical.
```
typedef logic [7:0] T[1:0];
...
input T x;
input [7:0] y[1:0];
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that it is possible to copy empty dynamic arrays and queues.
If the target is a dynamic arrays there are two ways of copying. Through
direct assignment as well as the array new operator.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
An empty dynamic array or queue is represented by a null object in vvp.
Currently when trying to copy such an object results in undefined behavior
in various places. Either hitting an assert or causing a nullptr
dereference.
Make sure that the empty object is handled correctly by treating it as a
special case.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There is nothing special to do for return class objects from a function.
They can be handled the same as other objects such as dynamic arrays and
queues.
But there currently is an assert in the code that handles function calls
assigned to objects that will trigger if the target type is not an queue or
dynamic array.
This is because Icarus allows dynamic arrays to be initialized with a
single value and for that the element with of the dynamic array needs to be
known, so the single value expression can be evaluated correctly.
Since classes can not be initialized from vector expressions the width does
not matter in that case.
Update the code to only query the element width if the target type is an
dynamic array or queue and pass a placeholder value of 1 for the width
otherwise.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For modules with parameters the vlog95 backend generates one module
declaration for each module instance. This is done so that different values
for the module parameters can be supported.
Local parameters are guaranteed to have the same value for all module
instances though. Add support for detecting the case that all module
parameters are local parameters and in that case only create one shared
module declaration. This is similar to what the vhdl backend does.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
We differentiate between local and non-overridable parameters
in the frontend to be able to generate better error messages.
For the backend they should both be considered local parameters.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a packed struct or union with an unpacked array, dynamic array
or queue as a member is detected as an error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Unpacked dimensions for struct or union members are currently silently
discarded. E.g.
```
struct packed { int x[2]; } s;
```
will elaborate successfully as a struct with a non-array int typed field.
This should instead elaborate to an unpacked array of ints typed field. And
subsequently, since unpacked arrays are not allowed in a packed struct or
union, result in an error instead.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The figure_packed_base_type() method can be used to check whether a type is
2-state or 4-state at parse time. The parser no longer cares about the
specific type of a data type. The figure_packed_base_type() function is
no longer used, so remove it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Packed arrays are only allowed of packed base types. Currently whether the
base type is packed is checked before elaborating the base type.
This works as long as the actual type is known before elaboration. But for
example with type parameters the actual type is only known after
elaboration. In order to be able to support type parameters move the check
for whether the type is packed after elaboration.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The parser used to have behavior that was dependent on the
`ivl_variable_type_t` of a signal. It also used the `ivl_variable_type_t`
of a signal to decide whether a signal can be re-declared as part of a
non-ANSI port declaration.
Neither of these is done anymore and most of the reference to
`ivl_variable_type_t` can be removed from the parser. The only thing it is
still needed for is to decide whether a vector type is 4-state or 2-state.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
`pform_make_task_ports()` has code very similar to `pform_set_net_range()`.
Use that helper function instead of duplicating the code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
pform_module_define_port() has code very similar to `pform_set_net_range()`.
Use that helper function instead of duplicating the code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Now that pform_set_range() is only used for vector types pass the
vector_type_t as an argument rather than deconstructing the type into range
and signedness.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>