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>
Check that all kinds of invalid repeated task port declarations are
detected as errors. They should not crash the application nor should they
result in successful elaboration.
The tests are created for corner cases that previously resulted in
incorrect behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that all kinds of invalid module port declarations, where the
declaration conflicts with previous declarations, are detected as errors.
They should not crash the application nor should they result in successful
elaboration.
The tests are created for corner cases that previously resulted in
incorrect behavior.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that when port direction and data type are declared separately that
an error is reported if the port direction has an explicit range
specification, but the data type has not. This should even be the case if
the data type has an implicit range, e.g `int` or a struct type.
For vector types also check that it is an error if the ranges are not
identical.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that when port direction and data type are declared separately that
an error is reported if the port direction has an explicit range
specification, but the data type has not. This should even be the case if
the data type has an implicit range, e.g `int` or a struct type.
For vector types also check that it is an error if the ranges are not
identical.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
(System)Verilog allows to declare the port direction separate from the
signal declaration. E.g.
```
output x;
integer x;
```
But this is only allowed if the port declaration
* does not have an explicit net type
* does not have an explicit data type
* is a non-ANSI style declaration
For all other cases of port declarations the signal is considered fully
defined and it is not allowed to have a separate signal declaration.
In addition the declared packed dimensions need to match between the port
and signal declaration.
In the current implementation there are a few cases where this is not
handled correctly.
1) It is possible to declare non-ANSI task ports with the same name over
and over again, if it was declared as a signal before the port.
```
task t;
string x;
input logic x;
output real x;
endtask
```
2) It is possible to re-declare non-ANSI input ports of a module that have
a data type, but no explicit net type.
```
module M;
input integer x;
wire integer x;
endmodule
```
3) It is possible to re-declare a ANSI port if it has an implicit data type.
```
module M(output [1:0] x);
reg [1:0] x;
endmodule
```
4) It is possible to declare a vector signal for a scalar non-ANSI task
port.
```
task t;
input x;
reg [7:0] x;
```
To handle all of these correctly refactor signal declaration and lookup a
bit.
The PWire class that represents a signal already has two flags `port_set_`
and `net_set_`. These flags indicate whether a signal has already been used
in a port or signal declaration. A port declaration that includes an
explicit data type is considered both a port and signal declaration.
Use these flags to decide whether it is possible to extend an existing
declaration. E.g. when creating a port without an explicit data type and a
PWire by that name already exists and the `port_set_` flag is not set
extend the existing PWire. On the other hand if the `port_set_` flag is
already set report an error.
Similar for signals but with the `net_set_` flag.
For port declarations with an explicit data type or ANSI style port
declarations it is always an error if a PWire by that name already exists.
This is for both module and task/function ports.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are some tests that use non-ANSI style task port declarations where
the port direction has no packed range specification, but the corresponding
signal declaration has as range specification.
This is not valid, the standard requires the range specification for both
to match.
These tests are currently passing because this error is not detected if the
port direction declaration is scalar.
In preparation for eventually detecting this error set the
`no-io-range-error` flag for these tests. When this flag is set the error
is downgraded to a warning.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The br_ml20150606 regression test uses ANSI style port declarations, but
also re-declares the ports inside module as signals.
This is not valid (System)Verilog, even though the data type in the port
declaration is an implicit type. An ANSI-style port is always fully
defined. This defined section 23.2.2.2 ("ANSI style list of port
declarations") of the SystemVerilog LRM (1800-2017) and section 12.3.4
("List of ports declarations") of the Verilog LRM (1364-2005).
The test was originally added in response to a similarly non-compliant test
in the Yosys test suite, but that test has subsequently been updated to
conform to the standard[2].
Remove the non-compliant test in preparation for adding strict standard
compliance checking on ANSI port redeclarations.
[1] https://sourceforge.net/p/iverilog/mailman/message/34182256/
[2] https://github.com/YosysHQ/yosys/issues/1570
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The default implementation of the virtual method `NetExpr::has_width()`
returns true. There are a few classes that directly inherit from NetExpr
that override the method with the exact same implementation. Remove these.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are no users for the `NetScope::find_enumeration_for_name()` and
`Definitons::enumeration_for_name()` methods. Remove both of them.
The last user was removed in commit 61a088fa78 ("Use elaborate_type()
infrastructure to elaborate signal types").
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The last user of the `make_range_from_width()` was removed in commit
f6042033d0 ("Correctly handle separate port type declaration for
`integer` and `time`").
Remove the function itself as well.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The last user of the `PExpr::is_the_same()` method was removed in commit
37b60a4c52 ("Clean up interface of the PWire class").
Remove the method.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that default values are support for module port lists.
* For output ports it is supported in both Verilog and SystemVerilog.
* For input ports it is only supported in SystemVerilog.
* For inout ports it is never supported
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Both Verilog (2005) and SystemVerilog support default port values for
variable output ports. SystemVerilog also supports default port values for
input ports. For port declaration lists it is possible to specify the
default value for port identifier.
E.g.
```
module M (
input integer x, y = 1,
output integer z, w = 2
) ...
```
Currently the parser only supports specifying the default value for the
first identifier in the list. Extend the parser to also allow to specify
the default value for identifiers in the list.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few places where it is possible to provide an optional
initializer in the form of `[ = <expression> ]`.
There are currently multiple rules that implement this behavior as well as
few places with duplicated rules, one with and one without the initializer.
Introduce a common helper rule for optional initializers. This allows to
remove some duplicated code from the parser.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
For output port lists with a default value for the first port declaration
all subsequent port declarations are declared as inout ports. This is due
to a small typo when setting the `port_declaration_context` port direction.
Fix this to make sure all ports in the port declaration list are declared
as output ports.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that SystemVerilog sign cast are supported correctly. The regression
tests are modeled after the existing tests for $unsigned/$signed.
They check that
* Width extension is done correctly on the cast expression
* Expressions in the sign cast are evaluated as self-determined
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog supports sign cast where it is possible to change the
signedness of an expression. Syntactical it is similar to width or type
casting, except that the keywords 'signed' or 'unsigned' are used in front
of the cast operator. E.g.
```
logic [3:0] a = 4'b1000;
logic [7:0] b = signed'(a); // b is 8'b11111000;
logic signed [3:0] c = 4'b1000;
logic signed [7:0] d = unsigned'(c); // d is 8'b00001000;
```
As noted by the LRM section 6.24.1 ("Cast operator") applying a sign cast
to an expression is equivalent to calling the $signed() and $unsigned()
system functions on the expression.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that the var keyword is supported in the following contexts
* Module ports (both ANSI and non-ANSI)
* Module variable declarations
* Package variable declarations
* Task and function ports
* block variable declarations
* for loop variable declarations
Also check that it is an error to use the var keyword in a for loop without
an explicit data type, as that is not allowed by the standard.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog adds the `var` keyword that can be used to declare a signal
as a variable.
In contexts where a signal is always a variable it is purely optional and
it makes no difference whether it is specified or not. This is in
* for loop variable declarations
* task and function port declarations
For variable declarations as block items when `var` is used it is possible
to omit the explicit data type and use a implicit data type instead. E.g.
all of the following are valid.
```
var x;
var signed y;
var [1:0] z;
```
For module input and output ports the `var` keyword can be used in place of
the net type. It can be combined with either an implicit or explicit data
type.
E.g.
```
input var x
output var [1:0] y
```
inout ports can not be variables and will be reported as an error.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Refactor the variable lifetime parser rules so that instead of having too
rules, one with lifetime and one without, there is a single rule where the
lifetime is an optional element.
This helps to avoid a combinatorial explosion of parser rules once we
add `var` support.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Currently the parser can recover from `integer` or `time` variable
declarations, but not for variables of other types. Refector the parser
rules so that it can recover for all variable types as well as events.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
SystemVerilog allows input ports to be variables. If something is connected
to the input port it will be converted to an unresolved wire.
This is handled the same as having a continuous assignment on a
SystemVerilog varibale.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>