diff --git a/doc/containers/building-syfala-containers.md b/doc/containers/building-syfala-containers.md deleted file mode 100644 index 180c101..0000000 --- a/doc/containers/building-syfala-containers.md +++ /dev/null @@ -1,66 +0,0 @@ -# Building Xilinx containers - -### Installing buildah - -- Archlinux: `yay -S buildah` -- Ubuntu: `sudo apt install buildah` - -If shell shows these kind of errors: - -```shell -WARN[0000] Reading allowed ID mappings: reading subuid mappings for user "user" and subgid mappings for group "user": no subuid ranges found for user "user" in /etc/subuid -WARN[0000] Found no UID ranges set aside for user "user" in /etc/subuid. -WARN[0000] Found no GID ranges set aside for user "user" in /etc/subgid. -``` - -do this: - -```shell -$ sudo echo "user:10000:65536" >> /etc/subuid -$ sudo echo "user:10000:65536" >> /etc/subgid -``` - -### Building image & container - -```shell - $ cd xilinx-ubuntu1804 - $ buildah build -f Containerfile -t xilinx-ubuntu1804 - $ buildah from --name xilinx-ubuntu1804-container xilinx-ubuntu1804 -``` - -### Running container to install the Xilinx toolchain - -```bash -$ xhost +local: -$ buildah run --user=syfala --network=host --env DISPLAY=$DISPLAY -v /path/to/Xilinx/installer:/home/syfala -v /tmp/.X11-unix:/tmp/.X11-unix:z -v /dev/dri:/dev/dri:z xilinx-ubuntu1804-container bash -``` - -Once inside the container: - -```shell -# sudo password is 'syfala' -$ xhost + -$ sudo chmod a+x /Xilinx/Xilinx_Unified_2022.2_1014_8888_Lin64.bin -$ ./Xilinx/Xilinx_Unified_2022.2_1014_8888_Lin64.bin -``` - -The installer window should now appear, you can proceed with the installation. - -### Updating & exporting OCI image - -Once the installation finished: - -```shell -# this may take a while, given the final size of the container -# you need to have more than 100Gb available on your disk as well... -$ buildah commit xilinx-ubuntu1804-container xilinx-ubuntu1804:2022-2 -# export image in oci format -$ buildah push --format oci xilinx-ubuntu1804:2022-2 oci:/your/path/xilinx-ubuntu1804-2022-2-oci -``` - -### Exporting .tar file of image - -```shell -$ podman save -o x2022-ubuntu1804.tar localhost/ubuntu1804:2022-2 -``` - diff --git a/doc/containers/using-syfala-containers.md b/doc/containers/using-syfala-containers.md deleted file mode 100644 index 029484b..0000000 --- a/doc/containers/using-syfala-containers.md +++ /dev/null @@ -1,65 +0,0 @@ -# Using syfala containers (with podman) - -### Installing podman - -- Archlinux: `yay -S podman` -- Ubuntu: `sudo apt install podman` -- macOS: `brew install podman` - -If shell shows these kind of errors: - -```shell -WARN[0000] Reading allowed ID mappings: reading subuid mappings for user "user" and subgid mappings for group "user": no subuid ranges found for user "user" in /etc/subuid -WARN[0000] Found no UID ranges set aside for user "user" in /etc/subuid. -WARN[0000] Found no GID ranges set aside for user "user" in /etc/subgid. -``` - -do this (replace `user` by your username): - -```shell -$ sudo echo "user:10000:65536" >> /etc/subuid -$ sudo echo "user:10000:65536" >> /etc/subgid -``` - -### Importing image - -The image is a directory with a specific structure, it is named `x2022-ubuntu1804` in our case. - -```shell -$ cd /path/to/parent/directory/of/image -# import image (make sure you have 125+gb of space left on your machine) -$ podman load -i my-container-image.tar -``` - -### Running container - -```shell -# first, allow X11 to share displays with local processes -$ xhost +local: -# check the name of your image (eg. localhost/syfala-x2022-debian11): -$ podman images -# spawn your container (this only needs to be done once, with the board's USB plugged in and powered up) -$ podman run -ti --privileged --name=syfala --group-add=keep-groups --network=host --env DISPLAY -v /tmp/.X11-unix -v /dev/dri -v /dev/bus/usb --device /dev/ttyUSB1 my-container-image /bin/bash -# once inside the container, you'll have to run: -$ xhost + -# you can now open vitis_hls, vivado, etc. -``` - -### Respawning container - -```shell -# Once you exit the container, you'll have to re-start it first: -$ podman start syfala -# Then, execute the command that you want: -$ podman exec -ti syfala /bin/bash -``` - -### Committing container to original image, and re-export - -```shell -# If you want to report the changes you made in your container on to the original image: -$ podman commit syfala -# And re-export a .tar image: -$ podman save -o syfala-image.tar my-container-image -``` - diff --git a/doc/dependencies.md b/doc/dependencies.md deleted file mode 100644 index a1dec89..0000000 --- a/doc/dependencies.md +++ /dev/null @@ -1,132 +0,0 @@ -# Syfala toolchain dependencies - -The Syfala toolchain is a compilation toolchain of Faust programs onto AMD-Xilinx FPGA targets. This document explains how to install and run the **version 0.7.1** of the toolchain on a Linux machine. In practice, installing the Syfala toolchain means: - -- Installing the required **linux-packages**, depending on your Linux distribution. -- Installing the **Faust** compiler -- Creating a **AMD-Xilinx account** and downloading/installing the **2022.2 version** (2020.2 is also still supported) of the AMD-Xilinx toolchain (providing softwares such as Vivado, Vitis, Vitis HLS). -- Installing the additional **Vivado Board Files** for Digilent Boards. -- Installing *udev* rules in order to use the JTAG connection. -- Cloning the **Syfala repository**, and running a **simple example** to make sure everything is working properly. - -## Linux targets - -We recommend using **Ubuntu** (>= 18.04 LTS) for installing and using the toolchain, since it is officially supported by AMD-Xilinx. While it is still possible to use other distributions, such as Archlinux, you may encounter unresolved bugs, which won't necessarily appear in our *Troubleshooting* section below. - -### Ubuntu dependencies - -```shell -$ sudo apt-get update -$ sudo apt-get install git libncurses5 libtinfo-dev build-essential default-jre pkg-config g++-multilib gtk+2.0 locales -``` - -### Archlinux dependencies - -```bash -# faust (required) -$ sudo pacman -S faust - -# for xilinx vivado/vitis etc. -$ yay -S ncurses5-compat-libs libxcrypt-compat libpng12 lib32-libpng12 xorg-xlsclients gtk2 -``` - -## Faust - -It is recommended to clone Faust from the official github repository: https://github.com/grame-cncm/faust - -```shell -$ git clone https://github.com/grame-cncm/faust.git -$ cd faust -$ make -$ sudo make install -``` - -## Vivado, Vitis & Vitis HLS (2022.2 version) - -- Open an account on https://www.xilinx.com/registration -- The AMD-Xilinx [download page](https://www.xilinx.com/support/download.html) contains links for downloading the **Vivado Design Suite - HLx Editions - Full Product**. It is available for both Linux and Windows. - - Download the Linux installer `Xilinx_Unified_2022.2_1014_8888_Lin64.bin` - -- Execute `chmod a+x Xilinx_Unified_2022.2_1014_8888_Lin64.bin` - -- Execute `./Xilinx_Unified_2022.2_1014_8888_Lin64.bin` - - - We suggest to use the "**Download Image (Install Separately)**" option. It creates a directory with a **xsetup** file to execute that you can reuse in case of failure during the installation - -- Execute `./xsetup` - - - Choose to install **Vitis** (it will still install **Vivado**, **Vitis**, and **Vitis HLS**). - - It will need **110GB of disk space**: if you uncheck *Ultrascale*, *Ultrascale+*, *Versal ACAP* and *Alveo acceleration platform*, it will use less space and still work. - - **Agree** with everything and choose a directory to install (e.g. ~/Xilinx) - - **Install and wait** (it may take quite a while) - -- **Setup a shell environment variable** allowing to use the tools when necessary (add this to your `~/.bashrc`, `~/.zshrc` or whatever you're currently using, replacing `$XILINX_ROOT_DIR` by the directory you chose to install all the tools) - - - ```shell - export XILINX_ROOT_DIR=$HOME/Xilinx - ``` - -### Installing Cable Drivers on Linux - -- Go to: `$XILINX_ROOT_DIR/Vivado/2022.2/data/xicom/cable_drivers/lin64/install_script/install_drivers` directory -- Run `./install_drivers` -- Run `sudo cp 52-xilinx-digilent-usb.rules /etc/udev/rules.d`, this allows **JTAG** connection through **USB**. - -### Installing Digilent Board Files - -- Download the board files from [github](https://github.com/Digilent/vivado-boards/archive/master.zip?_ga=2.76732885.1953828090.1655988025-1125947215.1655988024): -- Open the folder extracted from the archive and navigate to its `new/board_files` folder. You will be copying all of this folder's subfolders - - For the 2020.2 version, go to `$XILINX_ROOT_DIR/Vivado/2020.2/data/boards/board_files` - - For the 2022.2 version, go to `$XILINX_ROOT_DIR/Vivado/2022.2/data/xhub/boards/XilinxBoardStore/boards/Xilinx` - -- **Copy** all of the folders found in vivado-boards `new/board_files `folder and **paste** them into this folder - -### Installing the 2022 patch (AMD-Xilinx toolchain v2020.2 only) - -Vivado and Vitis tools that use HLS in the background are also affected by this issue. HLS tools set the ip_version in the format YYMMDDHHMM and this value is accessed as a signed integer (32-bit) that causes an overflow and generates the errors below (or something similar). - -- Follow this link: https://support.xilinx.com/s/article/76960?language=en_US - -- Download the file at the bottom of th page and unzip it in `$XILINX_ROOT_DIR` - -- run the following commands: - -- ```shell - $ cd $XILINX_ROOT_DIR - $ export LD_LIBRARY_PATH=$PWD/Vivado/2020.2/tps/lnx64/python-3.8.3/lib/ - $ Vivado/2020.2/tps/lnx64/python-3.8.3/bin/python3 y2k22_patch/patch.py - ``` - -## Cloning the Syfala repository - -To clone and install the latest stable version of the Syfala toolchain, you can use the following commands: - -```shell -$ git clone https://github.com/inria-emeraude/syfala -$ cd syfala -$ ./syfala.tcl install -$ syfala --help -``` - -In order to use the Syfala toolchain to compile your first example, please report to the main [README](https://github.com/inria-emeraude/syfala/blob/main/README.md) file located in the repository's root directory. - -## Troubleshooting - -On **Archlinux**, if you see an error like this one - -``` -/lib/../lib64/crti.o: file not recognized: File format not recognized -``` - -you'll have to rename the `Vivado/2020.2/tps/lnx64/binutils-2.26` (Vitis will then search in the system libraries). - -#### Vitis/Java issues - -On recent systems (or with **Archlinux**), you might have problems compiling the host-side (**ARM**) application. The problem is caused by system libraries requiring newer versions of GCC than the one provided by Vitis. Replacing GCC target in Vitis' path **by system GCC** works: - -```bash -$ cd $XILINX_ROOT_DIR/Vitis/2020.2/lib/lnx64.o/Default -$ mv libstdc++.so.6 libstdc++.so.6.old -$ rm -rf libstdc++.so (symlink) -$ sudo ln -s /usr/lib/libstdc++.so.6 libstdc++.so.6 -``` diff --git a/doc/developer-doc.pdf b/doc/developer-doc.pdf deleted file mode 100644 index ac3a631..0000000 Binary files a/doc/developer-doc.pdf and /dev/null differ diff --git a/doc/reference.md b/doc/reference.md deleted file mode 100644 index c412464..0000000 --- a/doc/reference.md +++ /dev/null @@ -1,178 +0,0 @@ -# Syfala command-line interface reference - -```shell -$ syfala [command-options] - -$ syfala help -$ syfala version -$ syfala tidy -$ syfala clean -$ syfala reset -$ syfala import -$ syfala export -$ syfala report -$ syfala log -$ syfala test -$ syfala flash -$ syfala start-gui -$ syfala open-project - -$ syfala [general-options] - [build-options] - [design-options] - [hls-options] - [arm-options] - [run-step] -# examples: -$ syfala examples/faust/bypass.dsp - --board Z10 - --linux --midi --osc --http - -$ syfala examples/cpp/templates/gain-control-hls.cpp - --board Z20 - --arm-target examples/cpp/gain-control-arm.cpp -``` - -## General options - -| name | description | arguments | -| -------------------- | ------------------------------------------------------------ | ------------------ | -| `-x` `--xilinx-root` | sets `XILINX_ROOT_DIR` for the current build | path | -| `--xversion` | sets `XILINX_VERSION` for the current build | `2020.2|2022.2*` | -| `--board, -b` | Defines the target board: Digilent Zybo Z7-10/20 or Genesys ZU-3EG | `Z10*|Z20|GENESYS` | - -## Commands - -| name | description | arguments | -| -------------- | ------------------------------------------------------------ | ---------------------- | -| `tidy` | removes all temporary files generated by the toolchain | none | -| `clean` | deletes current build directory | none | -| `reset` | deletes current build directory as well as the syfala_log & resets the current toolchain configuration | none | -| `import` | sets previously exported .zip build as the current build | path to the .zip build | -| `export` | exports current build in a .zip file located in the 'export' directory | name of the build | -| `report` | displays HLS or global report | | -| `log` | displays the current build's full log | none | -| `test` | builds & runs all toolchain tests | none | -| `flash` | flashes current build onto target device | none | -| `start-gui` | executes the Faust-generated GUI application | none | -| `open-project` | opens the generated .xpr project with Vivado | | -| `help` | prints list of available commands, options and run-time parameters | none | -| `version` | displays the current script's version | none | - -## Build options - -| name | description | -| --------- | ------------------------------------------------------------ | -| `--linux` | builds the embedded linux if doesn't already exist and exports the build in the root partition (`/home/syfala/mybuild`) | -| `--midi` | adds MIDI control for the Faust GUI and/or the Embedded Linux Control Application | -| `--osc` | adds OSC control for the Faust GUI and/or the Embedded Linux Control Application | -| `--http` | adds HTTP control for the Faust GUI and/or the Embedded Linux Control Application | - -## Design options - -| name | arguments | description | -| --------------- | ---------------------------------------------- | ------------------------------------------------------------ | -| `--multisample` | power of two integer (e.g. 16, 24, 32, *etc.*) | DSP block will compute a block of samples instead of a single one. This may improve overall throughput but will introduce audio i/o latency. | -| `--sigma-delta` | none | Builds the project with a *sigma-delta* dac configuration (*experimental*) | -| `--tdm` | none | Builds the project with *i2s TDM* (*experimental*) | -| `--ethernet` | none | (**linux only**) uses tcp/ip ethernet to convey input/output signals from & to faust | - -## HLS options - -| name | arguments | description | -| ----------------------------- | ----------------------------------------------------- | ------------------------------------------------------------ | -| `--accurate-use` | none | Runs HLS with the impl flow, shows more accurate resources/latency reports, but takes longer to run. | -| `--csim` | path to simulation .cpp file | Runs C simulation for the syfala DSP IP | -| `--csim-iter` | integer (1 to ...) | Sets the number of `syfala` calls during the C simulation | -| `--csim-inputs` | path to directory containing `in0.txt / in1.txt etc.` | Set the directory containing input samples files (as `.txt` files). Each sample should be normalized floating point values going from -1.f to 1.f separated by a white space or a line return. | -| `--mcd` | none | (**faust only**) Max-copy-delay: threshold between copy and ring buffer implementation (default 16). | -| `--unsafe-math-optimizations` | `--umo` | Adds the Vitis HLS `unsafe_math_optimizations` directive to the syfala DSP IP. | -| `--hls-flags` | Tcl string | n/a | - -## ARM options - -| name | arguments | description | -| ------------------- | ---------------------------------- | ------------------------------------------------------------ | -| `--shield` | `adau|motherboard` | Adds support for *ADAU1777*/*ADAU1787* external codecs, or for the *ADAU Motherboard* | -| `--benchmark` | none | (**faust only**) Enables benchmark for the ARM control-loop. | -| `--verbose` | none | n/a | -| `--arm-target` | path to .cpp file | Selects the main (.cpp) source file for the ARM control application. | -| `--controller-type` | `DEMO|PCB1*|PCB2|PCB3|PCB4|TEENSY` | Defines the controller used to drive the controls when SW3 is UP. | -| `--ssm-volume` | `FULL|HEADPHONE*|DEFAULT` | (**Zybo boards only**) `HEADPHONE`: lower volume for headphone use. `DEFAULT`: default value +1dB, the true 0dB (`0b001111001`) decreases the signal a little bit. | -| `--ssm-speed` | `FAST|DEFAULT*` | (**Zybo boards only**) changes **SSM ADC/DAC** sample rate. `DEFAULT`: 48kHz sample rate. **FAST**: 96Khz sample rate | - -## Run steps - -**Note**: the `--all` is not necessary if you wish to run all steps, just run `syfala myfaustdsp.dsp ` - -| `--all` | runs all toolchain compilation steps (from `--sources` to `--gui`) | -| ----------- | ------------------------------------------------------------ | -| `--sources` | uses Faust to generate ip/host cpp files for HLS and Host application compilation | -| `--hls` | runs Vitis HLS on generated ip cpp file | -| `--project` | generates Vivado project | -| `--synth` | synthesizes full Vivado project | -| `--host` | compiles Host application, exports sources and .elf output to `build/sw_export` | -| `--gui` | compiles Faust GUI control application | -| `--flash` | flashes boot files on device at the end of the run | -| `--report` | prints HLS report at the end of the run | -| `--export` | `` exports build to export/ directory at the end of the run | - -## Run parameters - -| parameter | accepted values | description | default value | -| :--------------- | ------------------------------------------ | ------------------------------------------------------------ | ------------- | -| `--memory, -m` | `DDR - STATIC` | (**faust only**) Choose between DDR & static memory layout for faust delay-lines, rd/rwtables. | `DDR` | -| `--sample-rate` | `48000 - 96000 - 192000 - 384000 - 768000` | Changes **sample rate** value (Hz). Only 48kHz and 96kHz is available for **SSM** embeded codec. 192000 (**ADAU1777** and **ADAU1787** only) 384000 (**ADAU1787** only) 768000 (**ADAU1787** only and with `--sample--width 16` only) | `48000` | -| `--sample-width` | `16 - 24 - 32` | Defines **sample bit depth** (16\|24\|32) | `16` | - -## Hardware configuration (Zybo Z7-10/20) - -### Syfala Hardware Controller Board (SW3 UP) - -If you use a Hardware Controller Board, please set the `--controller-type` command-line parameter to the proper value (see below) - -#### Controller-type values description - -- `DEMO`: Popophone demo box -- `PCB1`: Emeraude PCB config 1: 4 knobs, 2 switches, 2 sliders (default) -- `PCB2`: Emeraude PCB config 2: 8 knobs -- `PCB3`: Emeraude PCB config 3: 4 knobs, 4 switches -- `PCB4`: Emeraude PCB config 4: 4 knobs above, 4 switches below -- `TEENSY`: Teensy-based controller. - -You can **swap from hardware to software controller** during DSP execution by changing **SW3**. - -### Switch description - -Default configuration in **bold** - -
-  SW3   SW2    SW1    SW0
-+-----+-----+-------+------+
-| Hard| ADAU| BYPASS| MUTE |
-|     |     |       |      |
-|     |     |       |      |
-| GUI | SSM |USE DSP|UNMUTE|
-+-----+-----+-------+------+
-
-- **SW3**: Controller type select: hardware (Controller board) or software (GUI). -- **SW2**: Audio codec input select (ADAU=external or SSM=onboard). Does not affect output. -- **SW1**: Bypass audio dsp. -- **SW0**: Mute. - -### Status LEDs - -The RGB led indicate the program state: - -* **BLUE**: waiting -* **GREEN**: all good! -* **ORANGE**: warning (bypass or mute enabled) -* **RED**: ERROR! (configuration failed or incompatible), could happen if you select the SSM codec with incompatible sample rate. - -The 4 LEDs above the switches indicate the switches state. If one of them blink, it indicates the source of the warning/error. - -### SD card files (baremetal configuration) - -You can put the program on an SD card (if you want something reproducible and easily launchable, for the demos...). -After a `make` command, you should see a `BOOT.bin` file in SW_export (or you can build it with `make boot_file`). -Put the file on the root of SD card. And don't forget to put JP5 on 'SD' position ! diff --git a/doc/syfala-getting-started-src/Makefile b/doc/syfala-getting-started-src/Makefile deleted file mode 100644 index 764d105..0000000 --- a/doc/syfala-getting-started-src/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -#NAME=user-getting-started-doc -TEXMASTERS=developer-doc.tex user-getting-started-doc.tex -TEXSRC=$(wildcard *.tex) -TARGETS=$(TEXMASTERS:.tex=.pdf) -all: ${TARGETS} - - -%.pdf: %.tex dummy - pdflatex $< - -bib: dummy - bibtex developer-doc - pdflatex developer-doc.tex - pdflatex developer-doc.tex - -dummy: - -tar: dummy - cd ..;tar cvf $(NAME).tar $(NAME)/*.tex $(NAME)/*.bib $(NAME)/*.cls $(NAME)/*.bst $(NAME)/Makefile $(NAME)/fig/*.pdf - -clean: - \rm -f $(TARGETS) *.aux *.blg *.brf *.toc *.log *.out *.bbl - \rm -rf *~ - diff --git a/doc/syfala-getting-started-src/body-install-toolchain.tex b/doc/syfala-getting-started-src/body-install-toolchain.tex deleted file mode 100644 index af5c380..0000000 --- a/doc/syfala-getting-started-src/body-install-toolchain.tex +++ /dev/null @@ -1,526 +0,0 @@ -\section{Installation instruction of syfala v7 toolchain} -\label{annex} -\label{install} -The Syfala toolchain is a compilation toolchain of Faust programs on FPGA. This document explains how to install and run the toolchain v7 (version without petalinux), on a linux\footnote{tested on Ubuntu 18.04 and Ubuntu 20.04 and arch linux} machine. In practice, installing the Syfala tool-chain means: -\begin{itemize} -\item Installing the Faust compiler, see section~\ref{faust-install} below. -\item Creating a Xilinx account and downloading/installing the 2020.2 version of the Xilinx {\tt Vivado} toolchain: {\tt vitis\_hls}, {\tt vivado} and {\tt vitis}. See section~\ref{vitis-install} below. -\item Installing Vivado board files for Digilent boards, see section~\ref{board-file-install} -\item Installing udev rules to use JTAG connection, see section~\ref{board-file-install} -\item Cloning the Syfala directory and running a simple example as explained in Section~\ref{sec-syfala}. -\end{itemize} -Section~\ref{hard} explains the hardware configuration of the Zybo board for Syfala and Section~\ref{bug} list all the important bugs encountered when building Syfala. If you encounter a bug during the installation, please see Section~\ref{bug}. - - -{\bf Ubuntu dependencies:} Syfala dependencies on Linux Ubuntu are the following:\\ -\texttt{sudo apt install libncurses5 libtinfo-dev g++-multilib gtk2.0} - -{\bf Warning:} You need approximately 50GB of disk space to install the tool chain, and a good connection. The installation take several hours. -%If the installer prompts a choice for which version to install, select the {\bf WebPack Edition} - -%% {\bf Warning} all the tools of Vivado come with shell scripts that set up your {\tt \$PATH} to use them. It is quite dangerous to source them in the {\tt .bashrc} file because it provides older version of important utilities (such as {\tt cmake} for instance). We strongly advise you to use a fonction defined in your {\tt .bashrc} file such as the following: -%% ~\\ - -%% \begin{boxedminipage}{\textwidth} -%% \begin{verbatim} -%% function use_vitis -%% { -%% source $myXilinxToolDirectory/Vivado/2020.2/settings64.sh -%% source $myXilinxToolDirectory/Vitis_HLS/2020.2/settings64.sh -%% source $myXilinxToolDirectory/Vitis/2020.2/settings64.sh -%% } -%% \end{verbatim} -%% \end{boxedminipage} - -\section{Installing Faust} -\label{faust-install} -It is recommanded to clone Faust from the github repository: \url{https://github.com/grame-cncm/faust}: -\begin{verbatim} - git clone https://github.com/grame-cncm/faust faust - cd faust - make - sudo make install -\end{verbatim} -If you are using an older version of Syfala, you might need to use older version of Faust (see {\tt version} files in Syfala directory). The procedure is to get the commit number of the version you need here: \url{https://github.com/grame-cncm/faust/releases}. For instance, if you use Syfala v5.4, it requires Faust version 2.31.1 (at least), it commit number is: 32a2e92c955c4e057d424ab69a84801740d37920, then execute: -\begin{verbatim} -cd faust -git checkout 32a2e92c955c4e057d424ab69a84801740d37920 -make -sudo make install -\end{verbatim} - -\section{Installing {\tt Vivado}, {\tt Vitis} and {\tt Vitis\_hls} } -\label{vitis-install} - - -\begin{itemize} -\item - Open an account on https://www.xilinx.com/registration -\item - The Xilinx download page - (https://www.xilinx.com/support/download.html) and browse to the - 2020.2 version. The page contains links for downloading the - ``Xilinx\_Unified\_2020.2\_1118\_1232\_Lin64.bin'' (It is available - for both Linux and Windows but Syfala compiles only on Linux). - - \begin{itemize} - \item - Download the Linux installer - \texttt{Xilinx\_Unified\_2020.2\_1118\_1232\_Lin64.bin} - \end{itemize} -\item - execute - \texttt{chmod\ a+x\ Xilinx\_Unified\_2020.2\_1118\_1232\_Lin64.bin} -\item - execute \texttt{./Xilinx\_Unified\_2020.2\_1118\_1232\_Lin64.bin} - - \begin{itemize} - \item - We suggest to use the ``Download Image (Install Separately)'' - option. It creates a directory with a xsetup file to execute that - you can reuse in case of failure during the installation - \end{itemize} -\item - execute \texttt{./xsetup} - - \begin{itemize} - \item - Choose to install \textbf{Vitis} (it will still install - \textbf{Vivado}, \textbf{Vitis}, and \textbf{Vitis HLS}). - \item - It will need 110GB of disk space: if you uncheck \emph{Versal ACAP} and \emph{Alveo acceleration - platform}, it will use less space and still work. - \item - Agree with everything and choose a directory to install - (e.g.~\textasciitilde/Xilinx) - \item - Install and wait for hours\ldots{} - \end{itemize} -\item - Setup a shell function allowing to use the tools when necessary (add - this to your \texttt{\textasciitilde{}/.bashrc}, - \texttt{\textasciitilde{}/.zshrc} or whatever you're currently using, - replacing \texttt{\$XILINX\_ROOT\_DIR} by the directory you chose to - install all the tools) - - \begin{itemize} - \item -\begin{verbatim} - export XILINX_ROOT_DIR=$HOME/Xilinx -\end{verbatim} - \end{itemize} -\end{itemize} - -Then Install missing Vivado board files for Digilent boards and drivers for linux (explained in Section~\ref{board-file-install} below). - -\knownbug{You HAVE to read sections~\ref{localSetting} (locale setting) and \ref{2k22patch-install} (vivado 2022 bug patch). If you do not, you might end up with unpredictible behaviour of Vivado. -} - - - - -\section{Installing Vivado Board Files and Linux drivers} -\label{board-file-install} - -\subsection{Cable drivers (Linux only)} -\label{sec-udev} -\begin{itemize} -\item - go to:\\ - \texttt{\$XILINX\_ROOT\_DIR/}\\ - \texttt{Vivado/2020.2/data/xicom/cable\_drivers/lin64/install\_script/install\_drivers}\\ - directory -\item - run \texttt{./install\_drivers} -\item - run \texttt{sudo\ cp\ 52-xilinx-digilent-usb.rules\ /etc/udev/rules.d}, this - allows \textbf{JTAG} connection through \textbf{USB}. -\end{itemize} - -\subsection{Vivado Board Files for Digilent Boards} -{\bf Important}: This step is needed to enable vivado to generate code for the Zybo Z10 - -\begin{itemize} -\item - download:\\ -\href{https://github.com/Digilent/vivado-boards/archive/master.zip?\_ga=2.76732885.1953828090.1655988025-1125947215.1655988024}{https://github.com/Digilent/vivado-boards/archive/master.zip} -\item - Open the folder extracted from the archive and navigate to its - \texttt{new/board\_files} folder. You will be copying all of this - folder's subfolders -\item - go to - \texttt{\$XILINX\_ROOT\_DIR/Vivado/2020.2/data/boards/board\_files} -\item - \textbf{Copy} all of the folders found in vivado-boards - \texttt{new/board\_files} folder and \textbf{paste} them into this - folder -\end{itemize} - -% -\subsection{Installing the 2022 -patch}\label{2k22patch-install} - -\begin{itemize} -\item - Follow this link: - \href{https://support.xilinx.com/s/article/76960?language=en_US}{https ://support.xilinx.com/s/article/76960?language=en\_US} -\item - Download the file at the bottom of th page and unzip it in - \texttt{\$XILINX\_ROOT\_DIR} -\item - run \texttt{cd\ \$XILINX\_ROOT\_DIR} -\item - run (in one single command line):\\ - \texttt{export\ LD\_LIBRARY\_PATH=\$PWD/Vivado/ $\backslash$} \\ - \texttt{\ \ \ \ \ \ \ \ 2020.2/tps/lnx64/python-3.8.3/lib/ $\backslash$}\\ - \texttt{\ \ \ \ \ \ \ \ Vivado/2020.2/tps/lnx64/python-3.8.3/bin/python3\ y2k22\_patch/patch.py} -\end{itemize} - - - - -\section{Use Syfala (clone and launch)} -\label{sec-syfala} -The syfala repository is freely accessible (reading only) on github (\url{https://github.com/inria-emeraude/syfala}), you have to have a github account of course to clone it. As mentionned before, there may be several sub-directories with different version of Syfala (i.e. different interface for Faust hardware IP). Here are the step needed to run Syfala (after having following the installation instruction of Sections above): -\begin{itemize} -\item Clone the Syfala github repository. -\item install the {\tt syfala.tcl} script -\item Run the script -\end{itemize} - -\subsection{Clone the Syfala repository} -to clone the version needed and compile a first architecture you can use the following commands:\\ - -\begin{boxedminipage}{\textwidth} - \begin{verbatim} - git clone https://github.com/inria-emeraude/syfala mysyfala - cd mysyfala/ - ./syfala.tcl install - syfala examples/virtualAnalog.dsp -\end{verbatim} -\end{boxedminipage} - -~\\ - -or if you have installed your ssh key on github:\\ - -\begin{boxedminipage}{\textwidth} - \begin{verbatim} - git git@github.com:inria-emeraude/syfala.git mysyfala - cd mysyfala/ - ./syfala.tcl install - syfala examples/virtualAnalog.dsp -\end{verbatim} -\end{boxedminipage} - - -\subsection{Use the {\tt syfala.tcl} script} - -the command: - -\texttt{\$\ ./syfala.tcl\ install} - -will install a -\textbf{symlink} in \textbf{/usr/bin}. After this you'll be able to just -run: - -\texttt{\$\ syfala\ myfaustprogram.dsp} - -You'll also have to \textbf{edit} your shell \textbf{resource} -\textbf{file} (\textasciitilde/.\textbf{bashrc} / -\textasciitilde/.\textbf{zshrc}) and set the following environment -variable: - -\begin{verbatim} -export XILINX_ROOT_DIR=/my/path/to/Xilinx/root/directory -\end{verbatim} - -\texttt{XILINX\_ROOT\_DIR} is the root directory where all of the Xilinx -tools (Vivado, Vitis, Vitis\_HLS) are installed. - - -\subsubsection{Major Syfala commands}\label{quick-start} - -\hypertarget{build-examples}{% -\paragraph{build examples}\label{build-examples}} - -\begin{lstlisting} -$ syfala examples/virtualAnalog.dsp -# -> runs full toolchain on the virtualAnalog.dsp Faust dsp file, which will be ready to be flashed afterwards on a Zybo Z710 board (by default) - -$ syfala examples/virtualAnalog.dsp --board GENESYS --sample-rate 96000 -# -> runs full toolchain for the Genesys board, with a sample-rate of 96000Hz - -$ syfala examples/phasor.dsp --export phasor-build -# -> runs full toolchain on 'phasor.dsp', automatically exporting the build to -# export/phasor-build.zip - -$ syfala examples/fm.dsp --arch --hls --report -# -> only run 'arch' & 'high-level synthesis' (HLS) step on 'fm.dsp', and show the report afterwards. - -$ syfala examples/fm.dsp --board Z20 --arch --hls --export z20-fm-hls-build -# -> only run 'arch' & HLS step on 'fm.dsp' for Zybo Z20 board, and export the build. -\end{lstlisting} - -\subsubsection{Additional Syfala `one-shot' commands} - -\begin{tabular}{|c|p{9cm}|c|} - \toprule - name & description & arguments \\ -\midrule -\texttt{install} & installs this script as a symlink in /usr/bin/ & -none \\ -\texttt{clean} & deletes current build directory & none \\ -\texttt{import} & sets previously exported build as the -current build & .zip target\\ -\texttt{export} & exports current build in a .zip file located in the -`export' directory & build name\\ -\texttt{report} & prints HLS report of the current build & none \\ -\texttt{demo} & fully builds demo based on default example -(virtualAnalog.dsp) & none \\ -\texttt{flash} & flashes current build onto target device & none \\ -\texttt{gui} & executes the Faust-generated gui application & none \\ -\texttt{rebuild-app} & rebuilds the host control application, without -re-synthesizing the whole project & none \\ -\texttt{open-project} & opens the generated .xpr project -with Vivado & none \\ - -\bottomrule -\end{tabular} - -\paragraph{Syfala `one-shot' command examples} - -\begin{verbatim} -$ syfala clean -$ syfala demo -$ syfala export my-current-build -$ syfala rebuild-app -$ syfala flash -\end{verbatim} - -\subsubsection{General Options to Syfala command} - -\begin{tabular}{|c|c|p{8cm}|} - \toprule -option & accepted values & description \\ -\midrule -\texttt{-c\ -\/-compiler} & \texttt{HLS\ -\ VHDL} & chooses between -Vitis HLS and faust2vhdl for DSP IP generation. \\ -\texttt{-\/-reset} & / & resets current build directory before building -(\textbf{careful}! all files from previous build will be lost) \\ -\bottomrule -\end{tabular} - -\subsubsection{Controling Syfala Run steps} - -\textbf{Note}: the \texttt{-\/-all} is not necessary if you wish to run -all steps, just run: - -\texttt{syfala\ myfaustdsp.dsp} - -\begin{tabular}{|c|p{12cm}|} - \toprule -\texttt{-\/-all} & runs all toolchain compilation steps (from -\texttt{-\/-arch} to \texttt{-\/-gui}) \\ -\midrule -\texttt{-\/-arch} & uses Faust to generate ip/host cpp files for HLS and -Host application compilation \\ -\texttt{-\/-hls\ -\/-ip} & runs Vitis HLS on generated ip cpp file \\ -\texttt{-\/-project} & generates Vivado project \\ -\texttt{-\/-synth} & synthesizes full Vivado project \\ -\texttt{-\/-host\ -\/-app} & compiles Host application, exports sources -and .elf output to \texttt{build/sw\_export} \\ -\texttt{-\/-gui} & compiles Faust GUI controller \\ -\texttt{-\/-flash} & flashes boot files on device at the end of the -run \\ -\texttt{-\/-report} & prints HLS report at the end of the run \\ -\texttt{-\/-export} & \texttt{\textless{}id\textgreater{}} exports build -to export/ directory at the end of the run \\ -\bottomrule -\end{tabular} - -\subsubsection{Controlling the architecture build by Syfala} - -\begin{tabular}{|c|c|c|} - \toprule -parameter & accepted values & default value \\ -\midrule -\texttt{-\/-memory,\ -m} & \texttt{DDR\ -\ STATIC} & \texttt{DDR} \\ -\texttt{-\/-board,\ -b} & \texttt{Z10\ -\ Z20\ -\ GENESYS} & -\texttt{Z10} \\ -\texttt{-\/-sample-rate} & -\texttt{48000\ -\ 96000\ -\ 192000\ -\ 384000\ -\ 768000} & -\texttt{48000} \\ -\texttt{-\/-sample-width} & \texttt{16\ -\ 24\ -\ 32} & \texttt{24} \\ -\texttt{-\/-controller-type} & -\texttt{DEMO\ -\ PCB1\ -\ PCB2\ -\ PCB3\ -\ PCB4} & \texttt{PCB1} \\ -\texttt{-\/-ssm-volume} & \texttt{FULL\ -\ HEADPHONE\ -\ DEFAULT} & -\texttt{DEFAULT} \\ -\texttt{-\/-ssm-speed} & \texttt{FAST\ -\ DEFAULT} & \texttt{DEFAULT} \\ -\bottomrule -\end{tabular} -\\ - -Here is the description of these parameters:\\ -\begin{tabular}{|c|p{12cm}|} - \toprule -parameter & description \\ -\midrule -\texttt{-\/-memory,\ -m} & selects if \textbf{external} \textbf{DDR3} is -used. Enable if you use some delay, disable if you do want any memory -access (should not be disabled) \\ -\texttt{-\/-board} & Defines target board. \textbf{Z10} ,\textbf{Z20} -and \textbf{GENESYS} only. If you have a VGA port (rather than 2 HDMI -ports), you have an old Zybo version, which is not supported. \\ -\texttt{-\/-sample-rate} & Changes \textbf{sample rate} value (Hz). Only -48kHz and 96kHz is available for \textbf{SSM} embeded codec. 192000 -(\textbf{ADAU1777} and \textbf{ADAU1787} only) 384000 (\textbf{ADAU1787} -only) 768000 (\textbf{ADAU1787} only and with -\texttt{-\/-sample-\/-width\ 16} only) \\ -\texttt{-\/-sample-width} & Defines \textbf{sample bit depth} -(16\textbar24\textbar32) \\ -\texttt{-\/-controller-type} & Defines the controller used to drive the -controls when \textbf{SW3} is \textbf{UP}. (\textbf{SW3} \textbf{DOWN} -for \textbf{software} control), \textbf{SEE BELOW} for details on each -value \\ -\texttt{-\/-ssm-volume} & Chooses audio codec to use. For now, it only -changes the scale factor. \textbf{FULL}: Maximum (\textbf{WARNING}: for -speaker only, do not use with headphones). \textbf{HEADPHONE}: Lower -volume for headphone use. \textbf{DEFAULT}: Default value +1dB because -the true 0dB (\texttt{0b001111001}) decreases the signal a little -bit. \\ -\texttt{-\/-ssm-speed} & Changes \textbf{SSM ADC/DAC} sample rate. -\textbf{DEFAULT}: 48kHz sample rate. \textbf{FAST}: 96Khz sample rate \\ -\bottomrule -\end{tabular} - -\section{Hardware configuration (Zybo Z7-10/20)} -\label{hard} -\begin{itemize} - -\item - Jumper \textbf{JP5} should be on \emph{JTAG} -\item - \textbf{Power select} jumper should be on \emph{USB}\\ -\item - \textbf{Switches} SW0, SW1, SW2, SW3 should be \textbf{down} (i.e. toward the opposite side of the ethernet connector\\ -\item - The \textbf{audio input} is \textbf{LINE IN} (blue), not MIC IN\\ -\item - The \textbf{audio output} is the black \textbf{HPH OUT} jack -\end{itemize} - -\subsection{Control of the Syfala IP} -\label{control} - -To control your DSP, you can either use a Syfala Hardware Controller Board or a -GUI on your computer. Beguinner should use GUI control. - -\hypertarget{gui-sw3-down}{% -\paragraph{GUI (SW3 DOWN)}\label{gui-sw3-down}} - -\textbf{SW3} should be \textbf{down} (0). - -If you use GUI, open the GUIcontroller after booting with the following -command: - -\begin{verbatim} -make gui -\end{verbatim} - -\hypertarget{syfala-hardware-controller-board-sw3-up}{% -\paragraph{Syfala Hardware Controller Board (SW3 -UP)}\label{syfala-hardware-controller-board-sw3-up}} - -\textbf{SW3} should be \textbf{up} . - -If you use a Hardware Controller Board, please set the -\texttt{-\/-controller-type} command-line parameter to the proper value -(see below) - -\hypertarget{controller-type-values-description}{% -\subparagraph{Controller-type values -description}\label{controller-type-values-description}} - -\begin{itemize} - -\item - \textbf{DEMO}: Popophone demo box -\item - \textbf{PCB1}: Emeraude PCB config 1: 4 knobs, 2 switches, 2 sliders - (default) -\item - \textbf{PCB2}: Emeraude PCB config 2: 8 knobs -\item - \textbf{PCB3}: Emeraude PCB config 3: 4 knobs, 4 switches -\item - \textbf{PCB4}: Emeraude PCB config 4: 4 knobs above, 4 switches below -\end{itemize} - -You can swap from hardware to software controller during DSP execution -by changing SW3. - -\hypertarget{switch-description}{% -\subsubsection{Switch description}\label{switch-description}} - -\begin{verbatim} - SW3 SW2 SW1 SW0 -+-----+-----+-------+------+ -| Hard| ADAU| BYPASS| MUTE | -| | | | | -| | | | | -| GUI | SSM |USE DSP|UNMUTE| -+-----+-----+-------+------+ -\end{verbatim} -\begin{itemize} - -\item - \textbf{SW3}: Controller type select: hardware (Controller board) or - software (GUI). Default: {\bf GUI} -\item - \textbf{SW2}: Audio codec input select (ADAU=external or SSM=onboard). - Does not affect output. Default: \textbf{SSM} -\item - \textbf{SW1}: Bypass audio dsp. Default: \textbf{USE DSP} -\item - \textbf{SW0}: Mute. Default: \textbf{UNMUTE} -\end{itemize} - -\hypertarget{status-leds}{% -\subsubsection{Status LEDs}\label{status-leds}} - -The RGB led indicate the program state: - -\begin{itemize} - -\item - \textbf{BLUE} = WAITING -\item - \textbf{GREEN} = ALL GOOD -\item - \textbf{ORANGE} = WARNING (Bypass or mute enable) -\item - \textbf{RED} = ERROR (Config failed or incompatible). Could happen if - you select SSM codec with incompatible sample rate. -\end{itemize} - -The 4 LEDs above the switches indicate the switches state. If one of -them blink, it indicates the source of the warning/error. - -\hypertarget{sd-card-files}{% -\subsubsection{SD card files}\label{sd-card-files}} - -You can put the program on an SD card (if you want something -reproductible and easily launchable, for the demos\ldots).\\ -After a \texttt{make} command, you should see a \texttt{BOOT.bin} file -in SW\_export (or you can build it with \texttt{make\ boot\_file}).\\ -Put the file on the root of SD card. And don't forget to put JP5 on `SD' -position ! - - - - -\input{known-bugs} - -\input{syfala-team} diff --git a/doc/syfala-getting-started-src/developer-doc.tex b/doc/syfala-getting-started-src/developer-doc.tex deleted file mode 100644 index 53c3086..0000000 --- a/doc/syfala-getting-started-src/developer-doc.tex +++ /dev/null @@ -1,490 +0,0 @@ -\documentclass[11pt]{article} - -\usepackage[utf8]{inputenc} -\usepackage[T1]{fontenc} -%\usepackage[francais]{babel} -\usepackage[french]{babel} -\usepackage{eurosym} -\usepackage{lmodern} -\usepackage{boxedminipage} -\usepackage{moreverb} -\usepackage{microtype} -\usepackage{listings} -\lstset{ -basicstyle=\small\ttfamily, -columns=flexible, -breaklines=true -} - -\usepackage[pdftex]{graphicx} -\graphicspath{{./fig/}} -\usepackage[colorlinks,linkcolor=blue,citecolor=blue,pagebackref]{hyperref} -\usepackage{amsmath,amssymb,amsfonts,mathrsfs} -\usepackage[usenames,dvipsnames]{color} -\usepackage{float} -\usepackage{graphicx} -\usepackage{multirow} -\usepackage{pgfgantt} -\usepackage{multicol} -\usepackage{wrapfig,lipsum,booktabs} -\usepackage{tikz} -\usetikzlibrary{calc, arrows, shapes, fit} -\usetikzlibrary{positioning,intersections} -\usepackage{pgfplots} -\pgfplotsset{compat=1.8} - -%for timing diagrams -% tikz for chronogram -\usepackage{tikz-timing} - -%----------------------------------------------------------------------- -\usepackage[ -text={15cm,21cm}, -centering, -% showframe, -]{geometry} - -\numberwithin{equation}{section} -\numberwithin{figure}{section} -%\renewcommand{\theequation}{\thesection.\arabic{equation}} -%\renewcommand{\thetable}{\thesection.\arabic{table}} - -%----------------------------------------------------------------------- -% The following macros determine the part of the text that will actually -% be compiled. When the paper is completed, set all the macros to 0. - -\def\withtoc{0} - % "with table of contents (TOC)" - % 0: without TOC - % 1: with TOC - -%----------------------------------------------------------------------- - -\newcommand{\CAD}{c.-\`a-d.} -\newcommand{\PEX}{p.\,ex.} -\newcommand{\tocvspace}{-2.0ex} -\usepackage{xspace} -\newcommand{\syfala}{{Syfala}\xspace} -\newcommand{\todo}[1]{\footnote{#1}} - -%----------------------------------------------------------------------- - - -\newcommand{\tcb}{\textcolor{blue}} -\newcommand{\tcg}{\textcolor{OliveGreen}} -\newcommand{\red}{\textcolor{red}} - -\newcommand{\knownbug}[1]{ #1} - -\newcommand{\adtname}{SytaRiot} - -%----------------------------------------------------------------------- -\title{\Large\bf Developper documentation for the Syfala project: \\ From Faust to FPGA} -\author{The Syfala Team} -\date{\today} -\begin{document} -\maketitle - -\tableofcontents - -\setcounter{section}{-1} -\newpage -\section{Very Quick Start} -Last update of this document: \today - -\paragraph{Most recent version:} Syfala v7, Vivado 2020.2 and Faust $\geq$ 2.39.3\\ - -\begin{boxedminipage}{\textwidth} - \begin{verbatim} -#make sure that vivado (v=2020.2) and Faust (v>2.39.3) are installed -#on your computer (see Syfala install documentation) -git clone https://github.com/inria-emeraude/syfala.git my-clone-syfala -cd my-clone-syfala/ -./syfala.tcl install -# connect the Zybo by USB with all switchs down (i.e. opposite to -# ethernet connector plug) on LD0 side and blue jumper on JTAG -syfala examples/virtualAnalog.dsp --reset -#This will compile the ``example/virtualAnalog.dsp'' (~15mn) -# --reset option is useful if you need to recompile it -syfala flash -#listen to audio ``HPH OUT'' -syfala GUI -#Now you can control the virtualAnalog Synthesizer -\end{verbatim} -\end{boxedminipage} - -~\\ - -Syfala has been started in 2020~\cite{Risset20,SMC22}. There has been a number of {\em version} of Syfala, each {\em version} implying great changes in the source files, and tools used hence requiring a new source code. Initial development were performed on internal Inria gitlab site (\url{https://gitlab.inria.fr/risset/syfala}). Since feb. 2022 a public github syfala site has been opened (\url{https://github.com/inria-emeraude/syfala}). The current version released is v7, named simply {\tt syfala} in public github) makes the following choices: -\begin{itemize} -\item One-sample strategy: the FPGA DSP kernel is launched at each new sample and the result is available before the arrival of the next sample -\item No use of petalinux. The software running on the ARM of the Zynq SoC is used {\em bare-metal}: no operating system is present. -\item The external DDR memory is accessed by the FPGA DSP kernel, allowing to have long delay lines in DSP programs implemented. The DDR is also accessed in a {\em bare metal} manner: no MMU is used. -\item The whole design has been optimized for low latency, efficient memory accesses, and software initialization (see~\cite{SMC22}). -\item The FPGA DSP kernel can be controlled with a hardware interface or a software interface. The software interface is using the UART serial port between the host processor and the ARM on the Zynq. The hardware interface uses SPI interface for knobs and sliders. An open hardware board design is available on github/emeraude organisation). -\end{itemize} -\newpage - -\section{Syfala v7 compilation flow} -\label{syfala1} -The installation of the required tools ({\tt vivado, vitis, vitis\_hls, Faust}) is explained in the Syfala install documentation\footnote{\href{https://github.com/inria-emeraude/syfala/blob/main/doc/dependencies.md}{https://github.com/inria-emeraude/syfala/blob/main/doc/dependencies.md}}. - -The \syfala v7 compilation flows follows the schematics of Figure~\ref{fig1}. When cloning syfala github, Faust programs are located in the {\tt examples} directory, the compilation flow is configured by default to use a {\em software} control interface (i.e. not a hardware control interface) and to use the onboard audio codec (SSM2603 on Zybo Z7, ADAU1761 on Genesys). - -Since version 7 of Syfala, the {\tt syfala.tcl} script is used to launch the different Syfala commands. The command \texttt{./syfala.tcl install} will install in {\tt /sur/local/bin} (as root) a {\tt syfala} command that basically run the {\tt ./syfala.tcl} script. If you are to clone another instance of Syfala, make sure to run the {\tt `syfala.tcl install'} command again before using it. - -All Syfala generated files are produced in the {\tt build} directory -The sub-directories of the {\tt syfala} repository are the following -\begin{verbatim} -. -|-- README.md -|-- build // contains all the files generated by Syfala -|-- doc // Syfala documentation -|-- examples // Faust .dsp file -|-- include // include files for Syfala -|-- misc // misc (e.g. patches) -|-- scripts // All tcl scripts -|-- source // All sourcse files used by Syfala -|-- testbenches // VHDL testbenches (outdated now) -|-- tests // used for testing syfala (for dev. only) -`-- tools // higher level tools using Syfala (for dev. only) -\end{verbatim} - -The compile-time parameters added with the {\tt syfala} command will select both the way the audio DSP will be compiled (e.g sample rate, sample bit width) and the hardware interface (e.g. codec used). The successive commands called by the command: \\ -{\tt syfala examples/virtualAnalog.dsp} command are the following:\\ - - \begin{boxedminipage}{\textwidth} -\begin{verbatim} - TODO: update once commands are highlighted in the script - faust -lang c light -os2 -a fpga.cpp -uim -mcd 0 -o syfala.cpp \ - ../faust/virtualAnalog.dsp - vitis_hls -f ../scripts/ip_v6.tcl - vivado -mode batch -source scripts/project_v6.tcl -tclargs - faust -i -lang cpp -os2 -mcd 0 -a arm.cpp ../faust/virtualAnalog.dsp \ - -o syfala_application.cpp - xsct ./scripts/application_v6.tcl -\end{verbatim} -\end{boxedminipage} - - ~\\ - The same result can be equivalently obtained by performing each step individually with the following commands:\\ - - \begin{boxedminipage}{\textwidth} - \begin{verbatim} - syfala clean / removes the build directory / - syfala examples/virtualAnalog.dsp --arch /* uses faust to generate - HW (syfala_ip.cpp) and (syfala_application.cpp) files */ - syfala --ip /* uses vitis_hls to synthesize syfala_ip.cpp */ - syfala --project /* build the syfala_project.xpr vivado project */ - syfala --syn /* execute the vivado syfala_project.xpr project - and build the bitstream */ - syfala --app /* create and compile the control application on PC */ - syfala --flash /* download bitstream+app on Zynq (JTAG) and boot*/ - syfala --gui /* launch the control UI on the host computer */ - syfala --report /* prints HLS report */ -\end{verbatim} -\end{boxedminipage} - -\begin{figure}[h] - \begin{center} - \input{fig/compilerOverview.tex} - \end{center} - \caption{Syfala compilation flow, grey boxes are generated during the compilation flow} - \label{fig1} -\end{figure} - -The choices that have been made Syfala v7 are the following: -\begin{itemize} -\item Implement a {\em one sample} flag in the Faust compiler ({\tt -os2}) that generates a {\tt computemydsp()} function (in the CPP file generated by Faust) that computes only one sample. It implies that the FPGA signal processing treatment is not pipelined among the audio samples. -\item Have a fixed interface of the {\tt faust} IP that will be synthesized by {\tt vitis\_hls}. Despite this fixed interface, any number of controllers (i.e. sliders) can be used in the Faust program. This interface is present in the architecture file {\tt fpga.cpp} detailed in Section~\ref{sec:fpga} -\item Have a fixed software running on the ARM, performing constants and delays initialization and then constantly updating controllers -- using hardware or software interface -- and sending them to the IP. This {\em application} uses the {\tt arm.cpp} architecture file and is described in Section~\ref{sec:arm} -\end{itemize} - -\subsection{The Syfala IP and the {\tt fpga.cpp} architecture file} -\label{sec:fpga} -The {\tt fpga.cpp} file is the Faust {\em architecture file} for Xilinx FPGA target (currently only Xilinx FPGA architectures are supported by syfala). The {\tt fpga.cpp} determines the interface of the Syfala IP. It is important to understand this interface because it highly influences many performance issues. Changing this interface is possible but it implies to change all vivado scripts present in the compilation flow, hence it requires many manual tuning before getting to new automatic compilation flow with a new interface of the Syfala IP. - -The interface of the Syfala IP is determined by the parameters of the {\tt syfala()} function which is the function synthesized by {\tt vitis\_HLS}. The prototype of the {\tt syfala()} function, extracted from the {\tt Syfala\_ip.cpp} file is shown in Fig.~\ref{fig:interface}, HLS pragmas indicate how each parameter of the IP is interfaced with the rest of the system. The following conventions are used (see {\tt Syfala\_ip.cpp} file generated in the {\tt build/syfala\_ip} directory): - -\begin{figure} -\begin{boxedminipage}{\textwidth} - \small -\begin{verbatim} -void syfala( - sy_ap_int in_ch0_V, - sy_ap_int in_ch1_V, - sy_ap_int* out_ch0_V, - sy_ap_int* out_ch1_V, - bool *outGPIO, bool debugBtn, bool mute, bool bypass, - int ARM_fControl[9], - int ARM_iControl[2], - int ARM_passive_controller[2], - FAUSTFLOAT *ram, int ramBaseAddr, int ramDepth, bool enable_RAM_access) -{ -#pragma HLS INTERFACE s_axilite port=ARM_fControl -#pragma HLS INTERFACE s_axilite port=ARM_iControl -#pragma HLS INTERFACE s_axilite port=ARM_passive_controller -#pragma HLS INTERFACE s_axilite port=ramBaseAddr -#pragma HLS INTERFACE s_axilite port=ramDepth -#pragma HLS INTERFACE s_axilite port=enable_RAM_access -#pragma HLS INTERFACE m_axi port=ram latency=50 -[...] -\end{verbatim} -\end{boxedminipage} -\caption{Prototype of the {\tt syfala()} function defined in the {\tt fpga.cpp} architecture file for a stereo Input/Output DSP program. This file is generated from a template to adapt to the actual number of codecs used in our system architecture. This function is synthesized by {\tt vitis\_hls} to generate the Syfala IP} -\label{fig:interface} -\end{figure} - - -\begin{itemize} -\item Stereo input and output (i.e. \verb#in_ch0_V#, \verb#in_ch1_V#, \verb#out_ch0_V#, \verb#out_ch1_V#) are 24 bit wide signed integer interpreted as a value between -1 and 1, which are to be sent and received from the I2S transceiver which himself will interface with the audio codec. The sample bit depth and the number of Input/Output channels can be changed via syfala parameters. - \item All other parameters of the IP are transmitted from the ARM processor via the {\tt axilite} protocol\footnote{Throughout the document, we will refer to {\tt axilite} for the {\tt axilite 4} protocol used for IP parameter (sometimes called s-axilite) and {\tt AXI} for {\tt axi 4} protocol used to access the DDR memory (sometimes called m-axi)}, except the {\tt ram} parameter which is the access to the DDR memory. -\item The DDR memory is accessed via the AXI protocol in a {\em bare metal} manner: a memory zone is reserved by the ARM program (explicitely reserved in the linker script) and the address and size of this zone are transmitted to the IP via the {\tt ramBaseAddress} and {\tt ramDepth} parameters. Note the {\tt latency=50} pragmas which indicate that we {\em estimate} that a memory access will take 50 FPGA clock cycle (tuned at approx. 120Mhz), this estimate is used by {\tt vitis\_hls} to produce estimation of the timing performance of the IP (file {\tt syfala.rpt} in directory {\tt ./build/syfala\_ip/syfala/syn/report/}), but it is only an estimation of course. -\item {\tt ARM\_icontrol[9]} and {\tt ARM\_fControl[2]} arrays are used to transmit controllers values (integer values or floating point controllers) from ARM to IP. Again the `9' and `2' values are generated from the DSP audio file. -\item {\tt ARM\_passive\_controller[2]}, {\tt outGPIO}, {\tt mute}, {\tt bypass} can be used for debugging purpose. -\item {\tt enable\_RAM\_access} is a boolean that indicates to the IP that the DDR initialization performed by the ARM is finished and that the IP can start to access the DDR. -\end{itemize} - -the body of the {\tt syfala()} function is shown in Fig.~\ref{fig:body}. The {\tt computemydsp()} function is the function computing the effective signal processing on input/output, it is generated by the Faust compiler in the {\tt syfala.cpp} file. - -\begin{figure} - -\begin{boxedminipage}{\textwidth} - \small -\begin{verbatim} -void syfala([...]) -{ -if (enable_RAM_access) { - if (cpt==0) { - cpt++: - /* Download initialization of constants from DDR content */ - instanceConstantsFromMemmydsp(&DSP,SYFALA_SAMPLE_RATE,I_ZONE,F_ZONE); - } - else { - /* compute one sample */ - computemydsp(&DSP, inputs, outputs, icontrol, fcontrol, I_ZONE, F_ZONE); - sendToARM(ARM_passive_controller); - } - /* Saturate outputs, scaleFactor cast between float and ap_int */ - for(int i=0; i 1.0) outputs[i]=1.0; - else if (outputs[i]< -1.0) outputs[i]=-1.0; - } - *out_ch0_V = sy_ap_int(outputs[0] * scaleFactor); - *out_ch1_V = sy_ap_int(outputs[1] * scaleFactor); - } -} -\end{verbatim} -\end{boxedminipage} -\caption{Body of the {\tt syfala()} function synthesized by {\tt vitis\_hls} to generate the Syfala IP} -\label{fig:body} -\end{figure} - - -The {\tt scaleFactor} value (i.e. {\tt 8388607.0f}) is exactly $2^{23}-1 = (1 \ll (23)) -1$. If 24 bitwidth sample are used, The input/output of the {\tt syfala} function are arrays of type {\tt ap\_int<24>}, i.e. signed integer of 24 bit, they are interpreted as {\em decimal part of signed samples between -1 and 1}. The bitwidth are configure in the syfala command which generates the file {\tt build/include/syconfig.hpp}. - -The following table shows the correspondence between the floating point values output by the {\tt computemydsp} function and the corresponding sample input to the I2S transceiver: -{\small - \begin{tabular}{|c|c|c|c|} - \hline - Faust {\tt output} Float & value truncated & value stored in & 24 bits representation of $c$\\ - sample value ($a$) & for {\tt 24 bits} ($b$) & {\tt out\_ch0\_V} ($c$) & sent to i2s \\ - \hline - $0.12345678123456$ & $0.1234567$ & $c=a*2^{23}=1035630$ & [000011111100110101101110] \\ - \hline -$-0.12345678123456$ & $-0.1234567$ & $c=a*2^{23}=-1035630$ & [111100000011001010010010]\\ -\hline -\end{tabular} -} - - -\subsection{Interfacing Faust IP and audio codec: I2S} -\begin{figure}[ht] - \centerline{\includegraphics[width=16cm]{design_v7.png}} - \caption{The bloc design obtained by connecting Syfala IP,(\syfala v7), with I2S IPs and AXI interface to DDR} - \label{fig:design_6_3} -\end{figure} - -Figure~\ref{fig:design_6_3} shows how the Faust IP, is interconnected with the rest of the system. All these IPs have a hardwired system clock at 122.88Mhz (i.e. approx. 8 ns system clock). It is very easy and very useful to open the {\tt vivado} project that generates the design. This can be done with the following command (after the build is done): -\begin{verbatim} -syfala open-project -\end{verbatim}\\ -Then the block design shown on Fig.~\ref{fig:design_6_3} can be opened using {\tt open Block Design}. One can see that the audio input/output streams of the Syfala IP are directly connected to the I2S IP ({\tt i2s\_transceiver} block), one can also see the {\tt AXI} IP interface which is used to access DDR and the {\tt axilite} IP interface used for interface with ARM processor. The I2S IP is in turn directly connected to I/O of the Zynq with the following convention: -\begin{itemize} -\item The first two channels (Ch0 and Ch1) are connected to the pad of the onboard codec (SSM2603 for ZYBO, ADAU1761 for Genesys). -\item The first two channels (Ch0 and Ch1) are duplicated on GPIO pads for the use of an external codec. -\item All additional channels (if existing) are connected to the GPIO pads for the use of an external codec. -\end{itemize} -The onboard codec is configured from the ARM processor as described in section~\ref{sec:arm}\\ - - - -%\subsubsection{The {\tt i2s\_transceiver} IP} - -%% \begin{figure}[ht] -%% \centerline{\includegraphics[width=\textwidth]{i2s_serialbit_mode.png}} -%% \caption{J'ai laissé cette figure pour qu'on s'en inspire pour finit l'autre diagramme} -%% \label{figi2sold} -%% \end{figure} - - -\begin{figure}[ht] - \input{fig/clock_i2s.tex} - \caption{I2S protocol implemented {\tt i2s\_transceiver.vhd}, between the Syfala IP and the audio codec with 16-bit samples. The {\tt ws} signal select from left or right channel. The {\tt sd\_tx} bit stream corresponds to the 16 bits of the sample. it is shifted of 1 clock cycle from {\tt ws} changes. {\tt bclk} stands for {\em bit clock} and {\tt ws} stands for {\em word select}.} - \label{figi2s} -\end{figure} - -\begin{figure}[ht] - \input{fig/clock_i2s_zoom1.tex} - \caption{Zoom on the beginning of a right sample (sample number $i$) first bits transmission: {\tt mclk} is 4 time faster than {\tt bclk}. {\tt ws\_tx} and {\tt ws\_rx} are delayed version of {\tt ws}, used to synchronize starting of samples bits transmission. {\tt sd\_tx} is {\em produced} by the I2S IP as an output on the falling edge of {\tt bclk} and {\tt sd\_rx} is {\em read} as an input on the rising edge of {\tt bclk}.} - \label{figi2szoom1} -\end{figure} - -The {\tt i2s\_transceiver} is the one that really transmits the bits between the FPGA and the audio codec. The data is serialized and transmitted/received on the {\tt sd\_tx}/{\tt sd\_rx} port to the ports of the audio codec. The protocol used in our design is the one illustrated on Fig.~\ref{figi2s}, it can be configured to send 16, 24 or 32 bit-wide sample. For 16 bit configuration the sample cycle time is exactly divided in 32 cycles to transmit the $2\times16$ bits (left and right samples), as shown on Fig.~\ref{figi2s}. But for 24 bit-wide sample, the sample cycle is not divided in 48 (=$2\times24$), but in 64 cycles as it is for 32 bit-wide samples. The sample bits are serially transmitted along the {\tt bclk} clock as shown in Fig.~\ref{figi2s} (see also~\cite{ssm2603}). The {\tt ws} signal indicates whether current bits belong to left or right channel. However, as indicated in Fig.~\ref{figi2s}, there is a shift of 1 cycle: the first bit send after {\tt ws} clock fall-down is not the first bit of current left sample, it is the last bit of the previous right sample.\footnote{See for instance \url{https://www.sparkfun.com/datasheets/BreakoutBoards/I2SBUS.pdf}} - -\paragraph{Syfala I2S patch} In a normal transmission, the {\tt sd\_tx} bit is positioned on the falling edge of {\tt bclk} clock, it is transmitted from our (master) I2S to the (slave) I2S of the codec. Simultaneously, the slave I2S is positioning the {\tt sd\_rx} bit -- which is {\em his} {\tt sd\_tx} -- to be transmitted from the codec to our I2S. The {\tt sd\_rx} bit is effectively read by our I2S on the rising edge of {\tt bclk}, this allows time for the signal to arrive through the connection between the codec and the FPGA, this time is called {\tt Tsod} in analog device ADAUs codecs for instance (see Fig.~\ref{figi2szoom2}-(a) for illustration). - -In our design, we have used external codecs that allows internal clock as fast as 768kHz. We have noticed that, as we needed a level shifter to adapt power supplies between the codec and the Zybo, this half a bclk cycle time may be less than the time needed for {\tt sd\_rx} to stabilize. Hence we proposed a {\em patch} that delays of one {\tt mclk} cycle in addition to the half {\tt bclk} cycle shown on Fig.~\ref{figi2szoom2}-(b). - -\begin{figure}[ht] - \begin{tabular}{cc} - \begin{boxedminipage}{0.5\textwidth} - \input{fig/clock_i2s_zoom2.tex} - \end{boxedminipage} & - \begin{boxedminipage}{0.5\textwidth} - \input{fig/clock_i2s_zoom3.tex} - \end{boxedminipage}\\ - (a) Standard I2S & (b) Patched I2S \\ - \end{tabular} - \caption{The left chronogram (a) illustrates the {\tt Tsod} time needed for the information to transit from codec to FPGA. In a standard I2S, the {\tt sd\_rx} bit is sampled on the rising edge of {\tt bclk}. On the right (b) is illustrated our patch delaying the sampling of a {\tt mclk} period, taking into account the time needed to transit through the level shifter} - \label{figi2szoom2} -\end{figure} - -We have implemented the I2S protocol in VHDL (file {\tt src/i2s\_transceiver.vhd}). It can be parameterized by the sample bit depth as well as by the sample rate. - -The {\tt i2s\_transceiver} is connected to the {\tt Syfala} IP. It performs a hand shake ({\tt ap\_hs} protocol from Xilinx {\tt vitis\_hls}) with the Syfala IP in order to transmit and receive samples from the Syfala IP. The {\tt ap\_start} signal is initiated by the {\tt i2s\_transceiver} and when the two Syfala IP outputs are ready ({\tt out\_ch0\_V} and {\tt out\_ch1\_V}), the signals {\tt out\_ch0\_V\_ap\_vld} and {\tt out\_ch1\_V\_ap\_vld} are raised {\em for one system clock cycle}. A hand shake is proposed in the I2S transceiver to grab the output values when they are available (they are not necessarily available simultaneously). - - -\subsection{Time, Clocks and the ordering of ticks in the Syfala system} - -It is important to understand the origin and value of the different clocks in the system. The generation of the different clocks is highly simplified by the use of two {\tt Clocking Wizard} IP. The first clocking wizard inputs the external clock ({\tt sys\_clk}) and outputs the FPGA system clock {\tt board\_clk} and the second one outputs {\tt mclk} and another clock at 24MHz needed by the codecs. The reason for using {\em two} clocking wizard instead of one is that exact frequencies for the three clocks cannot be obtained with only one clocking wizard, we need two MMCM/PLL. - -\paragraph{FPGA system Clock: {\tt sys\_clk} at 122.88MHz} -The {\em internal} FPGA clock that triggers every registers of the FPGA is depending of the complexity of the design (i.e. the complexity of the longest combinatorial path), it is called {\tt sys\_clk} on Vivado block design. We follow two rules to set this clock: -\begin{itemize} -\item {\tt sys\_clk} can be as fast as wanted as long as it met timing constraints. -\item {\tt sys\_clk} and {\tt mclk} should be multiples to facilitate the timing closure and minimize the negative slack. -\end{itemize} -{\tt mclk} is a multiple of 48kHz and $f_{mclk}$=12.288MHz at 48kHz sampling rate (see below). So we usually impose {\tt sys\_clk} clock to be {\bf 122.88MHz} (i.e. setting a {\bf 8.13ns} clock when creating {\tt vivado} and {\tt vivado\_hls} projects). Faster clocks have been tested with Syfala and should work too. - -\paragraph{I2S Transceiver Master Clock: {\tt clk\_I2S} at $ 2\times 4 \times d_{width}\times f_s$} -We call $d_{width}$ the number of cycle needed to send the bits of one sample, remember that, as explained above: $d_{width}$ is 16 for 16 bit-wide samples but 32 for 24 bit wide samples (and 32 for 32 bit wide samples too). -The clock regulating the transceiver ({\tt mclk}) should be a multiple of the sampling frequency, it should be exactly $f_{mclk}=2\times 4\times d_{width}\times f_s$, where $f_s$ is the sample rate. Indeed, as $bclk$ clock will be four times slower than $mclk$ clock, we will have time to send 2 samples of $d_{width}$ bits in one sample cycle. - -For instance, if we want an I2S signal at 48kHz sampling rate with 24 bit samples, $f_{mclk}$ should be: $$f_{mclk}=8 \times 32 \times f_s=256*48kHz =12.288MHz$$ - -\paragraph{Codec system clock: {\tt clk\_24Mhz} at 24.576MHz} The last generated clock is the system clock needed by the codecs to works. It's configurable on each codec and has no effect on the sampling rate. We use a {\bf 24.576MHz} clock which is compatible with all our tested codecs and ensure the best performances.\\ - -{\em In practice, the clocking wizard is not able to obtain exactly the these frequencies (because of the limitation of a PLL) so the real sample frequency obtained is not exactly 48kHz. But we ensure that all frequencies are multiples specifying the nearest synthesizable frequency. For exemple, on ZYBO we have:} -$f_{sys\_clk}$=122.885835MHz, $f_{clk\_I2S}$=12.2885835MHz so $f_{s}$=48.002279kHz - -\paragraph{The {\tt i2s\_transceiver} clocks} -The I2S transceiver is using two more clocks: the {\bf sclk} clock, sometimes called {\bf bclk} ({\em bit clock} because it is clocking each bit as illustrated on figure~\ref{figi2s}) and the {\bf ws} clock (word select) which select the left or right channel (illustrated as {\tt ws} on Fig.~\ref{figi2s}). - -There is a fixed ratio between these two clocks and the {\tt mclk} mentioned above:{\tt mclk/sclk}=4 (i.e. {\tt mclk} is 4 time faster {\tt sclk}). The ratio between {\tt sclk} and {\tt ws} is also fixed but it depends on the bit depth of the sample: {\tt sclk/ws}$=2\times d_{width}$. We have hard-coded these ratios in {\tt i2s\_transceiver.vhd} generic VHDL parameters which are generated at compile time, depending on the sample bit-depth given as options to the {\tt syfala} command (24 by default). - -For instance, at 48kHz sampling rate with 24 bit samples, one {\tt ws} period is $T_{ws}=4\times 2\times 32\times T_{mclk}=256\times T_{mclk}=T_{audio}=\frac{1}{48kHz}=20.83\mu s$. Here are the generic parameters used for this configuration in {\tt i2s\_transceiver.vhd} - -{\small -\begin{verbatim} - generic( - mclk_sclk_ratio : integer := 4; --number of mclk periods per sclk period - sclk_ws_ratio : integer := 64; --number of sclk periods per word select period - d_width : integer := 24); --data width -\end{verbatim} -} - - -\begin{figure}[ht] - \centerline{\includegraphics[width=7cm]{zynq-mp-core-dual1.png}} - \caption{Architecture of Xilinx Zynq 7000 (ZYBO) processing system (from \url{https://www.xilinx.com/products/silicon-devices/soc/zynq-7000.html})} - \label{zynq} -\end{figure} - -\begin{figure}[ht] - \centerline{\includegraphics[width=7cm]{fig/ultrascale_MPSOC.png}} - \caption{Architecture of Xilinx UltraScale+ (Genesys) processing system (from \url{https://www.xilinx.com/products/silicon-devices/soc/zynq-ultrascale-mpsoc.html})} - \label{ultrascale} -\end{figure} -\subsection{The ARM application software and the {\tt arm.cpp} architecture file} -\label{sec:arm} - - -Zynq SoCs include a so-called {\em processing system} which consists in a - dual-core ARM Cortex-A9 for Zynq7000 SoC for ZYBO, or a Quad-core ARM Cortex-A53 on Ultrascale+ MPSoC for Genesys ZU-3EG. -These SoC also embed a high performance and general purpose buses between ARM and FPGA (axilite port) and an interface to an external DDR memory (see Fig.~\ref{zynq} and Fig.~\ref{ultrascale}). - -Ideally, the DSP computations should be executed on the FPGA and the control and initialization should be executed on the ARM processor. The Faust language proposes several interfaces to the user: sliders or button and even feedback information. In the remaining of this documents, we will refer to these interface devices as {\em controllers}. - -The {\tt faust} compiler is invoked a second time. The first invocation has generated the {\tt syfala.cpp} file used to generate the IP (using the {\tt fpga.cpp} architecture file). The second invocation is used to generate the {\tt syfala\_application.cpp} program that will run on the ARM (using the {\tt arm.cpp} architecture file). - - -The {\tt syfala\_application.cpp} is quite long because it re-uses many contributions from the Faust ecosystem. Here are the actions executed by the application on the ARM processor (i.e. the actions of the {\tt syfala\_application.cpp} file): - \begin{itemize} - \item It initializes the {\tt ddr\_ptr} pointer to the DDR memory and erases the part of the memory used by the FPGA IP. The address of the {\tt ddr\_ptr} is inherited from a macro defined in the linker script: -\begin{verbatim} - u32* ddr_ptr = (u32*)FRAME_BUFFER_BASEADDR; -\end{verbatim} - -\item It initializes the {\tt izone} and {\tt fzone} which are then transmitted to the Faust IP: -\begin{verbatim} - iZone = (int*)(ddr_ptr); - fZone = (float*)(ddr_ptr + FAUST_INT_ZONE); -\end{verbatim} -\item It initializes various peripherals of the Soc: - \begin{itemize} - \item GPIOs - \item SPI peripheral (used to get controlers/sliders valuers) - \item I2C (used to configure the audio codec) - \item Faust IP - \item DDR memory - \end{itemize} -\item It defines a user interface for the DSP program ({\tt UI}) -\item It defines a class {\tt mydsp} which correspond to all the variables of the DSP program stored in the Block Rams by the Faust IP: delay lines, temporary computation, etc. This ``additional'' declaration is used to initialize some of these variables (in particular constants). - \item It maintains a state for each controller and updates them when their values changes, either from hardware (in case of hardware interface) or from software (i.e. via the UART connection in case of software interface). - \item It sends these controllers values repetitively to the Faust IP. - \end{itemize} -\begin{figure}[ht] -\centering - \begin{tabular}{ccc} - \input{fig/interfaceOverview.tex}&~~~~ & - \includegraphics[width=4cm]{fig/popophone.jpg}\\ - (a) & &(b) - \end{tabular} -\caption{(a) Interface selection between software interface (GTK app) and hardware interface (knobs such those shown in (b)). The design of the hardware board such as (b) can be freely available on github.} -\label{fig:interfaceOverview} -\end{figure} - The {\tt syfala\_application.elf} file is cross-compiled to ARM binary format on the host using the cross compilation tool proposed by {\tt vitis} from the files {\tt syfala\_application.cpp}, and some other files present in the {\tt src} directory. The compilation is configured by Xilinx {\tt xsct} tool using the script {\tt scripts/application.tcl} - -Depending on the information of the syfala command, the code executed by {\tt syfala\_application.elf} launches a hardware interface to control the Faust IP or a software interface to control the Faust IP. This is shown on Fig.~\ref{fig:interfaceOverview}. - - -\section{A complete example: simple sinewave} -\input{sin-example.tex} - -\bibliographystyle{plain} -\bibliography{syfala.bib} - - -\newpage -\appendix -\label{Annex1} -\input{known-bugs} - -\input{syfala-team} -%\input{body-install-toolchain.tex} - - - -\end{document} - diff --git a/doc/syfala-getting-started-src/fig/clock_i2s.tex b/doc/syfala-getting-started-src/fig/clock_i2s.tex deleted file mode 100644 index 0f6e1b0..0000000 --- a/doc/syfala-getting-started-src/fig/clock_i2s.tex +++ /dev/null @@ -1,92 +0,0 @@ -\newcounter{wavenum} - -\setlength{\unitlength}{1cm} -% advance clock one cycle, not to be called directly -\newcommand*{\clki}{ - \draw (t_cur) -- ++(0,-.3) -- ++(.2,0) -- ++(0,.6) -- ++(.2,0) -- ++(0,-.3) - node[time] (t_cur) {}; -} -%ws clock = 32 * clock -\newcommand*{\wsi}{ - \draw (t_cur) -- ++(0,.3) -- ++(6.4,0) -- ++(0,-.6) -- ++(6.4,0) -- ++(0,.6) -- ++(0.4,0) - node[time] (t_cur) {}; -} - -\newcommand*{\bitvector}[3]{ - \draw[fill=#3] (t_cur) -- ++( .1, .3) -- ++(#2-.2,0) -- ++(.1, -.3) - -- ++(-.1,-.3) -- ++(.2-#2,0) -- cycle; - \path (t_cur) -- node[anchor=mid] {#1} ++(#2,0) node[time] (t_cur) {}; -} - -% \known{val}{length} -\newcommand*{\known}[2]{ - \bitvector{{\tiny #1}}{#2}{white} -} - -% \unknown{length} -\newcommand*{\unknown}[2][XXX]{ - \bitvector{{\tiny ..}}{#2}{black!2} -} - -% \bit{1 or 0}{length} -\newcommand*{\bit}[2]{ - \draw (t_cur) -- ++(0,.6*#1-.3) -- ++(#2,0) -- ++(0,.3-.6*#1) - node[time] (t_cur) {}; -} - -% \unknownbit{length} -\newcommand*{\unknownbit}[1]{ - \draw[ultra thick,black!50] (t_cur) -- ++(#1,0) node[time] (t_cur) {}; -} -% \nextwave{name} -\newcommand{\nextwave}[1]{ - \path (0,\value{wavenum}) node[left] {#1} node[time] (t_cur) {}; - \addtocounter{wavenum}{-1} -} - -% \clk{name}{period} -\newcommand{\clk}[2]{ - \nextwave{#1} - \FPeval{\res}{(\wavewidth+1)/#2} - \FPeval{\reshalf}{#2/2} - \foreach \t in {1,2,...,\res}{ - \bit{\reshalf}{1} - \bit{\reshalf}{0} - } -} - -% \ws{name}{period} -\newcommand{\ws}[2]{ - \nextwave{#1} - \FPeval{\res}{(\wavewidth+1)/#2} - \FPeval{\reshalf}{#2/2} - \foreach \t in {1,2,...,\res}{ - \bit{\reshalf}{1} - \bit{\reshalf}{0} - } -} - -% \begin{wave}[clkname]{num_waves}{clock_cycles} -\newenvironment{wave}[3][bclk]{ - \begin{tikzpicture}[draw=black, yscale=.7,xscale=1] - \tikzstyle{time}=[coordinate] - \setlength{\unitlength}{1cm} - \def\wavewidth{#3} - \setcounter{wavenum}{0} - \nextwave{#1} - \foreach \t in {0,1,...,\wavewidth}{ - \draw[dotted] (t_cur) +(0,.5) node[above] {{\tiny \t}} -- ++(0,.4-#2); - \clki - } - \nextwave{ws} - \wsi -}{\end{tikzpicture}} - -\begin{wave}{2}{32} - \nextwave{{ sd\_tx}} - \known{x}{.4} \known{1}{.4} \known{2}{.4} - \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4}\unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \known{13}{.4} \known{14}{.4} \known{15}{.4} \known{16}{.4} - \known{1}{.4} \known{2}{.4} \known{3}{.4} \known{4}{.4} - \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4}\unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \unknown[ ]{.4} \known{15}{.4} \known{16}{.4} - -\end{wave} diff --git a/doc/syfala-getting-started-src/fig/clock_i2s_zoom1.tex b/doc/syfala-getting-started-src/fig/clock_i2s_zoom1.tex deleted file mode 100644 index 86e3ac8..0000000 --- a/doc/syfala-getting-started-src/fig/clock_i2s_zoom1.tex +++ /dev/null @@ -1,126 +0,0 @@ -\setlength{\unitlength}{1cm} -%mclk -\newcommand*{\mclki}{ - \draw (t_cur) -- ++(0,.3) -- ++(0.25,0) -- ++(0,-.6) -- ++(0.25,0) -- ++(0,.3) - node[time] (t_cur) {}; -} - - -% advance clock one cycle, not to be called directly -\newcommand*{\clki}{ - \draw (t_cur) -- ++(0,-.3) -- ++(1,0) -- ++(0,.6) -- ++(1,0) -- ++(0,-.3) - node[time] (t_cur) {}; -} - -%ws clock = 32 * clock -\newcommand*{\wsi}{ - \draw (t_cur) -- ++(0,.3) -- ++(14,0) - node[time] (t_cur) {}; -} -\newcommand*{\wsitx}{ - \draw (t_cur) +(0,-.3) -- ++(1,-.3) -- ++(0,.6) -- ++(13,0) - node[time] (t_cur) {}; -} -\newcommand*{\wsirx}{ - \draw (t_cur) +(0,-.3) -- ++(2,-.3) -- ++(0,.6) -- ++(12,0) - node[time] (t_cur) {}; -} - -\newcommand*{\bitvector}[3]{ - \draw[fill=#3] (t_cur) -- ++( .1, .3) -- ++(#2-.2,0) -- ++(.1, -.3) - -- ++(-.1,-.3) -- ++(.2-#2,0) -- cycle; - \path (t_cur) -- node[anchor=mid] {#1} ++(#2,0) node[time] (t_cur) {}; -} - -% \known{val}{length} -\newcommand*{\known}[2]{ - \bitvector{{\tiny #1}}{#2}{white} -} - -% \unknown{length} -\newcommand*{\unknown}[2][XXX]{ - \bitvector{{\tiny ..}}{#2}{black!2} -} - -% \bit{1 or 0}{length} -\newcommand*{\bit}[2]{ - \draw (t_cur) -- ++(0,.6*#1-.3) -- ++(#2,0) -- ++(0,.3-.6*#1) - node[time] (t_cur) {}; -} - -% \unknownbit{length} -\newcommand*{\unknownbit}[1]{ - \draw[ultra thick,black!50] (t_cur) -- ++(#1,0) node[time] (t_cur) {}; -} - -% \nextwave{name} -\newcommand{\nextwave}[1]{ - \path (0,\value{wavenum}) node[left] {#1} node[time] (t_cur) {}; - \addtocounter{wavenum}{-1} -} - -% \clk{name}{period} -\newcommand{\clk}[2]{ - \nextwave{#1} - \FPeval{\res}{(\wavewidth+1)/#2} - \FPeval{\reshalf}{#2/2} - \foreach \t in {1,2,...,\res}{ - \bit{\reshalf}{1} - \bit{\reshalf}{0} - } -} - -% \ws{name}{period} -\newcommand{\ws}[2]{ - \nextwave{#1} - \FPeval{\res}{(\wavewidth+1)/#2} - \FPeval{\reshalf}{#2/2} - \foreach \t in {1,2,...,\res}{ - \bit{\reshalf}{1} - \bit{\reshalf}{0} - } -} - -% \begin{wave}[clkname]{num_waves}{clock_cycles} -\newenvironment{wave}[3][bclk]{ - \begin{tikzpicture}[draw=black, yscale=.7,xscale=1,scale=0.8,every node/.style={scale=0.8}] - \tikzstyle{time}=[coordinate] - \setlength{\unitlength}{1cm} - \def\wavewidth{#3} - \setcounter{wavenum}{0} - \nextwave{mclk} - \foreach \t in {0,1,...,2\wavewidth}{ - \mclki - } - \draw[dotted] (t_cur) -- ++(1,0); - \nextwave{bclk (sclk)} - \foreach \t in {0,1,...,\wavewidth}{ - \draw[dotted] (t_cur) +(0,1.5) node[above] {{\tiny \t}} -- ++(0,.4-#2); - \clki - } - \draw[dotted] (t_cur) -- ++(1,0); - \nextwave{ws} - \wsi \draw[dotted] (t_cur) -- ++(1,0); - \nextwave{ws\_tx} - \wsitx - \nextwave{ws\_rx} - \wsirx -}{\end{tikzpicture}} - -\begin{wave}{3}{6} - \nextwave{{ sd\_tx}} - \known{$Left^{i-1}(15)$}{2} \known{$Right^{i}(0)$}{2} \known{$Right^{i}(1)$}{2} \known{$Right^{i}(2)$}{2} \known{$Right^{i}(3)$}{2} \known{$Right^{i}(4)$}{2} \known{$Right^{i}(5)$}{2} \draw[dotted] (t_cur) -- ++(1,0); - \nextwave{{ sd\_rx}} - \draw (t_cur) ++(0, .3) -- ++(.9,0) -- ++(.1, -.3); - \draw (t_cur) ++(0, -.3) -- ++(.9,0) -- ++(.1, .3); - % -- ++(-.1,-.3) -- ++(.2-.5,0) -- cycle; - \path (t_cur) -- node[anchor=mid] {~} ++(1,0) node[time] (t_cur) {}; - \draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); - \known{$Left^{i-1}(15)$}{2} \draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(0)$}{2} \draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(1)$}{2} \draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(2)$}{2} \draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(3)$}{2} \draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(4)$}{2} \draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(5)$}{2} \draw[dotted] (t_cur) -- ++(1,0); -\end{wave} diff --git a/doc/syfala-getting-started-src/fig/clock_i2s_zoom2.tex b/doc/syfala-getting-started-src/fig/clock_i2s_zoom2.tex deleted file mode 100644 index 99085f1..0000000 --- a/doc/syfala-getting-started-src/fig/clock_i2s_zoom2.tex +++ /dev/null @@ -1,118 +0,0 @@ -\def\decalage{.7} -\def\shift{.3} - -\setlength{\unitlength}{1cm} -%mclk -\newcommand*{\mclki}{ - \draw (t_cur) -- ++(0,.3) -- ++(0.25,0) -- ++(0,-.6) -- ++(0.25,0) -- ++(0,.3) - node[time] (t_cur) {}; -} - - -% advance clock one cycle, not to be called directly -\newcommand*{\clki}{ - \draw (t_cur) -- ++(0,-.3) -- ++(1,0) -- ++(0,.6) node[time] (t_cur) {}; - \draw[dotted] (t_cur) +(0,-3.7) -- ++(0,0); - \draw (t_cur) -- ++(1,0) -- ++(0,-.3) node[time] (t_cur) {}; -} - -%ws clock = 32 * clock -\newcommand*{\wsi}{ - \draw (t_cur) -- ++(0,.3) -- ++(14,0) - node[time] (t_cur) {}; -} -\newcommand*{\wsil}{ - \draw (t_cur) +(0,-.3) -- ++(2,-.3) -- ++(0,.6) -- ++(12,0) - node[time] (t_cur) {}; -} - -\newcommand*{\bitvector}[3]{ - \draw[fill=#3] (t_cur) -- ++( .1, .3) -- ++(#2-.2,0) -- ++(.1, -.3) - -- ++(-.1,-.3) -- ++(.2-#2,0) -- cycle; - \path (t_cur) -- node[anchor=mid] {#1} ++(#2,0) node[time] (t_cur) {}; -} - -% \known{val}{length} -\newcommand*{\known}[2]{ - \bitvector{{\tiny #1}}{#2}{white} -} - -% \unknown{length} -\newcommand*{\unknown}[2][XXX]{ - \bitvector{{\tiny ..}}{#2}{black!2} -} - -% \bit{1 or 0}{length} -\newcommand*{\bit}[2]{ - \draw (t_cur) -- ++(0,.6*#1-.3) -- ++(#2,0) -- ++(0,.3-.6*#1) - node[time] (t_cur) {}; -} - -% \unknownbit{length} -\newcommand*{\unknownbit}[1]{ - \draw[ultra thick,black!50] (t_cur) -- ++(#1,0) node[time] (t_cur) {}; -} - -% \nextwave{name} -\newcommand{\nextwave}[1]{ - \path (0,\value{wavenum}) node[left] {#1} node[time] (t_cur) {}; - \addtocounter{wavenum}{-1} -} - -% \clk{name}{period} -\newcommand{\clk}[2]{ - \nextwave{#1} - \FPeval{\res}{(\wavewidth+1)/#2} - \FPeval{\reshalf}{#2/2} - \foreach \t in {1,2,...,\res}{ - \bit{\reshalf}{1} - \bit{\reshalf}{0} - } -} - -% \ws{name}{period} -\newcommand{\ws}[2]{ - \nextwave{#1} - \FPeval{\res}{(\wavewidth+1)/#2} - \FPeval{\reshalf}{#2/2} - \foreach \t in {1,2,...,\res}{ - \bit{\reshalf}{1} - \bit{\reshalf}{0} - } -} - -% \begin{wave}[clkname]{num_waves}{clock_cycles} -\newenvironment{wave}[3][bclk]{ - \begin{tikzpicture}[draw=black, yscale=.7,xscale=1,scale=0.8,every node/.style={scale=0.8}] - \tikzstyle{time}=[coordinate] - \setlength{\unitlength}{1cm} - \setcounter{wavenum}{0} - \nextwave{mclk} - \foreach \t in {0,1,...,12}{ - \mclki - } - \draw[dotted] (t_cur) -- ++(1,0); - \nextwave{bclk} - \foreach \t in {0,1,...,2}{ - \draw[dotted] (t_cur) +(0,1.5) node[above] {{\tiny \t}} -- ++(0,.4-#2); - \clki - } - \draw[dotted] (t_cur) -- ++(1,0); -}{\end{tikzpicture}} - -\begin{wave}{3}{3} - \nextwave{{ sd\_tx}} - \known{$Left^{i-1}(15)$}{2} \known{$Right^{i}(0)$}{2} \known{$Right^{i}(1)$}{2} -- ++(1,0); - \nextwave{~} - \draw[very thick] (t_cur) ++(0, 0.3) -- ++(0,-.6); - \draw[very thick] (t_cur) ++(\decalage, .3) -- ++(0,-1.2); - \draw[<->,thick] (t_cur)++(0,0) -- node[below] {\tiny $T_{sod}$} ++(\decalage,0); - \nextwave{{ sd\_rx}} - \draw (t_cur) ++(0, .3) -- ++(\decalage+\shift-.1,0) -- ++(.1, -.3); - \draw (t_cur) ++(0, -.3) -- ++(\decalage+\shift-.1,0) -- ++(.1, .3); - % -- ++(-.1,-.3) -- ++(.2-.5,0) -- cycle; - \path (t_cur) -- node[anchor=mid] {~} ++(\decalage+\shift,0) node[time] (t_cur) {}; - \known{$Left^{i-1}(15)$}{2} %\draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(0)$}{2} %\draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(1)$}{2} %\draw[dotted] (t_cur) +(0,3.7) -- ++(0,3.7); -\end{wave} diff --git a/doc/syfala-getting-started-src/fig/clock_i2s_zoom3.tex b/doc/syfala-getting-started-src/fig/clock_i2s_zoom3.tex deleted file mode 100644 index 4940478..0000000 --- a/doc/syfala-getting-started-src/fig/clock_i2s_zoom3.tex +++ /dev/null @@ -1,121 +0,0 @@ -\def\decalage{.7} -\def\shift{.8} - -\setlength{\unitlength}{1cm} -%mclk -\newcommand*{\mclki}{ - \draw (t_cur) -- ++(0,.3) -- ++(0.25,0) -- ++(0,-.6) -- ++(0.25,0) -- ++(0,.3) - node[time] (t_cur) {}; -} - - -% advance clock one cycle, not to be called directly -\newcommand*{\clki}{ - \draw (t_cur) -- ++(0,-.3) -- ++(1,0) -- ++(0,.6) node[time] (t_cur) {}; - \draw[dotted] (t_cur) +(0.5,-3.7) -- ++(0.5,0.4); - \draw (t_cur) -- ++(1,0) -- ++(0,-.3) node[time] (t_cur) {}; -} - -%ws clock = 32 * clock -\newcommand*{\wsi}{ - \draw (t_cur) -- ++(0,.3) -- ++(14,0) - node[time] (t_cur) {}; -} -\newcommand*{\wsil}{ - \draw (t_cur) +(0,-.3) -- ++(2,-.3) -- ++(0,.6) -- ++(12,0) - node[time] (t_cur) {}; -} - -\newcommand*{\bitvector}[3]{ - \draw[fill=#3] (t_cur) -- ++( .1, .3) -- ++(#2-.2,0) -- ++(.1, -.3) - -- ++(-.1,-.3) -- ++(.2-#2,0) -- cycle; - \path (t_cur) -- node[anchor=mid] {#1} ++(#2,0) node[time] (t_cur) {}; -} - -% \known{val}{length} -\newcommand*{\known}[2]{ - \bitvector{{\tiny #1}}{#2}{white} -} - -% \unknown{length} -\newcommand*{\unknown}[2][XXX]{ - \bitvector{{\tiny ..}}{#2}{black!2} -} - -% \bit{1 or 0}{length} -\newcommand*{\bit}[2]{ - \draw (t_cur) -- ++(0,.6*#1-.3) -- ++(#2,0) -- ++(0,.3-.6*#1) - node[time] (t_cur) {}; -} - -% \unknownbit{length} -\newcommand*{\unknownbit}[1]{ - \draw[ultra thick,black!50] (t_cur) -- ++(#1,0) node[time] (t_cur) {}; -} - -% \nextwave{name} -\newcommand{\nextwave}[1]{ - \path (0,\value{wavenum}) node[left] {#1} node[time] (t_cur) {}; - \addtocounter{wavenum}{-1} -} - -% \clk{name}{period} -\newcommand{\clk}[2]{ - \nextwave{#1} - \FPeval{\res}{(\wavewidth+1)/#2} - \FPeval{\reshalf}{#2/2} - \foreach \t in {1,2,...,\res}{ - \bit{\reshalf}{1} - \bit{\reshalf}{0} - } -} - -% \ws{name}{period} -\newcommand{\ws}[2]{ - \nextwave{#1} - \FPeval{\res}{(\wavewidth+1)/#2} - \FPeval{\reshalf}{#2/2} - \foreach \t in {1,2,...,\res}{ - \bit{\reshalf}{1} - \bit{\reshalf}{0} - } -} - -% \begin{wave}[clkname]{num_waves}{clock_cycles} -\newenvironment{wave}[3][bclk]{ - \begin{tikzpicture}[draw=black, yscale=.7,xscale=1,scale=0.8,every node/.style={scale=0.8}] - \tikzstyle{time}=[coordinate] - \setlength{\unitlength}{1cm} - \setcounter{wavenum}{0} - \nextwave{mclk} - \foreach \t in {0,1,...,12}{ - \mclki - } - \draw[dotted] (t_cur) -- ++(1,0); - \nextwave{bclk} - \foreach \t in {0,1,...,2}{ - \draw[dotted] (t_cur) +(0,1.5) node[above] {{\tiny \t}} -- ++(0,.4-#2); - \clki - } - \draw[dotted] (t_cur) -- ++(1,0); -}{\end{tikzpicture}} - -\begin{wave}{3}{3} - \nextwave{{ sd\_tx}} - \known{$Left^{i-1}(15)$}{2} \known{$Right^{i}(0)$}{2} \known{$Right^{i}(1)$}{2} -- ++(1,0); - \nextwave{~} - \draw[very thick] (t_cur) ++(0, 0.3) -- ++(0,-.6); - \draw[very thick] (t_cur) ++(\decalage, .3) -- ++(0,-.6); - \draw[<->,thick] (t_cur)++(0,0) -- node[below] {\tiny $T_{sod}$} ++(\decalage,0) node[time] (t_cur) {}; - - \draw[very thick] (t_cur) ++(\shift, .3) -- ++(0,-1.2); - \draw[<->,thick] (t_cur)++(0,0) -- node[above,yshift=0.2] {\tiny $^{shifter}$} ++(\shift,0); - \nextwave{{ sd\_rx}} - \draw (t_cur) ++(0, .3) -- ++(\decalage+\shift-.1,0) -- ++(.1, -.3); - \draw (t_cur) ++(0, -.3) -- ++(\decalage+\shift-.1,0) -- ++(.1, .3); - % -- ++(-.1,-.3) -- ++(.2-.5,0) -- cycle; - \path (t_cur) -- node[anchor=mid] {~} ++(\decalage+\shift,0) node[time] (t_cur) {}; - \known{$Left^{i-1}(15)$}{2} %\draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(0)$}{2} %\draw[dotted] (t_cur) +(0,3.7) -- ++(0,0); -\known{$Right^{i}(1)$}{2} %\draw[dotted] (t_cur) +(0,3.7) -- ++(0,3.7); -\end{wave} diff --git a/doc/syfala-getting-started-src/fig/compilerOverview.tex b/doc/syfala-getting-started-src/fig/compilerOverview.tex deleted file mode 100644 index 7138478..0000000 --- a/doc/syfala-getting-started-src/fig/compilerOverview.tex +++ /dev/null @@ -1,131 +0,0 @@ -%knob: piqué sur internet: https://tex.stackexchange.com/questions/525535/creating-a-audio-volume-dial-using-tikz -\def\centerarc[#1](#2)(#3:#4:#5) - { \draw[#1] ($(#2)+({#5*cos(#3)},{#5*sin(#3)})$) arc (#3:#4:#5); } - -\newcommand\knob[1]{ -\centerarc[name path=arcc,fill=none,draw=black,line width=0.2]($(#1)$)(-60:240:2mm) -\foreach \t [count=\i from 0] in {240,210,...,-60}{ -\path [name path=\t]($(#1)$)--++(\t:8.2mm); -\path [name intersections={of=arcc and \t,by={\t1}}]; -\draw [line cap=round, line width=0.2](\t1)--++(\t:0.5mm); -\path (\t1)--++(\t:1.5mm)node{\scalebox{0.5}{$\i$}}; -} -} - -% taken from https://tex.stackexchange.com/questions/103688/folded-paper-shape-tikz -\makeatletter -\pgfdeclareshape{document}{ -\inheritsavedanchors[from=rectangle] % this is nearly a rectangle -\inheritanchorborder[from=rectangle] -\inheritanchor[from=rectangle]{center} -\inheritanchor[from=rectangle]{north} -\inheritanchor[from=rectangle]{south} -\inheritanchor[from=rectangle]{west} -\inheritanchor[from=rectangle]{east} -% ... and possibly more -\backgroundpath{% this is new -% store lower right in xa/ya and upper right in xb/yb -\southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y -\northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y -% compute corner of ‘‘flipped page’’ -\pgf@xc=\pgf@xb \advance\pgf@xc by-10pt % this should be a parameter -\pgf@yc=\pgf@yb \advance\pgf@yc by-10pt -% construct main path -\pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}} -\pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}} -\pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yb}} -\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yc}} -\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}} -\pgfpathclose -% add little corner -\pgfpathmoveto{\pgfpoint{\pgf@xc}{\pgf@yb}} -\pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}} -\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yc}} -\pgfpathlineto{\pgfpoint{\pgf@xc}{\pgf@yc}} -} -} -\makeatother - -\begin{tikzpicture} - - %.cpp level - \node[fill=gray!20,draw=black,minimum width=2cm,label={[xshift=0.9cm,yshift=-0.1cm]\tiny IP}] (ipcpp) {sine.cpp}; - \node[fill=gray!20,draw=black, right of=ipcpp,xshift=2cm,minimum width=2cm,label={[xshift=-0.8cm,yshift=-0.1cm]\tiny App}] (appcpp) {sineApp.cpp}; - \node[fit=(ipcpp)(appcpp),yshift=0.5cm] (cpp) {}; - %Architecture files - \node[above of=appcpp,yshift=-0.5cm,xshift=0.4cm](armcpp){}; - \draw[fill=white](armcpp) ++(-10pt,8pt) --++(32pt,0pt) --++(0pt,-14pt) --++(-14pt,0pt) --++(-4pt,-4pt) --++(-4pt,+4pt) --++(-10pt,0pt) --++(0pt,14pt) --cycle; - \draw[fill=white] (armcpp)node[xshift=0.2cm]{\footnotesize arm.cpp}; - - \node[above of=ipcpp,yshift=-0.5cm,xshift=-0.8cm](fpgacpp){}; - \draw[fill=white](fpgacpp) ++(-12pt,8pt) --++(36pt,0pt) --++(0pt,-14pt) --++(-12pt,0pt) --++(-4pt,-4pt) --++(-4pt,+4pt) --++(-16pt,0pt) --++(0pt,14pt) --cycle; - \draw[fill=white] (fpgacpp)node[xshift=0.2cm]{\footnotesize fpga.cpp}; - - %Faust compilers and dsp - \node[rounded corners=0.15cm, draw=black, above of=cpp] (compil) { Faust compiler}; - \node[draw, - thick, - align=center, - color=black, - shape=document, - minimum height=16mm, - shape=document, - left of=compil, - xshift=-1.5cm, - yshift=0.4cm, - inner sep=2pt, - label={[xshift=-0.35cm, yshift=-0.35cm] \tiny Faust}] (dsp) {sine.dsp}; - - - - %Vitis/vivado level - \node[rounded corners=0.15cm, draw=black, below of=ipcpp,yshift=0.2cm,minimum height=0.55cm] (hls) {vitis\_hls / vivado}; - \node[rounded corners=0.15cm, draw=black, below of=appcpp,yshift=0.2cm ] (vitis) {vitis / gcc}; - - - %Zybo - \node[fill=gray!20,draw=black, below of=vitis,minimum height=0.8cm,yshift=-1cm,xshift=-0.5cm] (elf) {app.elf}; - \node[draw=black, fit=(elf),minimum height=1.6cm,minimum width=1.6cm,yshift=0.2cm,label={[yshift=-0.4cm,xshift=-0.4cm]\footnotesize ARM}] (arm) {}; - - \node[fill=gray!20,draw=black,thick, left of=elf,minimum width=1.5cm,minimum height=0.8cm,xshift=-1.4cm,yshift=0.4cm] (ip) {IP Faust}; - - \node[draw=black, fill=gray!20, below of=ip,xshift=-0.3cm,minimum width=0.8cm,] (iis) {\footnotesize I2S}; - - - \node[draw=black, fit=(arm)(ip)(iis),minimum width=3cm,minimum height=2.2cm,label={[xshift=1.8cm,yshift=-2.25cm]\footnotesize SoC}] (soc) {}; - \node[draw=black, below of=soc, minimum width=3.5cm,yshift=-0.5cm] (ddr) {\footnotesize DDR}; - \node[draw=black, fit=(soc)(ddr)][thick] (zybo) {}; - \node[above of=zybo,yshift=0.7cm] (zyboLabel) {\footnotesize ZYBO}; - - %GPIO - \node[draw=black,minimum width=0.5cm,minimum height=0.5cm, left of=iis,xshift=-0.4cm] (codec) {{\footnotesize Codec}}; - \draw[<-] ($(codec)+(0.1cm,0.9cm)$) -- ($(codec)+(0.1cm,0.4cm)$); - \draw[->] ($(codec)+(-0.1cm,0.9cm)$) -- ($(codec)+(-0.1cm,0.4cm)$); - \node[above of=codec, yshift=0.2cm](audio){Audio}; - \node[right of=arm,xshift=0.7cm,yshift=-1cm](knob){\tiny Controls}; - \knob{$(knob)-(0cm,-0.5cm)$}; - \node[above of=knob,yshift=0.7cm,xshift=-0.1cm] (spiLabel) {\tiny SPI/UART}; - -%Up to down arrow - \draw[-] (compil) ++(-33pt,0pt) -- ++(-19pt,0pt); - \draw[->] (compil) -- (ipcpp); - \draw[->] (compil) -- (appcpp); - \draw[-] (ipcpp) -- (hls); - \draw[-] (appcpp) -- (vitis); - \draw[->] (hls) -- ++(0pt,-33pt); - \draw[->] (vitis) ++(0pt,-8pt) --++(0pt,-5pt)-- ++(-10pt,0pt) -- ++(0pt,-32pt); - - -%Zybo arrow - \draw[thick][<->] (ip) ++(12pt,-12pt) --++(0pt,-33pt); - \draw[thick][<->] (elf) ++(-8pt,-17pt) --++(0pt,-16pt); - \draw[thick][<->] (iis) -- ++(0pt,16pt); - \draw[line width=0.7mm,draw=white][-] (iis) -- (codec); - \draw[thick][<->] (iis) -- (codec); - - \draw[thick][<->] (ip) ++(22pt,-5pt) -- ++(24pt,0pt); - \draw[line width=0.7mm,draw=white][-](arm) ++(23pt,15pt) -- ++(25pt,0pt)-- ++(0pt,-15pt); - \draw[thick][<-] (arm) ++(23pt,15pt) -- ++(25pt,0pt)-- ++(0pt,-15pt); - - -\end{tikzpicture} diff --git a/doc/syfala-getting-started-src/fig/design_v6_3.pdf b/doc/syfala-getting-started-src/fig/design_v6_3.pdf deleted file mode 100644 index 78695b4..0000000 Binary files a/doc/syfala-getting-started-src/fig/design_v6_3.pdf and /dev/null differ diff --git a/doc/syfala-getting-started-src/fig/design_v6_3.png b/doc/syfala-getting-started-src/fig/design_v6_3.png deleted file mode 100644 index f5f58eb..0000000 Binary files a/doc/syfala-getting-started-src/fig/design_v6_3.png and /dev/null differ diff --git a/doc/syfala-getting-started-src/fig/design_v7.png b/doc/syfala-getting-started-src/fig/design_v7.png deleted file mode 100644 index beec6f0..0000000 Binary files a/doc/syfala-getting-started-src/fig/design_v7.png and /dev/null differ diff --git a/doc/syfala-getting-started-src/fig/faust_v6_app.cpp b/doc/syfala-getting-started-src/fig/faust_v6_app.cpp deleted file mode 100644 index daf7c0b..0000000 --- a/doc/syfala-getting-started-src/fig/faust_v6_app.cpp +++ /dev/null @@ -1,42 +0,0 @@ -[...] -class mydsp : public one_sample_dsp_real { - - private: - - int fSampleRate; - float fConst0; - FAUSTFLOAT fHslider0; - int IOTA0; - int iVec0[2]; - float fRec0[2]; - float fRec1[2]; - - public: -[...] - virtual void control(int* RESTRICT iControl, float* RESTRICT fControl, int* RESTRICT iZone, float* RESTRICT fZone) { - fControl[0] = fConst0 * float(fHslider0); - fControl[1] = std::sin(fControl[0]); - fControl[2] = std::cos(fControl[0]); - } - [...] -} -struct ARMController { - // Control - ARMControlUIBase* fControlUI; - // DSP - mydsp* fDSP; - [...] -void sendControlToFPGA() - { - XSyfala_Write_ARM_fControl_Words(&xsyfala, 0,(u32*)fControl, FAUST_REAL_CONTROLS); - XSyfala_Write_ARM_iControl_Words(&xsyfala, 0,(u32*)iControl, FAUST_INT_CONTROLS); - } - - void controlFPGA() - { - // Compute iControl and fControl from controllers value - fDSP->control(iControl, fControl, iZone, fZone); - // send iControl and fControl to FPGA - sendControlToFPGA(); - } -[...] diff --git a/doc/syfala-getting-started-src/fig/faust_v6_app2.cpp b/doc/syfala-getting-started-src/fig/faust_v6_app2.cpp deleted file mode 100644 index a733c25..0000000 --- a/doc/syfala-getting-started-src/fig/faust_v6_app2.cpp +++ /dev/null @@ -1,13 +0,0 @@ -[...] -// main program infinite loop infinite loop - void run() - { - while (true) { - //check if reset btn is pressed - while (true) { - controlFPGA(); - UIhandler(); - fControlUI->update(); - } - } -[...] diff --git a/doc/syfala-getting-started-src/fig/gtkUI.png b/doc/syfala-getting-started-src/fig/gtkUI.png deleted file mode 100644 index b37175c..0000000 Binary files a/doc/syfala-getting-started-src/fig/gtkUI.png and /dev/null differ diff --git a/doc/syfala-getting-started-src/fig/i2s_serialbit_mode.png b/doc/syfala-getting-started-src/fig/i2s_serialbit_mode.png deleted file mode 100644 index 1e321ab..0000000 Binary files a/doc/syfala-getting-started-src/fig/i2s_serialbit_mode.png and /dev/null differ diff --git a/doc/syfala-getting-started-src/fig/interfaceOverview.tex b/doc/syfala-getting-started-src/fig/interfaceOverview.tex deleted file mode 100644 index 3a85ebd..0000000 --- a/doc/syfala-getting-started-src/fig/interfaceOverview.tex +++ /dev/null @@ -1,38 +0,0 @@ -%knob: piqué sur internet: https://tex.stackexchange.com/questions/525535/creating-a-audio-volume-dial-using-tikz -\def\centerarc[#1](#2)(#3:#4:#5) - { \draw[#1] ($(#2)+({#5*cos(#3)},{#5*sin(#3)})$) arc (#3:#4:#5); } - - -\newcommand\knob[1]{ -\centerarc[name path=arcc,fill=none,draw=black,line width=0.2]($(#1)$)(-60:240:2mm) -%\foreach \t [count=\i from 0] in {-60,-30,...,240}{ -\foreach \t [count=\i from 0] in {240,210,...,-60}{ -\path [name path=\t]($(#1)$)--++(\t:8.2mm); -\path [name intersections={of=arcc and \t,by={\t1}}]; -\draw [line cap=round, line width=0.2](\t1)--++(\t:0.5mm); -\path (\t1)--++(\t:1.5mm)node{\scalebox{0.5}{$\i$}}; -} -} - -\begin{tikzpicture}[>=stealth'] - \node[draw=black,minimum height=1cm] (arm) {ARM}; - \node[draw=black, below of=arm,minimum width=1.5cm, yshift=-0.4cm] (ip) {Faust IP}; - \node[draw=black,left of=arm, xshift=-0.5cm,rounded rectangle](type){\tiny HW/SW ?}; - \node[draw=black, fit=(arm)(ip)(type),minimum height=1.5cm,minimum width=1.5cm][thick] (zybo) {}; - - \node[draw=black,yshift=1cm,xshift=-0.5cm,minimum width=2.5cm,minimum height=1cm,left=of zybo,label={[xshift=-0.5cm,yshift=-0.1cm]\tiny Controller Board}] (interfBoard) {}; - \knob{$(interfBoard)+(-0.5cm,0cm)$}; - \knob{$(interfBoard)+(0.5cm,0cm)$}; - \node[draw=black,inner sep=0pt,minimum width=2.5cm,minimum height=1.5cm,below of=interfBoard, yshift=-0.7cm,label={[xshift=-0.8cm,yshift=-0.1cm]\tiny Host PC}] (hostPC) {\includegraphics[width=2.5cm]{gtkUI.png}}; - - \node[right of=hostPC,yshift=0.15cm,xshift=1cm] (uart) {\tiny UART/USB}; - \node[right of=interfBoard,yshift=0.15cm,xshift=0.6cm] (spi) {\tiny SPI}; - - - \draw[<-][thick] (ip) -- node[right]{\footnotesize s-AXI} (arm); - \draw[->][thick] (type) -- (arm); - \draw[->][thick] (hostPC) --++(100pt,0pt) --++(0pt,30pt); - \draw[->][thick] (interfBoard) --++(100pt,0pt) --++(0pt,-6pt); - -\end{tikzpicture} - diff --git a/doc/syfala-getting-started-src/fig/popophone.jpg b/doc/syfala-getting-started-src/fig/popophone.jpg deleted file mode 100644 index a649496..0000000 Binary files a/doc/syfala-getting-started-src/fig/popophone.jpg and /dev/null differ diff --git a/doc/syfala-getting-started-src/fig/sinewave-biquad-inlined.cpp b/doc/syfala-getting-started-src/fig/sinewave-biquad-inlined.cpp deleted file mode 100644 index 0995e6e..0000000 --- a/doc/syfala-getting-started-src/fig/sinewave-biquad-inlined.cpp +++ /dev/null @@ -1,49 +0,0 @@ -[...] -typedef struct { - int fSampleRate; - float fConst0; - FAUSTFLOAT fHslider0; - int IOTA0; - int iVec0[2]; - float fRec0[2]; - float fRec1[2]; -} mydsp; -[....] -void instanceConstantsFromMemmydsp(mydsp* dsp, int sample_rate, int* iZone, float* fZone) { - dsp->fSampleRate = sample_rate; - dsp->fConst0 = fZone[0]; -} -[....] -void computemydsp(mydsp* dsp, FAUSTFLOAT* inputs, - FAUSTFLOAT* outputs, int* iControl, float* fControl, - int* iZone, float* fZone) { - dsp->iVec0[(dsp->IOTA0 & 1)] = 1; - float fTemp0 = dsp->fRec1[((dsp->IOTA0 - 1) & 1)]; - float fTemp1 = dsp->fRec0[((dsp->IOTA0 - 1) & 1)]; - dsp->fRec0[(dsp->IOTA0 & 1)] = ((fControl[1]*fTemp0) + - (fControl[2] * fTemp1)); - dsp->fRec1[(dsp->IOTA0 & 1)] = (((float)(1 - - dsp->iVec0[((dsp->IOTA0 - 1) & 1)]) + (fControl[2] * - fTemp0)) - (fControl[1] * fTemp1)); - float fTemp2 = dsp->fRec1[((dsp->IOTA0 - 0) & 1)]; - outputs[0] = (FAUSTFLOAT)fTemp2; - outputs[1] = (FAUSTFLOAT)fTemp2; - dsp->IOTA0 = (dsp->IOTA0 + 1); -} -[....] -/* body of syfala() function */ -if (enable_RAM_access) { - if (cpt==0) { - /* first iteration: constant initialization */ - cpt++: - instanceConstantsFromMemmydsp(&DSP,SAMPLE_RATE,I_ZONE,F_ZONE); - } - else - { - /* all other iterations: compute one sample */ - - computemydsp(&DSP, inputs, outputs, icontrol, fcontrol, I_ZONE, F_ZONE); - - } - } -[...] diff --git a/doc/syfala-getting-started-src/fig/sinewave-biquad-inlined.dsp b/doc/syfala-getting-started-src/fig/sinewave-biquad-inlined.dsp deleted file mode 100644 index 71a5a23..0000000 --- a/doc/syfala-getting-started-src/fig/sinewave-biquad-inlined.dsp +++ /dev/null @@ -1,15 +0,0 @@ -import("stdfaust.lib"); - -freq = hslider("freq [knob:1]",440,50,1000,0.01); -nlf2(f,r,x) = ((_<:_,_),(_<:_,_) : - (*(s),*(c),*(c),*(0-s)) :> - (*(r),+(x))) ~ cross -with { - th = 2*ma.PI*f/ma.SR; - c = cos(th); - s = sin(th); - cross = _,_ <: !,_,_,!; -}; - -impulse = 1-1'; -process = impulse : nlf2(freq,1) : !,_ <: _,_; diff --git a/doc/syfala-getting-started-src/fig/ultrascale_MPSOC.png b/doc/syfala-getting-started-src/fig/ultrascale_MPSOC.png deleted file mode 100644 index d4a3618..0000000 Binary files a/doc/syfala-getting-started-src/fig/ultrascale_MPSOC.png and /dev/null differ diff --git a/doc/syfala-getting-started-src/fig/zynq-mp-core-dual1.png b/doc/syfala-getting-started-src/fig/zynq-mp-core-dual1.png deleted file mode 100644 index 077c9db..0000000 Binary files a/doc/syfala-getting-started-src/fig/zynq-mp-core-dual1.png and /dev/null differ diff --git a/doc/syfala-getting-started-src/known-bugs.tex b/doc/syfala-getting-started-src/known-bugs.tex deleted file mode 100644 index 0430fe6..0000000 --- a/doc/syfala-getting-started-src/known-bugs.tex +++ /dev/null @@ -1,100 +0,0 @@ -\section{Known bugs: Important ``tricks'' to be known!!} -\label{bug} - -This section regroups all the tricks that can result in unlimited waste of time if not known. These {\em known bugs} have been kept as they have been initially written, even if some of them do not occur anymore in more recent tool version. - -\subsection{Locale setting on linux} -\label{localSetting} -\knownbug{it is a known bug that {\tt vivado} is sensible to the ``locale'' environment variable on linux, hence you have to set these variables in your {\tt .bashrc} file:\\ -\tt export LC\_ALL=en\_US.UTF-8\\ -export LC\_NUMERIC=en\_US.UTF-8 -} - -If you do not, you might end up with unpredictible behaviour of Vivado. - -\subsection{Patch 2022 date bug} -\label{2k22patch} -\knownbug{Vivado and Vitis tools that use HLS in the background are also affected by this issue. HLS tools set the ip\_version in the format YYMMDDHHMM and this value is accessed as a signed integer (32-bit) that causes an overflow and generates the errors below (or something similar).} - -Follow this link: \url{https://support.xilinx.com/s/article/76960?language=en_US} - -Download the file at the bottom of the page and unzip it in your Xilinx base install directory (Xilinx file where you have your Vitis,Vitis\_HLS and Vivado files). - -DONT FOLLOW THE README... Just check the "Known Issues:" section on the Xilinx page which takes over the readme. - -From the Xilinx directory, run: -\begin{itemize} -\item export LD\_LIBRARY\_PATH=\$PWD/Vivado/2020.2/tps/lnx64/python-3.8.3/lib/ -\item Vivado/2020.2/tps/lnx64/python-3.8.3/bin/python3 y2k22\_patch/patch.py -\end{itemize} - -\subsection{Save the Vivado Install file in case of installation failure} -\label{installSave} - -Vivado installation tends to fail. To avoid having to redownload the installation file each time you try , we suggest to use the “ Download Image (Install Separately)” option. It creates a directory with a xsetup file to execute for installing. But don't forget to duplicate the installation file, because Vivado will delete the xsetup installation file you use if you choose to let him delete all files after the installation failed. -%Oui alors c'est pas clair.... -\subsection{Vivado Installation stuck at "final processing: Generating installed device list"} -If the install of Vivado is stuck at "final processing: Generating installed device list", cancel it and install the libncurses5 lib: -\begin{verbatim} -sudo apt install libncurses5 -\end{verbatim} - -\subsection{Installing Vivado Board Files for Digilent Boards} -\label{boardfiles} -It is necessary, once Vivado install, to add support for new digilent board. -the content of directory {\tt board\_files } has to be copied in \verb#$vivado/2019.2/data/boards/board_files# -(see \begin{verbatim}https://reference.digilentinc.com/learn/programmable-logic/tutorials/\ - zybo-getting-started-with-zynq/start?redirect=1# -\end{verbatim} - -Or directly here: \url{https://github.com/Digilent/vivado-boards} - -\subsection{Cable drivers (Linux only)} -For the Board to be recognized by the Linux system, it is necessary to install additional drivers. See \url{https://digilent.com/reference/programmable-logic/guides/install-cable-drivers} - - -\subsection{Digilent driver for linux} -On some linux install, programming the Zybo board will need to install an additionnal ``driver'': Adept2 \url{https://reference.digilentinc.com/reference/software/adept/start?redirect=1#software_downloads} - -\subsection{Vitis installation} -{\bf Warning} Apparently the installation process does not end correctly if the {\tt libtinfo-dev} package is not correctly installed (\url{https://forums.xilinx.com/t5/Installation-and-Licensing/Installation-of-Vivado-2020-2-on-Ubuntu-20-04/td-p/1185285}. In case of doubt, execute these commands (april 2020): -\begin{verbatim} -sudo apt update -sudo apt install libtinfo-dev -sudo ln -s /lib/x86_64-linux-gnu/libtinfo.so.6 /lib/x86_64-linux-gnu/libtinfo.so.5 -\end{verbatim} - -\subsection{"'sys/cdefs.h' file not found" during vitis\_HLS compilation} -If Vitis HLS synthesis fails with the following error: -\begin{verbatim} -'sys/cdefs.h' file not found: /usr/include/features.h -\end{verbatim} -You have to install the g++-multilib lib -\begin{verbatim} -sudo apt-get install g++-multilib -\end{verbatim} - -\subsection{Board files: version 1.0 or 1.1?} -Digilent updated his board file repository (mentioned above in section~\ref{boardfiles}) and unfortunately changes the version of the board from 1.0 to 1.1. This change must be reverted because it is not taken into account in past version of vivado. - -It you have a message like: -\begin{verbatim} -source /home/romain/reps/syfala/build/sources/project.tcl -notrace -ERROR: [Board 49-71] The board_part definition was not found for - digilentinc.com:zybo-z7-10:part0:1.0. The project's board_part property was - not set, but the project's part property was set to xc7z010clg400-1. - Valid board_part values can be retrieved with the 'get_board_parts' - Tcl command. Check if board.repoPaths parameter is set and the board_part - is installed from the tcl app store. -\end{verbatim} - -You should do the following: -\begin{itemize} - \item - go into directory:\\ - {\tt Vivado/2020.2/data/boards/board\_files/zybo-z7-10/A.0} -\item Edit the file {\tt 'board.xml'} - and change\\ - {\tt 1.1}\\ into\\ {\tt 1.0} -\item (Same thing for Z20 if you use Z20). -\end{itemize} diff --git a/doc/syfala-getting-started-src/sin-example.tex b/doc/syfala-getting-started-src/sin-example.tex deleted file mode 100644 index f79365e..0000000 --- a/doc/syfala-getting-started-src/sin-example.tex +++ /dev/null @@ -1,168 +0,0 @@ -\label{example} -\label{sec:example} -Imagine we want to implement on FPGA a filter-based sine wave oscillator. Such a sine wave is written in Faust in Fig.~\ref{fig:osc}, it is available in Syfala repository as program {\tt sinewave-biquad-inlined.dsp} of the {\tt examples} directory. There is one controller which selects the oscillator frequency. Note the {\tt ``[knob:1]''} meta data that indicates that this controller will be associated to the first knob in case of hardware interface. - -The computation of {\tt th}, {\tt c} and {\tt s} are depending on the frequency value, hence we expect all these variables to be computed at control rate, hence on the ARM, not on the FPGA. On the other hand, the computation of {\tt nlf2} is performed at each sample (sample rate) and will be implemented on the FPGA. - - -\begin{figure}[ht] - \begin{boxedminipage}{\columnwidth} - \tiny - \verbatiminput{fig/sinewave-biquad-inlined.dsp} - \end{boxedminipage} - \caption{Filter-based sine wave oscillator in Faust used for illustrating the compilation process (file {\tt sinewave-biquad-inlined.dsp} in {\tt examples} directory).} - \label{fig:osc} - \label{fig:biquad} -\end{figure} - -The whole compilation can be done using the command:\\ -{\tt syfala examples/sinewave-biquad-inlined.dsp}\\ -but we will detail the different steps. - -The first step of the compilation flow is to generate a C++ program from the Faust code, this is done by executing:\\ -\verb#syfala examples/sinewave-biquad-inlined.dsp --arch --reset# \\ -this command will generate {\tt syfala\_ip.cpp} and {\tt syfala\_application.cpp} files. All the generated files are generated in the directory {\tt build/}. The \verb#--reset# options is mandatory if another project has already been compiled in the {\tt build} directory. Warning, the \verb#--reset# option will erase your previous compiled Syfala project. - -The \verb#--arch# option generates the {\tt syfala\_ip.cpp} file in directory {\tt build/syfala\_ip/} and the {\tt syfala\_application.cpp} file in {\tt build/syfala\_application/}. Note that a file {\tt build/include/syconfig.hpp} is also created in which the parameters of the current design flow are saved (sample rate, board used, hard or software controller, etc.). From now on the {\tt build/sinewave-biquad-inlined.dsp} will be the default DSP program syfala is working on, hence the name of the {\tt .dsp} file do not have to be recalled at each syfala command.\\ -~\\ -\begin{boxedminipage}{1.03\textwidth} - \small -\begin{verbatim} -syfala-github$ syfala examples/sinewave-biquad-inlined.dsp --arch --reset -[ INFO ] Running syfala toolchain script (v7) on Linux (5.4.0-126-generic) -[...] -[ INFO ] Generating Faust IP from Faust compiler & architecture file -[ OK ] Generated /home/trisset/technical/syfala-github2/build/\ - syfala_ip/syfala_ip.cpp -[ ... ] -[ OK ] Generated /home/trisset/technical/syfala-github2/build/\ - syfala_application/syfala_application.cpp -[ ... ] -[ INFO ] Script has been running for 00 minutes and 00 seconds -[ OK ] Successful run! -\end{verbatim} -\end{boxedminipage} -~\\ - -\begin{figure}[ht] - \begin{boxedminipage}{\columnwidth} - \tiny - \verbatiminput{fig/sinewave-biquad-inlined.cpp} - \end{boxedminipage} - \caption{Excerpt of {\tt syfala\_ip.cpp} C++ code generated by the Faust compiler from the Faust code presented on Fig.~\ref{fig:biquad} when tuned for the FPGA target.} - \label{fig:oscCode} - \label{fig:biquadCode} -\end{figure} - -An excerpt of file {\tt syfala\_ip.cpp} is shown on Fig.~\ref{fig:oscCode}. One can first notice the structure {\tt mydsp} that is built for this example, the output samples are computed by the {\tt computemydsp()} function. In this example, as the memory used is small, all variables are stored in Block Rams, hence declared here, in {\tt syfala\_ip.cpp}. By looking at the body of the {\tt syfala() function} (i.e. the ``main'' syfala IP function), one can see that, at the very beginning, the function {\tt instanceConstantsFromMemmydsp()} is executed (it copies the initialized constant {\tt fconst0} on the FPGA), then the {\tt computemydsp} is executed for all other samples. {\tt fRec} names are usually used for delay lines, the IOTA is used to implement delay line by circular buffers. - -The second step of the compilation flow is to synthesize the Faust IP from the {\tt syfala\_ip.cpp} using {\tt vitis\_hls}, this is done by typing \verb#syfala --ip#. -The IP is generated in directory {\tt build/syfala\_ip/syfala}. The report of the HLS, indicating the size of the resulting IP and execution time in terms of FPGA cycles can be seen by typing {\tt syfala report}. -The execution time of the HLS is approximately 1 mn.\\ -~\\ -\begin{boxedminipage}{\textwidth} - \small -\begin{verbatim} -syfala-github> syfala --ip -[ INFO ] Running syfala toolchain script (v7) on Linux (5.4.0-126-generic) -[....] -[ INFO ] Running Vitis HLS on file [...]/syfala-github/scripts/hls.tcl -****** Vitis HLS - High-Level Synthesis from C, C++ and OpenCL v2020.2 (64-bit) -[...] - -[ INFO ] Script has been running for 00 minutes and 43 seconds -[ OK ] Successful run! -syfala-github> -\end{verbatim} -\end{boxedminipage} -~\\ - -The next step is to synthesize the whole design that includes the Faust IP. For that, we need to build the bloc design. Usually, it's done a first time with the Vivado GUI and can be exported in .tcl or .vhd "Bloc Design" file to script the synthesis of the project. But we choose to write a script called {\tt syfala\_maker.tcl} that will directly generate this "Bloc Design" file. The advantage is that the bloc design can be dynamically changed. For example, it allow us to change the number of I2S channels on the transceiver and adapt the number of used GPIO and the internal routing just with a macro. We couldn't do such a thing with a fixed block design file. - -Then, the synthesize of the project is done by executing \verb#syfala --project# and then \verb#syfala --syn#. The first command builds the {\tt syfala\_project.xpr} vivado project from the TCL files. The second command loads and then executes the {\tt syfala\_project.xpr} project in vivado to produce the bitstream. As a result, a file {\tt main\_wrapper.xsa} is generated in {\tt build/hw\_export} directory, it corresponds to an archive containing both the FPGA bitstream and configuration of the {\em processing system} (i.e. the ARM subsystem). One important point here is that the {\tt syfala\_project.xpr} can be opened directly with Vivado 2020.2 GUI (by executing \verb#syfala --open-project#) and modified and re-synthesized. This can be useful for exploring other block designs (other parameters for the Faust IP for instance). The \verb#syfala --export# command allows you to save all generated files in an {\tt export} directory in order not to loose them when executing a command with \verb#--reset# option.\\ - -\begin{boxedminipage}{\textwidth} - \small -\begin{verbatim} -syfala-github$ syfala --project -[ INFO ] Running syfala toolchain script (v7) on Linux (5.4.0-126-generic) -[...] -[ INFO ] Running Vivado on file /home/trisset/technical/syfala-github2/build/ - sources/project.tcl -****** Vivado v2020.2 (64-bit) -[...] -[ INFO ] Script has been running for 00 minutes and 26 seconds -[ OK ] Successful run! - -syfala-github$ syfala --syn -[ INFO ] Running syfala toolchain script (v7) on Linux (5.4.0-126-generic) -[...][ INFO ] Running Vivado on file /home/trisset/technical/syfala-github2/ - scripts/synthesis.tcl -****** Vivado v2020.2 (64-bit) -[...] -Waiting for synth_1 to finish... -[...] -[ INFO ] Script has been running for 08 minutes and 58 seconds -[ OK ] Successful run! -syfala-github> -\end{verbatim} -\end{boxedminipage} -~\\ - -Then you have to compile the application file that will run on the ARM processor. This application file has been generated by the Faust compiler at the first step (i.e. \verb#--arch# option). It uses the {\tt arm.cpp} architecture file as main file. Its re-uses many software components developed for the Faust ecosystem and uses also the drivers provided by Xilinx in {\tt vivado}. Then the {\tt application.tcl} script is executed with {\tt xsct} (Xilinx Software Command-line Tool) which is an an interactive and scriptable command-line interface to Xilinx {\tt vitis} (formerly Xilinx SDK). - -~\\ -\begin{boxedminipage}{1.01\textwidth} - \small -\begin{lstlisting} -syfala-github> syfala --app -[ INFO ] Running syfala toolchain script (v7) on Linux (5.4.0-126-generic) -[...] -[ INFO ] Compiling Host control application -make -C ps7_cortexa9_0/libsrc/xilffs_v4_4/src -s include "SHELL=/bin/sh" "COMPILER=arm-none-eabi-gcc" - "ASSEMBLER=arm-none-eabi-as" "ARCHIVER=arm-none-eabi-ar" "COMPILER_FLAGS= -O2 -c" - "EXTRA_COMPILER_FLAGS=-mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard -nostartfiles -g -Wall -Wextra" -[...] -5:11:05 Build Finished (took 1s.713ms) -Finished building projects -[ OK ] Finished building host application -[ OK ] Copied application sources and .elf output to sw_export directory -[ INFO ] Script has been running for 00 minutes and 43 seconds -[ OK ] Successful run! -[ OK ] To see the build's full log: open 'syfala_log.txt' in the repository's - root directory -syfala-github> -\end{lstlisting} -\end{boxedminipage} -~\\ - -An excerpt of file {\tt syfala\_application.cpp} is shown on Fig.~\ref{fig:oscARM}. One can see that the {\tt mydsp} class private fields are exactly the same as the structure {\tt mydsp} of the Faust IP (Fig.~\ref{fig:oscCode}). This allow us to have coherent view of the IP, either from inside the FPGA or from the ARM processor. - -\begin{figure}[ht] - \begin{boxedminipage}{\columnwidth} - \tiny - \verbatiminput{fig/faust_v6_app.cpp} - \end{boxedminipage} - \caption{Excerpt of C++ code generated by the Faust compiler from the Faust code presented on Fig.~\ref{fig:biquad} when tuned for the ARM application target.} - \label{fig:oscARM} -\end{figure} - - -One can see that the {\tt control} method of {\tt mydsp} on the ARM processor (Fig.~\ref{fig:oscARM}) corresponds to the computations of variables {\tt th}, {\tt c} and {\tt s} of the Faust program of Fig.~\ref{fig:osc}. As we expected, the control rate computations are executed on the ARM. Then the structure {\tt ARMcontroller} defines the functions {\tt sendControlToFPGA()} and {\tt controlFPGA()}. - -The function {\tt sendControlToFPGA()} is using Xilinx driver functions for accessing {\tt s-axilite} port of the Faust IP (here {\tt fControl} and {\tt iControl} ports). The function {\tt controlFPGA()} will first call {\tt \verb#fDSP->control()#} in order to get new values of the controllers from the hardware or software user interface, then it will call {\tt sendControlFPGA()} to send these values to the Faust IP. {\tt sendControlFPGA()} uses the API provided by Xilinx to communicate between the ARM and the FPGA IP (\verb#XSyfala_Write_ARM[...]()# functions) - -\begin{figure}[ht] - \begin{boxedminipage}{\columnwidth} - \tiny - \verbatiminput{fig/faust_v6_app2.cpp} - \end{boxedminipage} - \caption{Excerpt of C++ code generated by the Faust compiler from the Faust code presented on Fig.~\ref{fig:biquad} when tuned for the ARM application target.} - \label{fig:oscARM2} -\end{figure} - -Finally, the generated program can be transferred to the FPGA board with the \verb#syfala --flash# command (the Zybo board has to be plugged on a USB port of course, and a headphone should be used to hear the sounds). The control GUI is compiled with the \verb#syfala --gui# command, and then executed with \verb#syfala gui#. Once flashed, the {\tt syfala\_application} is launched automatically on the ARM and the bitstream is executing. The ARM has to boot first, so the {\tt enable\_RAM\_access} port (see figure~\ref{fig:body}) is used to indicate that the Syfala IP can start its computations. - - - - diff --git a/doc/syfala-getting-started-src/sinewave-biquad-inlined.cpp b/doc/syfala-getting-started-src/sinewave-biquad-inlined.cpp deleted file mode 100644 index 6cb2127..0000000 --- a/doc/syfala-getting-started-src/sinewave-biquad-inlined.cpp +++ /dev/null @@ -1,25 +0,0 @@ -[....] -void controlmydsp(mydsp* dsp, int* iControl, float* fControl, - int* iZone, float* fZone) { - fControl[0] = (dsp->fConst0 * (float)dsp->fHslider0); - fControl[1] = sinf(fControl[0]); - fControl[2] = cosf(fControl[0]); -} -[....] -void computemydsp(mydsp* dsp, FAUSTFLOAT* inputs, - FAUSTFLOAT* outputs, int* iControl, float* fControl, - int* iZone, float* fZone) { - dsp->iVec0[(dsp->IOTA0 & 1)] = 1; - float fTemp0 = dsp->fRec1[((dsp->IOTA0 - 1) & 1)]; - float fTemp1 = dsp->fRec0[((dsp->IOTA0 - 1) & 1)]; - dsp->fRec0[(dsp->IOTA0 & 1)] = ((fControl[1]*fTemp0) + - (fControl[2] * fTemp1)); - dsp->fRec1[(dsp->IOTA0 & 1)] = (((float)(1 - - dsp->iVec0[((dsp->IOTA0 - 1) & 1)]) + (fControl[2] * - fTemp0)) - (fControl[1] * fTemp1)); - float fTemp2 = dsp->fRec1[((dsp->IOTA0 - 0) & 1)]; - outputs[0] = (FAUSTFLOAT)fTemp2; - outputs[1] = (FAUSTFLOAT)fTemp2; - dsp->IOTA0 = (dsp->IOTA0 + 1); -} -[....] diff --git a/doc/syfala-getting-started-src/syfala-objectives.tex b/doc/syfala-getting-started-src/syfala-objectives.tex deleted file mode 100644 index a856c0b..0000000 --- a/doc/syfala-getting-started-src/syfala-objectives.tex +++ /dev/null @@ -1,17 +0,0 @@ -\section{The \syfala team objectives} -The \syfala project ({\em Synthetiseur Faible Latence pour FPGA}) has started as a FIL project, it will probably continue for a while. This docment explains the technical choices that have been made on the first versions of the \syfala toolchain. - -The \syfala toolchain is a compilation toolchain of Faust program on FPGA (currently Xilinx Zynq present on Zybo-Z7-10 board). The installation of the toolchain itself is explained in Annex here (from p~\pageref{Annex1}). - -The objective is to compile Faust\footnote{\url{https://faust.grame.fr/}} programs on a FPGA platform with the objective of obtaining a short latency between input and output of the signal. - -Audio signal is sampled at (say) 48kHz. Hence one audio sample (i.e. one on each channel, two channels for stereo audio) arrives roughly every $2.083 \times 10^{-5}$ seconds, hence approximately every 20$\mu s$. In general it is considered that the latency (i.e. the time between the input of a sample and its effect on output) cannot go below 1 sample delay (i.e. 20$\mu s$). Our current syfala version is able to reach a latency of 191 $\mu s$ with the intergrated Analog Device SSM2603 codec and a latency 11.1 $\mu s$ with a more efficient codec (Analog Device ADAU 1787). - -%% When performing audio processing with a software system, such as on Linux OS, the sound processing is performed by the audio driver which handles the samples coming from the audio codec. The typical application on these systems will play music files or apply an effect on a stream. Ultra-low latency is usually not a problem on this kind of software, but efficiency is. Efficiency is needed for audio real time (computing at least on sample every 20$\mu s$) and for having as few CPU cycles as possible, as audio processing is usually sharing the CPU resources with many other tasks. - -%% For efficiency reason, all audio drivers are using buffers to communicate with the audio codec, it means that one driver activation will compute a bunch of samples, usually 64 or more. If a buffer of 64 samples is used, the latency is at least $1.3m s$ (i.e roughly 64*20$\mu s$), then one have to add the time for interruption handling and audio processing itself. This latency has to be added to the codec latency itself (which usually can be configured, but is not negligible), which makes software solution inaplicable for low latency applications. - -%% Using and FPGA to realize audio processing would take advantage of $(i)$ high computing power (parallelism can be quite high on a FPGA circuit), and more important $(ii)$ low latency (as samples are directly coming from/going to audio codec to/from the FPGA circuit). - -Few examples of professional FPGA-based real-time audio DSP systems (i.e., Antelope Audio,\footnote{\url{https://en.antelopeaudio.com}} Korora Audio,\footnote{\url{https://www.kororaaudio.com}} etc.) and in these applications, FPGAs are dedicated to a specific task, limiting creativity and flexibility. Moreover, these designs where realized ``by hand'' i.e. by register transfer level design (in VHDL or Verilog) of the realized circuits. The idea of the \syfala project is to {\em compile} an FPGA configuration from a Faust audio processing specification. This is made possible by {\em High Level synthesis} (HLS) which is a compilation flow that transforms a software code (usually based on C-like syntax) into a HDL representation that can be further compiled with classical FPGA programming suites. The most well known HLS tools are {\tt vivadoHLS} (from {\tt Xilinx}), {\tt C2H} (from {\tt Altera}), {\tt CatapultC} (from {\tt Mentor Graphics}), but other tools are proposed today to bridge the gap between algorithmic representation and hardware level representation of a computation\footnote{See~\url{https://en.wikipedia.org/wiki/High-level_synthesis} for instance}. -This project has been launched by the Emeraude team\footnote{\url{https://team.inria.fr/emeraude/admin}} which is a collaboration between Grame research department\footnote{\url{https://www.grame.fr/recherche}} and Citi laboratory. diff --git a/doc/syfala-getting-started-src/syfala-team.tex b/doc/syfala-getting-started-src/syfala-team.tex deleted file mode 100644 index b45be22..0000000 --- a/doc/syfala-getting-started-src/syfala-team.tex +++ /dev/null @@ -1,22 +0,0 @@ -\section{The syfala team} -\label{team} -Here is a list of person that have contributed to the Syfala project: -\begin{itemize} -\item Tanguy Risset -\item Yann Orlarey -\item Romain Michon -\item Stephane Letz -\item Florent de Dinechin -\item Alain Darte -\item Yohan Uguen -\item Gero Müller -\item Adeyemi Gbadamosi -\item Ousmane Touat -\item Luc Forget -\item Antonin Dudermel -\item Maxime Popoff -\item Thomas Delmas -\item Oussama Bouksim -\item Pierre Cochard -\end{itemize} - diff --git a/doc/syfala-getting-started-src/syfala.bib b/doc/syfala-getting-started-src/syfala.bib deleted file mode 100644 index be4da7c..0000000 --- a/doc/syfala-getting-started-src/syfala.bib +++ /dev/null @@ -1,50 +0,0 @@ - -@inproceedings{SMC22, - TITLE = {{Faust2FPGA for Ultra-Low Audio Latency: Preliminary work in the Syfala project}}, - AUTHOR = {Risset, Tanguy and Michon, Romain and Orlarey, Yann and Letz, St{\'e}phane and M{\"u}ller, Gero and Gbadamosi, Adeyemi}, - URL = {https://hal.inria.fr/hal-03116958}, - BOOKTITLE = {{IFC 2020 - Second International Faust ConferenceInternationnal Faust Conference}}, - ADDRESS = {Paris, France}, - PAGES = {1-9}, - YEAR = {2020}, - MONTH = Dec, - PDF = {https://hal.inria.fr/hal-03116958/file/IFC-20.pdf}, - HAL_ID = {hal-03116958}, - HAL_VERSION = {v1}, -} - -@misc{syfala, - title = {Syfala Git Site}, - howpublished = {\url{https://gitlab.inria.fr/risset/syfala}} -} -@misc{faust, - title = {faust Git Site}, - howpublished = {\url{https://github.com/grame-cncm/faust}} -} -@misc{vivado, - title = {vivado Download site}, - howpublished = {\url{https://www.xilinx.com/support/download.html}} -} - -@misc{adeyemi, - title = {Low latency audio processing on FPGA by high level synthesis}, - author = {Adeyemi Gbadamosi}, - howpublished = {University of Burgundy, Master's Thesis}, - date=2019, -} - - -@misc{ssm2603, - title = {Low Power Audio Codec SSM2603 Data Sheet}, - author = {Analog Devices}, - howpublished = {\url{https://www.analog.com/en/products/ssm2603.html}}, - date=2019 -} - -@inproceedings{Risset20, - author = {T. Risset and R. Michon and Y. Orlarey and S. Letz and G. Müller and A. Gbadamosi}, - title = {faust2fpga for Ultra-Low Audio Latency: Preliminary Work in the SyFaLa Project}, - booktitle = {Proceedings of the International Faust Conference (IFC-20)}, - address={Paris (France)}, - year = {2020} -} diff --git a/doc/syfala-getting-started-src/user-getting-started-doc.tex b/doc/syfala-getting-started-src/user-getting-started-doc.tex deleted file mode 100644 index 0706b66..0000000 --- a/doc/syfala-getting-started-src/user-getting-started-doc.tex +++ /dev/null @@ -1,78 +0,0 @@ -\documentclass[11pt]{article} - -\usepackage[utf8]{inputenc} -\usepackage[T1]{fontenc} -\usepackage[francais]{babel} -\usepackage{eurosym} -\usepackage{lmodern} -\usepackage{boxedminipage} -\usepackage{microtype} -\usepackage{listings} -\lstset{ -basicstyle=\small\ttfamily, -columns=flexible, -breaklines=true -} - -\usepackage[colorlinks,linkcolor=blue,citecolor=blue,pagebackref]{hyperref} -\usepackage{amsmath,amssymb,amsfonts,mathrsfs} -\usepackage[usenames,dvipsnames]{color} -\usepackage{float} -\usepackage{graphicx} -\usepackage{multirow} -\usepackage{pgfgantt} -\usepackage{multicol} -\usepackage{wrapfig,lipsum,booktabs} - -%----------------------------------------------------------------------- -\usepackage[ -text={15cm,21cm}, -centering, -% showframe, -]{geometry} - -\numberwithin{equation}{section} -\numberwithin{figure}{section} -%\renewcommand{\theequation}{\thesection.\arabic{equation}} -%\renewcommand{\thetable}{\thesection.\arabic{table}} - -%----------------------------------------------------------------------- -% The following macros determine the part of the text that will actually -% be compiled. When the paper is completed, set all the macros to 0. - -\def\withtoc{0} - % "with table of contents (TOC)" - % 0: without TOC - % 1: with TOC - -%----------------------------------------------------------------------- - -\newcommand{\CAD}{c.-\`a-d.} -\newcommand{\PEX}{p.\,ex.} -\newcommand{\tocvspace}{-2.0ex} -\usepackage{xspace} -\newcommand{\syfala}{{Syfala}\xspace} - -%----------------------------------------------------------------------- - - -\newcommand{\tcb}{\textcolor{blue}} -\newcommand{\tcg}{\textcolor{OliveGreen}} -\newcommand{\red}{\textcolor{red}} - -\newcommand{\knownbug}[1]{{ #1}} - -\newcommand{\adtname}{SytaRiot} - -%----------------------------------------------------------------------- -\title{\Large\bf Syfala project: how to install and run Syfala toolchain on Linux} -\author{The Syfala Team} -\date{\today} -\begin{document} -\maketitle - -\input{body-install-toolchain.tex} -\bibliographystyle{alpha} -\bibliography{syfala} - -\end{document} diff --git a/doc/tutorials/cpp-tutorial-advanced.md b/doc/tutorials/cpp-tutorial-advanced.md deleted file mode 100644 index 569db96..0000000 --- a/doc/tutorials/cpp-tutorial-advanced.md +++ /dev/null @@ -1,849 +0,0 @@ -# Using syfala with C++ - -## Introduction - -While Faust is undoubtedly a nice and easy way to create complex and fully-controllable DSP programs on FPGAs, in some cases - where for instance balancing resource usage and latency becomes a critical issue - bypassing Faust and programming directly in C++ can become a more suitable solution. - -#### How does it work? - -Ordinarily, the easiest way to get started with *syfala* is to use *Faust* to generate the C++ code that is going to be fed to the **High Level Synthesis** (**HLS**) tool and turned into **Hardware Description Language** (HDL) code. The resulting DSP *kernel* (or *IP*: Intellectual Property) is then going to be added to a more global *design*, which will include the **processing system** (PS), our custom-made **Integrated Interchip Sound** (*i²s*) and various other modules as well. - -Consequently - and since we're already using *HLS* - programming the DSP *kernel* directly in C++ is entirely possible, but remains a more complex solution, and won't offer the same user-friendly features that Faust is able to provide out-of-the-box. - -#### Pros: - -- Better **balance control** between **FPGA resource usage** & **latency**. - - HLS-friendly/optimized code. - - HLS libraries, pragmas & tools. - - -#### Cons: - -- Limited support of C++ features (up to **C++14**). -- Complex HLS interfaces & documentation. -- **No out-of-the-box GUI/Serial** control interface. -- Data exchange with **ARM** through *AXI-Lite* or *DDR* memory has to be done manually. - -## Code structure - -The following describes how to program a syfala DSP *kernel* using C++. It is intended for advanced users. - -### Using pre-made examples - -To get an idea on how to program the DSP *kernel* in C++, you can refer to the `examples/cpp` directory in the **syfala** repository. - -For this tutorial, we will build a simple *stereo gain* DSP kernel. The interface that we propose is pretty straightforward, but there a couple of things that still need to be explained in details: - -### Signal types - -In the global syfala FPGA design, audio signals are conveyed as streams of **24-bits integers, by default**. The bit width can be changed using the `--sample-width` flag in the **syfala** command line interface, but cannot be changed to single or double precision floating point types. Since audio DSP programs are usually processing `float` or `double`-based signals, a few convenience functions and types have been added in the `syfala/utilities.hpp` header, which can be easily included in your C++ file: - -```c++ -#include -``` - -This header defines for instance the type `sy_ap_int`, as the following: - -```cpp -// include/syfala/utilities.hpp - -using sy_ap_int = ap_int; -// note: the 'ap_int' (arbitrary precision integer) type is defined by Vitis_HLS in $XILINX_ROOT_DIR/Vitis_HLS/2022.2/include/ap_int.h -``` - -It also defines the following **read/write convenience functions** between `sy_ap_int` and `float` types. These will come in handy when reading and writing from/to the audio input/output ports. - -```cpp -// include/syfala/utilities.hpp - -namespace Syfala::HLS { -/** - * @brief ioreadf Read sy_ap_int as float - * @param input sy_ap_int data input - * @return floating-point conversion of input - */ -float ioreadf(sy_ap_int const& input); -/** - * @brief iowritef write floating point data to ap_int - * top-level function output. - * @param f float data input - * @param output ap_int interface output. - */ -void iowritef(float f, sy_ap_int& output); -} -``` - -You should also be able, from this file, to access some useful *compile-time* data, such as the **current sample rate**, or **sample-width** which are defined with the following **macros**: - -```cpp -#define SYFALA_SAMPLE_RATE 48000 -#define SYFALA_SAMPLE_WIDTH 24 -``` - -### Audio inputs & outputs - -First, in order to generate the *block design* that is going to be synthesized by **Vivado** and make the proper connections with *i²s*, **syfala** needs to be **explicitly informed of the number of audio input/output** channels that the DSP program is going to have. In our case, for the *stereo gain* example, we want **2 inputs** and **2 outputs**. To do so, in the current version of **syfala**, the following C macros need to be defined somewhere in the code: - -```cpp -// examples/cpp/templates/gain.cpp -#define INPUTS 2 -#define OUTPUTS 2 -``` - -It will inform the toolchain to use the following **audio input and output ports**, which will be formatted like this in our final design: - -- `audio_in_#` (in our case, `audio_in_0` and `audio_in_1`) -- `audio_out_#` (in our case, `audio_out_0` and `audio_out_1`) - -### Top-level interface - -The *top-level function* is the DSP *kernel*'s' entrypoint, which, in the final *block design*, will be connected to other peripherals, such as the **i²s** and the **processing system**, with the help of various bus interfaces (AXI, AXI-Lite). - -Its **arguments** should be considered as a **list of input & output ports**, with: - -- **pointer** arguments being **output** arguments (or both *input* & *output* arguments) -- **non-pointer** arguments being **input** arguments only. -- **array** arguments can be both. - -It's **signature** should always be `void syfala(...)`: - -```cpp -// examples/cpp/templates/gain.cpp - -/* Top-level interface function */ -void syfala ( - // Audio input/output ports (variable): - sy_ap_int audio_in[INPUTS], - sy_ap_int audio_out[OUTPUTS], - // The following arguments are required and should not be changed: - int arm_ok, - bool* i2s_rst, - float* mem_zone_f, - int* mem_zone_i, - bool bypass, - bool mute, - bool debug -) { - [...] -``` - -Again, each **audio input & output arguments** have to be formatted exactly like the following: - -```cpp -void syfala ( - // Audio input/output ports (variable): - sy_ap_int audio_in[INPUTS], - sy_ap_int audio_out[OUTPUTS], -``` - -And have to be followed by **these exact same arguments** (which we will present in the next sections): - -```cpp - // The following arguments are required and their respective names should not be changed: - int arm_ok, - bool* i2s_rst, - float* mem_zone_f, - int* mem_zone_i, - bool bypass, - bool mute, - bool debug -) { - [...] -``` - -Below, the HLS interface **pragmas should also remain the same,** they're here to indicate to **Vitis HLS** two things: - -- to split the input/output audio arguments into **individual ports** (which will be named `audio_in_0`, `audio_in_1`, `audio_out_0`, `audio_out_1`) -- to map some of the top-level arguments to *AXI* and *AXI-Lite* bus interfaces (which will be further explained later). - -``` -#pragma HLS array_partition variable=audio_in type=complete -#pragma HLS array_partition variable=audio_out type=complete -#pragma HLS INTERFACE s_axilite port=arm_ok -#pragma HLS INTERFACE m_axi port=mem_zone_f latency=30 bundle=ram -#pragma HLS INTERFACE m_axi port=mem_zone_i latency=30 bundle=ram -``` - -### Initialization - -#### Waiting for ARM initialization - -Since the *DSP kernel* and the *ARM* are **not synchronized at a sample-rate level**, and the *ARM* has to first initialize a few peripherals (audio codecs, GPIOs, UART...) before being able to do anything else, it is necessary for the *DSP kernel* to wait for the `arm_ok` **signal** to be received before doing any initialization or processing. - -Once the *ARM* is ready, the initialization routine can be done manually with, for example, a static `initialization` variable. In our *stereo gain* example, we do: - -```cpp -static bool initialization = true; -[...] - /* Initialization and computations can start after the ARM - * has been initialized */ - if (arm_ok) { - /* First function call: initialization */ - if (initialization) { - // Initialize all runtime data here. - // don't forget to toggle the variable off - initialization = false; - } else { -``` - -### Bypass/mute switches - -In all standard **syfala designs**, the `bypass` and `mute` ports of a *DSP kernel* are pre-mapped to `SW0` and `SW1` in Zybo Z10/Z20 boards. You can choose to acknowledge and process them if you want: - -```cpp - } else { - /* Every other iterations: - * either process the bypass & mute switches... */ - if (bypass) { - audio_out[0] = audio_in[0]; - audio_out[1] = audio_in[1]; - } else if (mute) { - audio_out[0] = 0; - audio_out[1] = 0; - } else { -``` - -### DSP code - -Finally, here is an example of a *processing function* taking advantage of the `Syfala::HLS::ioreadf()` and `Syfala::HLS::iowritef()` convenience functions in order to switch back & forth between `float` and `sy_ap_int` types. - -```cpp - } else { - /* ... or compute samples here */ - compute(audio_in, audio_out); - } -``` - -For our *stereo gain* example, we first convert the input data to *float*, multiply it by `0.5f` and **write it back to the output ports**. - -```cpp -static void compute(sy_ap_int const inputs[], sy_ap_int outputs[]) -{ - // if you need to convert to float, use the following: - // (audio inputs and outputs are 24-bit integers by default) - float f0 = Syfala::HLS::ioreadf(inputs[0]) * 0.5f; - float f1 = Syfala::HLS::ioreadf(inputs[1]) * 0.5f; - Syfala::HLS::iowritef(f0, outputs[0]); - Syfala::HLS::iowritef(f1, outputs[1]); -} -``` - -## Building and flashing with the syfala CLI - -**syfala** works the same way with C++ targets, you'll only need to replace the Faust `.dsp` target with your `.cpp` file in the command line. We can now try to synthesize our *stereo gain DSP kernel*, in order to see if our code compiles: - -```shell -syfala examples/cpp/templates/gain.cpp --board Z20 --hls -``` - -Once the high-level synthesis is done, **syfala** should display the **Vitis HLS estimate** of the **kernel's latency and resource utilization**: - -``` -DSP 2% (6) -FF ~0% (997) -LUT 3% (2070) -BRAM 0% (0) - -Latency: -Tot. 47 Cycles 0.382us -``` - -## Verifying code with C simulation (CSIM) - -We know now that our code compiles, but we won't be able to test it until the full **Vivado synthesis** & **implementation** are done, which, depending on your machine, can take up some time. We'll then have to flash the device, connect an audio-input and a headset to the board, and see if the *stereo gain* in our example is properly applied. - -Needless to say, the process is a bit long and tedious. You don't really want to go through all of that too many times when you're debugging code, and that's precisely where **C simulation** (**CSIM**) comes into play. - -C simulation is an important Vitis HLS feature, which allows you to test your C-written kernel without having to get through the full synthesis process. In short: Vitis HLS *guarantees* (with a few exceptions) that the outputs of your kernel is going to be the same as they would be in a real context of execution. - -### Using pre-defined generic templates: - -Now, if we get back to our *stereo gain* example, and since it is a really simple one, we will take advantage of the generic **CSIM C++ template** that is available in the syfala source tree (located in `tests/csim/csim_cpp_template.cpp`). Here's an example of command that can be used: - -```shell -syfala examples/cpp/templates/gain.cpp --csim tests/csim/csim_cpp_template.cpp --csim-inputs tests/stimuli --csim-iter 64 -# output results will be stored in reports/csim/gain/out0.txt & reports/csim/gain/out1.txt -``` - -Where: - -- `--csim tests/csim/csim_cpp_template.cpp` - the simulation test file. -- `--csim-inputs tests/stimuli` - we specify using the `tests/stimuli` directory to fetch input samples. - - `tests/stimuli` contains two `.txt` files, named `in0.txt` and `in1.txt` and are filled with normalized (`-1.f` to `1.f`) floating point values. -- `--csim-iter 64` - the DSP kernel will be called 64 times (64 samples). - -We can finally verify the outputs of our *stereo gain* kernel, by comparing the input *stimuli* files with the output files (output samples should be `input/2`). - -### Writing your own CSIM - -While the generic template will work for simple *DSP kernels* that have the same top-level function signature, you will have to write your own CSIM file to validate kernels that have more complex interfaces. In order to do this, and since the generic template is scripted and a bit complicated to read, let's take inspiration from the `csim_cpp_template_gain.cpp` example file, and see what it is actually doing: - -- We first **declare the syfala top-level function prototype**, which is going to have the **exact same signature** as in our `gain.cpp` file. - -```cpp -// tests/csim/csim_cpp_template_gain.cpp - -void syfala ( - sy_ap_int audio_in[2], - sy_ap_int audio_out[2], - int arm_ok, - bool* i2s_rst, - float* mem_zone_f, - int* mem_zone_i, - bool bypass, - bool mute, - bool debug -); -``` - -- We then instantiate and pre-initialize **the values** that are going to be passed to the `syfala` **function arguments**: - -```cpp -sy_ap_int audio_in[2] = {0, 0}; -sy_ap_int audio_out[2] = {0, 0}; -// Here, we simulate having the ARM initialized and ready, by setting the 'arm_ok' variable to 'true': -int arm_ok = true; -// The i2s is not part of the simulation, so this really doesn't matter: -bool i2s_rst = false; -// We don't use DDR memory, nor the bypass/mute switches: set everything to zero: -float* mem_zone_f = nullptr; -int* mem_zone_i = nullptr; -bool bypass = false; -bool mute = false; -bool debug = false; -``` - -- We also instantiate `float` type copies of inputs and outputs, for setting random input values, and printing outputs. - -```cpp - float f_inputs[2] = {0, 0}; - float f_outputs[2] = {0, 0}; -``` - -- Then, call the `syfala` function with all the proper arguments. - -```cpp - // For each simulation iteration (set with the '--csim-iter' flag) - for (int i = 0; i < SYFALA_CSIM_NUM_ITER; i++) { - if (i > 0) { - // first iteration = initialization, inputs will be ignored - // wait for second iteration. - f_inputs[0] = (float)rand()/RAND_MAX; - f_inputs[1] = (float)rand()/RAND_MAX; - } - Syfala::HLS::iowritef(f_inputs[0], audio_in[0]); - Syfala::HLS::iowritef(f_inputs[1], audio_in[1]); - // call top-level function - syfala(audio_in, audio_out, - arm_ok, &i2s_rst, - mem_zone_f, mem_zone_i, - bypass, mute, debug - ); - [...] - } -``` - -- Once it is done, fetch and print the input/output samples (as float) : - -```cpp - [...] - f_outputs[0] = Syfala::HLS::ioreadf(audio_out[0]); - f_outputs[1] = Syfala::HLS::ioreadf(audio_out[1]); - printf("[ch0] input: %f, result: %f\n", f_inputs[0], f_outputs[0]); - printf("[ch1] input: %f, result: %f\n", f_inputs[1], f_outputs[1]); - } -``` - -## Optimizing code - -For simple examples, such as our previous *stereo-gain kernel*, there's obviously not going to be an immediate and imperative need for optimization. Consequently, we will this time get our hands on something a little **more resource and computation hungry**. - -In audio digital signal processing, **FIR filters** are encountered on a very regular basis, and, depending on the number of coefficients that they have, they can be tricky to implement on FPGAs, especially if no optimizations are made. Let's have a look at our `examples/cpp/fir/fir.cpp` example: - -```cpp -#include "coeffs.hpp" - -static float coeffs[] = { - 0.000000000000000000, - -0.000000914435621961, - 0.000000000000000000, - 0.000008609100789076, - [...] -}; - -#define INPUTS 0 -#define OUTPUTS 2 -#define NCOEFFS 115 - -static float samples[NCOEFFS]; -static float sawtooth; - -float compute_fir() { - float out = 0; - samples[0] = sawtooth; - for (int n = 0; n < NCOEFFS; ++n) { - out += mem[n] * coeffs115[n]; - } - for (int j0 = NCOEFFS-1; j0 > 0; --j0) { - mem[j0] = samples[j0-1]; - } - sawtooth += 0.01f; - sawtooth = fmodf(sawtooth, 1.f); - return out; -} -``` - -In this example, we first statically define a bunch of **FIR coefficients** in the `examples/cpp/fir/coeffs.hpp` header, as well as a **zero-initialized array** (`samples[NCOEFFS]`), which will be used to store the previous samples. The `compute_fir` function generates a really **basic phasor/sawtooth signal**, and feed it into the FIR filter. Once all the samples are computed for `NCOEFFS`, we **shift** the `samples[]` array by one in the right direction. Then, as in our previous examples, we call the '**compute**' function from the `syfala` top-level function. In this case, we are going to write the same signal on both left and right output channels. - -```cpp - /* ... or compute samples here - * if you need to convert to float, use the following: - * (audio inputs and outputs are 24-bit integers) */ - float f = compute_fir(); - Syfala::HLS::iowritef(f, audio_out[0]); - Syfala::HLS::iowritef(f, audio_out[1]); -``` - -### Monitoring latency & resource utilization - -Now, in order to evaluate the program's performance and efficiency, the first thing that we can do is run the **High Level Synthesis step** and carefully read the **output results**. This can be done using the following command: - -```shell -syfala examples/cpp/fir/fir.cpp --board Z10 --hls -``` - -which is going to give us this **estimate**: - -``` -fir.cpp Z10 48000 24 (Vitis HLS estimate) -115 coefficients - -- DSP: 8% (7) -- Reg: 5% (1829) -- LUT: 20% (3617) -- BRAM: 2% (3) - -Tot. 1057 Cycles, 8.602us -Max. 2559 Cycles, 20,8333us -Lat. 41% -``` - -Needless to say, even for a **Zybo Z7-10**, this is not really satisfying: if we project ourselves **linearly**, it means that we could probably only **fit at best a 300 coefficients FIR filter** or so without reaching the **maximum sample latency**. Let's try it out with 300 coefficients now: - -``` -fir.cpp Z10 48000 24 (Vitis HLS estimate) -300 coefficients - -- DSP: 8% (7) -- Reg: 5% (1837) -- LUT: 20% (3619) -- BRAM: 2% (4) - -Tot. 2722 Cycles, 22.152us -Max. 2559 Cycles, 20,8333us -Lat. 106% -``` - -With a **300-coefficients filter**, we even actually go a little bit **above max latency**. On the other hand, we can see that the resources stay pretty much the same as before, so there's probably room for improvement here in terms of **balance** between latency & resource utilization, and the first thing we can do to remedy this problem would maybe be to use some of the **Vitis HLS C/C++ pragmas**. - -### Using optimization directives & pragmas - -Now, what we really want Vitis HLS to do here, for the latency to drop down, would be to **parallelize the computations** a bit more. If we go through **Vitis HLS documentation**, there are a couple of things that can be tried in order to do that, without modifying the code too much. Our first choice here would be to use the **unroll #pragma**, which could introduce more parallelization in our **accumulation loop**: - -```cpp -float compute_fir() { - float out = 0; - mem[0] = sawtooth; - for (int n = 0; n < NCOEFFS; ++n) { - #pragma HLS UNROLL - out += mem[n] * coeffs[n]; - } - [...] -``` - -If we try to run HLS with this code, we see that pretty much nothing happens (the results may even be worse than before). That's because this particular accumulation loop cannot really be parallelized without using what we call a **balanced tree** (in our case, an 'adder tree'). By default, Vitis HLS does not automatically make this optimization for floating-point operations, but it can be enabled using the `--unsafe-math-optimizations` (or `--umo`) flag in the syfala command line: - -```shell -syfala examples/cpp/fir/fir300.cpp --hls --umo -``` - -Let's now try to see what it's giving us for our **300 coefficients** example: - -``` -fir.cpp Z10 48000 (Vitis HLS estimate) -300 coefficients - -- DSP: 31% (25) -- Reg: 18% (6532) -- LUT: 66% (3619) -- BRAM: 1% (2) - -Tot. 529 Cycles, 4.536us -Max. 2559 Cycles, 20,8333us -Lat. 20% -``` - -The results are definitely more reasonable in terms of latency. On the other hand, we can see that the resources (**LUTs** in particular) have increased a lot. If we push it a little bit more, let's say with **600 coefficients** this time, this is what we get: - -``` -fir.cpp Z10 48000 (Vitis HLS estimate) -600 coefficients - -- DSP: 31% (25) -- Reg: 23% (8101) -- LUT: 85% (15019) -- BRAM: 1% (2) - -Tot. 987 Cycles, 8.537us -Max. 2559 Cycles, 20,8333us -Lat. 38% -``` - -With **600 coefficients**, we're still okay on latency, but the **Lookup Table** (**LUT**) **number** is now getting dangerously **high**. - -Remember: the numbers shown on these reports are only **an estimate**, which means that this number could be in reality a bit higher, introducing the risk that our kernel might not actually fit on the Zybo Z7-10 board. - -#### Accurate reports - -In a situation like this one, it is usually a good idea to tell Vitis HLS that we need **a more accurate report** on the allocated resources. Adding the `--accurate-use` flag to the syfala command line will do exactly that for us: - -```shell -syfala examples/cpp/fir300.cpp --hls --umo --accurate-use -``` - -This will tell Vitis HLS to run both the **synthesis** and **implementation** **steps** on the *DSP kernel* only (not on the final design). It usually takes more time (approximately 5 to 10 minutes, depending on the kernel), but it will give precise and valuable information on the resources that will be used on the board: - -``` - GUIDELINE -- DSP: 31% (25) OK (80%) -- Reg: 22% (7912) OK (50%) -- LUT: 70% (12332) WARNING (70%) -- BRAM: 1% (2) OK (80%) -``` - -If we now look at the **GUIDELINE** column, we can see that we have indeed a **WARNING** on the LUT section, which basically means that the design may not fit on the board. But instead of trying to run the full synthesis and hope for the best, maybe we can tweak the **pragmas** a little more, to give ourselves a safer margin. - -**Vitis HLS documentation** tells us that we can add to the **UNROLL pragma ** a parameter called`factor` , which basically represents the level of parallelization that we want to introduce in the loop. When this parameter is **not explicitly set**, Vitis HLS will **fully unroll the loop**, which might explain why the number of LUTs has sky-rocketted in our previous examples. If we tune this factor with a lower number, it might help bring down the utilization of this specific FPGA resource. Let's try it now with a **factor** `10`, and see what it does: - -```cpp -float compute_fir() { - [...] - for (int n = 0; n < NCOEFFS; ++n) { - #pragma HLS UNROLL factor=10 - out += samples[n] * coeffs[n]; - } - [...] -``` - -Which is going to give us: - -``` -fir.cpp Z10 48000 (Vitis HLS estimate) -600 coefficients - -- DSP: 15% (12) -- Reg: 9% (3452) -- LUT: 28% (4966) -- BRAM: 3% (4) - -Tot. 1139 Cycles, 9.269us -Max. 2559 Cycles, 20,8333us -Lat. 44% -``` - -This is starting to get a lot better, and if we go up to **1000 coefficients** now: - -``` -fir.cpp Z10 48000 (Vitis HLS estimate) -1000 coefficients - -- DSP: 15% (12) -- Reg: 9% (3452) -- LUT: 28% (4966) -- BRAM: 3% (4) - -Tot. 1859 Cycles, 15.129us -Max. 2559 Cycles, 20,8333us -Lat. 72% -``` - -The results here are getting really interesting, since we can clearly see that **the resources used are exactly the same** as our 600 coefficients example. Latency is the only thing that has increased, from 44% to 72%, which remains a somewhat comfortable margin. - -### Using a 'sample block' configuration (--multisample) - -Another method that can be used in order to balance latency and resource utilization would be for the DSP kernel **to process a block of samples** instead of a single one, i.e. to '**bufferize**' the signal to maximize efficiency and parallelization. Not unlike CPUs, this may also result in better FPGA resource dispatch and/or throughput, but has on the other hand the drawback of introducing **I/O latency**. - -**Syfala** supports **sample block processing** for both Faust and C++ targets, by adding the `--multisample ` flag: - -```shell -syfala examples/cpp/templates/gain-multisample.cpp --multisample 16 --hls -``` - -For C++ targets, the code needs to be adapted a bit, since we now have **FIFO arrays** as inputs and outputs, we have to declare them as **C multidimensional arrays**, like the following: - -```cpp -void syfala ( - sy_ap_int audio_in[INPUTS][SYFALA_BLOCK_NSAMPLES], - sy_ap_int audio_out[OUTPUTS][SYFALA_BLOCK_NSAMPLES], - [...] -``` - -```cpp -#pragma HLS INTERFACE ap_fifo port=audio_in -#pragma HLS INTERFACE ap_fifo port=audio_out -#pragma HLS array_partition variable=audio_in type=complete -#pragma HLS array_partition variable=audio_out type=complete -#pragma HLS INTERFACE s_axilite port=arm_ok -#pragma HLS INTERFACE m_axi port=mem_zone_f latency=30 bundle=ram -#pragma HLS INTERFACE m_axi port=mem_zone_i latency=30 bundle=ram -``` - -Within the top-level function, this also changes the way we have to process the **bypass/mute switches**: - -```cpp - } else { - /* Every other iterations: - * either process the bypass & mute switches... */ - if (bypass) { - for (int n = 0; n < OUTPUTS; ++n) { - for (int m = 0; m < SYFALA_BLOCK_NSAMPLES; ++m) { - audio_out[n][m] = audio_in[n][m]; - } - } - } else if (mute) { - for (int n = 0; n < OUTPUTS; ++n) { - for (int m = 0; m < SYFALA_BLOCK_NSAMPLES; ++m) { - audio_out[n][m] = 0; - } - } -``` - -And finally our **compute function**: - -```cpp - } else { - /* ... or compute samples here */ - compute(audio_in, audio_out); - } -``` - -```cpp -// examples/cpp/templates/gain-multisample.cpp - -static void compute(sy_ap_int const inputs[INPUTS][SYFALA_BLOCK_NSAMPLES], - sy_ap_int outputs[OUTPUTS][SYFALA_BLOCK_NSAMPLES]) -{ - for (int n = 0; n < OUTPUTS; ++n) - for (int m = 0; m < SYFALA_BLOCK_NSAMPLES; ++m) { - // if you need to convert to float, use the following: - // (audio inputs and outputs are 24-bit integers by default) - float f = Syfala::HLS::ioreadf(inputs[n][m]) * 0.5f; - Syfala::HLS::iowritef(f, outputs[n][m]); - } - } -} -``` - -#### FIR example - -Let's get back to our FIR example, in order to see what can be done to optimize things a bit more. An unoptimized `multisample` example can be found in `examples/cpp/fir/fir-multisample.cpp`. - -Let's see what kind of results we get with a **block of size 16 and 300 coefficients**: - -```shell -syfala examples/cpp/fir/fir-multisample.cpp --board Z10 --multisample 16 --hls -``` - -``` -fir-multisample.cpp Z10 48000 (Vitis HLS estimate) -block size: 16 samples -300 coefficients - -- DSP: 8% (7) -- Reg: 5% (1935) -- LUT: 21% (3829) -- BRAM: 3% (4) - -Tot. 43585 Cycles, 0.355ms -Per sample: 2724 Cycles. -Max. 2559 Cycles, 20,8333us -Lat. 106% -``` - -Compared to our unoptimized 'one-sample' FIR example with the **same number of coefficients**, and considering we also introduce **an I/O latency of 16 samples** (about 0.3 milliseconds), we can say with confidence that this is not really good, and that's essentially because - if we carefully look at the more advanced reports that Vitis HLS is giving us - **the samples are still processed sequentially**, which is not going to introduce a lot of changes compared to the single-sample version. Consequently, even if we unroll our accumulation loop as we did before, the results are also going to be more or less the same. - -[...] - -#### CSIM with --multisample configuration: - -```shell -syfala examples/cpp/templates/gain-multisample.cpp - --multisample 32 - --csim tests/csim/csim_cpp_template_multisample.cpp - --csim-inputs tests/stimuli - --csim-iter 5 -# output results will be stored in reports/csim/gain-multisample/out0.txt & reports/csim/gain-multisample/out1.txt -``` - -## Sharing processing/control with the ARM executable - -Since the resources on a FPGA are far from being infinite, it is usually preferable to use a custom **ARM** executable for some specific use-cases, such as: - -- Initialization of **constants**, **wavetables**... -- Long **delay-lines** (stored/initialized in DDR memory). -- **Control-rate** computations. -- etc. - -This is exactly what **syfala** does under the hood with **Faust programs**: control-rate expressions, resulting from the sliders/button being interacted with, are for instance made on the ARM, and shared through a memory bus called **AXI-Lite**. - -The following example shows how we can implement a similar (though simpler) control-rate *gain* parameter, which we will be able update on the console and share with the DSP kernel. - -### Basic AXI-Lite control example - -This example, which you can find in `examples/cpp/templates/gain-control-hls.cpp`, is almost exactly the same as our previous `gain.cpp` example. The only difference is that we want to make **variable** the `gain` parameter that we *hardcoded* to `0.5f` before. All we basically need to do here is to introduce a new floating-point argument `gain` **in the top-level function**, which will also be declared as an **AXI-Lite** interface port using the appropriate `pragma`: - -```cpp -void syfala ( - sy_ap_int audio_in[INPUTS], - sy_ap_int audio_out[OUTPUTS], - [...] - float gain -) { -[...] -#pragma HLS INTERFACE s_axilite port=gain -``` - -For the rest of the code, we simply add `gain` to the `compute()` function's arguments, and then apply it to the inputs. - -```cpp - } else { - /* ... or compute samples here */ - compute(audio_in, audio_out, gain); - } -``` - -```cpp -static void compute(sy_ap_int const inputs[], - sy_ap_int outputs[] - float gain) { - float f0 = Syfala::HLS::ioreadf(inputs[0]) * gain; - float f1 = Syfala::HLS::ioreadf(inputs[1]) * gain; - Syfala::HLS::iowritef(f0, outputs[0]); - Syfala::HLS::iowritef(f1, outputs[1]); -} -``` - -That's it! On the **HLS side** of things, it remains pretty simple. On the **ARM side**, it gets unfortunately a bit more complicated, as we are going to see now :-) - -#### DSP kernel drivers - -We already know that Vitis HLS is going to take our `gain-control-hls.cpp` file and generate the VHDL-equivalent, which is then going to be integrated in our final design. But it's not the only thing that it does: among other things, **it also generates 'drivers' for interacting with the kernel from the ARM**. - -Let's first **synthesize** our DSP kernel with Vitis HLS, and take a look at some of the files that are generated in the `build` directory: - -```shell -syfala examples/cpp/templates/gain-control-hls.cpp --hls -``` - -If we now go in the `build/syfala_ip/syfala/impl/ip/drivers/syfala_v1_0/src` directory, we see that a Makefile and **some C files have been generated**, specifically: - -``` -- xsyfala.c -- xsyfala.h -- xsyfala_hw.h -- xsyfala_linux.c -- xsyfala_sinit.c -``` - -We're not going to go into details about each file: the one that is truly interesting to us in the context of our example is the `xsyfala.h` **C header** . If we **open this file**, we see that the following **function prototypes** are declared: - -```cpp -void XSyfala_Set_arm_ok(XSyfala *InstancePtr, u32 Data); -u32 XSyfala_Get_arm_ok(XSyfala *InstancePtr); -void XSyfala_Set_mem_zone_f(XSyfala *InstancePtr, u64 Data); -u64 XSyfala_Get_mem_zone_f(XSyfala *InstancePtr); -void XSyfala_Set_mem_zone_i(XSyfala *InstancePtr, u64 Data); -u64 XSyfala_Get_mem_zone_i(XSyfala *InstancePtr); -void XSyfala_Set_gain(XSyfala *InstancePtr, u32 Data); -u32 XSyfala_Get_gain(XSyfala *InstancePtr); -``` - -You can see that these functions' names match some of the arguments that we put in the top-level function. That's because these arguments are already registered as **AXI** or **AXI-Lite** interface arguments in our **DSP kernel code**: - -```cpp -void syfala ( - [...] - int arm_ok, - float* mem_zone_f, - int* mem_zone_i, - float gain -) { -#pragma HLS INTERFACE s_axilite port=arm_ok -#pragma HLS INTERFACE s_axilite port=gain -#pragma HLS INTERFACE m_axi port=mem_zone_f latency=30 bundle=ram -#pragma HLS INTERFACE m_axi port=mem_zone_i latency=30 bundle=ram -``` - - In our case, since the other arguments `arm_ok`, `mem_zone_f` and `mem_one_i` are already taken of by **syfala**, the one that is going to be useful to us is the `gain` parameter, and, specifically, its **'setter' function**: - -```cpp -void XSyfala_Set_gain(XSyfala *InstancePtr, u32 Data) -``` - -#### Writing the ARM executable - -In order to code the executable that is going to run on the ARM, we will take the code from`source/arm/baremetal/arm_minimal.cpp`, which contains all that is necessary for the application to run properly, and we are going to add our `gain` **control function**. The result can be seen in `examples/cpp/templates/gain-control-arm.cpp`. - -In our `update_gain()` function, we are simply going to fetch a new `gain` value using `scanf`, and update it on the FPGA using the `XSyfala_Set_gain` **driver function**: - -```cpp -static void update_gain(XSyfala& syfala) { - static float gain = 1.f; - printf("Enter gain value (from 0.f to 1.f)\r\n"); - scanf("%f", &gain); - printf("Gain: %f\r\n", gain); - XSyfala_Set_gain(&syfala, *reinterpret_cast(&gain)); -} -``` - -> **Note**: floating-point data have to be set using `reinterpret_cast`, otherwise, it will be interpreted as an integer and truncated. - -In the `main()` function, all we have to do now is call our `update_gain()` function in the **main event loop**, passing it the `XSyfala` handle `struct`. - -```cpp -int main(int argc, char* argv[]) { - XSyfala syfala; - UART::data uart; - // UART & GPIO should be initialized first, - // i.e. before outputing any information on leds & stdout. - GPIO::initialize(); - UART::initialize(uart); - // Wait for all peripherals to be initialized - Status::waiting(RN("[status] Initializing peripherals & modules")); - Audio::initialize(); - IP::initialize(syfala); - IP::set_arm_ok(&syfala, true); - Status::ok(RN("[status] Application ready, now running...")); - - // main event loop: - while (true) { - // -------------------------------------------------------- - update_gain(syfala); - sleep(1); - // -------------------------------------------------------- - } - return 0; -} -``` - -#### Running syfala - -Finally, **to fully run syfala on our example**, including the ARM executable, we need to add the `--arm-target` **flag** to the command line, with the path to our `.cpp` file as an argument: - -```shell -syfala examples/cpp/templates/gain-control-hls.cpp --arm-target examples/cpp/templates/gain-control-arm.cpp --board Z10 -``` - -### Delay-line AXI example (DDR memory) - -[...] diff --git a/doc/tutorials/getting-started-faust.md b/doc/tutorials/getting-started-faust.md deleted file mode 100644 index 7a73880..0000000 --- a/doc/tutorials/getting-started-faust.md +++ /dev/null @@ -1,281 +0,0 @@ -# Getting started with syfala and Faust - -## Introduction - -This tutorial is intended for **beginner**-users with **no background in FPGA or C++** development. Only basic knowledge of **Linux** and using the **terminal** is necessary. Prior experience using the **Faust language** is also preferable, but not required. - -### Minimum hardware/software requirements - -- [x] **Linux system** (preferably Ubuntu 18.04 or higher, Debian-based or Archlinux-based distributions in general). -- [x] 16GB of **RAM** (32 is recommended for bigger DSP programs). -- [x] 100 GB of **free disk space** (for AMD-Xilinx tools installation) - -One of the following development boards: - -- [x] Digilent **Zybo Z7-10** - Zynq-7000 ARM/FPGA SoC Development Board -- [x] Digilent **Zybo Z7-20** - Zynq-7000 ARM/FPGA SoC Development Board -- [x] Digilent **Genesys ZU-3EG** - Zynq UltraScale+ MPSoC Development Board - -### Objectives - -In this tutorial, we will cover the essential topics to get started with the **Faust programming language**, **syfala**, and audio programming on **FPGAs** in general. We will start by briefly presenting all of these programs and environments, and then we will get our hands on a very concrete audio program example that we're going to build, flash on our FPGA development board, and control remotely, using different protocols, such as **MIDI**, **OSC** and **HTTP**. - -## Faust - -Faust (Functional Audio Stream) is a **functional programming language** for sound synthesis and audio processing with a strong focus on the design of synthesizers, musical instruments, audio effects, etc. created at the [GRAME-CNCM Research Department](https://www.grame.fr/recherche). - -In order to get you started using Faust, we recommend that you follow this tutorial : https://faustdoc.grame.fr/manual/quick-start - -## Syfala - -### About syfala (and FPGAs) - -Syfala is a set of command-line tools & scripts aiming to **facilitate audio programming on FPGAs**. It currently targets **AMD-Xilinx** devices, such as the **Digilent Zybo Z7-10 & Z7-20**, or the **Genesys ZU-3EG**. It takes a **Faust** `.dsp` file or a **C++** `.cpp` file as input, and then configures and calls all the AMD-Xilinx softwares that will compile all the required binaries to be flashed on device. - -The **repository** itself is composed of a few different elements: - -- **Command-line interface** scripts (`syfala.tcl`). -- **Faust architecture files**, for interfacing with **High Level Synthesis** (HLS). -- **Tcp scripts**, used to configure and call the AMD-Xilinx softwares, such as Vitis HLS, Vivado, Vitis... -- **Baremetal/Linux C++ code**, for the ARM control executable. -- **VHDL code**: custom i²s implementations. -- Other types of **scripts** (for preprocessing, Makefile, Embedded Linux...) - -### Installing the toolchain - -#### Dependencies - -Please follow the instructions in the file [doc/dependencies.md](doc/dependencies.md) in order to install the **AMD-Xilinx** **toolchain** and various other dependencies. - -#### Installing Syfala - -```shell -git clone https://github.com/inria-emeraude/syfala.git syfala -cd syfala -make install -``` - -You'll also have to add the following **environment variable** to your shell **resource** **file** (~/.**bashrc** / ~/.**zshrc**) - -```shell -export XILINX_ROOT_DIR=/my/path/to/Xilinx/root/directory -``` - -where `XILINX_ROOT_DIR` is the root directory where all of the **AMD-Xilinx tools** (*Vivado*, *Vitis*, *Vitis_HLS*) are installed. - -### Your first example - -#### Building - -```shell -syfala [options] -``` - -```shell -# Depending on the development board that you have, the command will be: -syfala examples/faust/virtualAnalog.dsp --board Z10 - --board Z20 - --board GENESYS -``` - -This will run the **full syfala toolchain** on the `virtualAnalog.dsp` **Faust** file, which will then be ready to be **flashed** on your board. Under the hood, **syfala** will follow multiple steps, which you'll be able to monitor from the console log: - -1. [**sources**] It will **call Faust** to **generate the C++ code** from the `virtualAnalog.dsp` file, with a custom-made **syfala** *architecture file*. You'll be able to see the resulting code in `build/syfala_ip/syfala_ip_preprocessed.cpp`. -2. [**hls**] Once the C++ code is generated, it will call **Vitis HLS**, which will translate it into a self-contained *Hardware Description Language* (**HDL**) program, which we're going in this tutorial to call the **DSP kernel**. The resulting code of this *kernel* can be viewed in the `build/syfala_ip/syfala/impl/vhdl/syfala.vhd` **VHDL** file. -3. [**project**] Here, the **DSP kernel** generated by Vitis HLS is going to be imported into a more global *Vivado design*, which will include the **processing system** (PS), our custom-made **Integrated Interchip Sound** (**i²s**) transceiver, and various other modules as well. The resulting code can be viewed in the `build/syfala_project/syfala_project.gen/sources_1/bd/main/hdl/main_wrapper.vhd` -4. [**synthesis** & **implementation**] From here, **Vivado** will 'compile' the project's final *design* into what we call a **bitstream**, which is a hardware configuration file: it includes the description of the hardware logic, routing, and initial values for both registers and on-chip memory (e.g. LUT). -5. [**host control executable**] Finally, we will also need to cross-compile an ARM elf executable to take care of all initialization and control-rate computations, which are done on the CPU, and exchanged with the DSP kernel using a specific set of buses. - -#### Reading performance reports - -If the build went well, you should be able to see on your terminal a recap of the **build's configuration** and an **overview of its performance reports**. Since the **HLS report** is only an **estimate**, the **Vivado summary** is the one that you should really pay attention to. - -``` -virtualAnalog Z20 - -- DSP: 15% (35) -- Reg: 9% (9730) -- LUT: 16% (8820) -- BRAM: 0% (0) - -Tot. 344 Cycles, 2.799us -Max. 2604 Cycles, 20,8333us -Lat. 13% -``` - -##### Resources - -Here we can see that, on our Zybo Z7-20 development board, the final *design* doesn't take a lot of FPGA resources, so there's potentially room to add more cool stuff to our Faust program, if the latency is sufficiently low as well. - -##### Latency - -The report shows that the *DSP kernel*'s computations are done in 2.799 microseconds (344 FPGA clock cycles at 122 MHz): that is way **below** the **maximum allowed for the computation of a single sample**, which is defined by the reciprocal of the sample-rate (`1/48000` in our case, which equals to `20,8333` microseconds). - -#### Exporting and re-importing your builds - -Before flashing, or doing anything else, it's generally a good idea to **save and export your build outputs**, especially when compilation times are really long, like ours. You can do this with the following **syfala command**: - -```shell -syfala export my-faust-virtual-analog-build -# output in 'export/my-faust-virtual-analog-build.zip' -``` - -The resulting `.zip` file is then going to be available in the repository's `export` directory. Later, you'll be able to **re-import** it by doing: - -```shell -syfala import export/my-faust-virtual-analog-build.zip -``` - -#### Flashing - -Now we have our program fully compiled and exported, we can try it on our development Board. In order to do so, two options: - -1. Flash it **from USB** (with *JTAG*), by connecting an USB cable to the board's **UART port**. -2. Flash it from a bootable **SD card**. - -##### Hardware configuration - -In both cases, you'll have first to make sure that the board is set up with this configuration: - -- [ ] **Power select** jumper (JP6) should be on *USB* -- [ ] Board should be connected (**UART PROG port**) to your machine with a micro-USB to USB cable. -- [ ] **Switches** SW0, SW1, SW2, SW3 should be **down** -- [ ] The **audio input** is **LINE IN** (blue), not ~~MIC IN~~. -- [ ] The **audio output** is the black **HPH OUT** jack. - -##### USB (JTAG) - -- [ ] Hardware configuration: jumper **JP5** should be on *JTAG*. -- [ ] Board should be powered up with **SW4**. - -You can then quickly flash your program by entering the following syfala command from your terminal: - -```shell -syfala flash -``` - -Keep in mind that when you shutdown your device and power it up again, **it won't start your program again automatically** (because it is not kept in memory), so you'll have to enter the `syfala flash` command again. This is why working with SD cards is going to be a better solution if you have the need to reload your program every time your power up the board. - -##### SD card - -- [ ] Jumper **JP5** should be on *SD*. -- [ ] **SD card** should have a **FAT32 bootable partition**. - -To generate the bootable binary file `boot.bin`, you can add the `--boot` flag to your syfala command : - -```shell -syfala examples/faust/virtualAnalog.dsp --board Z20 --boot -``` - - It won't re-compile the whole project, it will just take the hardware and software outputs of your build and package them into a single **bootable binary file** (`boot.bin`), which you'll find in the `build/sw_export` directory. You can then just copy this file into your SD card, and insert it in the board's SD card socket, and then power the board up with **SW4**. - -### Monitoring and controlling the board remotely - -Once your build is flashed on your board, you'll first want to make sure that the program has been **loaded** and **executed properly**. You can obviously plug in a headset or a pair of speakers to check its audio output, but there are also a couple of ways of getting *debug* information, which you'll need in case the program is not working the way it is supposed to: - -#### LEDs - -Right after flashing your build, you can directly look at the board's **LD12** LED, which is supposed to **turn green when a bitstream has been properly loaded**. Then, you can look at the **LD5 RGB LED**, which will go from **blue** to **green** during the ARM control program execution. Audio will usually start right after this LED turns green. - -If an error occurs, and **LD12** is still off, or **LD5** turns **red**, the next step would be to check the board's console output, which is accessible through UART. - -#### UART console - -In order to view the board's console output, you will need to install a **serial device i/o tool**, such as `minicom` or `tio`. For this tutorial, we will use `tio`. Once the board is connected with an USB cable (**PROG UART port**) to your laptop or desktop computer, you can enter the following command: - -```shell -tio -b 115200 /dev/ttyUSB1 -``` - -This will tell `tio` to connect to the `ttyUSB1` serial device interface with a baud rate of `115200`. Once it is done and the board has been powered-up again, you should see debug information being displayed on the console. - -#### Remote control of Faust parameters - -##### USB-UART control - -All of the user-interface elements declared in the Faust DSP code are controllable. In *baremetal* mode, the preferred way of doing this remotely from your machine would be using the available GUI to Serial interface, that you can start with the following command, once the DSP program is running on your board: - -```shell -syfala start-gui -``` - -Syfala should now be building the user-interface after having retrieved the `.dsp` file's control parameters, and display it with a **GTK interface** when it's ready. You should now be able to play with the different *buttons*, *sliders* and *knobs* that have been defined in your Faust file. - -Now, GTK-based sliders and buttons are perfectly fine for testing your program, but you'll probably want at some point to have a nicer way to control its parameters, by using for instance **MIDI** or **OSC** interfaces. For now, in *baremetal* mode, it is not possible (yet) to plug a MIDI controller directly on the board's USB port and control your Faust parameters, because MIDI-USB baremetal drivers are unfortunately not yet implemented in syfala. The same goes for Ethernet-OSC. To remedy this problem, we offer at the moment two solutions : - -1. The **embedded Linux** for syfala ([doc/tutorials/linux/getting-started.md](linux/getting-started.md)) - - On **Linux**, MIDI, OSC & HTTP libraries are available, and ready-to-use with syfala. -2. **MIDI**, **OSC**, **HTTP** layers **on top of the Serial interface**. - - MIDI, OSC & HTTP interfaces will be used on your machine, and translated/channeled into the Serial interface to be transmitted to the board. This is not ideal and will introduce some more control latency to the setup, but is easy to use. - -##### MIDI control - -In order to build a target with MIDI-Serial support, you can add the `--midi` flag to the command line, and reload the `start-gui` command: - -```shell -syfala examples/faust/virtualAnalogMIDI.dsp --board Z20 --midi -syfala start-gui -``` - -You'll also have to explicitly map in your Faust code the controls (sliders, knobs, etc.) to a MIDI control element (note, cc, pressure, etc.). An example of MIDI-mapping can be viewed in `examples/faust/virtualAnalogMIDI.dsp`, and the Faust MIDI-mapping process is fully explained here : https://faustdoc.grame.fr/manual/midi/ - -##### OSC control - -In order to build a target with **OSC support**, you can add the `--osc` flag to the command line: - -```shell -syfala examples/faust/virtualAnalog.dsp --board Z20 --osc -syfala start-gui -``` - -The GUI control application will create an **Open Sound Control-compliant UDP server**. You'll be then able to control remotely the Faust DSP parameters by sending OSC messages like so: - -- */virtualAnalog/lfoRange 2000* - -- */virtualAnalog/oscFreq 500* - -- etc. - -More on: https://faustdoc.grame.fr/manual/osc/ - -##### HTTP control - -In order to build a target with **HTTP support**, you can add the `--http` flag to the command line: - -```shell -syfala examples/faust/virtualAnalog.dsp --board Z20 --http -syfala start-gui -``` - -The GUI control application **will create a HTTP server** allowing users to **control the Faust DSP parameters remotely** (given that you are on the same network as your FPGA board). - -At runtime, when executed, the **application will print the device's current network IP** (IPv4), and the **port** used by the HTTP server. You can then **use any web browser**, and control the application by entering the server's URL, for example *http://192.168.0.1:5510* - -#### SPI-based controllers - -[...] - -## Going further - -### Embedded Linux - -*Note: only available for Zybo Z7-10/Z7-20 boards (Genesys not yet supported)* . - -Starting from syfala 0.8, you can choose to build our **custom-made embedded Linux**, which will provide, in addition to all the things an OS has to offer (SSH control over Ethernet or Wi-Fi, package manager, etc.), the following features: - -- **No latency cost** (the *DSP kernel* still dwells in the Programmable Logic) -- **On-the-fly FPGA reprogramming** from Linux (with no need to reboot or re-login). -- **On-board USB-MIDI control** (from the board's USB OTG port). -- Direct **OSC/HTTP control**, pre-mapped to the Faust DSP program's user-defined GUI elements (sliders, buttons, checkboxes, etc.). - -From the syfala command line interface, all you need to do is add the `--linux` flag: - -```shell -syfala examples/virtualAnalog.dsp --linux -``` - -For the rest of the procedure, you can follow the [syfala-linux getting-started tutorial](linux/getting-started.md) - -### Using syfala with C++ - -If you'd rather write your DSP code directly in C++, or you have a more imperative need for performance and optimization, you can follow our [C++ tutorial here](cpp-tutorial-advanced.md) (advanced users). diff --git a/doc/tutorials/linux/developers.md b/doc/tutorials/linux/developers.md deleted file mode 100644 index 2d772ac..0000000 --- a/doc/tutorials/linux/developers.md +++ /dev/null @@ -1,664 +0,0 @@ -# syfala-linux (developers) - -## Status - -#### Boards - -- [x] Support for **Zybo-Z710** & **Z720** boards -- [ ] Support for **Genesys** board - -#### Peripherals & drivers - -- [x] **Ethernet**/**network** - - [ ] Ethernet-based streaming i/o (AVB?) - -- [x] **IIC-0** (SSM2603) -- [ ] **IIC-1** (external codecs) -- [ ] Serial Peripheral Interface (**SPI**) - - [x] **spidev** device identification (mcp3008) - - [ ] /!\ **jitter/noise issues** - -- [x] Shared/reserved **DDR** **memory** - - [ ] DMA (cache bypass) - -- [x] GPIO **LEDs** interface -- [x] GPIO **SWs** interface -- [ ] **Internal codecs ALSA** support -- [ ] **External codecs ALSA** support - -#### Control - -- [x] **MIDI** support -- [x] Open Sound Control (**OSC**) support - -- [ ] OSCQuery support - - [ ] **TUI** OSC support? - -- [x] **HTTP** support - -#### Misc. - -- [ ] Soundfiles - -- [ ] **Device-tree overlays** (DTO) - -- [x] **On-device** application **compilation** - -- [x] Wi-Pi (Ralink 5370 Wi-Fi USB Dongle) - -- [x] Avahi support - -# details on the build procedure - -The `syfala.tcl` main script, after receiving the `build-linux` or `build-linux boot` command, will call the `build_boot` procedure in the file `scripts/linux/build.tcl`. - -It will first create all the necessary **build** **subdirectories**: - -``` -# build-linux -# |---| boot (all boot-related build files) -# | |---| u-boot -# | |---| kernel -# | |---| device-tree -# |---| output (copies of all required files for boot partition) -# | |---| boot -# |---| root -``` - -The script then takes care of all the following build procedures. - -```shell -$ syfala linux build -``` - -- it will build both **boot** and **root** partition contents to be transferred to an external **SD** card - -#### Building or re-building boot & root partitions separately - -You can also build/update the boot & root partitions **separately** with the following commands: - -```shell -$ syfala linux build boot -``` - -this will only build **boot** partition's contents. These subcommands are also available: - -- `syfala linux build uboot` - recompiles and exports uboot -- `syfala linux build kernel` - recompiles and exports kernel image & modules -- `syfala linux build device-tree` - recompiles and exports device-tree - -```shell -$ syfala linux build root -``` - -this will only build **root** partition's contents. These subcommands are also available: - -- `syfala linux build dsp` - **re-builds the app** and update the **bitstream** in the **root partition** -- `syfala linux build app` - only **re-builds the app** - -## boot - -### Build steps - -#### 1. Cloning and compiling Xilinx' u-boot repository - -https://github.com/Xilinx/u-boot-xlnx - -*branch/tag xilinx-v2022.2* - -It will generate the **First Stage Boot Loader** (FSBL), and the **Secondary Program Loader** (SPL) included in the main '*boot.bin*' binary and the *u-boot.img* image. - -##### Outputs: - -- *boot.bin* -- *spl/u-boot.img* - -#### 2. Cloning and Compiling Xilinx' custom Linux Kernel repository (tag xilinx-v2022.2) - -https://github.com/Xilinx/linux-xlnx - -*branch/tag xilinx-v2022.2* - -This modified Kernel comes shipped with custom **Xilinx drivers**, and some **pre-configured options**. We add to that a **custom configuration file**, located in *source/linux/configs/zybo_z7_defconfig*, with the following options: - -##### UIO-related - -| Option | Value | Description | Comments | -| ------------------------ | ---------------- | ------------------------------------------------------------ | -------- | -| `CONFIG_UIO` | **Y** (activate) | allows userspace i/o communication with the **syfala ip** (including generic interrupt handling code) | | -| `CONFIG_UIO_PDRV_GENIRQ` | **Y** | | | - -##### SPI-related - -| Option | Value | Description | Comments | -| -------------------- | ---------------- | ------------------------------------------------------------ | -------- | -| `CONFIG_SPI_MASTER` | **Y** (activate) | | | -| `CONFIG_SPI_CADENCE` | **Y** | xilinx's own **spi_master** drivers | | -| `CONFIG_SPI_SPIDEV` | **Y** | generic **spidev** drivers for communication with the **SPI0 bus** **slave** (MCP3008 ADC) | | - -##### Sound-related (ALSA) - -| Option | Value | Description | Comments | -| ------------------------------------------- | ------------------ | ----------- | ------------------------------- | -| `CONFIG_SOUND` | **M** (module) | | required | -| `CONFIG_SOUND_OSS_CORE` | **N** (deactivate) | | | -| `CONFIG_SND` | **M** | | required | -| `CONFIG_SND_DRIVERS` | **Y** (activate) | | required | -| `CONFIG_SND_MAX_CARDS` | 32 | | | -| `CONFIG_SND_DYNAMIC_MINORS` | **Y** | ? | | -| `CONFIG_SND_DEBUG` | **Y** | | | -| `CONFIG_SND_PCM` | **M** | | | -| `CONFIG_SND_USB` | **Y** | | required | -| `CONFIG_SND_USB_AUDIO` | **M** | | required | -| `CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER` | **Y** | | ? | -| `CONFIG_SND_MIXER_OSS` | **N** | | | -| `CONFIG_SND_PCM_OSS` | **N** | | | -| `CONFIG_SND_SUPPORT_OLD_API` | **N** | | | -| `CONFIG_SND_DUMMY` | **M** | | optional | -| `CONFIG_SND_TIMER` | **M** | | | -| `CONFIG_SND_HRTIMER` | **M** | | | -| `CONFIG_SND_SIMPLE_CARD` | **M** | | | -| `CONFIG_SND_SIMPLE_CARD_UTILS` | **M** | | | -| `CONFIG_SND_HWDEP` | **M** | | | -| `CONFIG_SND_RAWMIDI` | **M** | | required for faust midi control | -| `CONFIG_SND_VIRMIDI` | **M** | | optional | -| `CONFIG_SND_SEQUENCER` | **M** | | required for faust midi control | -| `CONFIG_SND_SEQUENCER_OSS` | **N** | | | -| `CONFIG_SND_SEQ_DUMMY` | **M** | | | -| `CONFIG_SND_SEQ_DEVICE` | **M** | | required for faust midi control | -| `CONFIG_SND_SEQ_MIDI_EVENT` | **M** | | required (?) | -| `CONFIG_SND_SEQ_MIDI` | **M** | | required for faust midi control | -| `CONFIG_SND_SEQ_MIDI_EMUL` | **M** | | ? | -| `CONFIG_SND_SEQ_VIRMIDI` | **M** | | | -| `CONFIG_SND_SEQ_HRTIMER_DEFAULT` | **Y** | | ? | -| `CONFIG_SND_DMAENGINE_PCM` | **M** | | ? | - -##### WLAN-related (Wi-Pi example) - -| Option | Value | Description | Comments | -| --------------------------------- | ---------------- | ---------------------- | ---------------- | -| `CONFIG_WLAN` | **Y** (activate) | | | -| `CONFIG_WLAN_VENDOR_RALINK` | **Y** | | | -| `CONFIG_NL80211` | **Y** | | | -| `CONFIG_NL80211_TESTMODE` | **Y** | | | -| `CONFIG_RT2X00` | **Y** | for Ralink USB drivers | | -| `CONFIG_HAS_DMA` | **Y** | | | -| `CONFIG_RT2800USB` | **M** (module) | for Ralink USB drivers | | -| `CONFIG_RT2800USB_RT33XX` | **Y** | | | -| `CONFIG_RT2800USB_RT35XX` | **Y** | | | -| `CONFIG_RT2800USB_RT3573` | **Y** | | | -| `CONFIG_RT2800USB_RT53XX` | **Y** | for Wi-Pi | | -| `CONFIG_RT2800USB_RT55XX` | **Y** | | | -| `CONFIG_RT2800USB_UNKNOWN` | **Y** | | | -| `CONFIG_RT2800_LIB` | **M** | | | -| `CONFIG_RT2800_LIB_MMIO` | **M** | | | -| `CONFIG_RT2X00_LIB_MMIO` | **M** | | | -| `CONFIG_RT2X00_LIB_PCI` | **M** | | | -| `CONFIG_RT2X00_LIB_USB` | **M** | | | -| `CONFIG_RT2X00_LIB` | **M** | | | -| `CONFIG_RT2X00_LIB_FIRMWARE` | **Y** | | | -| `CONFIG_RT2X00_LIB_CRYPTO` | **Y** | | | -| `CONFIG_RT2X00_LIB_LEDS` | **Y** | | | -| `CONFIG_CFG80211` | **Y** | | | -| `CONFIG_CFG80211_WEXT` | **Y** | | | -| `CONFIG_MAC80211` | **Y** | | | -| `CONFIG_KEY_DH_OPERATIONS` | **Y** | | | -| `CONFIG_RFKILL` | **Y** | | | -| `CONFIG_CRYPTO_USER_API_HASH` | **Y** | | | -| `CONFIG_CRYPTO_USER_API_SKCIPHER` | **Y** | | | -| `CONFIG_CRYPTO_ECB` | **Y** | | | -| `CONFIG_CRYPTO_MD4` | **Y** | | required for iwd | -| `CONFIG_CRYPTO_MD5` | **Y** | | | -| `CONFIG_CRYPTO_CBC` | **Y** | | | -| `CONFIG_CRYPTO_SHA256` | **Y** | | | -| `CONFIG_CRYPTO_AES` | **Y** | | | -| `CONFIG_CRYPTO_DES` | **Y** | | | -| `CONFIG_CRYPTO_CMAC` | **Y** | | | -| `CONFIG_CRYPTO_HMAC` | **Y** | | | -| `CONFIG_CRYPTO_SHA512` | **Y** | | | -| `CONFIG_CRYPTO_SHA1` | **Y** | | | -| `CONFIG_CRYPTO_SHA1_SSSE3` | **Y** | | | -| `CONFIG_CRYPTO_AES_NI_INTEL` | **Y** | | | -| `CONFIG_CRYPTO_SHA512_SSSE3` | **Y** | | | -| `CONFIG_CRYPTO_AES_X86_64` | **Y** | | | -| `CONFIG_CRYPTO_DES3_EDE_X86_64` | **Y** | | | -| `CONFIG_CRYPTO_SHA256_SSSE3` | **Y** | | | - -**Outputs** - -- *uImage* -- **Kernel modules** (*see rootfs section*) - -#### 3. Building the device-tree from static sources - -Sources in: [source/linux/device-tree/system.dts](../source/linux/device-tree/system.dts) - -Due to the difficulties encountered with generating a proper and correct device-tree with the **Xilinx tools**, we use (for now) a **static device-tree source file** that has been modified by hand in order to facilitate the procedure. - -##### Modifications: - -- **boot arguments** (*bootargs*) - -Here, we have to specify - among other things - the location of the **rootfs** partition (*/dev/mmcblk0p2*) and its type (*ext4*). - -```bash -bootargs = "earlycon uio_pdrv_genirq.of_id=generic-uio root=/dev/mmcblk0p2 rootfstype=ext4 rw rootwait"; -``` - -- **reserved memory** - -**128Mo** of memory are here reserved for the **syfala IP**, starting at address *0x35000000*. - -**Note**: *0x38000000* address was originally chosen, but it seems in the **2022.2 version** of Xilinx' custom kernel (*5.15.0-xilinx*) that it's somehow already used/reserved for another purpose (CMA?), warning us at boot-time that the memory range cannot be reserved. - -```shell -reserved-memory { - #address-cells = <1>; - #size-cells = <1>; - ranges; - reserved: buffer@35000000 { - no-map; - reg = <0x35000000 0x08000000>; - }; -}; -reserved-driver@0 { - compatible = "xlnx,reserved-memory"; - memory-region = <&reserved>; -}; -``` - -- **SPI-0** - -The **SPI Master** device uses Xilinx's own **cadence** drivers (*spi-cadence.c*) - -We had to **add slave peripherals** as children of the master device. For instance, here it communicates with the **MCP3008**'s SPI controller with a maximum throughput frequency of 1 MHz. - -The *compatible* property has to be registered as a peripheral explicitly supported by the **spidev linux driver** (here, *lwn-bk4*, it can be anything as long as it's listed in *spidev.c*), otherwise, it won't be instantiated as an accessible device (**/dev/spidev0.0** in our case) - -```shell - spi0: spi@e0006000 { - compatible = "cdns,spi-r1p6""; - reg = <0xe0006000 0x1000>; - status = "okay"; - interrupt-parent = <&intc>; - interrupts = <0 26 4>; - clocks = <&clkc 25>, <&clkc 34>; - clock-names = "ref_clk", "pclk"; - #address-cells = <1>; - #size-cells = <0>; - is-decoded-cs = <0>; - num-cs = <3>; - slave@0 { - compatible = "lwn,bk4"; - reg = <0>; - spi-max-frequency = <1000000>; - }; -``` - -**Note**: the way the driver sets the **prescaler** is the following: - -* It fetches master's '*speed_hz*' property, compares it with the slave's. If it is different, it will add automatically add an appropriate **prescaler** to get master's frequency **below the slave's max-frequency**. We don't have to set it ourselves. But there still seems like we have some sort of **jitter/clocking issues** at play here - -- **clock-wizard** - -**Note:** for reasons not yet fully understood, the **clock-wizard** (*misc_clk_0*) has to be moved out of *amba_pl*, otherwise the connections to its peripherals are not properly established. - -```shell - misc_clk_0: misc_clk_0 { - #clock-cells = <0>; - clock-frequency = <122885835>; - compatible = "fixed-clock"; - }; - amba_pl: amba_pl { - #address-cells = <1>; - #size-cells = <1>; - compatible = "simple-bus"; - ranges ; -[...] -``` - -- **syfala IP** - -For the initialization and the axilite communication to work properly, the IP has to be registered as a "*generic-uio*" device. It will then be accessible as */dev/uio0* in our case. - -https://www.kernel.org/doc/html/v4.11/driver-api/uio-howto.html - -```shell - syfala: syfala@40010000 { - clock-names = "ap_clk"; - clocks = <&misc_clk_0>; - compatible = "generic-uio"; - status = "okay"; - reg = <0x40010000 0x10000>; - xlnx,s-axi-control-addr-width = <0x7>; - xlnx,s-axi-control-data-width = <0x20>; - }; -``` - -##### Outputs - -- *system.dtb* - -#### 4. Generate (sign) the Boot script file - -It will indicate to **u-boot** the proper commands to execute and the binaries to load when booting. - -```shell -fatload ${devtype} ${devnum}:${distro_bootpart} 0x00200000 uImage; -fatload ${devtype} ${devnum}:${distro_bootpart} 0x00e00000 system.dtb; -fatload ${devtype} ${devnum}:${distro_bootpart} 0x4000000 system.bit -fpga loadb 0 0x4000000 ${filesize} -bootm 0x00200000 - 0x00e00000 -exit; -``` - -##### Outputs - -- *boot.scr* - -### Boot partition contents - -Once all targets have been build, all the files of interest can be found in : - -*build-linux/output/boot*. It should contain **the following files**: - -- *bitstream.bit* (copied from *build/hw_export*) -- *boot.bin* (embedding the **FSBL**) -- *u-boot.img* (embedding the **SPL**) -- *boot.scr* (**boot script**) -- *system.dtb* (**device-tree** blob/binary) -- *uImage* (**kernel** image) - -All of these files can now be copied to the **SD card's** first (**FAT32**) **partition**. - -## root-filesystem (rootfs) - -For the *rootfs*, we chose (for now) a custom Alpine linux distribution, known to be lightweight, not relying on *gcc* and *systemd*, but instead on *musl*, *busybox* and *OpenRC* (https://en.wikipedia.org/wiki/Alpine_Linux). - -**Current version**: **3.17.0-armv7** - -### Build steps - -The script in charge of building the *rootfs* is located in [scripts/linux/root/alpine.tcl](../scripts/linux/root/alpine.tcl). It is called by the main [scripts/linux/build.tcl](../scripts/linux/build.tcl) script. - -#### 1. Downloading and unpacking sources - -First, the script downloads the Alpine sources from the official repository. It consists in 3 different compressed files: - -- the **u-boot archive** (uncompressed in build-linux/root/alpine-alpine-3.17.0/alpine-uboot) - - **NOTE**: (**unused** at the moment) - - https://dl-cdn.alpinelinux.org/alpine/releases/armv7/alpine-uboot-3.17.0-armv7.tar.gz -- the **apk-tools archive** - - needed for the base package installation - - https://dl-cdn.alpinelinux.org/alpine/main/armv7/apk-tools-static-2.12.9-r3.apk -- the **linux-firmware archive** - - https://dl-cdn.alpinelinnux.org/alpine/main/armv7/linux-firmware-other-20220509-r1.apk - -#### 2. Collect kernel modules - -Some Linux Kernel modules are built as *loadable modules*, meaning they can be loaded/unloaded at **runtime**, depending on the user's needs. We gather them and copy them in *build-linux/root/alpine-3.17.0/alpine-modloop* (more on modloop **TODO**), they will be loaded from the rootfs in the directory */lib/modules/kernel/5.15.0-xilinx*. - -#### 3. Creating rootfs structure and contents - -- Create required **subdirectories**: - - */usr/bin* - - */etc* - - */etc/apk* -- Copy **alpine-apk-tools** binaries into */sbin* -- Copy **qemu arm CPU emulator** to install *alpine* as **chroot** -- Copy **host resolving configuration** for the *chroot* environment to find the alpine-linux servers - - on *systemd* systems, apparently the *stub-resolv.conf* file is the one that works. -- **Copy the linux kernel loadable .ko modules** in */lib/modules* -- **Copy the linux firmwares** in */lib/firmware* -- **Install** the *alpine-base* package by running */sbin/apk.static* within a *chroot* (**apk** is the alpine-linux **package manager**). -- **Write alpine repositories' URL** in the file */etc/apk/repositories* -- **Install** all packages listed below (*Installed packages (apk) section*). -- **Register OpenRC processes** (similar to *systemd*) -- **Overwrite** *inittab* starting configuration file with a custom one -- **Add ** *snd-seq* (alsa sequencer) to the list of modules to be loaded on startup (otherwise it won't get loaded automatically). -- **Setup hostname, users and passwords** - - we usually have to **login as root** (pwd: **syfala**) - - we have to allow *ttyPS0* to login as root as well, by adding it to the */etc/securetty* file -- **Add root & syfala** to the 'audio' group - -#### 4. Install syfala-related files and applications - -- Copy **bitstream** and **host-side application** -- Copy **fpgautil.c**, **syfala-load.c** and the **fpga-bit-to-bin** python script -- **Compile** *fpgautil.c* and install it in */usr/bin* -- **Compile** *syfala-load.c* and install it in */usr/bin* -- **Convert** bitstream .bit to .bin with the help of the python script. -- **Install alpine faust package**. -- **Copy and compile ** host application files, using the Makefile - -The **rootfs** is now ready and moved to the *build-linux/output/root* directory, ready to be flashed on the **second partition** of the **SD card**. - -### Installed packages (apk) - -All the following packages are currently installed in the *rootfs* when building is complete. The table below has been made to keep track of the packages, their status, relevance... - -| name/category | description | flag | comments | -| ------------------ | ------------------------------------------------------------ | ----- | ------------------------------------------------------------ | -| *alpine-base* | meta-package for minimal alpine base | **Y** | **required** | -| **admin** | | | | -| *sudo* | | ? | Might not need it if we do everything as root? | -| *busybox-suid* | | ? | ^ | -| **network** | | | | -| openssh | | **Y** | **required** | -| ucspi-tcp6 | IPv6 enabled ucspi-tcp superserver | ? | | -| iw | nl80211 based CLI configuration utility for wireless devices | ? | | -| iwd | | **Y** | required for wlan | -| ~~wpa_supplicant~~ | utility providing key negotiation for WPA wireless networks | ? | replaced by iwd | -| dhcpcd | RFC2131 compliant DHCP client | **Y** | | -| dnsmasq | A lightweight DNS, DHCP, RA, TFTP and PXE server | **Y** | | -| hostapd | daemon for wireless software access points | ? | | -| iptables | Linux kernel firewall, NAT and packet mangling tools | ? | | -| avahi | | **Y** | Might be good to have an auto-connect/query system with OSC or something else... | -| wget | | ? | Is there really a need to ship it? | -| **system** | | | | -| dbus | Freedesktop.org message bus system | ? | | -| dcron | dillon's lightweight cron daemon | ? | | -| chrony | NTP client and server programs | ? | | -| gpsd | GPS daemon | ? | | -| musl-dev | the musl c library (libc) implementation (development files) | ? | | -| libconfig-dev | A simple library for manipulating structured configuration files | ? | | -| **audio/control** | | | | -| alsa-lib-dev | | ? | Useless at the moment | -| alsa-utils | | ? | ^ | -| alsaconf | | ? | | -| | | | | -| liblo-dev | Open Sound Control protocol implementation for POSIX systems | **Y** | Keep it for Faust control application | -| libmicrohttpd-dev | | **Y** | Remote Faust HTTP control | -| **development** | | | | -| bc | An arbitrary precision numeric processing language (calculator) | ? | | -| patch | Utility to apply diffs to files | ? | | -| make | | **Y** | **required** (on-device host application compilation) | -| gcc | | **Y** | **required** ^ | -| g++ | | **Y** | **required** ^ | -| libc6-compat | compatibility libraries for glibc | ? | ? | -| linux-headers | | **Y** | **required** for host application | -| python3 | | **Y** | **required** for fpga-bit-to-bin.py script | -| **utilities** | | | | -| vim | | ? | | -| emacs | | **Y** | for Tanguy ;) | -| i2c-tools | | **Y** | really useful for i2c-device probing | -| spi-tools | | **Y** | same, but for spi-device probing | -| faust-dev | | **Y** | used for linking with OSC and HTTP control libraries | -| autologin | | **O** | self-explanatory | -| hwdata-usb | | **Y** | useful for `lsusb` and peripheral debug | -| usbutils | | **Y** | ^ | - -## Userspace application - -### Communication with the faust dsp fpga block (IP) - -- source file: *arm/linux/ip.cpp* - -The initialization is pretty straightforward, all the drivers are generated by the Xilinx toolchain and located in the files *xsyfala.h/c* and *xsyfala_linux.h*. We just have to call the following function, which embeds all the proper *uio* system calls. - -```cpp -void initialize(XSyfala& x) { - XSyfala_Initialize(&x, "syfala"); - [...] -``` - -In *include/syfala/arm/ip.hpp*, some aliases have been written in the **IP namespace** in order to make the IP function calls more readable: - -```cpp -namespace Syfala::IP { - constexpr auto set_mem_zone_f = XSYFALA_SET(mem_zone_f); - constexpr auto set_mem_zone_i = XSYFALA_SET(mem_zone_i); -} -``` - -For example, these two functions, used to pass the DDR pointers to the IP, can be called like this: - -```cpp -IP::set_mem_zone_i(...); -IP::set_mem_zone_f(...); -``` - -### Inter-Integrated Circuit (i²c) - -- source file: *arm/linux/audio.cpp* - -The i²c initialization calls are pretty straightforward: - -```cpp -#include -// open /dev/i2c-0 and get its file-descriptor index -int fd = open("/dev/i2c-0", O_RDWR); -// then, acquire slave bus access -// I2C_SLAVE is defined in linux/i2c-dev.h -#define IIC_SSM_SLAVE_ADDR 0b0011010 -ioctl(fd, I2C_SLAVE, IIC_SSM_SLAVE_ADDR); -``` - -To write to the proper registers, the function that we use is pretty much the same as the one we use in the *baremetal* version: - -```cpp -static void write_reg(int fd, unsigned char offset, unsigned short data) { - unsigned char buffer[2]; - buffer[0] = offset << 1; - buffer[0] = buffer[0] | ((data >> 8) & 0b1); - buffer[1] = data & 0xff; - write(fd, buffer, sizeof(buffer)); -} -``` - -### GPIO (LED/SW) - -- source file: *arm/linux/gpio.cpp* - -**Note**: the API used here is apparently an old one, and is deprecated. It still works, but it **should be rewritten with the more recent one**. - -Here, we use two different 'devices': - -- `/dev/gpiochip0` - handling the **RGB LED** -- `/dev/gpiochip1` - handling the **switches** (including their LEDs) - -Like all other peripherals, calls are made with the `open-device()` and `ioctl()` functions. - -```cpp -// example for writing to the RGB LED -// it works pretty much the same way for 'read' calls -#define SYFALA_GPIO_AXI_LED_RGB_R_LINENO 6 -#define SYFALA_GPIO_AXI_LED_RGB_G_LINENO 5 -#define SYFALA_GPIO_AXI_LED_RGB_B_LINENO 4 - -static void write(const char* dev, int R, int G, int B) { - gpiohandle_request req; - giohandle_data data; - // requests are structured with 'lines', we set the line indexes first - req.lineoffsets[0] = SYFALA_GPIO_AXI_LED_RGB_R_LINENO; - req.lineoffsets[1] = SYFALA_GPIO_AXI_LED_RGB_G_LINENO; - req.lineoffsets[2] = SYFALA_GPIO_AXI_LED_RGB_B_LINENO; - req.lines = 3; - // set request's direction (output for write calls) - req.flags = GPIOHANDLE_REQUEST_OUTPUT; - // and now the matching data - data.values[0] = R; - data.values[1] = G; - data.values[2] = B; - // now, open device - int fd = open_device(dev, O_WRONLY); - // get a 'line handle file descriptor' from the request - ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); - close(fd); - // write the data - ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); - close(req.fd); -} -``` - -### Memory - -- source file: *arm/linux/memory.cpp* - -Accessing the reserved memory space specified in the device-tree requires a call to the `mmap()` function, like so: - -```cpp -#define MEM_ADDR 0x35000000 -#define MEM_LEN 0x08000000 -int fd = open("/dev/mem", O_RDRW | O_SYNC); -void* mem = mmap(NULL, MEM_LEN, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, off); -if (mem == MAP_FAILED) { - perror("Can't map reserved memory space"); - exit(1); -} -``` - -### Serial Peripheral Interface (SPI) - -- source file: *arm/linux/spi.cpp* - -**Note:** the *spi-cadence.c* driver only supports at the moment transfers using **PL-PS interruptions**, which are not enabled in our current projects (**polling mode** is used). Polling-mode transfers might be supported in a near future (see: https://lore.kernel.org/lkml/20221219144254.20883-4-wsadowski@marvell.com/). - -SPI uses, like other IO peripherals the `open-device()` and `ioctl()` functions, as well as a set of *userspace-targeted* macros: - -```cpp -#define SPI_MASTER_CLOCK_BASE_HZ 166666672 -#define SPI_SLAVE0_SPEED_MAX_HZ 1000000 -#define SPI_SLAVE0_DEV_ID "/dev/spidev0.0" - -static void initialize() { - int mode = SPI_MODE_0; - int speed = SPI_SLAVE0_SPEED_MAX_HZ; - int bpw = 8; - int fd = open(SPI_SLAVE0_DEV_ID, O_RDWR); - // set SPI mode, speed and bits-per-word parameters - // we use ioctl() and the SPI_IOC_WR_ macros to do so: - ioctl(fd, SPI_IOC_WR_MODE, &mode); - ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &mode); - ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &mode); -} -``` - -For **read/write transfers**, a specific data structure `spio_ioc_transfer` is used: - -```cpp -static u32 poll(int fd, int channel) { - struct spi_ioc_transfer xfer; - int r, value; - u8 data[3]; - // Full-duplex mode: - // we set both tx & rx buffers on the same 'transfer' - memset(&xfer, 0, sizeof(xfer)); - xfer.tx_buf = (__u64) data; - xfer.rx_buf = (__u64) data; - xfer.len = 3; - /* for the MCP30008 target: - * byte n°1 is used to send a 'start bit' - * byte n°2 is used to send the channel number we want to poll - * byte n°3 is a 'don't care' byte. */ - data[0] = 0b00000001; - data[1] = 0b10000000 | ((channel & 7) << 4); - data[2] = 0; - // request transfer with ioctl() - r = ioctl(fd, SPI_IOC_MESSAGE(1), &xfer); - // merge data[1] & data[2] to get proper result - value = (data[1] << 8) & 0b1100000000; - value |= (data[2] & 0xff); - return value; -} -``` diff --git a/doc/tutorials/linux/getting-started.md b/doc/tutorials/linux/getting-started.md deleted file mode 100644 index 5890ba4..0000000 --- a/doc/tutorials/linux/getting-started.md +++ /dev/null @@ -1,241 +0,0 @@ -# syfala-linux getting started - -## Requirements - -- **Xilinx toolchain** version **2022.2** - - for *gcc-compatibility* reasons -- `arm-none-eabi-gcc` **cross-compilation toolchain** -- An available **SD card** -- The following **Linux packages** installed on your machine: - - `bison flex libssl-dev bc u-boot-tools cpio libyaml-dev curl kmod squashfs-tools qemu-user-static` - - - -## Building - -### Available commands - -#### From scratch - -**First**, a regular **syfala project** has to be built with the following options: - -```shell -syfala examples/virtualAnalog.dsp --linux -``` - -The `--linux` option is used for **compiling the host-side** (**ARM**) **application** with the **linux-specific source files** (otherwise, it would be compiling the standard baremetal one). - -After **synthesis**, the script will detect that you don't currently have a linux build, which is required for building the application, and will download and build everything for you, you'll just have to flash it to your formatted SD card afterwards - -### Outputs - -The build outputs are located in the`build-linux/output` directory, with two distinct `boot` and `root` subdirectories, which then will have to be be flashed on the first and second partitions of your SD card. - -## Usage - -### Formatting the SD card - -The **SD card** has to be formatted like so: - -- **1st** partition: **FAT32** -- **2nd** partition: **ext4** (Linux filesystem) - -There are many ways to achieve this, for instance: - -```shell -# you can just replace with your SD device, e.g: /dev/sda or /dev/mmcblk0 -sudo parted /dev/... --script -- mklabel msdos -sudo parted /dev/... --script -- mkpart primary fat32 1MiB 128MiB -sudo parted /dev/... --script -- mkpart primary ext4 128MiB 100% -sudo parted /dev/... --script -- set 1 boot on -sudo parted /dev/... --script -- set 1 lba on -sudo mkfs.vfat /dev/device-partition-1 # e.g. /dev/sda1 -sudo mkfs.ext4 /dev/device-partition-2 # e.g. /dev/sda2 -sudo parted /dev/... --script print -``` - -### Flashing boot & root partitions - -```shell -# In case your SD device is /dev/sda -# 1. Copying boot partition files -sudo mount /dev/sda1 /mnt -sudo cp -r build-linux/output/boot/* /mnt -sync -sudo umount /mnt -# 2. Copying root partition contents -sudo mount /dev/sda2 /mnt -sudo cp -r build-linux/output/root/* /mnt -# This might take a while... -sync -sudo umount /mnt -``` - -### Booting - -Once flashed, just insert the SD card in your device's socket, **make also sure it is configured to boot on SD** (For the **Zybo** boards, you'll have to place a **shorting jumper on SD** instead of *JTAG*/*QSPI*). - -### Connecting - -You can still connect through the *ttyUSB* **Serial Port**, or with **SSH**. - -- for **Serial Port** connection, check that devices ``/dev/ttyUSB0``and ``/dev/ttyUSB1``are present on your host and use a serial communication program with following configuration: device ``/dev/ttyUSB1``, 115200 8N1 (115200 bits/second, one start bit, eight (8) data bits, no (N) parity bit, and one (1) stop bit), no hardware flow control and no software flow control. If hardware flow control is enable, the serial connection will not behave properly. for instance when using minicom: -```shell -minicom -b 115200 -D/dev/ttyUSB1 -8 -``` -(check hardware flow control in minicom, ctrl-A Z). Linux booting console will appear. A login prompt will appear as soon as the booting process has completed: -```shell -Welcome to Alpine Linux 3.17 -Kernel 5.15.0-xilinx on an armv7l (/dev/ttyPS0) - -syfala login: -``` -- for **SSH** connection, make sure that you are connected on the same network as your device's, get its IP address by serial connection as explained above and log as root: -```shell -ssh root@192.168.0.1 . -``` -### Login/users - -The rootfs has the same structure as any Linux build. The scripts adds a **default user named syfala**, which has its *home* directory in */home/syfala*. - -- The password required to **login as root** is *syfala* -- The password required to **login as syfala** is *syfala* - -### Faust DSP builds - -All the **DSP builds** made with the **syfala toolchain** are placed in the */home/syfala* directory by default. For instance, if you make a build from the **virtualAnalog.dsp** file , the *bitstream*/*application* outputs will be located in: - -- */home/syfala/virtualAnalog/bitstream.bin* -- */home/syfala/virtualAnalog/application.elf* - -You can then use the - -```shell -syfala-load [--list | --help] -``` - -utility command (e.g. `syfala-load virtualAnalog`), which will take care of **loading the bitstream** and **executing the app** properly. - -You can also do all of that manually of course: first, **load the bitstream** by entering the following command line: - -```shell -fpgautil -b /home/syfala/virtualAnalog/bitstream.bin -``` - -and then **execute the Host application** like you would normally do with a Linux binary: - -```shell -cd /home/syfala/virtualAnalog -./application.elf -``` - -If you wish to **add another build** to the SD card, you just have to re-run the syfala toolchain normally on your computer, with the `--linux` option. **Your previous builds won't be erased or modified.** - -```shell -syfala examples/fm.dsp --linux -``` - -Once the build is complete, you will have two distinct project directories in your`build-linux/output/root/home/syfala` directory: - -- `/home/syfala/virtualAnalog` -- `/home/syfala/fm` - -You will then have to **re-flash your SD card** to **update the root partition**, or directly copy the directory through **ssh** (e.g. with the `scp` command). - -### Getting the device's IP & port from avahi (for network-based control) - -Once a DSP target is loaded with the `syfala-load` command, an **avahi service** is automatically started in a separate thread. If your desktop machine is on the same network as the FPGA board, and you have **avahi** installed & running, you should be able to **retrieve the FPGA board's IP address and port** required for the HTTP/OSC controls. You can use the `avahi-browse` command in order to do so: - -```shell -avahi-browse _syfala._tcp --resolve -``` - -### HTTP control - -In order to build a target with **HTTP support**, you can add the `--http` flag to the command line: - -```shell -syfala examples/fm.dsp --linux --http -``` - -After loading a DSP target with the `syfala-load` command (or manually), the host application **will create a HTTP server** allowing users to **control the Faust DSP parameters remotely** (given that you are on the same network as your FPGA board). - -At runtime, when executed, the **application will print the device's current network IP** (IPv4), and the **port** used by the HTTP server. You can then **use any web browser**, and control the application by entering the server's URL, for example *http://192.168.0.1:5510* - -### OSC control - -In order to build a target with **OSC support**, you can add the `--osc` flag to the command line: - -```shell -syfala examples/fm.dsp --linux --osc -``` - -**Note:** your Faust **.dsp file must also contain this line** in order to enable OSC support: - -```faust -declare options "[osc:on]"; -``` - -In parallel, the Host application will also create an **Open Sound Control-compliant UDP server**, and **print its send/receive ports** when executed. You can then control remotely the Faust DSP parameters by sending OSC messages like so: - -- */virtualAnalog/lfoRange 2000* -- */virtualAnalog/oscFreq 500* -- ... - -More on: https://faustdoc.grame.fr/manual/osc/ - -### MIDI control - -In order to build a target with **MIDI support**, you can add the `--midi` flag to the command line: - -```shell -syfala examples/fm.dsp --linux --midi -``` - -**Note:** your Faust **.dsp file must also contain this line** in order to enable MIDI support: - -```faust -declare options "[midi:on]"; -``` - -The **Zybo boards** have a **Host USB port**, located next to the switches. It can be used to **connect a MIDI device** and map its controls accordingly. No additional driver configuration is needed, **but the board needs to be powered from an external power supply source**: - -> The supply must use a center-positive 2.1mm internal-diameter plug and deliver between 4.5V to 5.5V DC. It should also be able to output at least 2.5 A (12.5 Watts) in order to support power-hungry Zynq projects and external peripherals. To use an external supply with a barrel jack, plug it into the power jack (J17), set jumper JP6 to “WALL”, and then set SW4 to “ON”. - -You'll also have to put a **shorting jumper** on **JP2** (*HOST*), next to the USB port. - -The **Faust midi-mapping process** is explained here: https://faustdoc.grame.fr/manual/midi/ - -### Wi-Fi - -Wi-Fi is handled by *iwd* (provided you have an USB dongle, or the appropriate additional hardware, which Zybo boards do not possess natively), the available commands are: - -```shell -# List your available wifi device(s), look for wlan0 -iwctl device list -# If you don't know the SSID of your network, you can run a scan and retrieve a list of all the detected networks: -iwctl station wlan0 scan && iwctl station wlan0 get-networks -# To connect to a network (use connect-hidden if it is a private network): -iwctl station wlan0 connect -``` - -more on: https://wiki.alpinelinux.org/wiki/Wi-Fi - -### Autologin / Autostart DSP target - -In order to **autologin** as root on the board, you have to edit the file */etc/inittab* like the following: - -```shell -#ttyPS0::respawn:/sbin/getty -L ttyPS0 115200 vt100 -# For autologin (as root): comment out the previous line and uncomment the next one: -ttyPS0::respawn:/sbin/mingetty --autologin root --noclear ttyPS0 115200 vt100 -``` - -To **autostart a DSP target on boot**, create a *.start* file in */etc/local.d* , for example */etc/local.d/virtualAnalog.start*: - -```shell -#!/bin/sh -syfala-load virtualAnalog -``` - -Execute `chmod 755 /etc/local.d/virtualAnalog` . That's it! diff --git a/doc/user-getting-started-doc.pdf b/doc/user-getting-started-doc.pdf deleted file mode 100644 index c4cfd93..0000000 Binary files a/doc/user-getting-started-doc.pdf and /dev/null differ