Russell Merrick est un ingénieur en électronique qui travail sur des FPGA depuis plus de 15 ans. C’est l’auteur du site internet Nandland qui propose toute une série de tutoriels pour débuter et s’amuser avec des FPGA.
Russell vient de sortir un livre chez No Starch Press pour débuter avec un FPGA.
En seulement 280 pages, on peut dire que l’auteur couvre bien le sujet. Les deux langages HDL du «marché» sont décrits et tous les exemples sont donnés en Verilog ainsi qu’en VHDL.
C’est la première fois que, dans un livre, je vois un vrai comparatif des deux HDL. En effet, l’un est souvent balayé au profit de l’autre avec un «si vous connaissez l’un vous saurez vous servir de l’autre». Même si l’accent est mis sur le ICE40 de Lattice (Célèbre FPGA lowcost reversé dans le projet icestorm), on sent bien qu’il existe d’autres constructeurs et que l’auteur a travaillé avec.
Le livre n’est pas si gros et pourtant il traite vraiment de tout ce qu’il faut savoir pour bien commencer (et avancer) dans le FPGA.
Un chapitre entier est consacré aux bascule D (FlipFlop) et à la problématique de conception synchrone. La notion de domaines d’horloge et son franchissement, les machines d’états, les macro classique (RAM, PLL, DSP) ne sont pas en reste.
Et avant d’aborder les entrées sorties (I/O, LVDS, SerDes) un chapitre particulièrement intéressant sur l’arithmétique est abordé. Tout est dit pour additionner, soustraire, multiplier et diviser (enfin surtout les méthodes de contournement de la division) des entiers mais également des nombres en virgules fixe (Qn.m) dans un FPGA.
C’est un livre que j’aurais adoré avoir pour débuter en FPGA, mais qui fera tout de même un très bon livre de référence au besoin.
Nous avons déjà parlé du Gatemate dans les colonnes du FLF. Mais jusqu’à présent, seul le kit de développement officiel de CologneChip était disponible. Le tarif du kit officiel étant assez élevé on attendait avec impatience d’avoir des cartes développées par des tiers pour pouvoir investir.
Ce qui est chose faite avec les kits suivant. La note reste éditable au grès des sorties de kit muni du FPGA.
Evaluation board officielle par CologneChip
À tout seigneur tout honneur, citons d’abord du kit officiel qui est proposé à un prix de 226€ sur digikey.
Le kit officiel du GateMateA1 proposé par CologneChip dans sa belle boite en carton
Olimex GateMate-A1
Annoncé en décembre 2023 par Olimex, le kit GateMateA1 devrait être proposé au tarif de 50€.
La carte GateMate A1 annoncée par Olimex
TrenzMicro TEG2000-01-P001
Le SoM de TrenzMicro TEG2000-01-P001 est dans les même ordre de grandeur au niveau tarif (69€) mais nécessitera une carte d’accueil pour s’en servir.
Le SoM (System on Module) de Trenz micro avec le GatemateA1
Un langage de description matériel écrit en Ruby visiblement maintenu par deux personnes. Je ne sais pas ce qu’il vaut.
Le processus de synthèse/placement/routage/bitstream prenant beaucoup de temps, on est amené à faire d’autres activité pendant le traitement. Ce «switch» de tâche nous amène à faire des erreurs fréquentes de version de bitstream au moment de la configuration du FPGA.
Il est fréquent de passer des heures voir des jours sur un bug qui n’en était finalement pas un puisque nous n’avions pas mis à jour la version du bitstream.
Pour éviter ce problème il faut pouvoir lire la version du bitstream généré de manière à s’assurer qu’on travail bien avec la bonne.
C’est exactement l’objet de la macro «usr_access» des FPGA de la série 7 de Xilinx.
Cette macro est appelée de la manière suivante en VHDL :
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.numeric_std.all;
Entity usr_accesse2 is
port
(
CFGCLK : out std_logic;
DATA : out std_logic_vector(31 downto 0);
DATAVALID : out std_logic
);
end entity;
Architecture usr_accesse2_1 of usr_accesse2 is
begin
CFGCLK <= '1';
DATA <= x"00000E0F";
DATAVALID <= '1';
end architecture usr_accesse2_1;
Et la valeurs de la sortie «DATA» est ré-inscriptible jusqu’à la génération du bitstream avec l’option -g USR_ACCESS.
Pour y mettre la date et l’heure on utilisera l’option timestamp dans le menu tools->edit device property.
Cette action à pour effet d’ajouter la commande suivante dans le xdc :
Avec Cocotb nous avons parfois des coroutines qui sont susceptible de rester «coincées» dans une boucle d’attente infinie. Si l’on y prête pas garde, on a vite fait de remplir son disque dur de traces totalement inutile.
# Une coroutine qui attend bien trop longtemps
async def too_long_coroutine(self):
await Timer(1, units="sec")
Pour éviter ce problème, l’idéal serait de pouvoir ajouter un «timeout» à l’appel de la coroutine susceptible de bloquer.
Ça tombe bien, cocotb a prévu un trigger pour ça : with_timeout()
from cocotb.triggers import with_timeout
await with_timeout(testcls.too_long_coroutine(), 100, "ns")
Sauf que python n’a pas trop l’air d’accord pour exécuter notre coroutine comme un trigger.
TypeError: All triggers must be instances of Trigger! Got: coroutine
C’est dommage, on perd beaucoup de l’intérêt de ce trigger !
La solution donnée par marlonjames est d’«empaquetter» la coroutine dans la fonction start_soon() comme ceci :
C’est une réalité aujourd’hui, il y a encore beaucoup d’entreprises qui tournent exclusivement avec le système d’exploitation de Microsoft.
L’environnement Microsoft n’est pas idéal pour faire fonctionner les outils de simulations libre, mais c’est tout de même possible.
Voyons comment faire pour installer Yosys, GHDL, smtbmc, gtkwave et autres outils classique dans le monde de la simulation libre sur Windows 10 Famille.
MSYS2
MSYS2 est un environnement/shell de développement open-source pour windows. Pour l’installer il suffit de se rendre sur la page officiel du projet et de télécharger l’installeur (83.5Mo).
Le répertoire par défaut «c:/msys64» convient très bien et installera un raccourci dans le menu de windows. N’oubliez pas de désactiver votre antivirus avant de lancer l’installation, sinon il aura peur de gpg et vous empêchera de l’installer correctement !
Console MSYS2 permettant d’installer les différents package avec pacman
Une fois installé, la console se lance. Nous allons commencer par mettre à jours MSYS avec pacman :
$ pacman -Syu
La commande aura pour effet de fermer la fenêtre de console, qu’il faudra réouvrir pour lancer les commandes suivantes pour installer les dépendances:
À ce point de l’installation on peut fermer la fenêtre de console pour aller ouvrir la console nommée «MSYS2 MINGW64» dans laquelle on exécutera les programmes fraîchement installés.
Le répertoire «home/user» de cette console se retrouve ensuite dans le répertoire C:\msys2\home de votre ordinateur.
Cocotb
Cocotb utilise l’installateur de python nommé «pip»:
En ouvrant la console nommée «MSYS2 MINGW64» on est sûr d’avoir désormais un environnement de simulation correct pour développer des IP sous Windows.
L’exécution de ses différents makefile habituels est presque transparente. Il faudra quand même adapter certaine ligne de commande. Par exemple avec GHDL il est obligatoire d’élaborer le design avec «-e» avant de le lancer avec «-r». Alors que sous Linux on peut passer directement de l’analyse à l’exécution, GHDL devine ce qu’il faut élaborer.
CλaSH n’est pas un HLS (High Level Synthesis). La fonction d’un logiciel HLS consiste à convertir un algorithme écrit dans un langage de programmation classique (très souvent du C) dans une architecture numérique en Verilog/VHDL.
Non.
CλaSH est un langage de description matériel basé sur le langage fonctionnel Haskell.
Le langage Haskell est né dans les années 90, fondé par une société secrète de mathématiciens qui voulait reprendre le contrôle des ordinateurs. En effet, vexés de voir tous ces geeks maîtriser cette machine mieux qu’eux ils décidèrent de se réunir de manière anonyme dans une cave (où il fallait entrer avec un mot de passe à base de développement limités sur un Algèbre commutatif isomorphe) pour fonder un nouveau langage compris par eux seuls. Le Haskell était né ! Enfin je crois 😉
Haskell est un langage fonctionnel, qui nous impose une autre façons de penser un programme informatique. Du dire des auteurs de CλaSH, le paradigme fonctionnel est plus à même de décrire du matériel que le paradigme impératif.
Un composant décrit en CλaSH est directement convertible en Verilog ou en VHDL (les deux sont gérés dans la version 1.0). Ce qui fait qu’un composant décrit en CλaSH est synthétisable avec n’importe quel logiciel de synthèse FPGA.
Dans le cas de ce type de langage on parle de générateur de code, un peu comme Chisel (basé sur Scala), Migen/Litex (basé sur Python) ou SpinalHDL (basé également sur Scala). Ces langages sont en fait des librairies ou des modules du langage auquel ils sont accolés. Cette modularité permet de profiter d’un langage souvent bien établi avec énormément de fonctions optimisées (Scala, Python, Haskell…).
Le paradigme fonctionnel n’est pas du tout quelque chose qui coule de source pour un simple électronicien comme votre serviteur. Cette dépêche a donc été un peu différée le temps d’avaler les 100 premières pages de tutoriel permettant de faire un simple « hello world » en Haskell. Puis d’avaler le tutoriel CλaSH pour enfin faire clignoter cette fameuse LED sur un kit FPGA low cost de base.
Nous allons donc tenter un petit CλaSHtest permettant de faire clignoter une led.
Le type de base manipulé en CλaSH est le Signal. CλaSH ne permettant que des descriptions synchrones, un Signal représente une liste infinie de valeurs synchronisée sur une horloge et un reset pour la valeur initiale. L’horloge et le reset du signal sont décrit par le Domaine dom du signal. La forme d’un Signal est donc la suivante :
Signal (dom :: Domain) a
En logique synchrone, le composant de base est le registre, nommé register:
register
( HiddenClockResetEnable dom dom
, NFDataX a )
=> a
-> Signal dom a
-> Signal dom a
Son fonctionnement est assez basique : La valeur initiale (de reset) est donnée en premier argument, le second argument est le signal d’entrée qui est recopié sur le signal de sortie (valeur de retour de la fonction). On peut utiliser CλaSH en ligne de commande avec la commande clash.clashi.
$ clash.clashi
Clashi, version 1.0.1 (using clash-lib, version 1.0.1):
http://www.clash-lang.org/ :? for help
Clash.Prelude>
Mais on préférera rapidement enregistrer notre module dans un fichiers source au format *.hs.
Pour faire clignoter une LED dans un FPGA, la première chose à mettre en place est un compteur :
Clash.Prelude> counter = register 0 counter + 1
Cette fonction counter que nous venons de créer retourne un registre initialisé à 0 et qui ajoute 1 à sa sortie à chaque coup d’horloge. La définition est récursive, c’est à dire qu’elle ajoute 1 à elle même. Et comme on commence à 0 et qu’on ajoute 1, la valeur initiale sera 1. Cette fonction étant infinie, si nous voulons connaitre des valeurs il faut échantillonner :
On constate que la première valeur est en double car c’est la valeur initiale, avant le premier coup d’horloge. @System désigne le domaine d’horloge/reset/enable utilisé. @System est le domaine général, nous pourrions appliquer un domaine (dom) spécifique à une architecture comme @XilinxSystem ou @IntelSystem.
Le problème avec ce compteur c’est qu’il incrémente à l’infini, nous on voudrait un compteur avec une limite et qui se remet à 0 à une certaine valeur comme ça :
Clash.Prelude> counter value = if(value < 100) then value + 1 else 0
Clash.Prelude> counter 10
11
Clash.Prelude> counter 0
1
Clash.Prelude> counter 101
0
[notes] Je ne sais pas si je vais réussir à comprendre l’exemple de led qui clignote donné sur le blog de l’auteur de clash en fait.
Je suis parti un peu la fleur au fusil pour faire cette dépêche, mais je me rend compte que l’apprentissage de Clash (et surtout Haskell) est un loooong chemin.
Bref, je crois que je ne vais pas réussir à finir cette dépêche. Peut-être un jour aurais-je suffisamment de bouteille en Haskell pour comprendre Clash, mais là …