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 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>
If the parameter has no explicit type, the type is inferred from the RHS
expression. The first time the parameter is evaluated, the RHS hasn't yet
been elaborated, so the type is unknown. This causes the evaluation to be
performed by NetScope::evaluate_parameter_logic_, which correctly handles
both logic and real types. However, on subsequent evaluations of the
parameter, the expression type is now known, so the evaluation was being
performed by NetScope::evaluate_parameter_real_. This function requires
the parameter to have an explicit type.
For now, rather than add more code to NetScope::evaluate_parameter_real_
to handle an implicit type, force NetScope::evaluate_parameter_logic_ to
be used whenever we have an implicit type. This should probably be reworked
if support for more complex types is added.
Without this fix, ivlh_textio was failing at step 11 where the time is read from the file. This was because clang happens to put period directly after the units buffer on the stack. sscanf writes the terminating NUL overwriting the low byte of period, which is 100, so it returns 0.
Example clang warning fixed:
warning: 'sscanf' may overflow; destination buffer in argument 4 has size 2, but the corresponding specifier may require size 3 [-Wfortify-source]
Both the `vvp_fun_signal_real` and `vvp_fun_signal_string` classes
implement a `size()` method that returns 1. There are no users of these
methods, remove them.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Add regression tests for the following types partial writes for both
2-state and 4-state vectors.
* Non-blocking
* Blocking
* Blocking event control
Check that all in-bounds partial writes, partial out-of-bounds and
full out-of-bounds all works as expected.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Writes to 2-state arrays currently only support full writes. If the write
is a partial write it will trigger an assert. E.g.
```
int a[3:0]
int i = -1;
a[i+:8] = 8'h0; // Triggers assert
```
Add support for partial writes by doing a read-modify-write in the same way
as for 4-state arrays.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%store/vec4a` instruction does not handle partial of full
out-of-bounds writes to a vector array element. Trying to do so will
trigger an assert. E.g.
```
integer a[3:0];
integer i = -10;
a[0][i+:8] = 8'h0; // Triggers assert
```
For fully out-of-bounds writes the write should be skipped, for partial
out-of-bounds writes the value needs to be resized to be within the bounds
of the vector. Use the `resize_rval_vec()` helper function to implement
this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
There are a few functions that handle implement different kinds of vector
writes that have to handle that the assigned value partially or completely
out-of-bounds.
Each function has similar, but not identical, code for this, sometimes with
small bugs for corner cases.
Add a helper function that takes care of handling of updating the width and
offset of the assigned value if necessary.
This ensure consistent and correct behavior and allow to remove some
duplicated code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%assign/vec4/a/{d,e}` instructions, when checking for a full
out-of-bounds write on the low side, uses the target signal width, while it
should use the assigned value width.
This can lead to a fully out-of-bounds write to be assumed to be a partial
out-of-bounds access, which will trigger an assert later on.
E.g.
```
integer a[1:0];
integer i = -4;
a[0][i+:4] <= 4'h0; // Triggers assert
```
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that multiple events can be used in a non-blocking event control
assignment. The assignment should happen if either of the events trigger.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
When multiple events are used in a non-blocking event control they need to
be combined into a single event using `event/or`.
The generated `event/or` statement is missing the trailing semicolon and
newline, which results in parser error when vvp tries to run.
E.g.
```
event e, f;
integer x;
x <= @(e or f) 10;
```
Add the missing semicolon and newline to fix this.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that a non-blocking event control assignment works as expected to a
lvalue concatenation. All values that are part of the concatenation should
only be assigned after the event triggers.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that non-blocking event control assignments works on an array part
select if the part select index is not an immediate value.
This is a copy of the nb_ec_array_pv test, but using variable indices
instead of immediate values.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
A non-blocking event controlled assignment consists of 3 steps.
* Setup event
* Perform assignment
* Clear event
This works fine if the lvalue is a singular value. If the lvalue is a
concatenation multiple assignments are generated and the event is cleared
after each assignment. As a result only the first assignment is event
controlled. All other assignments will be regular non-blocking assignments.
E.g.
```
reg x, y;
event e;
{x,y} <= @e 2'b11;
$display(x, y); // x will be 1'b1, y will be 1'bx
```
To resolve this the event needs to be cleared after all assignments have
been done. This requires changes to both tgt-vvp and the vvp runtime.
tgt-vvp is updated to only insert a single `%evctl/c` instruction for each
event controlled non-blocking assignment.
The vvp runtime is not updated to implicitly clear the event in the
`%assign/vec4/e` instruction and instead rely on the explicit `%evctl/c`.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
VVP array assignment operations expect the array element index to be in
index register 3.
For array element assignments with a dynamic part select the array index
gets moved into a temporary index register and has to be moved into
register 3 after evaluating the dynamic part select. This is currently not
done non-blocking event control assignments. This causes the write to go to
the wrong array element. It will go to whatever value is in the register 3
from previous operations.
```
reg [3:0] a[1:0];
integer i = 0;
event e;
a[1][i+:2] <= @e 2'b10; // Will write to the wrong array element
->e;
```
Make sure to move the temporary register to register 3.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Both the `%concati/vec4` and `%pushi/vec4` instructions need to construct a
vector from the immediate value encoded in the instruction. Currently both
these instructions have a custom implementation for that.
Remove the custom implementations from those functions and use the
`get_immediate_rval()` helper function. This removes a bit of duplicated
code.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%cmp/ws` and `%cmp/wu` instructions compare two index registers. They
are currently unused. Since the index registers are not used for data there
is not really a need to compare them. Values can be compared before loading
them into an index register.
So remove these two instructions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `%mov/wu` instruction moves data from one index register to another.
The instruction is not used. It also does the same as `%ix/mov`. So remove
it.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The `recv_vec{4,8}_pv()` functions are used to implement a partial write to
a vector. As parameters they take both the value and the width of the
value.
All callers of of these functions pass `val.size()` or a variation thereof
as the width of the value. And all implementations that do anything with
the data have an assert that `val.size() == wid`.
Remove the `wid` parameter from these functions and just use `val.size()`
directly where needed. This allows to simplify the interface and also
to remove the asserts.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Check that assignment operators on real array entries are supported.
Also check that
* out-of-bounds indices work as expected
* it works after a comparison that set vvp flag 4 to 0
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The basic structure for supporting assignment operators on real arrays
exists in the tgt-vvp backend. But there are a few problems, most
importantly it generates the wrong instruction for loading data from the
real array.
The instruction it uses is `%load/reala`, but that instruction does not
exist, the correct name is `%load/ar`.
In addition to this there are a few minor problems.
* Out-of-bounds access on the array triggers an assert
* Missing `%pop/real` instruction when skipping a write due to
out-of-bounds access
Address these so assignment operators are supported on real array entries.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>