forked from YosysHQ/prjtrellis
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request YosysHQ#6 from daveshah1/libtrellis-db
Code to manage and manipulate database
- Loading branch information
Showing
38 changed files
with
1,521 additions
and
42 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
Database Development Overview | ||
============================= | ||
|
||
A targeted approach is used to construct bitstream databases as quickly as possible. The planned flow is for every | ||
routing mux or configuration setting we want to determine, to create post-place-and-route designs for all possibilities | ||
then run them through bitstream generation and compare the outputs. | ||
|
||
NCL Files | ||
---------- | ||
NCL files are file format used by Lattice (originating from NeoCAD), which are a textual representation of the internal | ||
design database. Although there is little documentation on them, the format is relatively straightforward. There are | ||
tools included with Diamond to convert the design database to and from a NCL file (``ncd2ncl`` and ``ncl2ncd``). These | ||
are wrapped by the script ``diamond.sh`` included in Project Trellis, that allows two possibilities: | ||
|
||
- If given a Verilog file, it will use Diamond for synthesis and PAR, and as well as a bitstream also dump the | ||
post-place-and-route design as a NCL file. This way you can inspect how the design maps to an NCL file, and the | ||
routing and configuration inside the tile. | ||
- If given a NCL file, it will skip synthesis and PAR. It will convert the NCL file to a design database, then | ||
generate a bitstream from that. | ||
|
||
In the planned fuzzing flow, we will first create a Verilog design for what we want to fuzz by hand, and convert it to | ||
an NCL file. Then we will manually create a template NCL file containing only the mux/config to be fuzzed. The Python | ||
fuzzer script will then subsitute this template file for each fuzz possibility. | ||
|
||
A template file for LUT initialisation is shown as an example: | ||
|
||
.. code-block:: none | ||
::FROM-WRITER; | ||
design top | ||
{ | ||
device | ||
{ | ||
architecture sa5p00; | ||
device LFE5U-25F; | ||
package CABGA381; | ||
performance "8"; | ||
} | ||
comp SLICE_0 | ||
[,,,,A0,B0,D0,C0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,] | ||
{ | ||
logical | ||
{ | ||
cellmodel-name SLICE; | ||
program "MODE:LOGIC " | ||
"K0::H0=${lut_func} " | ||
"F0:F "; | ||
primitive K0 i3_4_lut; | ||
} | ||
site R2C2A; | ||
} | ||
} | ||
The NCL file contains information about the device, components and routing (routing is not included in this example). As | ||
this was from a LUT initialisation fuzzer, ${lut_func} will be replaced by a function corresponding to the LUT init bit | ||
to be fuzzed (NCL files require an expression for LUT initialisation, rather than a series of bits). | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
libtrellis Overview | ||
==================== | ||
|
||
libtrellis is a C++ library containing utilities to manipulate ECP5 bitstreams, and the databases that correspond tile | ||
bits to functionality (routing and configuration). Although libtrellis can be used as a standard shared library, its | ||
primary use in Project Trellis is as a Python module (called pytrellis), imported by the fuzzing and utility scripts. | ||
The C++ classes are bound to Python using Boost::Python. | ||
|
||
Bitstream | ||
--------- | ||
This class provides functionality to read and write Lattice bitstream files, parse their commands, and convert them | ||
into a chip's configuration memory (in terms of frames and bits). | ||
|
||
To read a bitstream, use ``read_bit`` to create a ``Bitstream`` object, then call ``deserialise_chip`` on that to | ||
create a ``Chip``. | ||
|
||
Chip | ||
----- | ||
This represents a configured FPGA, in terms of its configuration memory (``CRAM``), tiles and metadata. You can either | ||
use ``deserialise_chip`` on a bitstream to construct a Chip from an existing bitstream, or construct a Chip by device | ||
name or IDCODE. | ||
|
||
The ``ChipInfo`` structure contains information for a particular FPGA device. | ||
|
||
CRAM | ||
----- | ||
This class stores the entire configuration data of the FPGA, as a 2D array (frames and bits). Although the array can be | ||
accessed directly, many cases will use ``CRAMView`` instead. ``CRAMView`` provides a read/write view of a window of the | ||
CRAM. This is usually used to represent the configuration memory of a single tile, and takes frame and bit offsets | ||
and lengths. | ||
|
||
Subtracting two ``CRAMView`` s, if they are the same size, will produce a ``CRAMDelta``, a list of the changes between | ||
the two memories. This is useful for fuzzing or comparing bitstreams. | ||
|
||
Tile | ||
----- | ||
This represents a tile of the FPGA. It includes a ``CRAMView`` to represent the configuration memory of the tile. | ||
|
||
TileConfig | ||
----------- | ||
This represents the actual configuration of a tile, in terms of arcs (programmable connections), config words (such as | ||
LUT initialisation) and config enums (such as IO type). It is the result of decoding the tile CRAM content using the bit | ||
database, and can be converted to a FASM-like format. | ||
|
||
The contents of ``TileConfig`` are ``ConfigArc`` for connections, ``ConfigWord`` for non-routing configuration words | ||
(which also includes single config bits), ``ConfigEnum`` for enum configurations with multiple textual values, and | ||
``ConfigUnknown`` for unknown bits not found in the database, which are simply stored as a frame, bit reference. | ||
|
||
The contents of a tile's configuration RAM can be converted to and from a ``TileConfig`` by using the ``tile_cram_to_config`` | ||
and ``config_to_tile_cram`` methods on the ``TileBitDatabase`` instance for the tile. | ||
|
||
TileBitDatabase | ||
---------------- | ||
There will always be only one ``TileBitDatabase`` for each tile type, which is enforced by requiring calling the | ||
function ``get_tile_bitdata`` (in ``Database.cpp``) to obtain a ``shared_ptr`` to the ``TileBitDatabase``. | ||
|
||
The ``TileBitDatabase`` stored the function of all bits in the tile, in terms of the following constructs: | ||
|
||
- Muxes (``MuxBits``) specify a list of arcs that can drive a given node. Each arc (``ArcData``) contains | ||
specifies source, sink and the list of bits that enable it as a ``BitGroup``. | ||
- Config words (``WordSettingBits``) specify non-routing configuration settings that are arranged as one or more bits. | ||
Each config bit has an associated list of bits that enable it. This would be used both for single-bit settings | ||
and configuration such as LUT initialisation and PLL dividers. | ||
- Config enums (``EnumSettingBits``) specify non-routing configuration settings that have a set of possible textual | ||
values, used for either modes/types (i.e. IO type) or occasionally "special" muxes not part of general routing. These | ||
are specified as a map between possible values and the bits that enable those values. | ||
|
||
``TileBitDatabase`` instances can be modified during runtime, in a thread-safe way, to enable parallel fuzzing. They can | ||
be saved back to disk using the ``save`` method. | ||
|
||
They can also be used to convert between tile CRAM data and higher level tile config, as described above. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
#!/usr/bin/env python3 | ||
|
||
import os | ||
from os import path | ||
import shutil | ||
|
||
import diamond | ||
from string import Template | ||
import pytrellis | ||
|
||
device = "LFE5U-25F" | ||
sink = "R2C2_A0" | ||
# Drivers found using ispTcl | ||
drivers = [ | ||
"R1C2_V02S0501", | ||
"R2C2_H02W0501", | ||
"R2C2_H01E0001", | ||
"R2C3_H02W0701", | ||
"R2C3_H02W0501", | ||
"R2C2_H02W0701", | ||
"R2C2_H02E0501", | ||
"R3C2_V02N0501", | ||
"R1C2_V02S0701", | ||
"R2C2_F5", | ||
"R2C2_H00L0000", | ||
"R2C2_F7", | ||
"R2C2_H02E0701", | ||
"R2C2_V02N0701", | ||
"R2C1_H02E0701", | ||
"R2C3_H01E0001", | ||
"R2C2_V02S0501", | ||
"R3C2_V02N0701", | ||
"R2C2_V02S0701", | ||
"R2C2_V01N0101", | ||
"R2C2_V02N0501", | ||
"R2C1_H02E0501", | ||
"R2C2_H00L0100", | ||
"R2C2_H00R0000" | ||
] | ||
|
||
|
||
def run_get_bits(mux_driver): | ||
route = "" | ||
if mux_driver != "": | ||
route = "route\n\t\t\t" + mux_driver + "." + sink + ";" | ||
with open("mux_template.ncl", "r") as inf: | ||
with open("work/mux.ncl", "w") as ouf: | ||
ouf.write(Template(inf.read()).substitute(route=route)) | ||
diamond.run(device, "work/mux.ncl") | ||
bs = pytrellis.Bitstream.read_bit("work/mux.bit") | ||
chip = bs.deserialise_chip() | ||
tile = chip.tiles["R2C2:PLC2"] | ||
return tile.cram | ||
|
||
|
||
def main(): | ||
pytrellis.load_database("../../../prjtrellis-db") | ||
shutil.rmtree("work", ignore_errors=True) | ||
os.mkdir("work") | ||
baseline = run_get_bits("") | ||
with open("a0_mux_out.txt", "w") as f: | ||
for d in drivers: | ||
bits = run_get_bits(d) | ||
diff = bits - baseline | ||
diff_str = ["{}F{}B{}".format("!" if b.delta < 0 else "", b.frame, b.bit) for b in diff] | ||
print("{0: <18}{1}".format(d, " ".join(diff_str)), file=f) | ||
f.flush() | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
Oops, something went wrong.