Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
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/`.
71 changes: 71 additions & 0 deletions axi/simlink/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# 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 Example

The repository's runnable example is the focused multi-instance regression:

- `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.

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
```

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`.

## 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 $@ -svlog $(SV_SOURCES)

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