Un coprocesseur CycloneV via le PCIe avec l’APF6_SP

Armadeus systems sort une nouvelle carte à base de processeur + FPGA au mois de février 2015: l’APF6_SP.

apf6_sp_show
Une photo de l’APF6_SP avec son processeur i.MX6D et son fpga CycloneV C3.

Armadeus systems s’est spécialisée dans les modules proc + fpga. Ils avaient déjà l’APF27 à base d’i.MX27 et de spartan3a ainsi que l’AFP51 à base d’i.MX51 et de spartan6. Ces deux cartes possèdent un lien de type bus mémoire avec le processeur de manière à ce que le FPGA soit vu dans sont espace mémoire de la même manière que les autres périphériques.

Schéma général de l'APF6_SP
Schéma général de l’APF6_SP

L’APF6_SP est toujours à base de processeur i.MX de chez Freescale : l’i.MX6. Ce processeur se décline en version solo, dual ou quad core. Une des particularité de cette nouvelle carte est qu’elle utilise un FPGA de chez Altera plutôt que Xilinx.

Deux gros changement interviennent avec cette nouvelle carte :

  • Le liens processeur-FPGA n’est plus de type «bus mémoire» mais utilise le PCI express. Ce qui le rend beaucoup plus standard.
  • Deux puces de RAM DDR3 sont dédiées au FPGA, en plus de la RAM dédiée au processeur. Cette caractéristique ouvre des perspectives en matière de traitement d’images/vidéo; en effet il est possible de stocker des images entières dans la DDR; possibilitée qui est très limités en utilisant les blocks de ram interne au FPGA.

Mais pourquoi cette carte est-elle intéressante aux yeux du front de libération des FPGA ?

Car Armadeus Systems se base essentiellement sur des logiciels libres pour faire tourner ses modules. Le BSP est à base de buildroot, tous les outils de développement peuvent fonctionner sous Linux. Et pour le CycloneV, Quartus en version gratuite (web edition) sous Linux suffit.

Armadeus System joue la transparence avec une documentation abondante via un wiki et fournie tout son code sur sourceforge.

Enfin, un portage pour POD est en cours. Ce qui permettra d’utiliser un outils libre pour architecturer ses projets FPGA.

Un modulateur PWM en Chisel

Pour changer des LED qui clignotent, voici un modulateur PWM écrit en Chisel avec son testbench.

Le code ci-dessous (PWM.scala) est du Scala standard utilisant la librairie Chisel.

import Chisel._
/* Classe contenant le comportement du module */
class PWM extends Module {
  /* Bundle io obligatoire */
  val io = new Bundle {
    val duty  = UInt(INPUT,  8)
    val out  = Bool(OUTPUT)
  }

  /* Registre 8 bits pour le compteur */
  val counter = Reg(UInt(width=8))
  counter := counter + UInt(1)

  /* Registre de sortie avec le comparateur */
  io.out := Reg(next=(counter<io.duty))  
}

/* Point d'entrée du programme */
object Example {
  def main(args: Array[String]): Unit = {
    chiselMain(args, () => Module(new PWM()))
  }
}

Le code du modulateur ci-dessus est découpé en deux parties.

La première décrit le comportement du module. Elle comprend le bundle (similaire au record en VHDL) appelé io, qui doit être présent dans chacun des modules pour décrire les entrées et les sorties, un compteur 8 bits, et le registre de sortie qui est alimenté par le comparateur de rapport cyclique.

La deuxième partie est nécessaire pour le module qui se trouve au sommet de la hiérarchie afin de décrire le point d’entrée qui servira à la génération du code.

Il est aussi nécessaire de fournir le fichier build.sbt qui sert à indiquer a SBT (l’outil de build Scala) qu’il doit également aller chercher Chisel dans ses paquets avant de lancer la compilation. SBT va d’office compiler tout les fichiers Scala (avec l’extension .scala) qu’il trouve dans le répertoire courant.

libraryDependencies += "edu.berkeley.cs" %% "chisel" % "latest.release"

scalacOptions ++= Seq("-deprecation", "-feature", "-unchecked", "-language:reflectiveCalls")

Il faut ensuite s’assurer que Chisel génère du Verilog en lançant la commande

sbt 'run --v'

Il manque un banc de test pour exercer le design. Chisel propose de compiler également pour nous un modèle C++ du design qu’on peut obtenir
en utilisant la commande suivante :

sbt 'run --test --genHarness --vcd'

On va maintenant créer un testbench C++ qui permettra de générer les VCD. Appelons ce fichier main_pwm.cpp.

#include "PWM.h"
#include <iostream>

int main (int argc, char* argv[]) { 
  // Créer l'objet PWM
  PWM_t* c = new PWM_t();

  // Recupérer le nombre de cycles à exécuter
  int lim = (argc > 1) ? atoi(argv[1]) : -1;
  if(lim == -1) {
     cout << "wrong argument, should be :" << endl;
     cout << "a.out <n>" << endl;
     return 1;
  }
  // Initialiser le modèle
  c->init();

  // Ecrire l'entête du VCD
  c->dump_init(stdout);

  // Ecrire le rapport cyclique
  c->PWM__io_duty = LIT<8>(100);
  for (int t = 0; lim < 0 || t < lim; t++) {
    // Active le reset sur le premier cycle
    dat_t<1> reset = LIT<1>(t == 0);

    // Dump du VCD
    c->dump(stdout,t);

    // Avancer d'une période d'horloge
    c->clock(reset);
    } 
}

Il reste juste à compiler le tout avec g++.

g++ PWM.cpp main_pwm.cpp

À exécuter

./a.out 10000 > out.vcd

Et admirer le résultat dans gtkwave

gtkwave out.vcd

Le FLF vous souhaite ses meilleurs vœux pour pour l’année 2015.

Que les outils pour les FPGA se libèrent et qu’ils se répandent dans tous les greniers et caves de tous les bidouilleurs.

Va-t-on voir émerger une chaîne de développement complète cette année ? Quelques signes donnent de l’espoir notamment  du coté de VTR .

Bonne année 2015

vhd2vl: Convertir du vhdl en verilog

vhd2vl est un petit utilitaire écris en C (flex/bison) permettant de convertir du VHDL synthétisable en verilog. La page officiel présente la version 2.4, cette version ne compile qu’avec quelques modification sur une distribution récente.

Une version modifiée pour compiler sur debian jessie se trouve sur le github de Martoni. Pour l’utiliser il suffit de descendre le code avec git :

git clone git@github.com:Martoni/vhd2vl.git

Et faire un simple «make» dans le répertoire src/.

Pour convertir un fichier vhdl en verilog rien de plus simple (on pourra utiliser les exemples se trouvant dans les sources):

vhd2vl exemple.vhd > exemple.v

Le programme fonctionne plutôt bien à condition d’adapter son code vhdl de manière à générer un verilog correct.

En le testant sur mon «blinking led project» (blp), j’ai pu néanmoins constater quelques problèmes comme:

  • Support hasardeux du type CONSTANT: Le type constant est converti en un «reg» ce qui n’est pas reconnu comme une constante par les logiciels de synthèse. On doit pouvoir modifier ça simplement pour qu’il génère un «localparam» par exemple.
  • Pas de warnings sur les mots clef: Les mots clefs en vhdl ne sont pas les même qu’en verilog, vhd2vl ne râle pas quand il y a une variable en vhdl qui est un mot clef en verilog (par exemple avec le mot clef «edge»).
  • Pas de support de l’underscore ‘_’ pour les nombres. En verilog/VHDL on peut mettre des séparateur pour les milliers histoire que ça soit plus lisible 1_000_000, vhd2vl ne comprend pas.
  • Pas de support du type time (unité sec): bon ça c’est un peu tordu, car ça n’est pas synthétisable en l’état de toute manière.

Bref vhd2vl est un petit logiciel comportant peu de fichiers sources : en fait juste deux. S’il ne répond pas tout à fait à nos attentes il est très facile d’aller le modifier pour l’adapter.

Après discussion avec Larry, visiblement la version 2.4 sera la dernière car l’objectif est de l’intégrer au projet icarus verilog. Mais j’ai beau compiler la dernière version du trunk de icarus, je ne parviens pas à faire la même chose avec.

[EDIT 7 janvier 2016] Non non, vhd2vl n’est pas mort, Larry continu a le développer.

Compiler debit sous Jessie (debian)

Debit est un projet de logiciel permettant de faire du reverse sur les bitstreams des fpga Xilinx et Altera de manière à pouvoir ensuite faire de la synthèse libre.

Le projet était porté par Jean-Baptiste Note, mais le site de son projet ulogic.org reste inaccessible en permanence.

Le git du code est lui par contre accessible sur google code.

Le code n’ayant pas bougé depuis 2008 il a été nécessaire de faire quelques modification pour pouvoir compiler, ces modifications se trouvent sur le github de Martoni.

Pré-requis

Pour pouvoir compiler le projet sur Debian Jessie, il faut d’abord installer quelques packets:

sudo apt-get install xmlto xvfb valgrind glade build-essential
sudo apt-get install libgtk2.0-dev automake libcanberra-gtk-module
sudo apt-get install icoutils scrollkeeper git

Glade 2.12

Debit utilise une version antique de glade qui n’est plus disponible dans les packets debian, il faut donc l’installer à la main.

Pour cela il faut télécharger l’archive et la décompresser:

$ cd /opt/
$ wget http://ftp.gnome.org/pub/GNOME/sources/glade/2.12/glade-2.12.2.tar.gz
$ tar -zxvf glade-2.12.2.tar.gz
$ cd glade-2.12.2

Le code ne compile pas en l’état il faut modifier légèrement les includes. On peut le faire rapidement avec la commande suivante :

sed -i 's/gtkclist.h/gtk.h/g' glade/*.c
sed -i 's/gtkclist.h/gtk.h/g' glade/*.h

On peut alors le compiler et l’installer avec les commandes classiques:

./configure
make
make install
make clean

Debit

Prendre ensuite le trunk du git de martoni :

git clone git@github.com:Martoni/debit.git

Et compiler avec les commandes classique des autotools :

$ cd debit
$ ./autodo.sh
$ ./configure
$ make

Compiler Torc sous Debian Jessie

Prérequis :

sudo apt-get install libboost-all-dev

Descendre le svn (avec git c’est mieux) :

git svn clone https://svn.code.sf.net/p/torc-isi/code/trunk torc

Faire un premier «make» dans src/, ce qui va créer un fichier nommé Makefile.local. Ouvrir ce fichier et ajouter les path vers boost :

BOOST_INCLUDE_DIR = /usr/include/boost/
BOOST_LIB_DIR = /usr/lib/

Faire un make (toujours dans src/) :

$ make

La configuration converti tous les warning en erreur (-Werror), et comme il reste des warnings visiblement dans le svn on arrive pas à tout compiler. Pour compiler malgré tout, virer l’option dans le fichier src/torc/Makefile.targets  (ligne 59):

-Werror \

 

Torc est un logiciel libre permettant de générer les bitstreams pour les fpga Xilinx:

http://torc-isi.sourceforge.net/documentation.php

Compiler GHDL avec ses petites mains

GHDL est le plus avancé des simulateurs libre pour le VHDL. GHDL est déjà intégré dans de nombreuses distributions, un simple «apt-get install ghdl» fonctionne sur une ubuntu ou une debian (wheezy).

Cependant, il se peut que nous souhaitions utiliser la dernière version en date de ghdl (0.32). Il se peut aussi que ghdl ne soit pas encore intégré à notre distribution préférée (c’est le cas de Debian Jessie), auquel cas nous aurons besoin de compiler l’outil depuis les sources.

dépendances

Les paquets suivants doivent être installé au préalable :

$ apt-get install gnat mercurial

Récupérer les sources
Les sources se trouvent sur sourceforge et utilise mercurial comme gestionnaire de version:

$ cd /opt/
$ hg clone http://hg.code.sf.net/p/ghdl-updates/code ghdl-updates-code

Nous allons aussi avoir besoin des sources de gcc:

$ wget ftp://ftp.uvsq.fr/pub/gcc/releases/gcc-4.9.2/gcc-4.9.2.tar.bz2

Une fois les sources téléchargées il faut générer une archive que nous décompresserons ensuite dans les sources de gcc.

$ cd ghdl-updates-code/translate/gcc
$ ./dist.sh sources

Installation du vhdl dans gcc

On décompresse tout d’abord les archives de ghdl fraichement générée et de gcc:

$ cd /opt/
$ tar -jxvf ghdl-updates-code/translate/gcc/ghdl-0.32dev.tar.bz2
$ tar -jxvf gcc-4.9.2.tar.bz2

Puis on copie le code du plugin vhdl dans gcc

$ cp -R ghdl-0.32dev/vhdl gcc-4.9.2/gcc/

Compilation

Pour compiler il nous suffit maintenant de nous rendre dans le répertoire de gcc puis de faire un ./configure, make, make install:

$ cd gcc-4.9.2/
$ mkdir /opt/ghdl/
$ ./configure --enable-languages=vhdl --disable-bootstrap --prefix=/opt/ghdl/
make CFLAGS="-O"

L’ajout de «–prefix=/opt/ghdl» permet d’éviter de péter son installation de gcc en installant ghdl dans un autre endroit.

Pour utiliser notre version compilée de ghdl il suffit donc de l’appeler en donnant le bon path :


$ /opt/ghdl/bin/ghdl --help
usage: /opt/bin/ghdl COMMAND [OPTIONS] ...
[...]

 

Compiler les exemples Chisel sur Jessie

Chisel est un langage de description hardware développé par l’université de Berkley basé sur le langage Scala.

Les mainteneurs du projet Chisel fournissent un github de code d’exemples avec un tutoriel qui va avec. Le guide d’installation est par contre un peu léger et nécessite quelques adaptations pour tourner correctement sous Debian Jessie.

Dépendances

Les paquets debian à installé sont les suivants:

  • Scala
  • sbt
  • g++4.8
  • openjdk-7-jre

Que l’on peut installer sous Jessie avec les commandes suivantes:

sudo apt-get install scala
sudo apt-get install g++-4.8-multilib
sudo apt-get install openjdk-7-jre

sbt n’étant pas intégré dans Jessie, il est nécessaire de l’installer à la main en décompressant l’archive:

wget https://dl.bintray.com/sbt/native-packages/sbt/0.13.6/sbt-0.13.6.tgz
tar -zxvf sbt-0.13.6.tgz

Puis en l’ajoutant à son .bashrc :

# Scala built tool
export PATH=$PATH:"/opt/sbt/bin/"

Installation des tutoriels

Tout d’abord il nous faut descendre le git des tutoriels :

git clone https://github.com/ucb-bar/chisel-tutorial.git
cd chisel-tutorial/example

Puis tenter de compiler l’exemple Parity avec le makefile :

$ make Parity.out
set -e -o pipefail; sbt -Dsbt.log.noformat=true "run Parity --genHarness --compile --test --backend c " | tee Parity.out
/bin/sh: 0: Illegal option -o pipefail
../suffix.mk:61: recipe for target 'Parity.out' failed
make: *** [Parity.out] Error 2

Et c’est le drame !

Pour que ça fonctionne il faut taper la commande à la main sans le «set -e -o pipefail».

$ sbt -Dsbt.log.noformat=true "run Parity --genHarness --compile --test --backend c " | tee Parity.out

...

STEP 1 -> 10
 PEEK Parity.io_out -> 0x0
EXPECT Parity.io_out <- 0 == 0 PASS
RAN 10 CYCLES PASSED
PASSED
[success] Total time: 31 s, completed 27 oct. 2014 12:28:46
$

 

Expérimentations de Migen sur APF27 avec debian

Migen est une tentative open-source de faire du design FPGA en python. La solution initiée par S.Bourdeauducq (principale développeur de milkymist) permet de simuler le design en python pur et de le générer en vérilog pour la synthèse sur le FPGA proprement dite.

Installation sur debian Wheezy

Pour installer Migen, il faut tout d’abord «cloner» le projet git hub avec la commande suivante :


$ git clone https://github.com/m-labs/migen.git

Puis de se rendre dans le répertoire ainsi créé et de taper la commande d’installation suivante:


$ cd migen
$ sudo python3 setup.py install
Migen requires python 3.3 or greater

Premier problème sur debian wheezy : python est trop vieux. Comme le dit le message il nous faut un python 3.3 minimum, et celui de wheezy en est à la version 3.2 🙁

Il va donc nous falloir installer la dernière version 3.4 de python (tant qu’à faire prendre la dernière).


tar -Jxvf Python-3.4.0.tar.xz
cd Python-3.4.0
./configure
make
make test
sudo make install

De là il est facile de s’installer Migen


sudo python3.4 setup.py install

Icarus

Migen génère du code en verilog. Pour pouvoir le simuler il est conseillé d’utiliser  le simulateur libre Icarus, logiciel qui se trouve dans le paquet «verilog» de debian :


sudo apt-get install verilog

Dans le répertoire vpi des sources de migen il faut également générer le plugin permettant de se connecter à icarus :


$ cd migen/vpi/
$ make
$ sudo make install
install -m755 -t /usr/lib/ivl migensim.vpi

Premiers pas avec Migen

Le «helloworld» de l’électronicien, c’est la led qui clignote. La conception sur FPGA se rapprochant plus de l’électronique que du logiciel, ça ne loupe pas : l’exemple donné dans la doc est une led qui clignote !

L’exemple pose plusieurs problème :

testmigen.py :


from migen.fhdl.std import *
from mibuild.platforms import m1
plat = m1.Platform()
led = plat.request("user_led")
m = Module()
counter = Signal(26)
m.comb += led.eq(counter[25])
m.sync += counter.eq(counter + 1)
plat.build_cmdline(m)

Si on exécute tel quel ce code on tombe sur une erreur de path «/opt/Xilinx»


$ python3.4 testmigen.py
Traceback (most recent call last):
File "testmigen.py", line 11, in 
plat.build_cmdline(m)
File "/usr/local/lib/python3.4/site-packages/migen-unknown-py3.4.egg/mibuild/generic_platform.py", line 272, in build_cmdline
self.build(*args, **kwargs)
File "/usr/local/lib/python3.4/site-packages/migen-unknown-py3.4.egg/mibuild/xilinx_ise.py", line 246, in build
self.map_opt, self.par_opt)
File "/usr/local/lib/python3.4/site-packages/migen-unknown-py3.4.egg/mibuild/xilinx_ise.py", line 133, in _run_ise
vers = [ver for ver in os.listdir(ise_path) if _is_valid_version(ise_path, ver)]
FileNotFoundError: [Errno 2] No such file or directory: '/opt/Xilinx'

Car Migen est capable d’aller jusqu’à la génération du design avec le webpack de xilinx. Mais pour cela il faut lui indiquer le bon chemin d’installation de ISE. Le code python de Migen référençant en dur le path, pour éviter de toucher au code, le plus simple est de faire un liens sur /opt/Xilinx.


$ sudo ln -s ~/myxilinxinstallation/ /opt/Xilinx
$ sudo chmod 755 /opt/Xilinx

De cette manière, nous pouvons maintenant lancer le «helloworld» qui va nous générer le bitstream final directement :


$ python3.4 testmigen.py
...
Sun May 4 16:06:25 2014

Running DRC.
DRC detected 0 errors and 0 warnings.
Creating bit map...
Saving bit stream in "top.bit".
Saving bit stream in "top.bin".
Bitstream generation is complete.

Tous les fichiers générés se trouve dans le répertoire «build» :


$ ls build/
build_top.sh top.bin top.drc top_map.ncd top.ngc top.pad top_par.xrpt top.srp top_usage.xml usage_statistics_webtalk.html xst
netlist.lst top.bit top.lso top_map.ngm top.ngc_xst.xrpt top_pad.csv top.pcf top_summary.xml top.v webtalk.log
par_usage_statistics.html top_bitgen.xwbt top_map.map top_map.xrpt top.ngd top_pad.txt top.prj top.ucf top.xpi xlnx_auto_0_xdb
top.bgn top.bld top_map.mrp top.ncd top_ngdbuild.xrpt top.par top.ptwx top.unroutes top.xst _xmsgs

Et la led ne clignote toujours pas !

Deuxième problème de l’exemple : la plate-forme utilisée est une m1, or nous utilisons une apf27.  Il faut que nous importions la bonne plate-forme pour pouvoir faire clignoter notre led. Nous allons donc changer notre script python pour intégrer l’apf27:

#!/usr/local/bin/python3.4
# -*- coding: utf-8 -*-
 
from migen.fhdl.std import *
from mibuild.generic_platform import Pins, IOStandard
from mibuild.platforms import apf27
 
ios = [
    ("user_led", 0, Pins("J2:22"), IOStandard("LVCMOS33"))
]
 
plat = apf27.Platform()
plat.add_extension(ios)
led = plat.request("user_led", 0)  # led pin on apf27dev
m = Module()
counter = Signal(26)
m.comb += led.eq(counter[25])
m.sync += counter.eq(counter + 1)
plat.build_cmdline(m)

Le bitstream généré se nomme top.bit et se trouve dans le répertoire «build» nouvellement créé.

Il suffit ensuite de télécharger top.bit sur le fpga (via uboot ou via Linux au choix)

Et la led clignote !