Reusable FPGA simulation and hardware-in-the-loop verification tools
Project description
fpga-verification
Reusable FPGA verification helpers. The package provides shared data formats, wire-protocol codecs, cocotb simulation utilities, and an Intel System Console HIL transport.
Install
Install the base package for format conversion and protocol codecs:
python -m pip install fpga-verification
Install cocotb simulation helpers:
python -m pip install "fpga-verification[sim]"
Install Intel System Console HIL helpers:
python -m pip install "fpga-verification[hil]"
Install everything:
python -m pip install "fpga-verification[all]"
Public API
from fpga_verification.formats import QFormat, UIntFormat, qformat
from fpga_verification.protocols.avalon_st.intel_video import (
VIPControlPacket,
VIPFrame,
VIPInterlacing,
VIPPacketType,
VIPUserPacket,
VIPVideoPacket,
vip_packet_from_symbols,
)
from fpga_verification.sim.buses import (
AvalonSTBeat,
AvalonSTBus,
AvalonSTFrame,
AvalonSTMonitor,
AvalonSTSink,
AvalonSTSource,
)
from fpga_verification.sim.bfms.intel_dma import (
DMAAddressRegion,
IntelDMABFM,
IntelDMACommandMonitor,
SparseByteMemory,
)
from fpga_verification.sim.platform_designer import platform_test_cocotb
from fpga_verification.sim.runners import intel_component_test_cocotb, rtl_test_cocotb
from fpga_verification.hil.intel import IntelSystemConsoleSession
Numeric Formats
UIntFormat and QFormat convert between Python/numpy values and raw integer
words used by hardware buses, memories, and scoreboards.
UIntFormat
from fpga_verification.formats import UIntFormat
pixel = UIntFormat(width=10)
raw_pixels = pixel.array([0, 1023, 1024, -1])
assert raw_pixels.tolist() == [0, 1023, 0, 1023]
assert raw_pixels.dtype == pixel.dtype
Inputs:
width: unsigned word width in bits, from 1 to 64.zeros(shape): creates a zero-filled numpy array.wrap(values): masks values to the configured width.array(values, shape=None): masks, casts to the smallest unsigned storage dtype, and optionally reshapes.
Outputs:
dtype: numpy unsigned dtype selected fromuint8,uint16,uint32, oruint64.mask: integer bit mask for the configured width.
QFormat
from fpga_verification.formats import QFormat
sample = QFormat(qi=3, qf=2, signed=True)
raw = sample.float_to_qraw([1.25, -1.0])
back = sample.qraw_to_float(raw)
assert raw.tolist() == [5, 28]
assert back.tolist() == [1.25, -1.0]
Inputs:
qi: integer width. For signed formats, this includes the sign bit.qf: fractional width.signed:Truefor two's-complement signed values,Falsefor unsigned.float_to_qraw(x, saturate=True): converts floats to raw fixed-point words.int_to_qraw(raw, saturate=True): converts signed integer values to raw stored words.qraw_to_int(raw): converts raw words to signed or unsigned integers.qraw_to_float(raw): converts raw words to floating-point values.multiply(left_raw, right_format, right_raw, out_qf=None): multiplies two raw fixed-point arrays. Ifout_qfis provided, the result is shifted to the requested fractional width.zeros(size=None),ones(size=None),full(size, value, raw=False), andrandomize(...): create test data.
Outputs:
width: total raw word width,qi + qf.scale:2 ** qf.mask: integer bit mask for the raw word.min_float,max_float: representable numeric range.dtype: numpy unsigned storage dtype for the raw word.
Avalon-ST Protocols
Avalon-ST helpers follow the Avalon interface terminology used by Intel/Altera. The protocol reference is: https://docs.altera.com/r/docs/683091/22.3/avalon-interface-specifications/introduction-to-the-avalon-interface-specifications
The protocol codec layer is independent of cocotb and simulator state. It accepts and returns Python lists of symbols.
Intel Avalon-ST Video Packets
from fpga_verification.protocols.avalon_st.intel_video import (
VIPControlPacket,
VIPFrame,
VIPInterlacing,
VIPUserPacket,
vip_packet_from_symbols,
)
control = VIPControlPacket(
width=1920,
height=1080,
interlacing=VIPInterlacing.PROGRESSIVE_FRAME,
)
symbols = control.to_symbols()
decoded = vip_packet_from_symbols(symbols)
assert decoded.width == 1920
assert decoded.height == 1080
frame = VIPFrame(
width=2,
height=2,
pixels=[0x10, 0x20, 0x30, 0x40],
user_packets=[VIPUserPacket(1, [0xA, 0xB])],
)
packets = frame.packets()
Inputs:
VIPControlPacket(width, height, interlacing=...): frame dimensions and interlacing metadata. Width and height must fit in 16 bits.VIPVideoPacket(payload): video payload symbols.VIPUserPacket(user_type, payload): user packet type1..8and payload symbols.VIPFrame(width, height, pixels, interlacing=..., user_packets=...): a black-box container that produces user, control, and video packets.vip_packet_from_symbols(symbols, symbols_per_beat=1): decodes one packet from raw symbols.symbols_per_beatcontrols how many symbols belong to the first Avalon-ST beat; payload starts after that first beat.
Outputs:
to_symbols(): returns a list of 4-bit packet symbols.VIPFrame.control_packet(): returns aVIPControlPacket.VIPFrame.video_packet(): returns aVIPVideoPacket.VIPFrame.packets(): returns user packets followed by control and video packets.VIPInterlacing.description: human-readable interlacing mode.
Ancillary packets are currently reported as unsupported by the decoder.
Avalon-ST Cocotb Bus Helpers
The cocotb bus helpers drive and observe Avalon-ST interfaces through cocotb
handles. They support scalar valid/ready, optional packet signals, optional
empty, error, and channel, and ready modes ready_latency=0 or
ready_latency=1.
Instantiating A Source And Sink
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from fpga_verification.sim.buses import (
AvalonSTBus,
AvalonSTFrame,
AvalonSTSink,
AvalonSTSource,
)
@cocotb.test()
async def stream_loopback_test(dut):
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
dut.reset.value = 1
await RisingEdge(dut.clk)
dut.reset.value = 0
source = AvalonSTSource(
AvalonSTBus.from_prefix(dut, "sink"),
dut.clk,
reset=dut.reset,
data_bits_per_symbol=8,
packets=True,
)
sink = AvalonSTSink(
AvalonSTBus.from_prefix(dut, "source"),
dut.clk,
reset=dut.reset,
data_bits_per_symbol=8,
packets=True,
)
await source.send(AvalonSTFrame([0x11, 0x22, 0x33]))
received = await sink.recv()
assert received.data == [0x11, 0x22, 0x33]
Inputs:
AvalonSTBus.from_prefix(dut, prefix): binds signals named like<prefix>_data,<prefix>_valid,<prefix>_ready,<prefix>_startofpacket, and<prefix>_endofpacket.AvalonSTFrame(data, channel=None, error=None, empty=None, tx_complete=None): frame payload and optional sideband metadata.AvalonSTSource(bus, clock, reset=None, data_bits_per_symbol=8, symbols_per_beat=None, first_symbol_in_high_order_bits=False, ready_latency=0, ready_allowance=None, packets=None, idle_value="x").AvalonSTSink(...)andAvalonSTMonitor(...): use the same bus format options asAvalonSTSource.send(frame)/send_nowait(frame): queue transmit data.recv()/recv_nowait(): receive complete frames.recv_beat()/recv_beat_nowait(): receive one transferred beat.set_pause_generator(generator): apply backpressure or idle insertion from an iterable of booleans.
Outputs:
AvalonSTFrame.data: list of symbols.AvalonSTFrame.channel,error,empty: captured sideband metadata.AvalonSTFrame.sim_time_start,sim_time_end: simulation timestamps.AvalonSTBeat: one handshake beat withdata, decodedsymbols,sop,eop,empty,error,channel, andsim_time.wait(): waits for a source to become idle or a monitor/sink to see activity, depending on the helper type.
Intel DMA BFM
IntelDMABFM is a cocotb black-box model for Intel read and write DMA streaming
interfaces. It consumes DMA command descriptors, emits DMA responses, sources
read data from memory, and stores write data into memory.
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import RisingEdge
from fpga_verification.sim.buses import AvalonSTBus
from fpga_verification.sim.bfms.intel_dma import (
DMAAddressRegion,
IntelDMABFM,
IntelDMACommandMonitor,
SparseByteMemory,
)
@cocotb.test()
async def dma_component_test(dut):
cocotb.start_soon(Clock(dut.clk, 10, units="ns").start())
memory = SparseByteMemory()
memory.write(0x1000, b"\x01\x02\x03\x04")
dma = IntelDMABFM(
dut,
clock=dut.clk,
reset=dut.reset,
memory=memory,
mode="full",
).start()
command_monitor = IntelDMACommandMonitor(
clock=dut.clk,
reset=dut.reset,
rdma_cmd_bus=AvalonSTBus.from_prefix(dut, "rdma_cmd"),
wdma_cmd_bus=AvalonSTBus.from_prefix(dut, "wdma_cmd"),
read_address_regions=[DMAAddressRegion("input", 0x1000, 0x4000)],
write_address_regions=[DMAAddressRegion("output", 0x8000, 0x4000)],
).start()
dut.reset.value = 1
await RisingEdge(dut.clk)
dut.reset.value = 0
# Drive the DUT here. The BFM responds on the DMA Avalon-ST interfaces.
# Later, inspect memory or descriptor logs as black-box outputs.
written_bytes = memory.read(0x8000, 16)
read_descriptors = command_monitor.read_descriptors
dma.stop()
command_monitor.stop()
Inputs:
IntelDMABFM(dut, clock, reset, memory=None, read_response_delay_cycles=2, write_response_delay_cycles=2, ..., mode="full").mode:"full","read"/"read_only", or"write"/"write_only".memory: optionalSparseByteMemoryshared by read and write paths.- Optional bus overrides:
rdma_cmd_bus,rdma_resp_bus,wdma_cmd_bus,wdma_resp_bus,din_bus, anddout_bus. If omitted, buses are discovered from DUT prefixes with the same names. SparseByteMemory.write(address, data): initializes byte-addressed memory.DMAAddressRegion(name, start, size): allowed address interval for passive checking. End address is exclusive.IntelDMACommandMonitor(...): pass command buses or existingAvalonSTMonitorinstances and optional allowed address regions.
Outputs:
SparseByteMemory.read(address, length): returns bytes stored by the BFM.IntelDMABFM.read_commands,write_commands: descriptor queues observed by the model.IntelDMABFM.read_responses,write_responses: queues of descriptors whose responses were issued.IntelDMACommandMonitor.read_descriptors,write_descriptors: decoded descriptor history.ReadDMADescriptor.decode(value)andWriteDMADescriptor.decode(value): convert raw descriptor words into address, length, and control fields.
HIL Session
IntelSystemConsoleSession opens one persistent system-console process and
uses it sequentially for Avalon-MM memory access and JTAG UART commands. Intel
Quartus system-console must be available on PATH.
import numpy as np
from fpga_verification.hil.intel import IntelSystemConsoleSession
frame = np.arange(1024 * 1280, dtype=np.uint16).reshape(1024, 1280)
with IntelSystemConsoleSession(
system_console="system-console",
master_index=0,
uart_index=0,
startup_timeout=30.0,
work_dir=".",
) as hw:
hw.write_memory(frame, address=0x01E84800)
response = hw.command("g\n", timeout=3.0)
frame_out = hw.read_memory((1024, 1280), address=0x02DC6C00)
print(response)
print(frame_out.shape)
Inputs:
system_console: executable name or path.master_index: System Console Avalon-MM master index.uart_index: JTAG UART service index.startup_timeout: seconds to wait for the Tcl worker to become ready.work_dir: directory used for temporary binary transfer files.write_memory(data, address, chunk_size=4096): writes numpy-compatible data as little-endian 16-bit words.read_memory(shape, address, chunk_size=4096): reads little-endian 16-bit words and reshapes them.command(command, timeout=3.0, debug=False): sends a UTF-8 command over JTAG UART and waits for the first non-empty response line.
Outputs:
read_memory(...): numpy array with the requested shape.command(...): response string.- Methods raise
TimeoutErrororRuntimeErrorif System Console stops or reports a protocol error.
Simulation Runners
The simulation helpers cover three levels of generated and non-generated designs:
rtl_runner
RTL sources -> cocotb build/test
intel_component_runner
*_hw.tcl -> ip-generate -> generated composition HDL + original RTL -> rtl_runner
platform_runner
already generated Platform Designer sim dir/msim_setup.tcl -> simulator flow
rtl_test_cocotb is the direct RTL path. Pass it explicit HDL sources or source
directories, and it delegates build/test to the selected cocotb simulator runner.
intel_component_test_cocotb is for Platform Designer component .tcl files.
It generates only the HDL needed for simulation, keeps composition HDL that has
no source equivalent, replaces generated copies of project RTL with exact
matches from source_dirs, and then calls rtl_test_cocotb.
Its generated-catalog flow is:
source_dirs
-> ip-make-ipx --thorough-descent --source-directory=<source_dirs>
-> components.ipx in generated temp dir
-> ip-generate --search-path=<components.ipx>,$
-> parse .spd
-> replace generated RTL copies with original source files
-> rtl_test_cocotb
Pass generate_only=True to retain and return the generated composition
directory without running simulation.
platform_test_cocotb is for already generated Platform Designer simulation
trees. The expected layout is:
project_root/
<hdl_toplevel>/
<hdl_toplevel>/
testbench/
mentor/
msim_setup.tcl
For Questa, the platform runner compiles through msim_setup.tcl and runs
cocotb against the generated simulator libraries. For Verilator, it reads
Verilog/SystemVerilog sources from msim_setup.tcl and builds them directly.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fpga_verification-0.2.1-cp314-cp314-win_amd64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp314-cp314-win_amd64.whl
- Upload date:
- Size: 662.7 kB
- Tags: CPython 3.14, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
317943699cbd3c3d52699f75ed833dcba318ed3fe686c2277b86cebca8983087
|
|
| MD5 |
7991d8a65d4edc56725c79ef309fcc7c
|
|
| BLAKE2b-256 |
769b5643c78b0c3f113b70e4106e93f1d968281d65ca551b99034fae1c255a22
|
File details
Details for the file fpga_verification-0.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 4.7 MB
- Tags: CPython 3.14, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30b0550b8395da98023b5d33d390d3071d53c0451a8ae72d439c5606de5ce29e
|
|
| MD5 |
7dcff2fc5ceb12656ffc049c785a19d3
|
|
| BLAKE2b-256 |
70e534c87c226f5fe5c2bdcd020bf58d6383a78654d6f7f03db71543ecb20d50
|
File details
Details for the file fpga_verification-0.2.1-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 648.2 kB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89828af453e4fb888f9aef6690b7e48eda33771e3aa189b996614d6c537d762d
|
|
| MD5 |
33ce3f7b1e999825b5b0bbd9964fd3af
|
|
| BLAKE2b-256 |
184db5f964d4f3dff8e20d9f58f2e33eeb2e45a19b2e1b982543668b43d5fc5d
|
File details
Details for the file fpga_verification-0.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 4.8 MB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30d6153720bd80138aef8fb41973e26c522671ee083e018c2d9efecf407d856a
|
|
| MD5 |
79da62bbf1f90442b5e8ccc74d432cd4
|
|
| BLAKE2b-256 |
1d1d5c58b5c8ebaf77e9c14760c17e8f85f012d429416d3e600ce98842824110
|
File details
Details for the file fpga_verification-0.2.1-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 651.8 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46b20dc21fdbe63fe8e42e051c4269c0ce9a988d611dfdba7ae30f62ddb5c247
|
|
| MD5 |
ed5ab93a811705f7d7b21a02400629f8
|
|
| BLAKE2b-256 |
fc5e91087cfc4e2a2365c7259815360109132140534bccb683ca82e76ca7a931
|
File details
Details for the file fpga_verification-0.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 4.8 MB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bc8459428587175f8233d87b31496480943e1c9617f37bc6a170b9fdec8fc73b
|
|
| MD5 |
f8e097dc668a60df4914faf5f3ecb348
|
|
| BLAKE2b-256 |
b6184659d98da233725c92b8ef623412cc11b655e13b68527b3a90d92f055876
|
File details
Details for the file fpga_verification-0.2.1-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 659.7 kB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
702e707fa96eafee6f288c7929d4150dbc6f47e55c22ad9a77aefc129ea6e9de
|
|
| MD5 |
3d098780fab9c708d7f4e3811062a2ca
|
|
| BLAKE2b-256 |
bb7ae68855b86685c5317a208b5c4bdae804560daf00963ae146a07b9c14d6cc
|
File details
Details for the file fpga_verification-0.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 4.7 MB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
34719f2d0a9bfd4572b5d90a4f03b90f40c2f4baa868177b35e25df5707c7830
|
|
| MD5 |
69ae4a8614b6c7fa9bc5442097264143
|
|
| BLAKE2b-256 |
dbeb40861cfd010f622e2ea806027506acddb57fd5c999f010b240399172d09c
|
File details
Details for the file fpga_verification-0.2.1-cp310-cp310-win_amd64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp310-cp310-win_amd64.whl
- Upload date:
- Size: 660.9 kB
- Tags: CPython 3.10, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c27afafe13d8af241ec8a37f677b2207fccc69509ec8ec45b3d0df52da0393ca
|
|
| MD5 |
227dcb475822c38f71ea02969903d7b3
|
|
| BLAKE2b-256 |
f2d439f7ebaf9e49ed28675864e9b47ee4ee7504e15bdc62ad09f8911d077439
|
File details
Details for the file fpga_verification-0.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fpga_verification-0.2.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 4.5 MB
- Tags: CPython 3.10, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd06b30d80d52ab4b554237f7bd269c977697697f99c23c8d74d6921e10632bf
|
|
| MD5 |
48e22631d5f8bb152cbfb250defa9ecb
|
|
| BLAKE2b-256 |
34136bc38b673d3b9766ff0324830b7bc9555e3a9d530d891dcd92d91c460fd8
|