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