Merge branch 'master' of github.com:SymbiFlow/prjxray into tilegrid-ng

This commit is contained in:
Clifford Wolf 2018-02-14 13:37:54 +01:00
commit 5b74b282c2
58 changed files with 1176 additions and 233 deletions

15
.gcloudignore Normal file
View File

@ -0,0 +1,15 @@
# This file specifies files that are *not* uploaded to Google Cloud Platform
# using gcloud. It follows the same syntax as .gitignore, with the addition of
# "#!include" directives (which insert the entries of the given .gitignore-style
# file at that point).
#
# For more information, run:
# $ gcloud topic gcloudignore
#
.gcloudignore
#!include:.gitignore
# Don't bother uploading files not needed to generate a database.
experiments
minitests
vagrant

4
.gitignore vendored
View File

@ -1,3 +1,5 @@
/build/
.Xil
database/*
# Ignore database directories _except_ for their settings
database/*/*
!database/*/settings.sh

12
Dockerfile Normal file
View File

@ -0,0 +1,12 @@
ARG DEV_ENV_IMAGE
FROM ${DEV_ENV_IMAGE} AS db_builder
ARG NUM_PARALLEL_JOBS=1
COPY . /source
RUN cd /source && make -j${NUM_PARALLEL_JOBS} database
RUN find /source/database -mindepth 1 -maxdepth 1 -type d -exec /source/htmlgen/htmlgen.py --settings={}/settings.sh --output=/output/html \;
RUN mkdir -p /output/raw && find /source/database -mindepth 1 -maxdepth 1 -type d -exec cp -R {} /output/raw \;
FROM nginx:alpine
COPY --from=db_builder /output /usr/share/nginx/html

View File

@ -1,13 +1,21 @@
JOBS ?= $(shell nproc)
JOBS ?= 2
CLANG_FORMAT ?= clang-format
go:
.PHONY: database format clean
build:
git submodule update --init --recursive
mkdir -p build
cd build; cmake ..; make -j$(JOBS)
cd build; cmake ..; $(MAKE)
database: build
$(MAKE) -C $@
format:
find . -name \*.cc -and -not -path './third_party/*' -and -not -path './.git/*' -exec $(CLANG_FORMAT) -style=file -i {} \;
find . -name \*.h -and -not -path './third_party/*' -and -not -path './.git/*' -exec $(CLANG_FORMAT) -style=file -i {} \;
find . -name \*.py -and -not -path './third_party/*' -and -not -path './.git/*' -exec yapf -p -i {} \;
clean:
$(MAKE) -C database clean
$(MAKE) -C fuzzers clean
rm -rf build

21
cloudbuild.yaml Normal file
View File

@ -0,0 +1,21 @@
steps:
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '--build-arg'
- 'DEV_ENV_IMAGE=${_DEV_ENV_IMAGE}'
- '--build-arg'
- 'NUM_PARALLEL_JOBS=${_NUM_CPUS}'
- '-t'
- '${_GCR_ZONE}/$PROJECT_ID/${_IMAGE_NAME}:${TAG_NAME}'
- '.'
options:
disk_size_gb: 1000
machine_type: N1_HIGHCPU_32
timeout: '21600s'
substitutions:
_GCR_ZONE: 'gcr.io'
_IMAGE_NAME: 'prjxray-db'
_NUM_CPUS: '16'
images:
- '${_GCR_ZONE}/$PROJECT_ID/${_IMAGE_NAME}:${TAG_NAME}'

10
database/Makefile Normal file
View File

@ -0,0 +1,10 @@
.NOTPARALLEL:
SUBDIRS := $(patsubst %/,%, $(wildcard */))
.PHONY: $(SUBDIRS)
$(MAKECMDGOALS): $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ -f ../Makefile.database $(MAKECMDGOALS)

View File

@ -0,0 +1,15 @@
.PHONY: all clean
all: tilegrid.json
# Small dance to say that there is a single recipe that is run once to generate
# multiple files.
tileconn.json tilegrid.json: fuzzers
.INTERMEDIATE: fuzzers
fuzzers: SHELL:=/bin/bash
fuzzers: settings.sh
source settings.sh && $(MAKE) -C ../../fuzzers all
clean:
rm -f *.db tileconn.json tilegrid.json *.yaml
rm -rf html

1
docs/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
_build

24
docs/Makefile Normal file
View File

@ -0,0 +1,24 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXAUTOBUILD = sphinx-autobuild
SPHINXPROJ = ProjectX-Ray
SOURCEDIR = .
BUILDDIR = _build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
livehtml:
@$(SPHINXAUTOBUILD) -b html --ignore \*.swp --ignore \*~ $(SPHINXOPTS) "$(SOURCEDIR)" "$(BUILDDIR)/html"
.PHONY: help livereload Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

View File

@ -0,0 +1,43 @@
Bitstream format
================
.. todo::
Expand on rough notes
* Specific byte pattern at beginning of file to allow hardware to determine
width of bus providing configuration data.
* Rest of file is 32-bit big-endian words
* All data before 32-bit synchronization word (0xAA995566) is ignored by
configuration state machine
* Packetized format used to perform register reads/writes
* Three packet header types
* Type 0 packets exist only when performing zero-fill between rows
* Type 1 used for writes up to 4096 words
* Type 2 expands word count field to 27 bits by omitting register address
* Type 2 must always be proceeded by Type 1 which sets register address
* NOP packets are used for inserting required delays
* Most registers only accept 1 word of data
* Allowed register operations depends on interface used to send packets
* Writing LOUT via JTAG is treated as a bad command
* Single-frame FDRI writes via JTAG fail
* CRC
* Calculated automatically from writes: register address and data written
* Expected value is written to CRC register
* If there is a mismatch, error is flagged in status register
* Writes to CRC register can be safely removed from a bitstream
* Alternatively, replace with write to command register to reset calculated
CRC value
* Xilinx BIT header
* Additional information about how bitstream was generated
* Unofficially documented at
http://www.fpga-faq.com/FAQ_Pages/0026_Tell_me_about_bit_files.htm
* Really does require NULL-terminated Pascal strings
* Having this header is the distinction between .bin and .bit in Vivado
* Is ignored entirely by devices

View File

@ -0,0 +1,130 @@
Configuration
=============
Within an FPGA, various memories (latches, block RAMs, distributed RAMs)
contain the state of signal routing, :term:`BEL` configuration, and runtime
storage. Configuration is the process of loading an initial state into all of
these memories both to define the intended logic operations as well as set
initial data for runtime memories. Note that the same mechanisms used for
configuration are also capable of reading out the active state of these
memories as well. This can be used to examine the contents of a block RAM or
other memory at any point in the device's operation.
Addressing
----------------
As described in :ref:`architecture_overview-label`, 7-Series FPGAs are constructed
out of :term:`tiles <tile>` organized into :term:`clock domains <clock
domain>`. Each tile contains a set of :term:`BELs <BEL>` and the memories used
to configure them. Uniquely addressing each of these memories
involves first identifying the :term:`horizontal clock row`, then the tile within
that row, and finally the specific bit within the tile.
:term:`Horizontal clock row` addressing follows the hierarchical structure described
in :ref:`architecture_overview-label` with a single bit used to indicate top or bottom half
and a 5-bit integer to encode the row number. Within the row, tiles are connected to
one or more configuration busses depending on the type of tile and what configuration
memories it contains. These busses are identified by a 3-bit integer:
+---------+-------------------+---------------------+
| Address | Name | Connected tile type |
+=========+===================+=====================+
| 000 | CLB, I/O, CLB | Interconnect (INT) |
+---------+-------------------+---------------------+
| 001 | Block RAM content | Block RAM (BRAM) |
+---------+-------------------+---------------------+
| 010 | CFG_CLB | ??? |
+---------+-------------------+---------------------+
Within each bus, the connected tiles are organized into columns. A column roughly
corresponds to a physical vertical line of tiles perpendicular to and centered over
the horizontal clock row. Each column contains varying amounts of configuration data
depending on the types of tiles attached to that column. Regardless of the amount,
a column's configuration data is organized into a multiple of :term:`frames <frame>`.
Each frame consists of 101 words with 100 words for the connected tiles and 1 word for
the horizontal clock row. The 7-bit address used to identify a specific frame within
the column is called the minor address.
Putting all these pieces together, a 32-bit frame address is constructed:
+-----------------+-------+
| Field | Bits |
+=================+=======+
| Reserved | 31:26 |
+-----------------+-------+
| Bus | 25:23 |
+-----------------+-------+
| Top/Bottom Half | 22 |
+-----------------+-------+
| Row | 21:17 |
+-----------------+-------+
| Column | 16:7 |
+-----------------+-------+
| Minor | 6:0 |
+-----------------+-------+
CLB, I/O, CLB
^^^^^^^^^^^^^
Columns on this bus are comprised of 50 directly-attached interconnect tiles with various
kinds of tiles connected behind them. Frames are striped across the interconnect tiles
with each tile receiving 2 words out of the frame. The number of frames in a column
depends on the type of tiles connected behind the interconnect. For example, interconnect
tiles always have 26 frames and a CLBL tile has an additional 12 frames so a column of CLBs
will have 36 frames.
Block RAM content
^^^^^^^^^^^^^^^^^
As the name says, this bus provides access to the Block RAM contents. Block RAM configuration
data is accessed via the CLB, I/O, CLB bus. The mapping of frame words to memory locations is
not currently understood.
CFG_CLB
^^^^^^^
While mentioned in a few places, this bus type has not been seen in any bitstreams for Artix7
so far.
Loading sequence
----------------------
.. todo::
Expand on these rough notes.
* Device is configured via a state machine controlled via a set of registers
* CRC of register writes is checked against expected values to verify data
integrity during transmission.
* Before writing frame data:
* IDCODE for configuration's target device is checked against actual device
* Watchdog timer is disabled
* Start-up sequence clock is selected and configured
* Start-up signal assertion timing is configured
* Interconnect is placed into Hi-Z state
* Data is then written by:
* Loading a starting address
* Selecting the write configuration command
* Writing configuration data to data input register
* Writes must be in multiples of the frame size
* Multi-frame writes trigger autoincrementing of the frame address
* Autoincrement can be disabled via bit in COR1 register.
* At the end of a row, 2 frames of zeros must be inserted before data for the next row.
* After the write has finished, the device is restarted by:
* Strobing a signal to activate IOB/CLB configuration flip-flops
* Reactivate interconnect
* Arms start-up sequence to run after desync
* Desynchronizes the device from the configuration port
* Status register provides detail of start-up phases and which signals are asserted
Other
-----
* ECC of frame data is contained in word 50 alongside horizontal clock row configuration
* Loading will succeed even with incorrect ECC data
* ECC is primarily used for runtime bit-flip detection

View File

@ -0,0 +1,72 @@
Glossary
========================
.. glossary::
basic element
BEL
basic logic element
BLE
For example a LUT5, LUT6, CARRY4, or MUX, but not PIPs.
BELs come in two types:
* Basic BEL - A logic unit which does things.
* Routing BEL - A unit which is statically configured at the routing time.
bitstream
Binary data that is directly loaded into an FPGA to perform configuration.
Contains configuration :term:`frames <frame>` as well as programming
sequences and other commands required to load and activate same.
clock domain
Portion of a :term:`horizontal clock row` to one side of the global clock
spine. Often refers to :term:`tiles <tile>` that are associated with these
clocks.
column
Collection of :term:`tiles <tile>` physically organized as a vertical line.
configurable logic block
CLB
Basic building block of logic.
frame
Fundamental unit of configuration data consisting of 101 :term:`words <word>`.
half
Portion of a device defined by a virtual line dividing the two sets of global
clock buffers present in a device. The two halves are simply referred to as
the top and bottom halves.
node
Collection of :term:`wires <wire>` spanning one or more tiles.
programmable interconnect point
PIP
Connection point between two wires in a tile that may be enabled or
disabled by the configuration.
horizontal clock row
Portion of a device including 12 horizontal clocks and the 50 interconnect
and function tiles associated with them. A :term:`half` contains one or
more horizontal clock rows and each half may have a different number of
rows.
site
Portion of a tile where :term:`BELs <BEL>` can be placed. :term:`Slices
<slice>` in a :term:`CLB` tile are sites.
slice
Portion of a :term:`CLB` tile that contains :term:`BELs <BEL>`.
tile
Fundamental unit of physical structure containing a single type of
resource or function.
wire
Physical wire within a :term:`tile`.
word
32-bits stored in big-endian order. Fundamental unit of :term:`bitstream` format.

View File

@ -0,0 +1,33 @@
.. _architecture_overview-label:
Overview
========
.. todo:: add diagrams.
Xilinx 7-Series architecture utilizes a hierarchical design of chainable
structures to scale across the Spartan, Artix, Kintex, and Virtex product
lines. This documentation focuses on the Artix and Kintex devices and omits
some concepts introduced in Virtex devices.
At the top-level, 7-Series devices are divided into two :term:`halves <half>`
by a virtual horizontal line separating two sets of global clock buffers
(BUFGs). While global clocks can be connected such that they span both sets of
BUFGs, the two halves defined by this division are treated as separate entities
as related to configuration. The halves are referred to simply as the top and
bottom halves.
Each half is next divided vertically into one or more :term:`horizontal clock
rows <horizontal clock row>`, numbered outward from the global clock buffer
dividing line. Each horizontal clock row contains 12 clock lines that extend
across the device perpendicular to the global clock spine. Similar to the
global clock spine, each horizontal clock row is divided into two halves by two
sets of horizontal clock buffers (BUFHs), one on each side of the global clock
spine, yielding two :term:`clock domains <clock domain>`. Horizontal clocks
may be used within a single clock domain, connected to span both clock domains
in a horizontal clock row, or connected to global clocks.
Clock domains have a fixed height of 50 :term:`interconnect tiles
<interconnect tile>` centered around the horizontal clock lines (25 above, 25
below). Various function tiles, such as :term:`CLBs <CLB>`, are attached to interconnect
tiles.

179
docs/conf.py Normal file
View File

@ -0,0 +1,179 @@
# -*- coding: utf-8 -*-
#
# Project X-Ray documentation build configuration file, created by
# sphinx-quickstart on Mon Feb 5 11:04:37 2018.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import os
import re
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.imgmath', 'sphinx.ext.autodoc', 'sphinx.ext.doctest',
'sphinx.ext.autosummary', 'sphinx.ext.napoleon', 'sphinx.ext.todo'
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Project X-Ray'
copyright = u'2018, SymbiFlow Team'
author = u'SymbiFlow Team'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The full version, including alpha/beta/rc tags.
release = re.sub('^v', '', os.popen('git describe ').read().strip())
# The short X.Y version.
version = release
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Enable github links when not on readthedocs
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd:
html_context = {
"display_github": True, # Integrate GitHub
"github_user": "symbiflow", # Username
"github_repo": "prjxray", # Repo name
"github_version": "master", # Version
"conf_py_path": "/doc/",
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'prjxray'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(
master_doc, 'ProjectX-Ray.tex', u'Project X-Ray Documentation',
u'SymbiFlow Team', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'projectx-ray', u'Project X-Ray Documentation', [author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(
master_doc, 'ProjectX-Ray', u'Project X-Ray Documentation', author,
'ProjectX-Ray', 'One line description of project.', 'Miscellaneous'),
]
# Example configuration for intersphinx: refer to the Python standard library.
intersphinx_mapping = {'https://docs.python.org/': None}

23
docs/index.rst Normal file
View File

@ -0,0 +1,23 @@
.. Project X-Ray documentation master file, created by
sphinx-quickstart on Mon Feb 5 11:04:37 2018.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Project X-Ray
=========================================
`Project X-Ray`_ documents the `Xilinx`_ 7-Series FPGA architecture to enable
development of open-source tools. Our goal is to provide sufficient information
to develop a free and open Verilog to bitstream toolchain for these devices.
.. _Project X-Ray: https://github.com/SymbiFlow/prjxray
.. _Xilinx: http://www.xilinx.com/
.. toctree::
:maxdepth: 2
:caption: Xilinx 7-series Architecture
architecture/overview
architecture/configuration
architecture/bitstream_format
architecture/glossary

View File

@ -26,7 +26,7 @@ for l in f:
# Theory: there is one bit for each mux positon
# In each config 3 muxes are in one position, other 3 are in another
inv = int(i == n)
segmk.addtag(loc, "%c5FF.MUX.A" % which, def_a ^ inv)
segmk.addtag(loc, "%c5FF.MUX.B" % which, 1 ^ def_a ^ inv)
segmk.addtag(loc, "%c5FFMUX.IN_A" % which, def_a ^ inv)
segmk.addtag(loc, "%c5FFMUX.IN_B" % which, 1 ^ def_a ^ inv)
segmk.compile()
segmk.write()

View File

@ -0,0 +1,42 @@
Purpose:
Document nFFMUX family of CLB muxes
Algorithm:
Outcome:
CLB.SLICE_X0.AFFMUX.B0 30_00
CLB.SLICE_X0.AFFMUX.B1 30_01
CLB.SLICE_X0.AFFMUX.B2 30_02
CLB.SLICE_X0.AFFMUX.B3 30_03
CLB.SLICE_X0.BFFMUX.B0 30_27
CLB.SLICE_X0.BFFMUX.B1 30_26
CLB.SLICE_X0.BFFMUX.B2 30_25
CLB.SLICE_X0.BFFMUX.B3 30_24
CLB.SLICE_X0.CFFMUX.B0 30_35
CLB.SLICE_X0.CFFMUX.B1 30_36
CLB.SLICE_X0.CFFMUX.B2 30_37
CLB.SLICE_X0.CFFMUX.B3 30_38
CLB.SLICE_X0.DFFMUX.B0 30_62
CLB.SLICE_X0.DFFMUX.B1 30_61
CLB.SLICE_X0.DFFMUX.B2 30_60
CLB.SLICE_X0.DFFMUX.B3 30_59
CLB.SLICE_X1.AFFMUX.B0 31_00
CLB.SLICE_X1.AFFMUX.B1 31_01
CLB.SLICE_X1.AFFMUX.B2 31_02
CLB.SLICE_X1.AFFMUX.B3 30_04
CLB.SLICE_X1.BFFMUX.B0 31_25
CLB.SLICE_X1.BFFMUX.B1 31_27
CLB.SLICE_X1.BFFMUX.B2 31_26
CLB.SLICE_X1.BFFMUX.B3 31_24
CLB.SLICE_X1.CFFMUX.B0 31_35
CLB.SLICE_X1.CFFMUX.B1 31_38
CLB.SLICE_X1.CFFMUX.B2 31_37
CLB.SLICE_X1.CFFMUX.B3 31_36
CLB.SLICE_X1.DFFMUX.B0 30_58
CLB.SLICE_X1.DFFMUX.B1 31_61
CLB.SLICE_X1.DFFMUX.B2 31_62
CLB.SLICE_X1.DFFMUX.B3 31_60

View File

@ -1,42 +0,0 @@
Purpose:
Document AFFMUX family of CLB muxes
Algorithm:
Outcome:
CLB.SLICE_X0.AFF.DMUX.B0 30_00
CLB.SLICE_X0.AFF.DMUX.B1 30_01
CLB.SLICE_X0.AFF.DMUX.B2 30_02
CLB.SLICE_X0.AFF.DMUX.B3 30_03
CLB.SLICE_X0.BFF.DMUX.B0 30_27
CLB.SLICE_X0.BFF.DMUX.B1 30_26
CLB.SLICE_X0.BFF.DMUX.B2 30_25
CLB.SLICE_X0.BFF.DMUX.B3 30_24
CLB.SLICE_X0.CFF.DMUX.B0 30_35
CLB.SLICE_X0.CFF.DMUX.B1 30_36
CLB.SLICE_X0.CFF.DMUX.B2 30_37
CLB.SLICE_X0.CFF.DMUX.B3 30_38
CLB.SLICE_X0.DFF.DMUX.B0 30_62
CLB.SLICE_X0.DFF.DMUX.B1 30_61
CLB.SLICE_X0.DFF.DMUX.B2 30_60
CLB.SLICE_X0.DFF.DMUX.B3 30_59
CLB.SLICE_X1.AFF.DMUX.B0 31_00
CLB.SLICE_X1.AFF.DMUX.B1 31_01
CLB.SLICE_X1.AFF.DMUX.B2 31_02
CLB.SLICE_X1.AFF.DMUX.B3 30_04
CLB.SLICE_X1.BFF.DMUX.B0 31_25
CLB.SLICE_X1.BFF.DMUX.B1 31_27
CLB.SLICE_X1.BFF.DMUX.B2 31_26
CLB.SLICE_X1.BFF.DMUX.B3 31_24
CLB.SLICE_X1.CFF.DMUX.B0 31_35
CLB.SLICE_X1.CFF.DMUX.B1 31_38
CLB.SLICE_X1.CFF.DMUX.B2 31_37
CLB.SLICE_X1.CFF.DMUX.B3 31_36
CLB.SLICE_X1.DFF.DMUX.B0 30_58
CLB.SLICE_X1.DFF.DMUX.B1 31_61
CLB.SLICE_X1.DFF.DMUX.B2 31_62
CLB.SLICE_X1.DFF.DMUX.B3 31_60

View File

@ -52,7 +52,7 @@ for l in f:
src = which + "X"
# add the 1-tag for this connection
tag = "%sFF.DMUX.%s" % (which, src)
tag = "%sFFMUX.%s" % (which, src)
segmk.addtag(loc, tag, 1)
# remove this MUX from the cache, preventing generation of 0-tags for this MUX
@ -65,7 +65,7 @@ for loc, muxes in cache.items():
if src == "F7" and which not in "AC": continue
if src == "F8" and which not in "B": continue
if src == "AX": src = which + "X"
tag = "%sFF.DMUX.%s" % (which, src)
tag = "%sFFMUX.%s" % (which, src)
segmk.addtag(loc, tag, 0)

View File

@ -0,0 +1,52 @@
Purpose:
Document nOUTMUX family of CLB muxes
TODO: document O6
Algorithm:
Outcome:
CLB.SLICE_X0.AOUTMUX.B0 30_11
CLB.SLICE_X0.AOUTMUX.B1 30_08
CLB.SLICE_X0.AOUTMUX.B2 30_06
CLB.SLICE_X0.AOUTMUX.B3 30_07
CLB.SLICE_X0.BOUTMUX.B0 30_20
CLB.SLICE_X0.BOUTMUX.B1 30_21
CLB.SLICE_X0.BOUTMUX.B2 30_22
CLB.SLICE_X0.BOUTMUX.B3 30_23
CLB.SLICE_X0.COUTMUX.B0 30_45
CLB.SLICE_X0.COUTMUX.B1 30_44
CLB.SLICE_X0.COUTMUX.B2 30_40
CLB.SLICE_X0.COUTMUX.B3 30_43
CLB.SLICE_X0.DOUTMUX.B0 30_56
CLB.SLICE_X0.DOUTMUX.B1 30_51
CLB.SLICE_X0.DOUTMUX.B2 30_52
CLB.SLICE_X0.DOUTMUX.B3 30_57
CLB.SLICE_X1.AOUTMUX.B0 31_09
CLB.SLICE_X1.AOUTMUX.B1 31_07
CLB.SLICE_X1.AOUTMUX.B2 31_10
CLB.SLICE_X1.AOUTMUX.B3 30_05
CLB.SLICE_X1.BOUTMUX.B0 31_20
CLB.SLICE_X1.BOUTMUX.B1 30_28
CLB.SLICE_X1.BOUTMUX.B2 31_21
CLB.SLICE_X1.BOUTMUX.B3 30_29
CLB.SLICE_X1.COUTMUX.B0 31_43
CLB.SLICE_X1.COUTMUX.B1 30_42
CLB.SLICE_X1.COUTMUX.B2 31_40
CLB.SLICE_X1.COUTMUX.B3 30_41
CLB.SLICE_X1.DOUTMUX.B0 31_56
CLB.SLICE_X1.DOUTMUX.B1 30_53
CLB.SLICE_X1.DOUTMUX.B2 31_57
CLB.SLICE_X1.DOUTMUX.B3 31_53
From manual O6 testing
30_11 X0 AOUTMUX O6
30_20 X0 BOUTMUX O6
30_45 X0 COUTMUX O6
30_56 X0 DOUTMUX O6
31_09 X1 AOUTMUX O6
31_20 X1 BOUTMUX O6
31_43 X1 COUTMUX O6
31_56 X1 DOUTMUX O6

View File

@ -1,52 +0,0 @@
Purpose:
Document AOUTMUX family of CLB muxes
TODO: document O6
Algorithm:
Outcome:
CLB.SLICE_X0.AMUX.B0 30_11
CLB.SLICE_X0.AMUX.B1 30_08
CLB.SLICE_X0.AMUX.B2 30_06
CLB.SLICE_X0.AMUX.B3 30_07
CLB.SLICE_X0.BMUX.B0 30_20
CLB.SLICE_X0.BMUX.B1 30_21
CLB.SLICE_X0.BMUX.B2 30_22
CLB.SLICE_X0.BMUX.B3 30_23
CLB.SLICE_X0.CMUX.B0 30_45
CLB.SLICE_X0.CMUX.B1 30_44
CLB.SLICE_X0.CMUX.B2 30_40
CLB.SLICE_X0.CMUX.B3 30_43
CLB.SLICE_X0.DMUX.B0 30_56
CLB.SLICE_X0.DMUX.B1 30_51
CLB.SLICE_X0.DMUX.B2 30_52
CLB.SLICE_X0.DMUX.B3 30_57
CLB.SLICE_X1.AMUX.B0 31_09
CLB.SLICE_X1.AMUX.B1 31_07
CLB.SLICE_X1.AMUX.B2 31_10
CLB.SLICE_X1.AMUX.B3 30_05
CLB.SLICE_X1.BMUX.B0 31_20
CLB.SLICE_X1.BMUX.B1 30_28
CLB.SLICE_X1.BMUX.B2 31_21
CLB.SLICE_X1.BMUX.B3 30_29
CLB.SLICE_X1.CMUX.B0 31_43
CLB.SLICE_X1.CMUX.B1 30_42
CLB.SLICE_X1.CMUX.B2 31_40
CLB.SLICE_X1.CMUX.B3 30_41
CLB.SLICE_X1.DMUX.B0 31_56
CLB.SLICE_X1.DMUX.B1 30_53
CLB.SLICE_X1.DMUX.B2 31_57
CLB.SLICE_X1.DMUX.B3 31_53
From manual O6 testing
30_11 X0 AOUTMUX O6
30_20 X0 BOUTMUX O6
30_45 X0 COUTMUX O6
30_56 X0 DOUTMUX O6
31_09 X1 AOUTMUX O6
31_20 X1 BOUTMUX O6
31_43 X1 COUTMUX O6
31_56 X1 DOUTMUX O6

View File

@ -52,7 +52,7 @@ for l in f:
src = which + "5Q"
# add the 1-tag for this connection
tag = "%sMUX.%s" % (which, src)
tag = "%sOUTMUX.%s" % (which, src)
segmk.addtag(loc, tag, 1)
# remove this MUX from the cache, preventing generation of 0-tags for this MUX
@ -65,7 +65,7 @@ for loc, muxes in cache.items():
if src == "F7" and which not in "AC": continue
if src == "F8" and which not in "B": continue
if src == "5Q": src = which + "5Q"
tag = "%sMUX.%s" % (which, src)
tag = "%sOUTMUX.%s" % (which, src)
segmk.addtag(loc, tag, 0)

View File

@ -3,11 +3,9 @@ SPECIMENS := $(addprefix specimen_,$(shell seq -f '%03.0f' $(N)))
SPECIMENS_OK := $(addsuffix /OK,$(SPECIMENS))
database: $(SPECIMENS_OK)
${XRAY_SEGMATCH} -o seg_clblx.segbits $(addsuffix /segdata_clbl[lm]_[lr].txt,$(SPECIMENS))
${XRAY_SEGMATCH} -o seg_clblx.segbits $(addsuffix /segdata_clblm_[lr].txt,$(SPECIMENS))
pushdb:
${XRAY_MERGEDB} clbll_l seg_clblx.segbits
${XRAY_MERGEDB} clbll_r seg_clblx.segbits
${XRAY_MERGEDB} clblm_l seg_clblx.segbits
${XRAY_MERGEDB} clblm_r seg_clblx.segbits

View File

@ -23,7 +23,7 @@ namespace xc7series {
class BitstreamWriter {
public:
typedef std::array<uint32_t, 6> header_t;
typedef std::vector<ConfigurationPacket> packets_t;
typedef std::vector<std::unique_ptr<ConfigurationPacket>> packets_t;
// Only defined if a packet exists
typedef absl::optional<absl::Span<const uint32_t>> op_data_t;
typedef absl::Span<const uint32_t>::iterator data_iterator_t;

View File

@ -0,0 +1,34 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_COMMAND_H_
#define PRJXRAY_LIB_XILINX_XC7SERIES_COMMAND_H_
namespace prjxray {
namespace xilinx {
namespace xc7series {
enum class Command : uint32_t {
NOP = 0x0,
WCFG = 0x1,
MFW = 0x2,
LFRM = 0x3,
RCFG = 0x4,
START = 0x5,
RCAP = 0x6,
RCRC = 0x7,
AGHIGH = 0x8,
SWITCH = 0x9,
GRESTORE = 0xA,
SHUTDOWN = 0xB,
GCAPTURE = 0xC,
DESYNC = 0xD,
IPROG = 0xF,
CRCC = 0x10,
LTIMER = 0x11,
BSPI_READ = 0x12,
FALL_EDGE = 0x13,
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_COMMAND_H_

View File

@ -0,0 +1,122 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H
#define PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H
#include <prjxray/bit_ops.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
class ConfigurationOptions0Value {
public:
enum class StartupClockSource : uint32_t {
CCLK = 0x0,
User = 0x1,
JTAG = 0x2,
};
enum class SignalReleaseCycle : uint32_t {
Phase1 = 0x0,
Phase2 = 0x1,
Phase3 = 0x2,
Phase4 = 0x3,
Phase5 = 0x4,
Phase6 = 0x5,
TrackDone = 0x6,
Keep = 0x7,
};
enum class StallCycle : uint32_t {
Phase0 = 0x0,
Phase1 = 0x1,
Phase2 = 0x2,
Phase3 = 0x3,
Phase4 = 0x4,
Phase5 = 0x5,
Phase6 = 0x6,
NoWait = 0x7,
};
ConfigurationOptions0Value() : value_(0) {}
operator uint32_t() const { return value_; }
ConfigurationOptions0Value& SetUseDonePinAsPowerdownStatus(
bool enabled) {
value_ = bit_field_set(value_, 27, 27, enabled ? 1 : 0);
return *this;
}
ConfigurationOptions0Value& SetAddPipelineStageForDoneIn(bool enabled) {
value_ = bit_field_set(value_, 25, 25, enabled ? 1 : 0);
return *this;
}
ConfigurationOptions0Value& SetDriveDoneHigh(bool enabled) {
value_ = bit_field_set(value_, 24, 24, enabled);
return *this;
}
ConfigurationOptions0Value& SetReadbackIsSingleShot(bool enabled) {
value_ = bit_field_set(value_, 23, 23, enabled);
return *this;
}
ConfigurationOptions0Value& SetCclkFrequency(uint32_t mhz) {
value_ = bit_field_set(value_, 22, 17, mhz);
return *this;
}
ConfigurationOptions0Value& SetStartupClockSource(
StartupClockSource source) {
value_ = bit_field_set(value_, 16, 15,
static_cast<uint32_t>(source));
return *this;
}
ConfigurationOptions0Value& SetReleaseDonePinAtStartupCycle(
SignalReleaseCycle cycle) {
value_ =
bit_field_set(value_, 14, 12, static_cast<uint32_t>(cycle));
return *this;
}
ConfigurationOptions0Value& SetStallAtStartupCycleUntilDciMatch(
StallCycle cycle) {
value_ =
bit_field_set(value_, 11, 9, static_cast<uint32_t>(cycle));
return *this;
};
ConfigurationOptions0Value& SetStallAtStartupCycleUntilMmcmLock(
StallCycle cycle) {
value_ =
bit_field_set(value_, 8, 6, static_cast<uint32_t>(cycle));
return *this;
};
ConfigurationOptions0Value& SetReleaseGtsSignalAtStartupCycle(
SignalReleaseCycle cycle) {
value_ =
bit_field_set(value_, 5, 3, static_cast<uint32_t>(cycle));
return *this;
}
ConfigurationOptions0Value& SetReleaseGweSignalAtStartupCycle(
SignalReleaseCycle cycle) {
value_ =
bit_field_set(value_, 2, 0, static_cast<uint32_t>(cycle));
return *this;
}
private:
uint32_t value_;
}; // namespace xc7series
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_CONFIGURATION_OPTIONS_0_VALUE_H

View File

@ -0,0 +1,33 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H
#define PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H
#include <memory>
#include <absl/types/span.h>
#include <prjxray/bit_ops.h>
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
template <int Words>
class ConfigurationPacketWithPayload : public ConfigurationPacket {
public:
ConfigurationPacketWithPayload(
Opcode op,
ConfigurationRegister reg,
const std::array<uint32_t, Words>& payload)
: ConfigurationPacket(1, op, reg, absl::Span<uint32_t>(payload_)),
payload_(std::move(payload)) {}
private:
std::array<uint32_t, Words> payload_;
}; // namespace xc7series
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H

View File

@ -25,6 +25,7 @@ enum class ConfigurationRegister : unsigned int {
COR1 = 0x0e,
WBSTAR = 0x10,
TIMER = 0x11,
UNKNOWN = 0x13,
BOOTSTS = 0x16,
CTL1 = 0x18,
BSPI = 0x1F,

View File

@ -0,0 +1,24 @@
#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H
#define PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H
#include <prjxray/xilinx/xc7series/configuration_packet.h>
#include <prjxray/xilinx/xc7series/configuration_register.h>
namespace prjxray {
namespace xilinx {
namespace xc7series {
class NopPacket : public ConfigurationPacket {
public:
NopPacket()
: ConfigurationPacket(1,
Opcode::NOP,
ConfigurationRegister::CRC,
{}) {}
};
} // namespace xc7series
} // namespace xilinx
} // namespace prjxray
#endif // PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H

View File

@ -28,7 +28,7 @@ BitstreamWriter::BitstreamWriter(const packets_t& packets)
BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_begin() {
// itr_packets = packets.begin();
const ConfigurationPacket& packet = *itr_packets_;
const ConfigurationPacket& packet = **itr_packets_;
return BitstreamWriter::packet_iterator(
&packet, BitstreamWriter::packet_iterator::STATE_HEADER,
@ -36,7 +36,7 @@ BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_begin() {
}
BitstreamWriter::packet_iterator BitstreamWriter::iterator::packet_end() {
const ConfigurationPacket& packet = *itr_packets_;
const ConfigurationPacket& packet = **itr_packets_;
return BitstreamWriter::packet_iterator(
&packet, BitstreamWriter::packet_iterator::STATE_END,
@ -138,7 +138,7 @@ BitstreamWriter::iterator BitstreamWriter::begin() {
if (itr_packets != packets_.end()) {
// op_packet_itr = packet_begin();
// FIXME: de-duplicate this
const ConfigurationPacket& packet = *itr_packets;
const ConfigurationPacket& packet = **itr_packets;
packet_iterator packet_itr =
packet_iterator(&packet, packet_iterator::STATE_HEADER,
packet.data().begin());

View File

@ -50,7 +50,8 @@ void dump_packets(xc7series::BitstreamWriter writer, bool nl = true) {
}
// Special all 0's
void AddType0(std::vector<xc7series::ConfigurationPacket>& packets) {
void AddType0(
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>& packets) {
// InitWithWords doesn't like type 0
/*
static std::vector<uint32_t> words{0x00000000};
@ -61,27 +62,32 @@ void AddType0(std::vector<xc7series::ConfigurationPacket>& packets) {
static std::vector<uint32_t> words{};
absl::Span<uint32_t> word_span(words);
// CRC is config value 0
packets.push_back(xc7series::ConfigurationPacket(
packets.emplace_back(new xc7series::ConfigurationPacket(
0, xc7series::ConfigurationPacket::NOP,
xc7series::ConfigurationRegister::CRC, word_span));
}
void AddType1(std::vector<xc7series::ConfigurationPacket>& packets) {
void AddType1(
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>& packets) {
static std::vector<uint32_t> words{MakeType1(0x2, 0x3, 2), 0xAA, 0xBB};
absl::Span<uint32_t> word_span(words);
auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span);
packets.push_back(*(packet.second));
packets.emplace_back(
new xc7series::ConfigurationPacket(*(packet.second)));
}
// Empty
void AddType1E(std::vector<xc7series::ConfigurationPacket>& packets) {
void AddType1E(
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>& packets) {
static std::vector<uint32_t> words{MakeType1(0x2, 0x3, 0)};
absl::Span<uint32_t> word_span(words);
auto packet = xc7series::ConfigurationPacket::InitWithWords(word_span);
packets.push_back(*(packet.second));
packets.emplace_back(
new xc7series::ConfigurationPacket(*(packet.second)));
}
void AddType2(std::vector<xc7series::ConfigurationPacket>& packets) {
void AddType2(
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>& packets) {
// Type 1 packet with address
// Without this InitWithWords will fail on type 2
xc7series::ConfigurationPacket* packet1;
@ -90,8 +96,9 @@ void AddType2(std::vector<xc7series::ConfigurationPacket>& packets) {
absl::Span<uint32_t> word_span(words);
auto packet1_pair =
xc7series::ConfigurationPacket::InitWithWords(word_span);
packets.push_back(*(packet1_pair.second));
packet1 = &packets[0];
packets.emplace_back(
new xc7series::ConfigurationPacket(*(packet1_pair.second)));
packet1 = packets[0].get();
}
// Type 2 packet with data
{
@ -100,13 +107,14 @@ void AddType2(std::vector<xc7series::ConfigurationPacket>& packets) {
absl::Span<uint32_t> word_span(words);
auto packet = xc7series::ConfigurationPacket::InitWithWords(
word_span, packet1);
packets.push_back(*(packet.second));
packets.emplace_back(
new xc7series::ConfigurationPacket(*(packet.second)));
}
}
// Empty packets should produce just the header
TEST(BitstreamWriterTest, WriteHeader) {
std::vector<xc7series::ConfigurationPacket> packets;
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
xc7series::BitstreamWriter writer(packets);
std::vector<uint32_t> words(writer.begin(), writer.end());
@ -120,7 +128,7 @@ TEST(BitstreamWriterTest, WriteHeader) {
}
TEST(BitstreamWriterTest, WriteType0) {
std::vector<xc7series::ConfigurationPacket> packets;
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
AddType0(packets);
xc7series::BitstreamWriter writer(packets);
// dump_packets(writer, false);
@ -133,7 +141,7 @@ TEST(BitstreamWriterTest, WriteType0) {
EXPECT_EQ(words, ref);
}
TEST(BitstreamWriterTest, WriteType1) {
std::vector<xc7series::ConfigurationPacket> packets;
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
AddType1(packets);
xc7series::BitstreamWriter writer(packets);
// dump_packets(writer, false);
@ -147,7 +155,7 @@ TEST(BitstreamWriterTest, WriteType1) {
}
TEST(BitstreamWriterTest, WriteType2) {
std::vector<xc7series::ConfigurationPacket> packets;
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
AddType2(packets);
xc7series::BitstreamWriter writer(packets);
// dump_packets(writer, false);
@ -164,7 +172,7 @@ TEST(BitstreamWriterTest, WriteType2) {
}
TEST(BitstreamWriterTest, WriteMulti) {
std::vector<xc7series::ConfigurationPacket> packets;
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>> packets;
AddType1(packets);
AddType1E(packets);
AddType2(packets);

View File

@ -1,4 +1,4 @@
.PRECIOUS: harness_impl.dcp %_impl.dcp %.bit
.PRECIOUS: harness_impl.dcp %_impl.dcp %.bit %_roi_partial.bit
# Top-level target for generating a programmable bitstream. Given a .fasm
# file, calling make with the .fasm extension replaced with _hand_crafted.bit
@ -6,49 +6,14 @@
# ready for programming to a board. For example,
# 'make inv_hand_crafted.bit' will generate a bitstream that includes the
# design from roi_noninv.fasm.
%_hand_crafted.bit: init_sequence.bit %_no_headers.bin final_sequence.bin
cat $^ > $@
%_no_headers.bin: %_patched.bin
# WARNING: these values need to be tweaked if anything about the
# Vivado-generated design changes.
xxd -p -s 0x18 $< | xxd -r -p - $@
%_patched.bin: %_roi_partial.frm harness.bit
%_hand_crafted.bit: %_roi_partial.frm harness.bit
${XRAY_TOOLS_DIR}/xc7patch \
--part_file ${XRAY_PART_YAML} \
--part_name "${XRAY_PART}" \
--part_file "${XRAY_PART_YAML}" \
--bitstream_file harness.bit \
--frm_file $< \
--output_file $@
# xc7patch currently only generates the actual frame writes which is
# insufficient to program a device. Grab the initialization and finalization
# sequences from the harness bitstream so they can be tacked on to the
# xc7patch-generated bitstream to create a programmable bitstream.
#
# The offsets used below were determined by manually inspecting
# harness.bit with a hex editor. init_sequence.bit is the beginning of
# the file until just before the actual frame data is sent via a write to FDRI.
# final_sequence.bin is from just after the frame data write to the end of the
# file. Note that final_sequence.bin normally includes at least one CRC check.
# The sed command replaces any CRC checks with a Reset CRC command which is the
# same behavior as setting BITSTREAM.GENERAL.CRC to Disabled. These offset
# should not change unless you alter the bitstream format used (i.e. setting
# BITSTREAM.GENERAL.DEBUGBITSTREAM or BITSTREAM.GENERAL.PERFRAMECRC to YES).
init_sequence.bit: harness.bit
# WARNING: these values need to be tweaked if anything about the
# Vivado-generated design changes.
xxd -p -l 0x147 $< | xxd -r -p - $@
final_sequence.bin: harness.bit
# WARNING: these values need to be tweaked if anything about the
# Vivado-generated design changes.
xxd -p -s 0x216abf $< | \
tr -d '\n' | \
sed -e 's/30000001.\{8\}/3000800100000007/g' | \
fold -w 40 | \
xxd -r -p - $@
# Generate a suitable harness by using Vivado's partial reconfiguration
# feature. inv.v is used as a sample reconfiguration design as one is
# required to generate a partial reconfiguration design.

View File

@ -30,28 +30,11 @@ echo "Out .bit: $bit_out"
${XRAY_DIR}/tools/fasm2frame.py $fasm_in roi_partial.frm
${XRAY_TOOLS_DIR}/xc7patch \
--part_name ${XRAY_PART} \
--part_file ${XRAY_PART_YAML} \
--bitstream_file $bit_in \
--frm_file roi_partial.frm \
--output_file patched.bin
# WARNING: these values need to be tweaked if anything about the
# Vivado-generated design changes.
xxd -p -l 0x147 $bit_in | xxd -r -p - init_sequence.bit
# WARNING: these values need to be tweaked if anything about the
# Vivado-generated design changes.
xxd -p -s 0x18 patched.bin | xxd -r -p - no_headers.bin
# WARNING: these values need to be tweaked if anything about the
# Vivado-generated design changes.
xxd -p -s 0x216abf $bit_in | \
tr -d '\n' | \
sed -e 's/30000001.\{8\}/3000800100000007/g' | \
fold -w 40 | \
xxd -r -p - final_sequence.bin
cat init_sequence.bit no_headers.bin final_sequence.bin >$bit_out
--output_file $bit_out
#openocd -f $XRAY_DIR/utils/openocd/board-digilent-basys3.cfg -c "init; pld load 0 $bit_out; exit"

View File

@ -1,2 +1,5 @@
yapf
futures
sphinx
sphinx_rtd_theme
sphinx-autobuild
yapf

View File

@ -21,6 +21,7 @@ target_link_libraries(gen_part_base_yaml
add_executable(xc7patch xc7patch.cc)
target_link_libraries(xc7patch
absl::strings
absl::time
gflags
libprjxray
)

View File

@ -5,14 +5,23 @@
#include <string>
#include <vector>
#include <absl/strings/str_cat.h>
#include <absl/strings/str_split.h>
#include <absl/time/clock.h>
#include <absl/time/time.h>
#include <gflags/gflags.h>
#include <prjxray/memory_mapped_file.h>
#include <prjxray/xilinx/xc7series/bitstream_reader.h>
#include <prjxray/xilinx/xc7series/bitstream_writer.h>
#include <prjxray/xilinx/xc7series/command.h>
#include <prjxray/xilinx/xc7series/configuration.h>
#include <prjxray/xilinx/xc7series/configuration_options_0_value.h>
#include <prjxray/xilinx/xc7series/configuration_packet_with_payload.h>
#include <prjxray/xilinx/xc7series/ecc.h>
#include <prjxray/xilinx/xc7series/nop_packet.h>
#include <prjxray/xilinx/xc7series/part.h>
DEFINE_string(part_name, "", "");
DEFINE_string(part_file, "", "Definition file for target 7-series part");
DEFINE_string(bitstream_file,
"",
@ -111,54 +120,16 @@ int main(int argc, char* argv[]) {
uint32_t ecc = 0;
for (size_t ii = 0; ii < frame_data.size(); ++ii) {
uint32_t word = frame_data[ii];
uint32_t offset = ii * 32;
if (ii > 0x25) {
offset += 0x1360;
} else if (ii > 0x6) {
offset += 0x1340;
} else {
offset += 0x1320;
}
// Mask out where the ECC should be.
if (ii == 0x32) {
word &= 0xFFFFE000;
}
for (int jj = 0; jj < 32; ++jj) {
if ((word & 1) == 1) {
ecc ^= offset + jj;
}
word >>= 1;
}
ecc = xc7series::icap_ecc(ii, frame_data[ii], ecc);
}
uint32_t v = ecc & 0xFFF;
v ^= v >> 8;
v ^= v >> 4;
v ^= v >> 2;
v ^= v >> 1;
ecc ^= (v & 1) << 12;
// Replace the old ECC with the new.
frame_data[0x32] &= 0xFFFFE000;
frame_data[0x32] |= (ecc & 0x1FFF);
}
#if 0
for (auto& frame : frames) {
std::cout << "0x" << std::hex
<< static_cast<uint32_t>(frame.first) << " ";
for (auto& word : frame.second) {
std::cout << "0x" << std::hex << word << ",";
}
std::cout << std::endl;
}
#endif
std::vector<xc7series::ConfigurationPacket> out_packets;
std::vector<std::unique_ptr<xc7series::ConfigurationPacket>>
out_packets;
// Generate a single type 2 packet that writes everything at once.
std::vector<uint32_t> packet_data;
@ -177,18 +148,167 @@ int main(int argc, char* argv[]) {
}
packet_data.insert(packet_data.end(), 202, 0);
out_packets.push_back(xc7series::ConfigurationPacket(
// Initialization sequence
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::TIMER, {0x0}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::WBSTAR, {0x0}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::NOP)}));
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::UNKNOWN, {0x0}));
// Configuration Options 0
out_packets.emplace_back(new xc7series::ConfigurationPacketWithPayload<
1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::COR0,
{xc7series::ConfigurationOptions0Value()
.SetAddPipelineStageForDoneIn(true)
.SetReleaseDonePinAtStartupCycle(
xc7series::ConfigurationOptions0Value::SignalReleaseCycle::
Phase4)
.SetStallAtStartupCycleUntilDciMatch(
xc7series::ConfigurationOptions0Value::StallCycle::NoWait)
.SetStallAtStartupCycleUntilMmcmLock(
xc7series::ConfigurationOptions0Value::StallCycle::NoWait)
.SetReleaseGtsSignalAtStartupCycle(
xc7series::ConfigurationOptions0Value::SignalReleaseCycle::
Phase5)
.SetReleaseGweSignalAtStartupCycle(
xc7series::ConfigurationOptions0Value::SignalReleaseCycle::
Phase6)}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::COR1, {0x0}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::IDCODE, {part->idcode()}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::SWITCH)}));
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::MASK, {0x401}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CTL0, {0x501}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::MASK, {0x0}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CTL1, {0x0}));
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::FAR, {0x0}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::WCFG)}));
out_packets.emplace_back(new xc7series::NopPacket());
// Frame data write
out_packets.emplace_back(new xc7series::ConfigurationPacket(
1, xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::FDRI, {}));
out_packets.push_back(xc7series::ConfigurationPacket(
out_packets.emplace_back(new xc7series::ConfigurationPacket(
2, xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::FDRI, packet_data));
#if 0
for (auto& packet : out_packets) {
std::cout << packet << std::endl;
// Finalization sequence
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::GRESTORE)}));
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::LFRM)}));
for (int ii = 0; ii < 100; ++ii) {
out_packets.emplace_back(new xc7series::NopPacket());
}
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::START)}));
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::FAR, {0x3be0000}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::MASK, {0x501}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CTL0, {0x501}));
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::RCRC)}));
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(new xc7series::NopPacket());
out_packets.emplace_back(
new xc7series::ConfigurationPacketWithPayload<1>(
xc7series::ConfigurationPacket::Opcode::Write,
xc7series::ConfigurationRegister::CMD,
{static_cast<uint32_t>(xc7series::Command::DESYNC)}));
for (int ii = 0; ii < 400; ++ii) {
out_packets.emplace_back(new xc7series::NopPacket());
}
#endif
// Write bitstream.
xc7series::BitstreamWriter out_bitstream_writer(out_packets);
@ -199,6 +319,61 @@ int main(int argc, char* argv[]) {
return 1;
}
// Xilinx BIT header.
// Sync header
std::vector<uint8_t> bit_header{0x0, 0x9, 0x0f, 0xf0, 0x0f,
0xf0, 0x0f, 0xf0, 0x0f, 0xf0,
0x00, 0x00, 0x01, 'a'};
auto build_source = absl::StrCat(FLAGS_frm_file, ";Generator=xc7patch");
bit_header.push_back(
static_cast<uint8_t>((build_source.size() + 1) >> 8));
bit_header.push_back(static_cast<uint8_t>(build_source.size() + 1));
bit_header.insert(bit_header.end(), build_source.begin(),
build_source.end());
bit_header.push_back(0x0);
// Source file.
bit_header.push_back('b');
bit_header.push_back(
static_cast<uint8_t>((FLAGS_part_name.size() + 1) >> 8));
bit_header.push_back(static_cast<uint8_t>(FLAGS_part_name.size() + 1));
bit_header.insert(bit_header.end(), FLAGS_part_name.begin(),
FLAGS_part_name.end());
bit_header.push_back(0x0);
// Build timestamp.
auto build_time = absl::Now();
auto build_date_string =
absl::FormatTime("%E4Y/%m/%d", build_time, absl::UTCTimeZone());
auto build_time_string =
absl::FormatTime("%H:%M:%S", build_time, absl::UTCTimeZone());
bit_header.push_back('c');
bit_header.push_back(
static_cast<uint8_t>((build_date_string.size() + 1) >> 8));
bit_header.push_back(
static_cast<uint8_t>(build_date_string.size() + 1));
bit_header.insert(bit_header.end(), build_date_string.begin(),
build_date_string.end());
bit_header.push_back(0x0);
bit_header.push_back('d');
bit_header.push_back(
static_cast<uint8_t>((build_time_string.size() + 1) >> 8));
bit_header.push_back(
static_cast<uint8_t>(build_time_string.size() + 1));
bit_header.insert(bit_header.end(), build_time_string.begin(),
build_time_string.end());
bit_header.push_back(0x0);
bit_header.insert(bit_header.end(), {'e', 0x0, 0x0, 0x0, 0x0});
out_file.write(reinterpret_cast<const char*>(bit_header.data()),
bit_header.size());
auto end_of_header_pos = out_file.tellp();
auto header_data_length_pos =
end_of_header_pos - static_cast<std::ofstream::off_type>(4);
for (uint32_t word : out_bitstream_writer) {
out_file.put((word >> 24) & 0xFF);
out_file.put((word >> 16) & 0xFF);
@ -206,5 +381,13 @@ int main(int argc, char* argv[]) {
out_file.put((word)&0xFF);
}
uint32_t length_of_data = out_file.tellp() - end_of_header_pos;
out_file.seekp(header_data_length_pos);
out_file.put((length_of_data >> 24) & 0xFF);
out_file.put((length_of_data >> 16) & 0xFF);
out_file.put((length_of_data >> 8) & 0xFF);
out_file.put((length_of_data)&0xFF);
return 0;
}