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>
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>
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>
A `return` statement in a function gets translated into a vvp `%disable`
instruction. This works fine as long as no recursion is involved. The
`%disable` instruction will stop execution of all active threads of a
particular scope. For recursive functions this means as soon as the inner
most function returns all containing outer function calls get disabled as
well. This results in incorrect behavior.
To make recursive functions using the `return` statement work use the new
vvp `%disable/parent` instruction. This instruction will only disable the
closest thread in the thread hierarchy that matches the target scope.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
The unique, unique0, and priority keywords can decorate case statements
to tell the run time (or synthesis) to do extra tests (or make extra
assumptions). These tests are not implemented in the vvp run time, but
now the decorations make it to the code generators.
SystemVerilog allows a mixture of procedural and continuous assignments
to be applied to different parts of the same vector. The previous attempt
to make this work for non-blocking assignments was flawed (see preceding
fix for vvp_fun_part_pv::recv_vec4_pv). Instead, handle this case by
converting the non-blocking assignment into a delayed force statement,
which matches the way mixed continuous and blocking assignments are
handled.
Create The %callf/* opcodes to invoke user defined functions in a
more specialized way. This allows for some sanity checking on the
way, and also is a step towards keeping return values on stacks.
Defining __USE_MINGW_ANSI_STDIO=1 provides C99 compatible printf
and scanf routines, which avoids the need for workarounds for the
various failings of the Microsoft C runtime library.
If either the index or part offset expressions generate an undefined
value then the assignment is skipped. This patch reworks the code that
handles the flags used to detect this. For some simple cases a global
flag is not needed, but for other cases one is needed since there are
two expressions that can generate an error and even when there is only
a variable expression this error state needs to be preserved if there
is a variable delay. An undefined delay value defaults to zero and is
not an error.
When generating code for a condition expression, i.e. directly
before a %jmp/X statement, try to generate the result into the
flag bit without passing through the vec4 stack. For example, the
%cmpX/X instructions generate results into the flag bits, so it
makes no sense to push these bits into the vec4 stack then pop
them back into the flag bit. So try to handle this case.
A procedural continuous assignment is supposed to be updated any time
a variable on the RHS changes. Currently this only happens if the RHS
is a simple signal.