diff --git a/docs/.gitattributes b/docs/.gitattributes new file mode 100644 index 0000000..60b4186 --- /dev/null +++ b/docs/.gitattributes @@ -0,0 +1,3 @@ +*.png binary +*.gif binary +*.jpg binary diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..e35d885 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_build diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help 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/building-examples.rst b/docs/building-examples.rst new file mode 100644 index 0000000..835865e --- /dev/null +++ b/docs/building-examples.rst @@ -0,0 +1,82 @@ +Building example designs +======================== + +Before building any example, set the installation directory to match what you +set it to earlier, for example: + +.. code-block:: bash + :name: export-install-dir + + export INSTALL_DIR=~/opt/symbiflow + +Select your fpga family: + +.. tabs:: + + .. group-tab:: Artix-7 + + .. code-block:: bash + :name: fpga-fam-xc7 + + FPGA_FAM="xc7" + + .. group-tab:: EOS S3 + + .. code-block:: bash + :name: fpga-fam-eos-s3 + + FPGA_FAM="eos-s3" + +Next, prepare the enviroment: + +.. code-block:: bash + :name: conda-prep-env + + export PATH="$INSTALL_DIR/$FPGA_FAM/install/bin:$PATH"; + source "$INSTALL_DIR/$FPGA_FAM/conda/etc/profile.d/conda.sh" + +Finally, enter your working Conda enviroment: + +.. code-block:: bash + :name: conda-act-env + + conda activate $FPGA_FAM + +.. note:: + + If you don't know how to upload any of the following examples onto your + development board, please refer to the Running examples section. + + +Xilinx 7-Series +--------------- + +Enter the directory that contains examples for Xilinx 7-Series FPGAs: + +.. code-block:: bash + :name: enter-dir-xc7 + + cd xc7 + +.. jinja:: xc7_counter_test + :file: templates/example.jinja + +.. jinja:: xc7_picosoc_demo + :file: templates/example.jinja + +.. jinja:: xc7_linux_litex_demo + :file: templates/example.jinja + + +QuickLogic EOS S3 +----------------- + +Enter the directory that contains examples for QuickLogic EOS S3: + +.. code-block:: bash + :name: enter-dir-eos-s3 + + cd eos-s3 + +.. jinja:: eos-s3_btn_counter + :file: templates/example.jinja diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..6ef6e5a --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,247 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# 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('.')) + + +# -- Project information ----------------------------------------------------- + +project = u'SymbiFlow examples' +authors = u'SymbiFlow' +copyright = authors + u', 2020' + +# -- General configuration --------------------------------------------------- + +# 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_tabs.tabs', + 'sphinxcontrib.jinja', +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# + +html_show_sourcelink = True +html_sidebars = { + "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] +} + +html_theme = 'sphinx_material' +html_theme_options = { + 'nav_title': project, + 'color_primary': 'deep-purple', + 'color_accent': 'purple', + 'repo_name': "antmicro/symbiflow-examples", + 'repo_url': 'https://github.com/antmicro/symbiflow-examples', + 'globaltoc_depth': 2, + 'globaltoc_collapse': True +} + +# 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'] + +import os +from docutils.core import publish_doctree + + +full_name_lut = { + 'a35t': 'Arty 35T', + 'a100t': 'Arty 100T', + 'basys3': 'Basys 3', + 'eos_s3': 'EOS S3', +} +families = ('xc7', 'eos-s3') + + +def handle_default_with_literals(block): + text = "" + + for node in block.traverse(include_self=False, condition=lambda x: + x.parent.tagname.strip() != 'literal'): + tagname = node.tagname.strip() + if tagname in ('paragraph',): + continue + + if tagname == 'literal': + text = text + '``' + node.astext() + '``' + else: + text = text + node.astext() + + ret = {} + ret['type'] = block.tagname.strip() + ret['text'] = text + + return ret + + +def subtree_has_tag(block, tagname): + for node in block.traverse(include_self=False): + if node.tagname.strip() == tagname: + return True + + return False + + +def handle_title(block): + ret = { + 'type': 'title', + 'text': '\n'.join((block.astext(), '~' * 20)), + } + + return ret + + +def handle_img(block): + ret = {} + ret['type'] = 'image' + ret['uri'] = os.path.join(*block['uri'].split('/')[3:]) + ret['align'] = block.get('align', 'center') + ret['width'] = block.get('width', '100%') + + return ret + + +def handle_literal_block(block): + ret = {} + ret['type'] = 'literal_block' + ret['text'] = block.astext().split('\n') + ret['classes'] = block['classes'] + + try: + ret['name'] = full_name_lut[''.join(block['names']).split('-')[2]] + except: + ret['name'] = '' + + return ret + + +def handle_note(block): + ret = {} + ret['type'] = block.tagname.strip() + + if subtree_has_tag(block, 'literal'): + for node in block.traverse(condition=lambda x: + x.tagname.strip() == 'paragraph'): + ret['text'] = handle_default_with_literals(node)['text'] + else: + ret['text'] = block.astext() + + ret['text'] = ret['text'].split('\n') + + return ret + + +def handle_default(block): + if subtree_has_tag(block, 'literal'): + return handle_default_with_literals(block) + + ret = {} + ret['type'] = block.tagname.strip() + ret['text'] = block.astext() + + return ret + + +handle_block_funcs = { + 'title': handle_title, + 'image': handle_img, + 'literal_block': handle_literal_block, + 'note': handle_note, + 'default': handle_default, +} + + +def get_blocks(text): + doctree = publish_doctree(text) + + return doctree.traverse(condition=lambda x: x.tagname.strip() != 'document' + and x.parent.tagname.strip() != 'note') + + +def fill_context(text): + ret = [] + + start_group = False + in_group = False + for block in get_blocks(text): + tagname = block.tagname.strip() + + # do not process those + if tagname in ('#text', 'inline', 'literal'): + continue + + # try do get handler; if not found, use the default one + if tagname not in handle_block_funcs.keys(): + handler = 'default' + else: + handler = tagname + + entry = handle_block_funcs[handler](block) + + # internal logic for grouping code blocks into tab groups + if tagname == 'literal_block' and 'group' in ''.join(block['names']): + if not in_group: + start_group = True + in_group = True + else: + start_group = False + in_group = True + else: + in_group = False + start_group = False + + entry['start_group'] = start_group + entry['in_group'] = in_group + + ret.append(entry) + + return ret + + +# register examples +jinja_contexts = {} +top_dir = os.path.join(os.path.dirname(__file__), '..') +for family in families: + examples = os.scandir(os.path.join(top_dir, family)) + for example in examples: + if example.is_dir(): + + # get README + path = os.path.join(top_dir, family, example, 'README.rst') + + # skip if file does not exist + if not os.path.isfile(path): + continue + + with open(path) as f: + text = f.read() + + key = '_'.join((family, example.name)) + jinja_contexts[key] = {'blocks': fill_context(text)} diff --git a/docs/getting-symbiflow.rst b/docs/getting-symbiflow.rst new file mode 100644 index 0000000..bd5b118 --- /dev/null +++ b/docs/getting-symbiflow.rst @@ -0,0 +1,137 @@ +Getting SymbiFlow +================= + +This section describe how to install SymbiFlow and setup a fully working +enviroment to later build example desings. + +Prerequisites +------------- + +To be able to follow through this tutorial, install the following software: + +.. tabs:: + + .. group-tab:: Ubuntu + + .. code-block:: bash + :name: install-reqs-ubuntu + + apt install -y git wget picocom + + .. group-tab:: CentOS + + .. code-block:: bash + :name: install-reqs-centos + + yum install -y git wget picocom + + .. group-tab:: Arch + + .. code-block:: bash + :name: install-reqs-arch + + pacman -Sy git wget picocom + +Next, clone the SymbiFlow examples repository and enter it: + +.. code-block:: bash + :name: get-symbiflow + + git clone https://github.com/SymbiFlow/symbiflow-examples + cd symbiflow-examples + +Toolchain installation +---------------------- + +Now we are able to install the SymbiFlow toolchain. This procedure is divided +into three steps: + +- installing the Conda package manager, +- choosing an installation directory, +- downloading the architecture definitions and installing the toolchain. + +Conda +~~~~~ + +Download Conda installer script: + +.. code-block:: bash + :name: wget-conda + + wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O conda_installer.sh + +Choose the install directory +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The install directory can either be in your home directory +such as ``~/opt/symbiflow`` or in a system directory such as ``/opt/symbiflow``. +If you choose a system directory, you will need root permission to perform the installation, +and so you will need to add some ``sudo`` commands to the instructions below. + +.. code-block:: bash + :name: conda-install-dir + + export INSTALL_DIR=~/opt/symbiflow + +Toolchain +~~~~~~~~~ + +Select your target FPGA family: + +.. tabs:: + + .. group-tab:: Artix-7 + + .. code-block:: bash + :name: fpga-fam-xc7 + + export FPGA_FAM=xc7 + + .. group-tab:: EOS S3 + + .. code-block:: bash + :name: fpga-fam-eos-s3 + + export FPGA_FAM=eos-s3 + +Next, setup Conda and your system's enviroment: + +.. code-block:: bash + :name: conda-setup + + bash conda_installer.sh -u -b -p $INSTALL_DIR/$FPGA_FAM/conda; + source "$INSTALL_DIR/$FPGA_FAM/conda/etc/profile.d/conda.sh"; + conda env create -f $FPGA_FAM/environment.yml + +Download architecture definitions: + +.. tabs:: + + .. group-tab:: Artix-7 + + .. code-block:: bash + :name: download-arch-def-xc7 + + mkdir -p $INSTALL_DIR/xc7/install; + wget -qO- https://storage.googleapis.com/symbiflow-arch-defs/artifacts/prod/foss-fpga-tools/symbiflow-arch-defs/presubmit/install/1049/20201123-030526/symbiflow-arch-defs-install-05bd35c7.tar.xz | tar -xJC $INSTALL_DIR/xc7/install; + mkdir -p $INSTALL_DIR/xc7/install/share/symbiflow/arch; + wget -qO- https://storage.googleapis.com/symbiflow-arch-defs/artifacts/prod/foss-fpga-tools/symbiflow-arch-defs/presubmit/install/1049/20201123-030526/symbiflow-xc7a50t_test.tar.xz | tar -xJC $INSTALL_DIR/xc7/install/share/symbiflow/arch; + wget -qO- https://storage.googleapis.com/symbiflow-arch-defs/artifacts/prod/foss-fpga-tools/symbiflow-arch-defs/presubmit/install/1049/20201123-030526/symbiflow-xc7a100t_test.tar.xz | tar -xJC $INSTALL_DIR/xc7/install/share/symbiflow/arch + + .. group-tab:: EOS-S3 + + .. code-block:: bash + :name: download-arch-def-eos-s3 + + wget -qO- https://quicklogic-my.sharepoint.com/:u:/p/kkumar/EWuqtXJmalROpI2L5XeewMIBRYVCY8H4yc10nlli-Xq79g?download=1 | tar -xJ -C $INSTALL_DIR/eos-s3/ + +If the above commands exited without errors, you have successfuly installed and configured your working enviroment. + +Build Example Designs +--------------------- + +With the toolchain installed, you can build the example designs. +The example designs are provided in separate directories: + +* ``xc7`` directory for the Artix-7 devices +* ``eos-s3`` directory for the EOS S3 devices diff --git a/docs/images/arty-usb-ethernet.png b/docs/images/arty-usb-ethernet.png new file mode 100644 index 0000000..a84457f Binary files /dev/null and b/docs/images/arty-usb-ethernet.png differ diff --git a/docs/images/arty.png b/docs/images/arty.png new file mode 100644 index 0000000..13a065d Binary files /dev/null and b/docs/images/arty.png differ diff --git a/docs/images/basys3-usb.png b/docs/images/basys3-usb.png new file mode 100644 index 0000000..83ef637 Binary files /dev/null and b/docs/images/basys3-usb.png differ diff --git a/docs/images/basys3.png b/docs/images/basys3.png new file mode 100644 index 0000000..2f18d71 Binary files /dev/null and b/docs/images/basys3.png differ diff --git a/docs/images/counter-example-arty.gif b/docs/images/counter-example-arty.gif new file mode 100644 index 0000000..3a61ef5 Binary files /dev/null and b/docs/images/counter-example-arty.gif differ diff --git a/docs/images/counter-example-basys3.gif b/docs/images/counter-example-basys3.gif new file mode 100644 index 0000000..22edbbc Binary files /dev/null and b/docs/images/counter-example-basys3.gif differ diff --git a/docs/images/ethernet-cable.png b/docs/images/ethernet-cable.png new file mode 100644 index 0000000..cde9633 Binary files /dev/null and b/docs/images/ethernet-cable.png differ diff --git a/docs/images/linux-example-arty.jpg b/docs/images/linux-example-arty.jpg new file mode 100644 index 0000000..09c48f6 Binary files /dev/null and b/docs/images/linux-example-arty.jpg differ diff --git a/docs/images/linux-example-console.gif b/docs/images/linux-example-console.gif new file mode 100644 index 0000000..d5ad96a Binary files /dev/null and b/docs/images/linux-example-console.gif differ diff --git a/docs/images/picosoc-example-basys3.gif b/docs/images/picosoc-example-basys3.gif new file mode 100644 index 0000000..c2b05ce Binary files /dev/null and b/docs/images/picosoc-example-basys3.gif differ diff --git a/docs/images/tftp-server-status.png b/docs/images/tftp-server-status.png new file mode 100644 index 0000000..fea9a11 Binary files /dev/null and b/docs/images/tftp-server-status.png differ diff --git a/docs/images/usb-a-to-micro-b-cable.png b/docs/images/usb-a-to-micro-b-cable.png new file mode 100644 index 0000000..457c537 Binary files /dev/null and b/docs/images/usb-a-to-micro-b-cable.png differ diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..2b55698 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,30 @@ +Welcome to SymbiFlow examples! +============================== + +This guide explains how to get started with SymbiFlow and build example designs from the `SymbiFlow Examples `_ GitHub repository. It currently focuses on two FPGA families: + +- Artix-7 from Xilinx, +- EOS S3 from QuickLogic. + +Follow this guide to: + +- :doc:`install SymbiFlow ` and all of its dependencies, +- :doc:`build ` and :doc:`upload ` example designs onto the devboard of your choice. + +About SymbiFlow +--------------- + +SymbiFlow is a fully open source toolchain for the development of FPGAs, currently targeting chips from multiple vendors, e.g.: + +- Xilinx 7-Series +- Lattice iCE40 +- Lattice ECP5 FPGAs +- QuickLogic EOS S3 + +.. toctree:: + :maxdepth: 2 + :caption: Sections + + getting-symbiflow + building-examples + running-examples diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..ec187b5 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,4 @@ +Sphinx==3.3.0 +sphinx-material==0.0.32 +sphinx-tabs==1.3.0 +sphinx-jinja==1.1.1 diff --git a/docs/running-examples.rst b/docs/running-examples.rst new file mode 100644 index 0000000..e7522a8 --- /dev/null +++ b/docs/running-examples.rst @@ -0,0 +1,123 @@ +Running example designs +======================== + +This section desribes how to properly connect your board. +It also helps you configure and run any other software that is necessary to observe results. + +Connecting development boards +----------------------------- + +Arty board +~~~~~~~~~~ + +#. Connect the board to your computer using the USB cable: +#. Connect the board to your computer using the Ethernet cable + (only if you want to test the LiteX Linux Example) + +.. image:: images/arty-usb-ethernet.png + :width: 49% + :align: center + +Basys 3 board +~~~~~~~~~~~~~ + +Connect the Basys3 Board to your computer using the USB cable: + +.. image:: images/basys3-usb.png + :width: 49% + :align: center + +Connecting to UART +------------------ + +First check available teletypes with: + +.. code-block:: bash + + ls -l /dev | grep ttyUSB + +You should see at least one, e.g.: + +.. code-block:: bash + + crw-rw----+ 1 root plugdev 188, 0 11-06 13:58 ttyUSB0 + crw-rw----+ 1 root plugdev 188, 1 11-06 13:58 ttyUSB1 + +Simply use ``picocom`` to connect: + +.. code-block:: bash + + picocom -b 115200 --imap lfcrlf /dev/ttyUSB1 + +.. warning:: + + Substitute ``115200`` with the baud rate that your design uses! + +.. warning:: + + Please note that ``/dev/ttyUSB1`` is just an example. The number appearing may change! + +.. note:: + + If the picocom is unable to connect to any ``ttyUSBx`` device, you probably don't have appropriate user permissions. + On Debian distributions, type the command below to add the user to the ``dialout`` group. + This should resolve the missing permissions problem: + + .. code-block:: bash + + sudo usermod -a -G dialout `whoami` + +Setting up TFTP +--------------- + +It is assumed that the server is running on port ``6069`` and uses ``/tftp`` directory. + +#. Install tftp with (Ubuntu example): + + .. code-block:: bash + + sudo apt install tftpd-hpa + +#. Create a directory for the server: + + .. code-block:: bash + + sudo mkdir -p /tftp + sudo chmod 777 -R /tftp + sudo chown tftp -R /tftp + +#. Set up your TFTP configuration with: + + .. code-block:: bash + + cat << EOF | sudo tee /etc/default/tftpd-hpa + TFTP_USERNAME="tftp" + TFTP_DIRECTORY="/tftp" + TFTP_ADDRESS=":6069" + TFTP_OPTIONS="--secure" + EOF + +#. Restart the TFTP server: + + .. code-block:: bash + + sudo systemctl restart tftpd-hpa + +Configuring your network interfaces +----------------------------------- + +Check your network interfaces with: + +.. code-block:: + + ip link + +Add IPv4 address to you interface: + +.. code-block:: bash + + ip addr add 192.168.100.100/24 dev eth0 + +.. warning:: + + ``192.169.100.100/24`` and ``eth0`` are just examples! diff --git a/docs/templates/example.jinja b/docs/templates/example.jinja new file mode 100644 index 0000000..d9ee657 --- /dev/null +++ b/docs/templates/example.jinja @@ -0,0 +1,51 @@ +{% for block in blocks -%} + +{% if block.type == 'literal_block' %} + +{% if not block.start_group and not block.in_group %} +.. code-block:: {% if 'bash' in block.classes %}bash{% endif %} + + {% for line in block.text -%} + {{ line }} + {% endfor %} + +{% elif block.start_group %} +.. tabs:: + + .. group-tab:: {{ block.name }} + + .. code-block:: bash + + {% for line in block.text -%} + {{ line }} + {% endfor %} +{% elif block.in_group %} + .. group-tab:: {{ block.name }} + + .. code-block:: bash + + {% for line in block.text -%} + {{ line }} + {% endfor %} + +{% endif %} + +{% elif block.type == 'image' %} +.. image:: {{ block.uri }} + :align: {{ block.align }} + :width: {{ block.width }} + +{% elif block.type == 'note' %} +.. note:: + + {% for line in block.text -%} + {{ line }} + {% endfor %} + + +{% else %} +{{ block.text }} + +{% endif %} + +{% endfor %}