Memory Modeling
PySilicon provides a lightweight memory model that lets you simulate AXI-style and local-array-style memory interfaces in Python, then connect those simulations directly to Vitis HLS kernels and testbenches.
What is a memory model in PySilicon?
A memory model is a sparse, word-addressed store that lives in Python during simulation. Rather than pre-allocating a large flat buffer, you allocate only the regions you actually use. Each allocated region is backed by a NumPy array, so the full NumPy ecosystem is available for generating and inspecting data.
The central class is Memory, imported from pysilicon.hw.memory:
from pysilicon.hw.memory import AddrUnit, Memory
Key features
- Sparse allocation — only regions explicitly allocated with
alloc()consume memory. There is no large flat backing array. - Configurable word size —
word_sizecan be 32, 64, or wider (> 64 bits are stored asuint64chunks). - Configurable address size —
addr_sizesets the notional width of addresses in bits. - Two addressing models — byte-addressed (AXI4/DDR style) or word-indexed (local-array style), selected via
addr_unit. - Deterministic first-fit allocation —
alloc()always places the next segment immediately after the highest existing segment, making allocation order reproducible across Python and C++ testbenches. - Array serialization compatibility —
Memory.read()andMemory.write()accept NumPy arrays produced by thewrite_array/read_arrayhelpers, keeping Python models and HLS kernels consistent.
Two addressing models
The AddrUnit enum controls how addresses are interpreted:
addr_unit |
Meaning of an address | Typical use case |
|---|---|---|
AddrUnit.byte |
Byte offset from the start of the buffer | AXI4 / DDR / PYNQ memory interfaces |
AddrUnit.word |
Word index into the underlying array | Local arrays, BRAM-like interfaces |
AddrUnit.byte — AXI-style byte addressing
With byte addressing, alloc() returns a byte address. Addresses must be aligned to the word size (e.g., a multiple of 4 bytes for a 32-bit word). The memory model converts byte addresses to word indices internally:
word_index = byte_addr // (word_size // 8)
This matches the AXI4 convention used by Vitis HLS m_axi ports and PYNQ DDR buffers.
AddrUnit.word — word-indexed addressing
With word addressing, alloc() returns a word index. Addresses map directly to indices into the backing NumPy array. This models local arrays and BRAM-like interfaces where the hardware accesses words by index, not by byte address.
Connecting Python models to Vitis flows
The memory model bridges two sides of a PySilicon flow:
- Python simulation — the Python accelerator model reads inputs from and writes outputs to a
Memoryinstance, exactly as the synthesized kernel will access the AXI memory port. - Vitis/HLS testbench — the C++ testbench uses
MemMgr<word_dwidth>(frommemmgr_tb.hpp) to mirror the Python allocation layout. Because both sides use the same first-fit algorithm, byte addresses computed in Python are valid in the C++ testbench as well.
The histogram example demonstrates the full round-trip:
- Python allocates regions and writes packed input arrays.
- The Python accelerator model reads from and writes to those regions.
- The same addresses are written into a command descriptor.
- The C++ testbench reconstructs the same layout, runs the HLS kernel, and writes results back.
- Python reads the results and compares against the reference.
Next steps
- Using Memory in Python — how to create a
Memory, allocate regions, and serialize arrays. - Memory Interfaces in Vitis HLS — how the memory model maps to
m_axiand local-array interfaces.