nextpnr
repository·main·Indexed 23 days ago
https://github.com/yosyshq/nextpnrA vendor-neutral, timing-driven, open-source FPGA place and route tool. It supports various architectures, including Lattice iCE40, ECP5, Nexus, Gowin, and provides experimental support for Xilinx 7-series and Cyclone V.
What's inside nextpnr
- pybind11 is a lightweight, header-only C++ library designed to expose C++ types in Python and vice versa. It is primarily used to create Python bindings for existing C++ code. It aims to minimize boilerplate by using compile-time introspection to infer type information, similar to Boost.Python but optimized for C++11 and newer standards. Because it is header-only, there is no need to link against additional libraries; it only requires Python (3.6+ or PyPy) and the C++ standard library.
What is Binary Blob Assembler (bba)?
mainBinary Blob Assembler (bba) is a tool that reads a text file describing binary data and writes a binary file. It is commonly used in a workflow where a Python script generates the input text file, and the resulting binary output is linked or loaded into a C program. The binary data is typically interpreted using (packed) structs.
Key feature: All references (pointers) are encoded as 32-bit byte offsets relative to the location of the pointer, making the resulting binary blob position-independent.
Capabilities and limitations of nextpnr-machxo2
mainnextpnr-machxo2is an experimental FOSS Place and Route backend for Lattice MachXO2 FPGAs.Known Working Features
- Basic routing from pads to SLICEs and back.
- Basic packing of one type of FF and LUT into half of a SLICE.
- Using the internal oscillator
OSCHas a clock. LOGICSLICE mode.
Untested Features
- Non-3.3V I/O standards that do not use bank VREFs.
Planned/Missing Features
- More intelligent/efficient packing.
- Global Routing.
- Secondary High Fanout Nets.
- Edge Clocks (clock pads work, but not routed to global routing).
- PLLs.
- Synchronous Release Global Set/Reset Interface (
SGSR). - Embedded Function Block (
EFB). - All DDR-related functionality.
- Bank VREFs.
- Embedded Block RAM (
EBR). CCU2andDPRAMSLICE modes.
Understand the nextpnr netlist core structures
mainThe nextpnr in-memory design is built around several fundamental structures that represent the physical and logical connections of an FPGA design:
CellInfo: Represents an instantiation of a physical block (cell) in the netlist. Currently, all cells in nextpnr are treated as blackboxes.NetInfo: Represents a connection between cell ports. A net has at most one driver and zero or more users (sinks).BaseCtx/Context: The top-level container that holds all cells and nets.BaseCtxis the base class, which is subclassed byArchto becomeContext.PortInfo: Stores metadata for cell ports, including name, direction, and the connected net.PortRef: A reference used to identify the source or sink ports of a net, pointing back to a specific cell and port name.
Understand type conversion strategies in pybind11
mainWhen binding C++ to Python using pybind11, you can handle data types using one of three strategies. Choosing the right one depends on whether you prioritize performance, ease of use, or native type access:
- Native C++ types everywhere: Use this when you want to work with C++ objects directly. You must wrap the types using pybind11-generated bindings so Python can interact with them.
- Native Python types everywhere: Use this when you want to work with Python objects directly. You must wrap these types so C++ functions can interact with them.
- Type conversion: This is often the most "natural" approach. You use native C++ types on the C++ side and native Python types on the Python side. pybind11 handles the translation automatically.
Note on Type Conversion Performance: Because C++ and Python types typically have different memory layouts, a copy of the data must be made every time data transitions between Python and C++.
Understand the Dear ImGui binding architecture
mainDear ImGui separates its core logic from platform and rendering implementation. To integrate ImGui into an application, you typically need two types of bindings:
- Platform Bindings: Responsible for handling OS-level inputs (mouse, keyboard, gamepad), cursor shapes, timing, and windowing. Examples include
imgui_impl_win32.cpp,imgui_impl_glfw.cpp, andimgui_impl_sdl.cpp. - Renderer Bindings: Responsible for managing the font atlas texture and rendering the indexed textured triangles provided by ImGui. Examples include
imgui_impl_dx11.cpp,imgui_impl_opengl3.cpp, andimgui_impl_vulkan.cpp.
Some high-level frameworks (like Allegro 5 or Marmalade) provide single files that combine both Platform and Renderer responsibilities.
- Platform Bindings: Responsible for handling OS-level inputs (mouse, keyboard, gamepad), cursor shapes, timing, and windowing. Examples include
Handle dimension differences between Eigen and NumPy vectors
mainEigen and NumPy treat vectors differently, which affects how data is passed and returned:
Passing arrays to Eigen
- 2D NumPy Arrays: If you pass a 2D NumPy array (1xN or Nx1), the Eigen type must have matching dimensions. You cannot pass an Nx1 array to an Eigen type expecting a row vector.
- 1D NumPy Arrays: pybind11 allows passing 1D NumPy arrays of length N to Eigen.
- If the Eigen type can hold a column vector, it is passed as a column vector (this takes precedence).
- If not, but the type accepts a row vector, it is passed as a row vector.
- Example: Passing a 1D array of size 5 to
Eigen::MatrixXdresults in a 5x1 Eigen matrix.
Returning Eigen vectors to NumPy
When returning an Eigen vector, the conversion to NumPy can be ambiguous (e.g., a row vector of length 4 could be 1D or 2D). pybind11 follows these rules:
- Compile-time vectors: If the Eigen type has either rows or columns set to 1 at compile time, pybind11 converts it to a 1D NumPy array.
- Run-time vectors: For types that are only vectors at runtime (e.g.,
Eigen::MatrixXdorEigen::Matrix<float, Dynamic, 4>), pybind11 returns a 2D NumPy array.
If the returned dimension is not what you expect, use
array.reshape(...)in Python to get the desired view.Additional pybind11 features and goodies
mainBeyond core mapping, pybind11 provides several advanced capabilities:
- Lambda Support: Bind C++11 lambda functions with captured variables (capture data is stored in the resulting Python function object).
- Efficient Data Transfer: Uses C++11 move constructors and move assignment operators.
- Buffer Protocol: Expose internal storage of custom types to Python's buffer protocol, enabling fast conversion between C++ matrix classes (like Eigen) and NumPy without expensive copies.
- Vectorization: Automatically vectorize functions to apply them transparently to NumPy array arguments.
- Slicing: Support Python's slice-based access and assignment with minimal code.
- Pickling: C++ types can be pickled and unpickled like regular Python objects with little extra effort.
- Performance: Smaller binaries and faster compile times compared to Boost.Python due to
constexprprecomputation of function signatures.
Choose the appropriate FFT package version
mainThe Ooura FFT package provides different implementations based on your hardware architecture and the dimensionality of your data:
By Hardware Optimization
fft4f2d.*: Optimized for older machines that lack large CPU caches.fftsg2d.*andfftsg3d.*: Optimized for modern machines with multi-level (L1, L2, etc.) caches. These versions utilize the 1D FFT routines found infftsg.*.
By Dimensionality
- 1D FFT: Provided by
fftsg.*(C and Fortran versions). - 2D FFT: Provided by
fft4f2d.*(radix 4, 2) orfftsg2d.*(Split-Radix). - 3D FFT: Provided by
fftsg3d.*(Split-Radix).
Implement Cell to Bel mapping
mainWhen designing an Architecture API, you must decide how to represent the relationship between cell types and bel types. There are two primary patterns:
- Common Type Transformation: The packer transforms input cells into specific nextpnr cell types that have a 1-to-1 relationship with bel types. In this model,
isValidBelForCellTypeis a simple equality check:
bool isValidBelForCellType(IdString cell_type, BelId bel) const { return cell_type == getBelType(bel); }- Fast Validity Checking: Implement a high-performance
isValidBelForCellTypemethod that determines if a specific cell type can be bound to a specific bel without requiring a 1-to-1 mapping.
- Common Type Transformation: The packer transforms input cells into specific nextpnr cell types that have a 1-to-1 relationship with bel types. In this model,
Handle grapheme clusters in character literals
mainA single grapheme (like 'é') might be represented in Unicode as multiple code points (e.g., 'e' + combining acute accent). If such a sequence is passed to a C++ function expecting a single character type, the combining character will be lost.
To resolve this, normalize the string using
unicodedata.normalize("NFC", ...)in Python before passing it to C++.>>> import unicodedata >>> combining_e_acute = "e" + "\u0301" >>> example.pass_wchar(unicodedata.normalize("NFC", combining_e_acute)) 'é'How the Property Browser framework works
mainThe Property Browser is a framework designed to allow users to edit sets of properties through a browser widget. It uses a decoupled architecture consisting of three main parts:
Browser Widgets: The UI component that displays properties with labels and editing widgets. The framework provides three ready-made implementations:
QtTreePropertyBrowserQtButtonPropertyBrowserQtGroupBoxPropertyBrowser
Property Managers: These handle specific data types (e.g.,
QtIntPropertyManagerfor integers,QtStringPropertyManagerfor strings, or a variant-based manager).Editor Factories: These determine which UI widget is used to edit a property (e.g.,
QtSpinBoxFactoryfor integers orQtLineEditFactoryfor strings).
To use the framework, you associate a Property Manager with a preferred Editor Factory for each property type.