VCS SimLink Backend
August 11, 2026 ยท View on GitHub
This backend implements the common SimLink leaves with Synopsys VCS VHPI. See the architecture reference and shared C internals. For common dependencies, backend selection, and the first transaction, start with the getting-started guide.
Call chain and value representation
The VHDL leaves carry a VHPI FOREIGN attribute naming each model's init
function. At elaboration, each Rogue*Init supplies a static direction/width
table to VhpiGeneric, which allocates port values and registers a clock
value-change callback. The generic callback reads VHPI values, calls the model
update, and writes outputs. The model update detects the rising edge and
invokes one shared FSM step.
VHPI exposes scalar and vector enumeration values. VhpiGeneric converts
logic zero/one to integers and vectors before the shared step, then performs
the inverse conversion for outputs. Ports up to 32 bits retain the historical
integer representation. Wider Stream ports use little-endian arrays of 32-bit
words, with the elaborated vector width inferred from RogueTcpStream.
Build and load
A VCS environment must define VCS_HOME and VCS_VERSION; the ruckus VCS
flow defines SIMLINK_PWD. The Makefile compiles the three adapters and
VhpiGeneric.c with the VCS headers into one libRogueSimLinkVhpi.so:
make -C simlink/vcs \
SIMLINK_PWD="$PWD/simlink/vcs" \
VCS_HOME="$VCS_HOME" VCS_VERSION="$VCS_VERSION"
Use the normal ruckus VCS simulation target for a project build. SURF also provides an opt-in cocotb regression that builds this library, compiles the same active eight-instance VHDL topology used by GHDL, wraps it with a thin SystemVerilog VPI-visible bridge, and runs the common tagged-traffic scenario through VCS. The bridge is required because cocotb supports VCS through VPI, not through a VHDL VHPI top; the production Rogue leaves inside the topology continue to use their independent VHPI callbacks.
source /sdf/group/faders/tools/synopsys/vcs/X-2025.06/settings.sh
export VCS_VERSION=2025
export SIMLINK_RUN_VCS=1
export SIMLINK_VCS_LICENSE_FILE=27000@cadlic-ext.stanford.edu # optional
./.venv/bin/python -m pytest -q -n 0 \
tests/simlink/vcs
SIMLINK_RUN_VCS=1 is an intentional license-checkout opt-in. The test skips
unless it is running on Linux with VCS_HOME, VCS_VERSION, vcs, vhdlan,
vlogan, the C build tools, and that opt-in. VHDL and the SystemVerilog bridge
are pre-analyzed into the same work library before elaboration. Every build,
elaboration, simulation, peer, and cocotb wait is bounded.
SIMLINK_VCS_LICENSE_FILE, when set, overrides
SNPSLMD_LICENSE_FILE only for the test subprocesses; this is useful on hosts
whose default server list begins with an unreachable license server.
Lifecycle and limitations
The legacy axi/simlink/src implementation had no simulator-restart callback
or preserved-state mechanism. Every elaboration allocated fresh zeroed model
state, and the functions then named Rogue*Restart merely created and bound
the ZeroMQ sockets after the port was first sampled. The familiar workflow in
which Rogue survived a VCS reload worked because Rogue's client sockets stayed
alive and reconnected when the newly loaded model rebound the same ports.
Queued client work could consequently arrive as a burst after reload.
The aligned implementation retains that external-software contract. Its
internal transport-start functions are named Rogue*StartTransport to avoid
confusing socket startup with a simulator restart. It does not attempt to copy
old simulator-side FSM state into newly loaded modules.
- Model, port metadata, port-value, vector-buffer, and name allocations are checked and report a fatal VHPI error on failure. Callback records are embedded in retained metadata rather than allocated separately.
- No
vhpiCbEndOfSimulationcallback is registered in the cocotb/VCS flow. Registering it can race VPI teardown and cause a simulator shutdown fault. Commonatexitcleanup handles worker/socket side effects. The exportedVhpiGenericCleanuproutine still removes value/error callbacks, releases callback and port handles, frees vector values and names, and destroys each common instance when a safe non-cocotb caller invokes it. - The common process-wide registry rejects invalid, changed, and overlapping complete port pairs before socket bind.
- All sockets are worker-owned; VHPI callbacks do not call ZeroMQ.
- Parameterized Stream beats support 1 through 128 data bytes.
- Checked-in active-traffic coverage uses VCS X-2025.06.
- An opt-in licensed regression elaborates and invokes VCS twice against one
persistent peer, with its second request queued between
simvruns. The exact in-place VCS GUI/UCLI module re-exec command still needs separate characterization, especially with an interrupted transaction.
The generic lifecycle and declarative adapter ABIs also have a simulator-free
native regression under tests/simlink/native/. It verifies that the end
callback is absent and calls VhpiGenericCleanup directly. See the
test matrix for exact VCS coverage.