-
Notifications
You must be signed in to change notification settings - Fork 16
WIP: Merges for documentation and to support LIFCL 33/33U #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
8faaa3a
6e60732
4e3472d
54656f3
dddc797
b8de947
5e3c9c5
daae938
9393828
80e9a27
853b293
d6b924f
39d0398
08f9b43
387f835
75cf8b6
ace51a1
1926dd0
eedca4a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| # Overview | ||
|
|
||
| The tiletype of a tile dictates which BEL's are available on a given tile and which options they might have exposed. This is mapped out fully in prjoxide/libprjoxide/prjoxide/src/bels.rs, namely in `get_tile_bels`. | ||
|
|
||
| A given bel might span over multiple logical tiles. It's anchor tile is the one with the appropriate tiletype but for routing information on where the related tile is there is rel_x and rel_y; which encode the relative tile offset for the related tile. This data can be varied based on the family, device and actual tile in question. | ||
|
|
||
| For bels with these offsets, the offset information is used in fuzzing the routing to map the interconnect. The offset themselves can be devined from the output of the dev_get_nodes command and report for nearby CIB tiles. For instance, related tiles to LRAM will have LRAM_CORE wires in their tile. | ||
|
|
||
| Bel information is encoded in the bba file which is produced by prjoxide and ingested in the build process of nextpnr. | ||
|
|
||
| # References | ||
|
|
||
| - [Terminology](https://fpga-interchange-schema.readthedocs.io/device_resources.html) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| # Database | ||
|
|
||
| The chip database for prjoxide is ingested into libprjoxide and used to construct the BBA database used by nextpnr. | ||
|
|
||
| ## Per device files | ||
|
|
||
| Each supported device has the following json files to describe it: | ||
|
|
||
| ### baseaddr.json | ||
|
|
||
| Some primitives are internally routed on an LMMI bus that is used for configuration. This file describes the addresses of mapped primitives and the length of their address in bits. | ||
|
|
||
| These addresses are mapped with the fuzzer in fuzzers/LIFCL/100-ip-base. This requires, for each device, a mapping between the primitive type in question and it's site. This mapping isn't immediately apparent; but can usually be derived by placing the known number of that primitive in a design and looking at it in the physical designer / routing tool in lattice. | ||
|
|
||
| ### iodb.json | ||
|
|
||
| The IO database file contains information on a particular pins function and logical name for each given package. | ||
|
|
||
| Each entry describes the pin in terms of it's physical location. Since all the IO pins are on the outside edge of the chip, you can map the tile as a combination of it's 'offset' and it's 'side' -- a pin on the top for instance with an offset of 58 maps to tile 58, 0. The pio attribute describes which pin in that tile is being described. | ||
|
|
||
| The iodb.json files are constructed by running tools/parse_pins.py against the CSV files lattice makes available in the documentation section for each device. | ||
|
|
||
| ### tilegrid.json | ||
|
|
||
| The tile grid file describes where the physical location of the tile is, what it's type is, and where it is encoded into the final bitstream file. | ||
|
|
||
| This file is generated by tools/tilegrid_all.py. A new device will require some custom fields in the devices.json file but also tools/extract_tilegrid.py. | ||
|
|
||
| ## Shared database files | ||
|
|
||
| The various .ron files are serialized/deserialized to rust. Each fuzzer deserializes the current database, processes samples, and then reserializes out the updated database. | ||
|
|
||
| ### devices.json | ||
|
|
||
| This serves as a master listing of each device and metadata associated with that device: | ||
|
|
||
| - packages: Comes from various lattice documentation, can also be seen by looking at the radiant device selection dialog. | ||
| - frame metadata: There are various necessary peices of data here. All are available in the "sysCONFIG Guide for Nexus Platform" document from the lattice website. | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. might be nice to expand this a bit more? |
||
| - idcode: This is also availble in the above document. | ||
| - max_row / max_cols: These are retreivable from the physical designer for a given chip, or from the tilegrid metadata file. | ||
|
|
||
| This file serves as the central index for devices in the libprjoxide library. | ||
|
|
||
| ### iptypes | ||
|
|
||
| These files are generated by various fuzzers associated with the given primitive. They map out the relationship between configuration parameters and the bits set in the bitstream. | ||
|
|
||
| ### tiletypes | ||
|
|
||
| These files are also generated by fuzzers. While they also map out the relationship between various parameters and bits in the bitstream, they mainly focus on the interconnection between tiles themselves. This gives both a graph on what connections are possible but also the way those connections are configured in the bitstream. | ||
|
|
||
| ### timing | ||
|
|
||
| This is a collection of a bunch of cell types and a description of the delay timing between pins as well as the setup and hold time for each pin in the cell. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # Cacheing | ||
|
|
||
| The fuzzers all require a lot of runtime in building bitfiles and pulling data from radiant tools. | ||
|
|
||
| ## Bitstream cacheing | ||
|
|
||
| The main cacheing mechanism is the bitstreamcache -- tools/bitstreamcache.py. This stores checksums for input files and | ||
| the bitstream in `.bitstreamcache`. | ||
|
|
||
| The bitstreams are stored compressed and libprjoxide can read them compressed. Instead of copying the files around, the | ||
| cache fetch generates symbolic links. | ||
|
|
||
| This folder should be cleared very rarely. | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. most notably it needs to be cleared if you want to switch radiant version
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I did not realize this. I think it makes sense to make the radiant version as part of the hash path. I'll probably make it check both old and new too so my current cache isn't burnt
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That sounds like a good plan |
||
|
|
||
| ## Stored deltas | ||
|
|
||
| Each solve generates serialized delta files in `.deltas` of the given fuzzer. This is useful to see what changed for each | ||
| solver run, but is also used as a marker -- if that file exists, the solver assumes it has been applied already and skips | ||
| generating / fetching bitstreams and calling into the fuzzer solvers. | ||
|
|
||
| Delete these folders when making heavy changes to fuzz.rs or other portions of the rust library. | ||
|
|
||
| ## Lapie cache database | ||
|
|
||
| Lapie / Lark is a radiant tool used to query the internal chip lattice database. Each run of this program has around | ||
| 10 seconds of overhead and it only returns around 60 results per second after that. | ||
|
|
||
| To speed these accesses up, a sqlite database is generated at `.cache/<radiant version>/<device>-nodes.sqlite` to cache | ||
| the results of these queries. Specifically, it caches node data and site data per device as well as the jumpwires list. | ||
|
|
||
| Queries, once cached, return nearly instantaneously in comparison, but these files do end up being around 100M in size. | ||
|
|
||
| ## Cachier | ||
|
|
||
| Other methods are annotated with cachier -- a decoration that caches calls into a function by its arguments. These | ||
| entries are stored in `.cache/<radiant version>/cache.db`. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # Overview | ||
|
|
||
| The primary thing to solve for to be able to run placement and routing on a given device is the relationship between BELs | ||
| that nextpnr understands to sites on the device, as well as the routing pips available, and what bits need to be flipped | ||
| in the bitstream frames to achieve a given route / BEL configuration. | ||
|
|
||
| The main process is to create a minimal verilog file with the features that need to be isolated, generate a bitstream | ||
| from that file, and compare it to a baseline bitstream without that feature. This generates a bitstream delta which is | ||
| represented as a list of (tile, frame, bit) tuples which changed between the two. | ||
|
|
||
| The main difficulty presented is that generating a bitstream takes a few seconds, and given the scale of number of things | ||
| to test, some care has to be taken to minimize the state space to attempt. To completely map a single device requires | ||
| thousands to tens of thousands of bitstream generations. | ||
|
|
||
| The results of all this fuzzing ends up in the database. | ||
|
|
||
| ## BEL Fuzzing | ||
|
|
||
| BEL fuzzing tends to be straightforward, although it does rely on knowing how to configure the primitive in question, in | ||
| terms of what options it supports and how to specify those options. Most configuration options can be fuzzed in isolation | ||
| with the others which keeps down the number of bitstreams to generate. | ||
|
|
||
| ### Enum Fuzzing | ||
|
|
||
| Many primitives have documented series of enumerated values. One bitstream is typically generated per enum value, and the | ||
| mapping is relatively simple. The main work required here is to identify which options are valid and when they are | ||
| operative. | ||
|
|
||
| ### Word Fuzzing | ||
|
|
||
| Word fuzzing is conceptually the same as enum fuzzing, but is used against parameters that exist as integers. There is | ||
| an assumption here that a word of `N` bits long will require only `N` evaluations to map; ie that any bit in the value | ||
| maps to only one bit in the config block. Otherwise something like the initialization values of a LUT would be intractable. | ||
|
|
||
| ## PIP Fuzzing | ||
|
|
||
| PIP fuzzing is the most difficult aspect to constrain to a limited number of trials. We can test these by placing a single | ||
| ARC (with a SLICE so it is not optimized away), and then looking at which tiles were impacted. This is usually done by | ||
| passing in a set of nodes to pull the PIPs from, and then creating a design with each of those pips placed in isolation. | ||
|
|
||
| While BEL fuzzing tends to operate against only one or two tiles at a time, a given node is hard to constrain to a given | ||
| tile. Some PIPs are also predicated on a related site being active. | ||
|
|
||
| Some edges between nodes are always active. These are detected by placing the ARC and observing no change in relevant | ||
| tiles. These are refered to as 'connections' in the database. For fuzzing purposes, it is important to pass the correct | ||
| ignore list to the solver since if an irrelevant tile has a change in it, it will not mark it as a pure connection. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| # Overview | ||
|
|
||
| At it's most basic level, the nexus (and most other FPGAs) is composed of basic elements (BELs), pins, wires and | ||
| Programmable Interconnect Points (PIPs). The bitstream configures the BELs and which PIPs are active. | ||
|
|
||
| Loosely speaking, on the lattice components each BEL corresponds to a site. The internal tooling for lattice refers to | ||
| wires as nodes and the terms are used interchangeably. | ||
|
|
||
| The lattice parts overlay a tile grid over this structure. Largely speaking the tile grid informs on where the component | ||
| might be on the chip, but also where the configuration data can be found / specified for any given chip. | ||
|
|
||
| ## Sites (BELs) | ||
|
|
||
| Every site has a type, and the type dictates both it's pin capabilities and what programmable options and modes exist for | ||
| that given site. Sites correspond most closely to the primitives found in lattice documentation, but sometimes a site | ||
| isn't directly translated as a primitive, and instead has multiple modes which map the same site to multiple primitives | ||
| as defined in the manual. | ||
|
|
||
| Nearly every site name contains a prefix indicating the row and column it is most aligned to, and that tile is used to | ||
| configure that site. A tile can have multiple sites in it, or the same site type can occur in multiple tile types where | ||
| it's configuration bits occur at different offsets. | ||
|
|
||
| Many exceptions do exist where a site is named for one row-column pair but it's configuration lives in another tile, and | ||
| that tile has the appropriate tile type. For instance, LRAM's typically are like this. Part of what the fuzzers are configured | ||
| for is to represent the mapping between the site tile location and the config tile location. | ||
|
|
||
| ## Nodes (Wires) and PIPs | ||
|
|
||
| Nodes represent physical wires with gates connecting it to other nodes. Nodes can have pins tied directly onto them. | ||
|
|
||
| Lattice has a TCL library exposed in a tool -- lapie / lark depending on version -- which can be used to query the node | ||
| graph. This tooling gives you which PIPs and pins are associated with the node, as well as what aliases are associated | ||
| with it. | ||
|
|
||
| In terms of scale, there are about 1.7 million nodes on the LIFCL-40 part. | ||
|
|
||
| Nodes also have aliases. The typical reason for this is that nodes can span multiple tiles, and so each tile has a local | ||
| name for that node. Only the primary name associated with the node is directly queryable, so there is no robust way in | ||
| general to determine every node that is associated with a given tile. | ||
|
|
||
| ### Node Naming | ||
|
|
||
| Nodes have a semantically meaningful structure to their naming. They are all prefixed with `R<r>C<c>_` which gives a hint | ||
| to it's location; although nodes can span multiple tiles. | ||
|
|
||
| After that there are the following naming conventions: | ||
|
|
||
| ## Tile types | ||
|
|
||
| Tiles of a given tile type will always have the same set of: | ||
|
|
||
| - Sites | ||
| - Nodes | ||
| - PIPs | ||
|
|
||
| Often they will also dictate the relationship between neighboring tiles in a rigid way. For instance, LRAM instances | ||
| have an associated `CIB_LR` tiletype at an offset determined by it's tiletype. | ||
|
|
||
| Tile types also are the fundamental building block to configuring the chip since it rigidly maps the bits in it's | ||
| configuration bits to the sites and pips associated with it. | ||
|
|
||
| Tile types are also standard across devices -- the way you configure a PLC tile is identical in LIFCL-17 as it is in LIFCL-40, | ||
| for instance. It should be noted though that lattice is inconsistent with this principal, and so some tile types are | ||
| flagged and changed when the tilegrid is imported from lattice's interchange format. | ||
|
|
||
| ## Global Routes | ||
|
|
||
| There is a global distribution network on the LIFCL devices for clocks and resets to limit skew to any given logic cell: | ||
|
|
||
| - Starts at CMUX | ||
| - Branch out left or right -- LHPRX or RHPRX | ||
| - Distributed along HROW's to SPINEs - HPRX1000 -> VPSX1000 | ||
| - SPINEs push to branch nodes VPSX1000 -> R..C44_HPBX..00 | ||
| - PLCs local to the SPINE can be fed from here. An additional branch jump HPBX0 can reach the rest. | ||
|
|
||
| See global.json for a listing of those cells for each device. | ||
|
|
||
| ### Example routing: | ||
|
|
||
| To get from R82C25_JCLKO_DCC_DCC0 -> R4C35_JCLK_SLICED on LIFCL-33 | ||
|
|
||
| - R37C25_JCLKO_DCC_DCC0 feeds [R37C25_JJCLKUL_CMUX_CORE_CMUX0, R37C25_JJCLKUL_CMUX_CORE_CMUX1] | ||
| - These feed out to [R37C25_JHPRX{LANE}_CMUX_CORE_CMUX0, R37C25_JHPRX{LANE}_CMUX_CORE_CMUX1] respectively | ||
| - These feed out to [R37C25_LHPRX{LANE}, R37C25_RHPRX{LANE}]. LHPRX branches out to C0 to C25. RHPRX branches out from C25 to C50 | ||
| - Following R37C25_LHPRX{LANE}, it drives R37C31_HPRX{LANE}00 | ||
| - This drives R41C37_VPSX{LANE}00 | ||
| - R41C37_VPSX{LANE}00 drives R{ROW}C44_HPBX{INST}00 | ||
| - R4C32_HPBX{INST}00 provides local access to tiles R38 to R50. It also provides access to a branch R4C32_HPBX{INST}00 node. | ||
| - R4C32_HPBX{INST}00 provides local access to tiles R25 to R37, namely R4C35_JCLK1 | ||
| - R4C35_JCLK1 drives R4C35_JCLK_SLICED | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| PROJ=SpinexMinimal | ||
| #DEVICE=LIFCL-33-8CTG104C | ||
| DEVICE=LIFCL-33U-8CTG104C | ||
| PDC=tinyclunx.pdc | ||
| TOP=SpinexMinimal | ||
| EXTRA_VERILOG=SpinexMinimal_references.v | ||
|
|
||
| include ../common.mk |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: derived