Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
f4a4927
feat(simlink): add Vivado xsim DPI-C co-simulation backend
ruck314 Jul 8, 2026
2350f79
Create plan for multi-instance streams.
bengineerd Jul 16, 2026
b0af9ac
fix(simlink): support multiple xsim DPI instances
bengineerd Jul 16, 2026
60f360b
Fix makefile and tests.
bengineerd Jul 16, 2026
40df756
Add design spec for xsim multi-instance live traffic test
bengineerd Jul 16, 2026
a89ad8d
Add implementation plan for xsim multi-instance live traffic test
bengineerd Jul 16, 2026
9155a31
test(simlink): add per-tag vector helpers for xsim traffic peers
bengineerd Jul 16, 2026
edab6b3
feat(simlink): thread optional --tag through Rogue-TCP peer modes
bengineerd Jul 16, 2026
4696742
refactor(simlink): extract shared xsim test helpers into xsim_test_utils
bengineerd Jul 16, 2026
12746aa
test(simlink): xsim live-traffic top + orchestration for Stream insta…
bengineerd Jul 16, 2026
fca53b2
fix(simlink): spawn xsim traffic peers after elaboration; raise peer …
bengineerd Jul 17, 2026
9881a3a
test(simlink): add Memory instances to xsim live-traffic top
bengineerd Jul 17, 2026
4efd039
test(simlink): add SideBand instances to xsim live-traffic top
bengineerd Jul 17, 2026
72236a7
test(simlink): finalize xsim traffic isolation checks and settle-dela…
bengineerd Jul 17, 2026
64d1653
docs(simlink): record xsim live-traffic validation progress notes
bengineerd Jul 17, 2026
481ffcf
test(simlink): rename traffic test to reflect full 8-instance scope
bengineerd Jul 17, 2026
0368541
test(simlink): use surf.AxiDualPortRam as the xsim Memory AXI-Lite slave
bengineerd Jul 17, 2026
0b7935c
docs(simlink): clarify AxiDualPortRam write-data coverage and surf so…
bengineerd Jul 17, 2026
c505a2e
docs(simlink): update progress notes for AxiDualPortRam memory slave
bengineerd Jul 17, 2026
f20b421
Refactor RogueXsimTrafficTb and rogue_tcp_peer for improved tagging a…
bengineerd Jul 18, 2026
04d38ef
docs(simlink): update README with additional xsim examples and clarif…
bengineerd Jul 18, 2026
9386f89
docs(simlink): update README and progress notes for xsim live-traffic…
bengineerd Jul 18, 2026
5c62fee
Merge branch 'ci-RogueTcpMemoryWrap-RogueTcpStreamWrap' into cosim-xsim
bengineerd Jul 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ ruckus
ruckus/
build/
sim_build*
xsc.pb
.coverage*

# Local editor/agent state
Expand Down
2 changes: 1 addition & 1 deletion axi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ This tree contains reusable AXI-family RTL and wrappers. Top-level `axi/ruckus.t
- `axi4/`: full AXI4 support blocks and adapters.
- `bridge/`: bridges between AXI-family buses and SURF protocol records.
- `dma/`: DMA register, descriptor, FIFO, and stream integration cores.
- `simlink/`: simulator-link support and C/C++/VHDL pieces used by simulation flows.
- `simlink/`: simulator-link support and C/C++/VHDL pieces used by simulation flows (GHDL, VCS, and Vivado xsim backends). See [simlink/README.md](simlink/README.md) for the Rogue TCP/SideBand co-simulation usage guide.

Use existing package record types before adding flattened ports. Put durable adapter entities in `ip_integrator/` or `wrappers/`, and keep executable cocotb tests under `tests/axi/`.
83 changes: 83 additions & 0 deletions axi/simlink/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Simlink

This directory holds three interchangeable Rogue co-simulation backends -- GHDL/VHPIDIRECT (`ghdl/`), Synopsys VCS/VHPI (`vcs/`), and Vivado xsim/DPI (`xsim/`) -- selected automatically by `ruckus.tcl` based on the active simulator. All three backends share the same `shared/` C cores and speak the same ZeroMQ wire protocol to a Rogue-side Python peer, so a testbench built against one backend behaves the same on any of the others.

## Prerequisites

- `libzmq >= 4.1.0` -- check with `pkg-config --modversion libzmq`.
- Vivado simulator tools (`xsc`, `xvlog`, `xvhdl`, `xelab`, and `xsim`) for
the xsim backend.
- A compatible Rogue or ZeroMQ peer for the selected Stream, Memory, or
SideBand wire protocol.

## Running the Vivado xsim Co-Simulation

An external target must provide a simulation top containing one or more
`RogueTcpStream`, `RogueTcpMemory`, `RogueSideBand`, or corresponding SURF
wrapper instances. It must drive clock/reset, assign a distinct two-port pair
to every live instance, and provide a peer that implements the matching wire
protocol. The first instance uses `portNum` and `portNum+1`; a subsequent
instance must therefore start at least two ports higher.

From a target using the standard ruckus simulation flow, run `make gui` or the
target's xsim make target. `axi/simlink/ruckus.tcl` selects `xsim/`, the build
creates the combined `RogueTcpDpi.so`, and elaboration binds it once with
`-sv_lib RogueTcpDpi`. After reset is released, each instance prints its
`Listening on ports N & N+1` message.

The transport preserves the long-standing VCS/GHDL operating contract:
connect the peer and keep it draining before HDL produces outbound messages.
Simulator-thread receive is nonblocking, but send retains the existing
synchronous ZeroMQ behavior across all three backends.

## Checked-In xsim Examples

The repository includes two focused multi-instance regressions:

- `tests/axi/simlink/RogueXsimMultiTb.vhd` instantiates four Stream, two
Memory, and two SideBand models concurrently.
- `tests/axi/simlink/test_RogueXsimMulti.py` builds the DPI library, checks the
generated DPI-C prototypes, compiles the mixed-language design, runs xsim,
and verifies duplicate-port rejection.
- `tests/axi/simlink/RogueXsimTrafficTb.vhd` drives the same eight-instance
topology with isolated Stream, Memory, and SideBand traffic.
- `tests/axi/simlink/test_RogueXsimTraffic.py` starts one deterministic
`rogue_tcp_peer.py` process per instance and verifies the xsim and peer-side
results.

The standalone DPI library and ABI check can be built with:

```bash
make -C axi/simlink/xsim all abi-check
```

Run it from the repository root in a Vivado-enabled shell:

```bash
./.venv/bin/python -m pytest -q -n 0 \
tests/axi/simlink/test_RogueXsimMulti.py \
tests/axi/simlink/test_RogueXsimTraffic.py
```

The test skips with an explicit reason when Vivado simulator tools are not on
`PATH`. The protocol codecs and deterministic ZeroMQ peer used by the broader
simlink regressions are in `tests/axi/simlink/rogue_tcp_peer.py`. The active
traffic regression uses test-only ready files to tell the parent process that
each peer has configured its sockets and issued its ZeroMQ connect calls. It
then retains a short fixed settle delay because the underlying ZeroMQ
connection handshake is asynchronous. This coordination does not add a socket,
message, or handshake to the production Rogue TCP wire protocol.

## Troubleshooting

**"libzmq package was not found"**
If the Tcl console prints:
```
libzmq package was not found
Please make sure that you have libzmq installed
or have sourced the necessary rogue setup scripts
```
install libzmq (or source the Rogue setup scripts that put it on `PKG_CONFIG_PATH`) and re-run `make gui`.

**Idle waveform, no data movement**
If the console printed `Listening on ports N & N+1` but the waveform never shows activity, the peer has not connected. Confirm the driver script is running, targeting the same host (loopback `127.0.0.1`) and port pair as the module under test, and that push/pull directions are not swapped.
37 changes: 31 additions & 6 deletions axi/simlink/ruckus.tcl
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,36 @@ source $::env(RUCKUS_PROC_TCL)
# Load Simulation
loadSource -lib surf -sim_only -dir "$::DIR_PATH/tb"

# Check if not GHDL
if {![info exists ::env(GHDLFLAGS)]} {
# Include VHPI
loadSource -lib surf -sim_only -dir "$::DIR_PATH/vcs"
# Select the simulator backend. Prefer the backend explicitly requested by the
# ruckus make target (make xsim/gui -> xsim, make vcs -> vcs). Fall back to
# environment sniffing for older ruckus. Note: sniffing VCS_VERSION alone is
# unreliable because users commonly source both Vivado and VCS in one setup
# script, so VCS_VERSION is set even during a Vivado xsim run.
if {[info exists ::env(RUCKUS_SIM_BACKEND)]} {
set simBackend $::env(RUCKUS_SIM_BACKEND)
} elseif {[info exists ::env(GHDLFLAGS)]} {
set simBackend "ghdl"
} elseif {[info exists ::env(VCS_VERSION)]} {
set simBackend "vcs"
} else {
# Exclude VHPI
loadSource -lib surf -sim_only -dir "$::DIR_PATH/ghdl"
set simBackend "xsim"
}

# When re-generating an existing Vivado project, purge sibling-backend sources
# so switching backends doesn't leave duplicate RogueTcp* entities in sim_1.
# Only remove when present, to avoid needless add/remove churn in the project.
# Guard on VIVADO_VERSION because get_files/remove_files are Vivado-only; GHDL
# re-analyzes from scratch and has no persistent project to clean.
if {$::env(VIVADO_VERSION) > 0.0} {
foreach other {ghdl vcs xsim} {
if {${other} ne ${simBackend}} {
set staleFiles [get_files -quiet [file normalize "$::DIR_PATH/${other}/*"]]
if {[llength ${staleFiles}] > 0} {
remove_files -quiet ${staleFiles}
}
}
}
}

# Load the selected backend
loadSource -lib surf -sim_only -dir "$::DIR_PATH/${simBackend}"
2 changes: 1 addition & 1 deletion axi/simlink/tb/RogueTcpStreamWrap.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ begin
end generate;

-- Channels
U_ChanGen : for i in 0 to CHAN_COUNT_C-1 generate
GEN_CHAN : for i in 0 to CHAN_COUNT_C-1 generate
------------------
-- Inbound Resizer
------------------
Expand Down
67 changes: 67 additions & 0 deletions axi/simlink/xsim/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
##############################################################################
## This file is part of 'SLAC Firmware Standard Library'.
## It is subject to the license terms in the LICENSE.txt file found in the
## top-level directory of this distribution and at:
## https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
## No part of 'SLAC Firmware Standard Library', including this file,
## may be copied, modified, propagated, or distributed except according to
## the terms contained in the LICENSE.txt file.
##############################################################################
# xsc-based build (Vivado xsim DPI-C), re-targeted from ghdl/Makefile's
# gcc -shared -fPIC + pkg-config libzmq pattern to the xsc two-step compile/
# link flow. Builds the combined RogueTcpDpi.so from every module's DPI-C
# adapter plus the shared per-instance ownership manager; a single
# "-sv_lib RogueTcpDpi" binds all of them. The file is named RogueTcpDpi.so
# (no "lib" prefix): xelab's "-sv_lib
# RogueTcpDpi" resolves the DPI library as <name>.so, not lib<name>.so
# (per UG900). xsc stages its compiled object under its own implicit
# ./xsim.dir/work/xsc/ directory (no BUILD_DIR indirection like GHDL/VCS use).
##############################################################################

CC := xsc
ELAB := xelab
# -I../shared resolves the shared RogueTcp*Core.h headers that every backend
# includes; xsc's underlying gcc searches the including file's own dir
# first, so the xsim/ RogueTcp*.h still take precedence. svdpi.h is
# auto-found by xsc (adds $XILINX_VIVADO/data/xsim/include automatically).
CFLAGS := -I../shared $(shell pkg-config --cflags libzmq)
# Vivado <= 2024.1 bundles a gcc-9.3.0 whose link driver invokes its own
# binutils via -B and does not search the host multiarch lib dir, so the
# RogueTcpDpi.so link fails with "cannot find crti.o / -lzmq / -lm". Point both
# the startfile search (-B, for crt*.o) and the library search (-L) at the
# active gcc's lib dir, derived portably from `gcc -print-file-name=crti.o`
# (resolves to /usr/lib/x86_64-linux-gnu on Debian/Ubuntu, /usr/lib64 on RHEL).
# Harmless on Vivado >= 2024.2, whose xsc already resolves these.
MULTIARCH_DIR := $(dir $(shell gcc -print-file-name=crti.o))
LFLAGS := $(shell pkg-config --libs libzmq) -B$(MULTIARCH_DIR) -L$(MULTIARCH_DIR)

LIB := RogueTcpDpi.so
SOURCES := RogueDpiInstance.c RogueTcpStream.c RogueTcpMemory.c RogueSideBand.c
HEADERS := RogueDpiInstance.h RogueTcpStream.h RogueTcpMemory.h RogueSideBand.h \
../shared/RogueTcpStreamCore.h ../shared/RogueTcpMemoryCore.h \
../shared/RogueSideBandCore.h
SV_SOURCES := RogueTcpStreamDpi.sv RogueTcpMemoryDpi.sv RogueSideBandDpi.sv
ABI_HEADER := xsim.dir/RogueTcpDpi.generated.h

all: $(LIB)

$(LIB): $(SOURCES) $(HEADERS)
$(CC) -c RogueDpiInstance.c -gcc_compile_options "$(CFLAGS)"
$(CC) -c RogueTcpStream.c -gcc_compile_options "$(CFLAGS)"
$(CC) -c RogueTcpMemory.c -gcc_compile_options "$(CFLAGS)"
$(CC) -c RogueSideBand.c -gcc_compile_options "$(CFLAGS)"
$(CC) --shared -o $(LIB) -gcc_link_options "$(LFLAGS)"

$(ABI_HEADER): $(SV_SOURCES)
mkdir -p $(dir $@)
$(ELAB) -dpiheader $@ $(foreach src,$(SV_SOURCES),-svlog $(src))

abi-check: $(ABI_HEADER) $(SOURCES) $(HEADERS)
$(CC) -c RogueTcpStream.c -gcc_compile_options "$(CFLAGS) -include $(abspath $(ABI_HEADER))"
$(CC) -c RogueTcpMemory.c -gcc_compile_options "$(CFLAGS) -include $(abspath $(ABI_HEADER))"
$(CC) -c RogueSideBand.c -gcc_compile_options "$(CFLAGS) -include $(abspath $(ABI_HEADER))"

clean:
rm -rf xsim.dir xsc.pb xsc.log xelab.pb xelab.log xelab.jou $(LIB)

.PHONY: all abi-check clean
Loading