Instead of implementing the C++ API, you can programmatically build up a description of an FPGA using the generic architecture and the Python API.
A basic packer is provided that supports LUTs, flipflops and IO buffer insertion. Packing could also be implemented using the Python API.
At present there is no support for cell timing in the generic architecture. This will be worked on in the future.
All identifiers (
IdString) are automatically converted to
and from a Python string, so no manual conversion is required.
Argument names are included in the Python bindings, so named arguments may be used.
Adds a wire with a name, type (for user purposes only, ignored by all nextpnr code other than the UI) to the FPGA description. x and y give a nominal location of the wire for delay estimation purposes. Delay estimates are important for router performance (as the router uses an A* type algorithm), even if timing is not of importance.
Adds a pip (programmable connection between two named wires). Pip delays that correspond to delay estimates are important for router performance (as the router uses an A* type algorithm), even if timing is otherwise not of importance.
Loc is constructed using
Loc(x, y, z). ‘z’ for pips is only important if region constraints (e.g. for partial reconfiguration regions) are used.
Adds a wire alias (fixed connection between two named wires). Alias delays that correspond to delay estimates are important for router performance (as the router uses an A* type algorithm), even if timing is otherwise not of importance.
Adds a bel to the FPGA description. Bel type should match the type of cells in the netlist that are placed at this bel (see below for information on special bel types supported by the packer). Loc is constructed using
Loc(x, y, z) and must be unique.
Adds an input, output or inout pin to a bel, with an associated wire. Note that both
wire must have been created before calling this function.
Add a bel, wire, pip or subgroup to a group, which will be created if it doesn't already exist. Groups are purely for visual presentation purposes in the user interface and are not used by any place-and-route algorithms.
Add a graphic element to a decal, a reusable drawing that may be used to represent multiple wires, pips, bels or groups in the UI (with different offsets). The decal will be created if it doesn't already exist
Sets the decal ID and offset for a wire, bel, pip or group in the UI.
Sets an attribute on a wire, pip or bel. Attributes are displayed in the tree view in the UI, but have no bearing on place-and-route itself.
Sets the number of input pins a LUT in the architecture has. Only affects the generic packer, if a custom packer or no packer is used this value has no effect - there is no need for the architecture to have LUTs at all in this case.
Set the linear scaling vs distance and fixed offset (both values in nanoseconds) for routing delay estimates. Delay estimates that correlate to pip delays, even if they have no bearing to reality, are important for reasonable routing runtime.
Set the timing class of a port on a particular cell to a clock input.
NOTE: All cell timing functions apply to an individual named cell and not a cell type. This is because cell-specific configuration might affect timing, e.g. whether or not the register is used for a slice.
Specify the combinational delay between two ports of a cell, and set the timing class of those ports as combinational input/output.
Specify setup and hold timings for a port of a cell, and set the timing class of that port as register input.
Specify clock-to-out time for a port of a cell, and set the timing class of that port as register output.
The generic packer combines K-input LUTs (
LUT cells) and simple D-type flip flops (
DFF cells) (posedge clock only, no set/reset or enable) into a
GENERIC_SLICE cell. It also inserts
GENERIC_IOBs onto any top level IO pins without an IO buffer. Constrained IOBs can be implemented by instantiating
GENERIC_IOB and setting the
BEL attribute to an IO location.
Thus, the architecture should provide bels with the following ports in order to use the generic packer:
FLUT output and
QFF output (N.B. both LUT and FF outputs are not available at the same time, to represent the constraints of some FPGAs).
Ioutput buffer input,
ENoutput enable input, and
Oinput buffer output.
See prims.v for Verilog simulation models for all these cells.
synth_generic.tcl can be used with Yosys to perform synthesis to the generic
DFF cells which the generic packer supports. Invoke it using
tcl synth_generic.tcl K out.json where K is the number of LUT inputs and out.json the name of the JSON file to write.
The generic packer in its current state is intended for experimentation and proof-of-concept tests. It is not intended to make use of all FPGA features or support complex designs. In these cases a proper Arch API implementation is strongly recommended.
The following constraints are enforced by the generic architecture during placement.
GENERIC_SLICEbels may only have one clock signal per tile (xy location)
PACK_GROUPattribute is set to a non-zero value on cells, then only cells with the same
PACK_GROUPnegative or unset) may share a tile. This could be set by the Python API or during synthesis.
An artificial, procedural architecture is included in the generic/examples folder. simple.py sets up the architecture, and report.py saves post-place-and-route design to a text file (in place of bitstream generation). simple.sh can be used to synthesise and place-and-route a simple blinky for this architecture.