diff --git a/.gcloudignore b/.gcloudignore new file mode 100644 index 00000000..ef2ea2e4 --- /dev/null +++ b/.gcloudignore @@ -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 diff --git a/.gitignore b/.gitignore index 05e207ba..28f10758 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ /build/ .Xil -database/* +# Ignore database directories _except_ for their settings +database/*/* +!database/*/settings.sh diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..a2544951 --- /dev/null +++ b/Dockerfile @@ -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 diff --git a/Makefile b/Makefile index 297b666e..2028b5d9 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/cloudbuild.yaml b/cloudbuild.yaml new file mode 100644 index 00000000..c3f12bcc --- /dev/null +++ b/cloudbuild.yaml @@ -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}' diff --git a/database/Makefile b/database/Makefile new file mode 100644 index 00000000..99fab407 --- /dev/null +++ b/database/Makefile @@ -0,0 +1,10 @@ +.NOTPARALLEL: + +SUBDIRS := $(patsubst %/,%, $(wildcard */)) + +.PHONY: $(SUBDIRS) + +$(MAKECMDGOALS): $(SUBDIRS) + +$(SUBDIRS): + $(MAKE) -C $@ -f ../Makefile.database $(MAKECMDGOALS) diff --git a/database/Makefile.database b/database/Makefile.database new file mode 100644 index 00000000..2e407968 --- /dev/null +++ b/database/Makefile.database @@ -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 diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..e35d8850 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_build diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..b52c6680 --- /dev/null +++ b/docs/Makefile @@ -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) diff --git a/docs/architecture/bitstream_format.rst b/docs/architecture/bitstream_format.rst new file mode 100644 index 00000000..5c74fb21 --- /dev/null +++ b/docs/architecture/bitstream_format.rst @@ -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 diff --git a/docs/architecture/configuration.rst b/docs/architecture/configuration.rst new file mode 100644 index 00000000..e75174f5 --- /dev/null +++ b/docs/architecture/configuration.rst @@ -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 ` organized into :term:`clock domains `. Each tile contains a set of :term:`BELs ` 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 `. +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 diff --git a/docs/architecture/glossary.rst b/docs/architecture/glossary.rst new file mode 100644 index 00000000..ef29cec2 --- /dev/null +++ b/docs/architecture/glossary.rst @@ -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 ` 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 ` that are associated with these + clocks. + + column + Collection of :term:`tiles ` 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 `. + + 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 ` 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 ` can be placed. :term:`Slices + ` in a :term:`CLB` tile are sites. + + slice + Portion of a :term:`CLB` tile that contains :term:`BELs `. + + 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. diff --git a/docs/architecture/overview.rst b/docs/architecture/overview.rst new file mode 100644 index 00000000..ec66cfb1 --- /dev/null +++ b/docs/architecture/overview.rst @@ -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 ` +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 `, 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 `. 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 +` centered around the horizontal clock lines (25 above, 25 +below). Various function tiles, such as :term:`CLBs `, are attached to interconnect +tiles. diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 00000000..9d14b725 --- /dev/null +++ b/docs/conf.py @@ -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} diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 00000000..81041af0 --- /dev/null +++ b/docs/index.rst @@ -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 diff --git a/fuzzers/005-tilegrid/README.txt b/fuzzers/005-tilegrid/README.md similarity index 100% rename from fuzzers/005-tilegrid/README.txt rename to fuzzers/005-tilegrid/README.md diff --git a/fuzzers/011-ffconfig/README.txt b/fuzzers/011-ffconfig/README.md similarity index 100% rename from fuzzers/011-ffconfig/README.txt rename to fuzzers/011-ffconfig/README.md diff --git a/fuzzers/012-clbn5ffmux/README.txt b/fuzzers/012-clbn5ffmux/README.md similarity index 100% rename from fuzzers/012-clbn5ffmux/README.txt rename to fuzzers/012-clbn5ffmux/README.md diff --git a/fuzzers/012-clbn5ffmux/generate.py b/fuzzers/012-clbn5ffmux/generate.py index 6c44af1c..e2e5a7d9 100644 --- a/fuzzers/012-clbn5ffmux/generate.py +++ b/fuzzers/012-clbn5ffmux/generate.py @@ -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() diff --git a/fuzzers/013-clbncy0/README.txt b/fuzzers/013-clbncy0/README.md similarity index 100% rename from fuzzers/013-clbncy0/README.txt rename to fuzzers/013-clbncy0/README.md diff --git a/fuzzers/014-ffsrcemux/README.txt b/fuzzers/014-ffsrcemux/README.md similarity index 100% rename from fuzzers/014-ffsrcemux/README.txt rename to fuzzers/014-ffsrcemux/README.md diff --git a/fuzzers/015-clbnffmux/README.md b/fuzzers/015-clbnffmux/README.md new file mode 100644 index 00000000..f67ed3b6 --- /dev/null +++ b/fuzzers/015-clbnffmux/README.md @@ -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 + + diff --git a/fuzzers/015-clbnffmux/README.txt b/fuzzers/015-clbnffmux/README.txt deleted file mode 100644 index 820fcf39..00000000 --- a/fuzzers/015-clbnffmux/README.txt +++ /dev/null @@ -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 - - diff --git a/fuzzers/015-clbnffmux/generate.py b/fuzzers/015-clbnffmux/generate.py index 38fd2a80..79b49912 100644 --- a/fuzzers/015-clbnffmux/generate.py +++ b/fuzzers/015-clbnffmux/generate.py @@ -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) diff --git a/fuzzers/016-clbnoutmux/README.md b/fuzzers/016-clbnoutmux/README.md new file mode 100644 index 00000000..d0e31619 --- /dev/null +++ b/fuzzers/016-clbnoutmux/README.md @@ -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 + diff --git a/fuzzers/016-clbnoutmux/README.txt b/fuzzers/016-clbnoutmux/README.txt deleted file mode 100644 index 6bcb8088..00000000 --- a/fuzzers/016-clbnoutmux/README.txt +++ /dev/null @@ -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 - diff --git a/fuzzers/016-clbnoutmux/generate.py b/fuzzers/016-clbnoutmux/generate.py index 7c8dda15..ede555f0 100644 --- a/fuzzers/016-clbnoutmux/generate.py +++ b/fuzzers/016-clbnoutmux/generate.py @@ -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) diff --git a/fuzzers/017-clbprecyinit/README.txt b/fuzzers/017-clbprecyinit/README.md similarity index 100% rename from fuzzers/017-clbprecyinit/README.txt rename to fuzzers/017-clbprecyinit/README.md diff --git a/fuzzers/018-clbram/README.txt b/fuzzers/018-clbram/README.md similarity index 100% rename from fuzzers/018-clbram/README.txt rename to fuzzers/018-clbram/README.md diff --git a/fuzzers/019-ndi1mux/Makefile b/fuzzers/019-ndi1mux/Makefile index 1a7faa6e..5e13cafb 100644 --- a/fuzzers/019-ndi1mux/Makefile +++ b/fuzzers/019-ndi1mux/Makefile @@ -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 diff --git a/fuzzers/019-ndi1mux/README.txt b/fuzzers/019-ndi1mux/README.md similarity index 100% rename from fuzzers/019-ndi1mux/README.txt rename to fuzzers/019-ndi1mux/README.md diff --git a/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h b/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h index ae0634d7..806cc9a2 100644 --- a/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h +++ b/lib/include/prjxray/xilinx/xc7series/bitstream_writer.h @@ -23,7 +23,7 @@ namespace xc7series { class BitstreamWriter { public: typedef std::array header_t; - typedef std::vector packets_t; + typedef std::vector> packets_t; // Only defined if a packet exists typedef absl::optional> op_data_t; typedef absl::Span::iterator data_iterator_t; diff --git a/lib/include/prjxray/xilinx/xc7series/command.h b/lib/include/prjxray/xilinx/xc7series/command.h new file mode 100644 index 00000000..2ff16e86 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/command.h @@ -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_ diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h b/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h new file mode 100644 index 00000000..1b7c1c13 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/configuration_options_0_value.h @@ -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 +#include +#include + +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(source)); + return *this; + } + + ConfigurationOptions0Value& SetReleaseDonePinAtStartupCycle( + SignalReleaseCycle cycle) { + value_ = + bit_field_set(value_, 14, 12, static_cast(cycle)); + return *this; + } + + ConfigurationOptions0Value& SetStallAtStartupCycleUntilDciMatch( + StallCycle cycle) { + value_ = + bit_field_set(value_, 11, 9, static_cast(cycle)); + return *this; + }; + + ConfigurationOptions0Value& SetStallAtStartupCycleUntilMmcmLock( + StallCycle cycle) { + value_ = + bit_field_set(value_, 8, 6, static_cast(cycle)); + return *this; + }; + + ConfigurationOptions0Value& SetReleaseGtsSignalAtStartupCycle( + SignalReleaseCycle cycle) { + value_ = + bit_field_set(value_, 5, 3, static_cast(cycle)); + return *this; + } + + ConfigurationOptions0Value& SetReleaseGweSignalAtStartupCycle( + SignalReleaseCycle cycle) { + value_ = + bit_field_set(value_, 2, 0, static_cast(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 diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_packet_with_payload.h b/lib/include/prjxray/xilinx/xc7series/configuration_packet_with_payload.h new file mode 100644 index 00000000..bdcdc3c3 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/configuration_packet_with_payload.h @@ -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 + +#include +#include +#include +#include + +namespace prjxray { +namespace xilinx { +namespace xc7series { + +template +class ConfigurationPacketWithPayload : public ConfigurationPacket { + public: + ConfigurationPacketWithPayload( + Opcode op, + ConfigurationRegister reg, + const std::array& payload) + : ConfigurationPacket(1, op, reg, absl::Span(payload_)), + payload_(std::move(payload)) {} + + private: + std::array payload_; +}; // namespace xc7series + +} // namespace xc7series +} // namespace xilinx +} // namespace prjxray + +#endif // PRJXRAY_LIB_XILINX_XC7SERIES_g_CONFIGURATION_PACKET_WITH_PAYLOAD_H diff --git a/lib/include/prjxray/xilinx/xc7series/configuration_register.h b/lib/include/prjxray/xilinx/xc7series/configuration_register.h index 9f75a090..4fbc5d4c 100644 --- a/lib/include/prjxray/xilinx/xc7series/configuration_register.h +++ b/lib/include/prjxray/xilinx/xc7series/configuration_register.h @@ -25,6 +25,7 @@ enum class ConfigurationRegister : unsigned int { COR1 = 0x0e, WBSTAR = 0x10, TIMER = 0x11, + UNKNOWN = 0x13, BOOTSTS = 0x16, CTL1 = 0x18, BSPI = 0x1F, diff --git a/lib/include/prjxray/xilinx/xc7series/nop_packet.h b/lib/include/prjxray/xilinx/xc7series/nop_packet.h new file mode 100644 index 00000000..65339883 --- /dev/null +++ b/lib/include/prjxray/xilinx/xc7series/nop_packet.h @@ -0,0 +1,24 @@ +#ifndef PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H +#define PRJXRAY_LIB_XILINX_XC7SERIES_NOP_PACKET_H + +#include +#include + +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 diff --git a/lib/xilinx/xc7series/bitstream_writer.cc b/lib/xilinx/xc7series/bitstream_writer.cc index 3a7da30d..eb388ca5 100644 --- a/lib/xilinx/xc7series/bitstream_writer.cc +++ b/lib/xilinx/xc7series/bitstream_writer.cc @@ -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()); diff --git a/lib/xilinx/xc7series/bitstream_writer_test.cc b/lib/xilinx/xc7series/bitstream_writer_test.cc index 752fa4c9..be2d41ec 100644 --- a/lib/xilinx/xc7series/bitstream_writer_test.cc +++ b/lib/xilinx/xc7series/bitstream_writer_test.cc @@ -50,7 +50,8 @@ void dump_packets(xc7series::BitstreamWriter writer, bool nl = true) { } // Special all 0's -void AddType0(std::vector& packets) { +void AddType0( + std::vector>& packets) { // InitWithWords doesn't like type 0 /* static std::vector words{0x00000000}; @@ -61,27 +62,32 @@ void AddType0(std::vector& packets) { static std::vector words{}; absl::Span 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& packets) { +void AddType1( + std::vector>& packets) { static std::vector words{MakeType1(0x2, 0x3, 2), 0xAA, 0xBB}; absl::Span 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& packets) { +void AddType1E( + std::vector>& packets) { static std::vector words{MakeType1(0x2, 0x3, 0)}; absl::Span 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& packets) { +void AddType2( + std::vector>& 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& packets) { absl::Span 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& packets) { absl::Span 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 packets; + std::vector> packets; xc7series::BitstreamWriter writer(packets); std::vector words(writer.begin(), writer.end()); @@ -120,7 +128,7 @@ TEST(BitstreamWriterTest, WriteHeader) { } TEST(BitstreamWriterTest, WriteType0) { - std::vector packets; + std::vector> 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 packets; + std::vector> packets; AddType1(packets); xc7series::BitstreamWriter writer(packets); // dump_packets(writer, false); @@ -147,7 +155,7 @@ TEST(BitstreamWriterTest, WriteType1) { } TEST(BitstreamWriterTest, WriteType2) { - std::vector packets; + std::vector> packets; AddType2(packets); xc7series::BitstreamWriter writer(packets); // dump_packets(writer, false); @@ -164,7 +172,7 @@ TEST(BitstreamWriterTest, WriteType2) { } TEST(BitstreamWriterTest, WriteMulti) { - std::vector packets; + std::vector> packets; AddType1(packets); AddType1E(packets); AddType2(packets); diff --git a/minitests/bram/README.txt b/minitests/bram/README.md similarity index 100% rename from minitests/bram/README.txt rename to minitests/bram/README.md diff --git a/minitests/clb_bused/README.txt b/minitests/clb_bused/README.md similarity index 100% rename from minitests/clb_bused/README.txt rename to minitests/clb_bused/README.md diff --git a/minitests/clb_ffcfg/README.txt b/minitests/clb_ffcfg/README.md similarity index 100% rename from minitests/clb_ffcfg/README.txt rename to minitests/clb_ffcfg/README.md diff --git a/minitests/clb_muxf8/README.txt b/minitests/clb_muxf8/README.md similarity index 100% rename from minitests/clb_muxf8/README.txt rename to minitests/clb_muxf8/README.md diff --git a/minitests/clb_n5ffmux/README.txt b/minitests/clb_n5ffmux/README.md similarity index 100% rename from minitests/clb_n5ffmux/README.txt rename to minitests/clb_n5ffmux/README.md diff --git a/minitests/clb_ncy0/README.txt b/minitests/clb_ncy0/README.md similarity index 100% rename from minitests/clb_ncy0/README.txt rename to minitests/clb_ncy0/README.md diff --git a/minitests/clb_ndi1mux/README.txt b/minitests/clb_ndi1mux/README.md similarity index 100% rename from minitests/clb_ndi1mux/README.txt rename to minitests/clb_ndi1mux/README.md diff --git a/minitests/clb_nffmux/README.txt b/minitests/clb_nffmux/README.md similarity index 100% rename from minitests/clb_nffmux/README.txt rename to minitests/clb_nffmux/README.md diff --git a/minitests/clb_noutmux/README.txt b/minitests/clb_noutmux/README.md similarity index 100% rename from minitests/clb_noutmux/README.txt rename to minitests/clb_noutmux/README.md diff --git a/minitests/clb_ram/README.txt b/minitests/clb_ram/README.md similarity index 100% rename from minitests/clb_ram/README.txt rename to minitests/clb_ram/README.md diff --git a/minitests/fixedpnr/README.txt b/minitests/fixedpnr/README.md similarity index 100% rename from minitests/fixedpnr/README.txt rename to minitests/fixedpnr/README.md diff --git a/minitests/partial_reconfig_flow/Makefile b/minitests/partial_reconfig_flow/Makefile index f451f815..239cac4f 100644 --- a/minitests/partial_reconfig_flow/Makefile +++ b/minitests/partial_reconfig_flow/Makefile @@ -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. diff --git a/minitests/picorv32-v/README.txt b/minitests/picorv32-v/README.md similarity index 100% rename from minitests/picorv32-v/README.txt rename to minitests/picorv32-v/README.md diff --git a/minitests/picorv32-y/README.txt b/minitests/picorv32-y/README.md similarity index 100% rename from minitests/picorv32-y/README.txt rename to minitests/picorv32-y/README.md diff --git a/minitests/roi_harness/README.txt b/minitests/roi_harness/README.md similarity index 100% rename from minitests/roi_harness/README.txt rename to minitests/roi_harness/README.md diff --git a/minitests/roi_harness/fasm2bit.sh b/minitests/roi_harness/fasm2bit.sh index 3e7798c9..5beb90f5 100755 --- a/minitests/roi_harness/fasm2bit.sh +++ b/minitests/roi_harness/fasm2bit.sh @@ -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" diff --git a/requirements.txt b/requirements.txt index 612ba388..f16b1bd9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,5 @@ -yapf futures +sphinx +sphinx_rtd_theme +sphinx-autobuild +yapf diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 06dc18c0..85023a91 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -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 ) diff --git a/tools/xc7patch.cc b/tools/xc7patch.cc index 3e0c549f..9ea3962d 100644 --- a/tools/xc7patch.cc +++ b/tools/xc7patch.cc @@ -5,14 +5,23 @@ #include #include +#include #include +#include +#include #include #include #include #include +#include #include +#include +#include +#include +#include #include +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(frame.first) << " "; - - for (auto& word : frame.second) { - std::cout << "0x" << std::hex << word << ","; - } - - std::cout << std::endl; - } -#endif - std::vector out_packets; + std::vector> + out_packets; // Generate a single type 2 packet that writes everything at once. std::vector 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(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(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(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(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(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(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(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(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(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(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 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((build_source.size() + 1) >> 8)); + bit_header.push_back(static_cast(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((FLAGS_part_name.size() + 1) >> 8)); + bit_header.push_back(static_cast(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((build_date_string.size() + 1) >> 8)); + bit_header.push_back( + static_cast(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((build_time_string.size() + 1) >> 8)); + bit_header.push_back( + static_cast(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(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(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; }