Implement the IEEE 1364 structural VPI objects that Icarus previously left
unimplemented, so a single-source consumer (e.g. a dataflow/waveform viewer)
gets real data instead of empty fallbacks. Each object is sourced faithfully
from the compiler and threaded ivl -> tgt-vvp -> .vvp directive -> assembler
-> runtime __vpi* -> scope iterator -> vpi_user.h constants.
* vpiProcess (always/initial/final): .process directive from ivl_design_process;
object reports vpiType/vpiLineNo/vpiFile/vpiScope.
* vpiPrimitive / vpiPrimTerm (gate/switch/UDP): .primitive directive from
ivl_scope_logs; reports vpiPrimType, vpiSize (#inputs), name, location, and
iterates terminals (vpiDirection, vpiTermIndex).
* vpiDriver: the tri resolver already retains each driver's value+strength;
tgt-vvp tags each input with its driver scope (.resolv_drv), and
vpi_iterate(vpiDriver, net) exposes per-driver value (vpiStrengthVal) and
scope. signal->node->fun is the resolver, so no extra linkage is needed.
* vpiContAssign (+vpiLhs/vpiRhs): continuous assignments are preserved through
the frontend (NetScope records each lval/rval/location/drive in
PGAssign::elaborate; dll_target::end_design builds ivl_cont_assign_s, exposed
via the new ivl_scope_cassigns/ivl_cassign_* API); tgt-vvp emits .contassign
and the runtime materialises __vpiContAssign. vpiLhs/size/location are always
faithful; vpiRhs resolves to the r-value net for simple assigns and is null
for an expression r-value (anonymous synthesised temp).
* EVCD ($dumpports) inout conflict states: sys_evcd.c walks vpiDriver on an
inout's net, separates module-side from external drives by scope, and maps
the pair to the full IEEE 1364-2005 18.4.3 state characters (0/1/?/F, the
A/a/B/b/C/c conflicts, and d/u/l/h by drive strength) instead of collapsing
a genuine bus conflict to '?'. New ivtest evcd_inout covers it.
Full Verilog regression (regress-vlg.list) stays clean: the only failures are
pre-existing (gold-less Expected-Fail tests, a VHDL test, a test needing
-gno-io-range-error, and a pre-existing .port_info bug).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This causes tgt-vvp to use a lower case 'c' instead of an upper case
'C' as the prefix for constant values used to initialise undriven nets.
For use by the following commit.
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 `%disable` instruction will stop the execution of all active
threads of a specific scope. This is what is required to implement
the semantics of the Verilog `disable` statement.
But it is not suited to implement the SystemVerilog flow control
statements such as `return`, `continue` and `break`. These only
affect the thread hierarchy from which it is called, but not other
concurrently running threads from the same scope.
Add a new `%disable/flow` instruction that will only disable the thread
closest to the current thread in the thread hierarchy. This can either be
the thread itself or one of its parents. This will leave other concurrent
threads of the same scope untouched and also allows function recursion
since only the closest parent thread is disabled.
Note that it is not possible to implement this using `%jmp` instructions
since a block in a function with variable declarations will be its own
sub-thread, but using flow control instructions it is possible to exit from
that thread to the parent scope, which is not possible with `%jmp`
instructions.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
IEEE Std 1800-2017 Section 7.6 Array assignments
Assignment of a dynamic array creates a duplicate of the source,
so that assignments to the copy don't impact the original. Handle
all sorts of dynamic array base types.
In 64-bit Windows, an unsigned long is 32 bits, so initialising the num
member of the union did not properly initialise the ptr member. The num
member isn't actually needed, so eliminate it.
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.
The .scope needs to be aware of return types so that the %call/vec4
function knows how to intialize the return value. We also need to
extend the %ret/vec4 to support writing parts of the return value.
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.
These bypass the vec4 stack in some common cases, saving instructions
and vec4 manipulations.
Also, minor improvement to the %flag/set/vec4 statement.
Kill a few warnings.