Nous l’attendions depuis au moins deux ans, le FPGA européen GateMate des allemands de CologneChip est désormais disponible dans votre crémerie habituelle.
La dimension européenne de ce FPGA n’est pas la seule nouveauté, c’est également un des premier (mais pas le premier) à privilégier les outils open source pour son utilisation. Que cela soit pour la simulation ou pour la synthèse tous les exemples donnés dans la documentation utilisent des logiciels libres (Icarus, GHDL et surtout Yosys). Même pour la visualisation des chronogrammes, gtkwave est utilisé par défaut en exemple.
[À noter que le kit de développement m’a été offert gracieusement par CologneChip]
Caractéristiques du GateMate
Les caractéristiques du GateMate le positionne au niveau d’un petit Spartan7 de Xilinx ou d’un Trion T20 de Efinix.
Le composant est gravé par GlobalFounderies en 28nm.
La cellule de base est nommée CPE pour «Central Programming Element».
On notera l’absence remarqué de blocs multiplieurs. Cette absence est compensée par le «fast signal path routing» qui permet de chaîner les CPE afin de construire un multiplieur de dimension voulue.
Caractéristiques du kit
Pour le moment, seuls les trois petit FPGA de la gamme GateMate semblent être en production. CologneChip propose un kit de développement muni du plus petit GateMate : le CCGM1A1
La carte de développement possède deux entrées USB:
- une pour l’alimentation
- et une pour la programmation et la communication avec le FPGA (FTDI 2232), mais qui peut également servir d’alimentation.
La magie du logiciel libre openFPGALoader permet de détecter le FPGA directement au branchement:
$ openFPGALoader --detect
Jtag frequency : requested 6.00MHz -> real 6.00MHz
index 0:
idcode 0x20000001
manufacturer colognechip
family GateMate Series
model GM1Ax
irlength 6
En effet, avant même la sortie du gatemate, CologneChip avait déjà proposé le support du composant sur le dépot openFPGALoader.
Toolchain
CologneChip fourni un guide d’installation de la chaîne de développement sur son site internet.
Tous les outils sont connus du monde du FPGA opensource et leurs installations sont intensivement décrites dans les différents dépôts des projets.
Si l’on souhaite éviter la case compilation, l’entreprise fournie même des versions binaires. Ces binaires ne sont téléchargeable que via un compte enregistré sur leur site pour le moment. Deux paquets de logiciels sont nécessaires :
- Yosys compilé pour le gatemate: pour la synthèse Verilog
- p_r: le logiciel de placement routage.
Pour le moment, la version binaire proposée en téléchargement sur le site n’est disponible que pour windows. Ces «.exe» s’exécutent cependant parfaitement sous Linux au moyen de l’émulateur wine bien connu des Linuxiens.
L’archive téléchargée se décompresse simplement avec unzip :
$ unzip cc-toolchain-win.zip
Archive: cc-toolchain-win.zip
extracting: cc-toolchain-win/openFPGALoader-mingw64-v.0.8.0+80eeaef.zip
extracting: cc-toolchain-win/p_r-2022.04-001.zip
inflating: cc-toolchain-win/ug1002-toolchain-install-2022-04.pdf
extracting: cc-toolchain-win/yosys-win32-mxebin-0.15+57.zip
La version windows de openFPGALoader ne fonctionne pas bien en émulation wine, il est préférable d’en compiler une version à jour à partir des sources officiels.
Pour le reste, on peut s’affranchir de compiler yosys en utilisant celle fournie. Et pour p_r, les sources n’étant pas fournies pour le moment, cette version est la seule que nous pourrons utiliser.
Pour les installer, il suffit de les décompresser :
$ cd cc-toolchain-win/
$ unzip p_r-2022.04-001.zip
$ unzip yosys-win32-mxebin-0.15+57.zip
La notice d’utilisation des commandes est données dans le pdf de l’archive nommé ug1002-toolchain-install-2022-04.pdf.
C’est l’installation la plus simple que j’ai pu avoir à faire pour des outils de développement FPGA. La place occupée sur le disque dur de son ordinateur est plusieurs milliers de fois plus petites que les logiciels habituels :
$ cd p_r-2022.04-001/
$ du -sh .
24M .
$ cd yosys-win32-mxebin-0.15+57/
$ du -sh .
32M .
Évidemment, c’est pour seulement un modèle de FPGA, mais cela reste beaucoup plus petit.
Clignotons
Il est temps de rentrer dans le vif du sujet et de faire clignoter les LED. L’exemple donné dans le document ug1002 est trop rapide pour voir les LED clignoter. Nous allons donc faire un clignoteur plus traditionnel comme visible ci-dessous en Verilog :
`timescale 1ns / 1ps
module blink(
input wire clk,
input wire rst,
output reg led
);
localparam MAX_COUNT = 10_000_000;
localparam CNT_TOP = $clog2(MAX_COUNT);
wire i_clk;
reg [CNT_TOP-1:0] counter;
assign i_clk = clk;
always @(posedge i_clk)
begin
if (!rst) begin
led <= 0;
counter <= 0;
end else begin
if(counter < MAX_COUNT/2)
led <= 1;
else
led <= 0;
if (counter >= MAX_COUNT)
counter <= 0;
else
counter <= counter + 1'b1;
end
end
endmodule
Contrairement à beaucoup de FPGA, le GateMate ne définit pas d’états initial à 0 de ses registres. Une entrée reset est donc nécessaire.
Le pinout est décrit au moyen d’un fichier «ccf» :
## blink.ccf
Pin_in "clk" Loc = "IO_SB_A8" | SCHMITT_TRIGGER=true;
Pin_in "rst" Loc = "IO_EB_B0"; # SW3
Pin_out "led" Loc = "IO_EB_B1"; # D1
Une fois que ces deux fichiers sont prêt il suffit de lancer yosys pour la synthèse :
$ wine ../../cc-toolchain-win/yosys-win32-mxebin-0.15+57/yosys.exe -l yosys.log -p 'read_verilog blink.v; synth_gatemate -top blink -vlog blink_synth.v'
Wine génère tout un tas d’erreurs mais fini par nous lancer la synthèse tout de même
$ wine ../../cc-toolchain-win/yosys-win32-mxebin-0.15+57/yosys.exe -l yosys.log -p 'read_verilog blink.v; synth_gatemate -top blink -vlog blink_synth.v'
wine: created the configuration directory '/home/oem/.wine'
0012:err:ole:marshal_object couldn't get IPSFactory buffer for interface {00000131-0000-0000-c000-000000000046}
0012:err:ole:marshal_object couldn't get IPSFactory buffer for interface {6d5140c1-7436-11ce-8034-00aa006009fa}
0012:err:ole:StdMarshalImpl_MarshalInterface Failed to create ifstub, hres=0x80004002
0012:err:ole:CoMarshalInterface Failed to marshal the interface {6d5140c1-7436-11ce-8034-00aa006009fa}, 80004002
0012:err:ole:get_local_server_stream Failed: 80004002
0014:err:ole:marshal_object couldn't get IPSFactory buffer for interface {00000131-0000-0000-c000-000000000046}
0014:err:ole:marshal_object couldn't get IPSFactory buffer for interface {6d5140c1-7436-11ce-8034-00aa006009fa}
0014:err:ole:StdMarshalImpl_MarshalInterface Failed to create ifstub, hres=0x80004002
0014:err:ole:CoMarshalInterface Failed to marshal the interface {6d5140c1-7436-11ce-8034-00aa006009fa}, 80004002
0014:err:ole:get_local_server_stream Failed: 80004002
Could not find Wine Gecko. HTML rendering will be disabled.
Could not find Wine Gecko. HTML rendering will be disabled.
wine: configuration in L"/home/oem/.wine" has been updated.
On ne va pas recopier toute la trace de synthèse ici mais juste la partie ressources utilisées donnée en fin de synthèse :
2.49. Printing statistics.
=== blink ===
Number of wires: 49
Number of wire bits: 294
Number of public wires: 5
Number of public wire bits: 28
Number of memories: 0
Number of memory bits: 0
Number of processes: 0
Number of cells: 159
CC_ADDF 65
CC_BUFG 1
CC_DFF 25
CC_IBUF 2
CC_LUT1 24
CC_LUT2 5
CC_LUT4 36
CC_OBUF 1
2.50. Executing CHECK pass (checking for obvious problems).
Checking module blink...
Found and reported 0 problems.
2.51. Executing OPT_CLEAN pass (remove unused cells and wires).
Finding unused cells or wires in module \blink..
2.52. Executing Verilog backend.
2.52.1. Executing BMUXMAP pass.
2.52.2. Executing DEMUXMAP pass.
Dumping module `\blink'.
End of script. Logfile hash: dcf7a4084e
Yosys 0.15+57 (git sha1 207417617, i686-w64-mingw32.static-g++ 11.2.0 -Os)
Time spent: 1% 19x opt_clean (0 sec), 1% 18x opt_expr (0 sec), ...
Le fichier de sortie blink_synth.v est au format … Verilog également! C’était bien la peine de lancer Yosys tient !
Mais non, Verilog est un excellent format pour décrire une netlist autant que du RTL. Et de fait, le code Verilog généré n’est pas hyper lisible. Il est constitué d’une série d’instanciations et de connections des primitives du FPGA :
//...
CC_LUT2 #(
.INIT(4'h8)
) _051_ (
.I0(_041_[0]),
.I1(_041_[1]),
.O(_043_[2])
);
CC_LUT4 #(
.INIT(16'h0001)
) _052_ (
.I0(counter[15]),
.I1(counter[20]),
.I2(counter[23]),
.I3(counter[13]),
.O(_041_[0])
);
//...
Code qui reste parfaitement simulable avec Icarus pour faire de la simulation post-synthèse comme expliqué dans la documentation officielle.
Maintenant que nous avons notre netlist passons aux choses sérieuses avec le placement routage :
$ wine ../../cc-toolchain-win/p_r-2022.04-001/p_r.exe -i blink_synth.v -o blink -lib ccag
GateMate (c) Place and Route
Version 4.0 (4 April 2022)
All Rights Reserved (c) Cologne Chip AG
...
Comme pour la synthèse, nous n’allons pas mettre tous les messages ici. Une des information qui nous intéresse en priorité pour le placement routage est la performance en vitesse.
...
Static Timing Analysis
Longest Path from Q of Component 25_1 to D-Input of Component 33/1 Delay: 18215 ps
Maximum Clock Frequency on CLK 230/3: 54.90 MHz
...
La vitesse d’horloge maximale est donc de 54.90Mhz. Cela peut sembler ridicule mais il faut prendre en compte que :
- L’architecture du «clignoteur» avec un énorme compteur pour diviser l’horloge n’est absolument pas optimisée. Pour faire bien il faudrait pipeliner le compteur mais ça n’est pas le sujet ici. Ces mauvais résultats sont cohérent avec ce qu’on pourrait obtenir avec un autre FPGA «mainstream».
- Ces performances sont «conservatrice» c’est le pire cas quand le FPGA est très chaud.
Bref, pour faire clignoter une LED, on peut raisonnablement doubler cette fréquence d’horloge si on veut 🙂 Mais comme nous n’utilisons pas de PLL ici, la fréquence d’entrée de 10Mhz rentre dans la specification.
Les statistiques d’utilisation du FPGA sont données à la fin de la synthèse :
CPE_USAGE_INPUT - CPE_COMBSEQ 1/8 : 0 / 21 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMBSEQ 2/8 : 11 / 21 ( 52.4%)
CPE_USAGE_INPUT - CPE_COMBSEQ 3/8 : 0 / 21 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMBSEQ 4/8 : 0 / 21 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMBSEQ 5/8 : 0 / 21 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMBSEQ 6/8 : 10 / 21 ( 47.6%)
CPE_USAGE_INPUT - CPE_COMBSEQ 7/8 : 0 / 21 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMBSEQ 8/8 : 0 / 21 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMB 1/8 : 3 / 3 ( 100.0%)
CPE_USAGE_INPUT - CPE_COMB 2/8 : 0 / 3 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMB 3/8 : 0 / 3 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMB 4/8 : 0 / 3 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMB 5/8 : 0 / 3 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMB 6/8 : 0 / 3 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMB 7/8 : 0 / 3 ( 0.0%)
CPE_USAGE_INPUT - CPE_COMB 8/8 : 0 / 3 ( 0.0%)
CPE_USAGE_INPUT - CPE COMBSEQ+COMB 1/8 : 3 / 24 ( 12.5%)
CPE_USAGE_INPUT - CPE COMBSEQ+COMB 2/8 : 11 / 24 ( 45.8%)
CPE_USAGE_INPUT - CPE COMBSEQ+COMB 3/8 : 0 / 24 ( 0.0%)
CPE_USAGE_INPUT - CPE COMBSEQ+COMB 4/8 : 0 / 24 ( 0.0%)
CPE_USAGE_INPUT - CPE COMBSEQ+COMB 5/8 : 0 / 24 ( 0.0%)
CPE_USAGE_INPUT - CPE COMBSEQ+COMB 6/8 : 10 / 24 ( 41.7%)
CPE_USAGE_INPUT - CPE COMBSEQ+COMB 7/8 : 0 / 24 ( 0.0%)
CPE_USAGE_INPUT - CPE COMBSEQ+COMB 8/8 : 0 / 24 ( 0.0%)
IO_USAGE : 3 / 144 ( 2.1%) of all IOs
IO_USAGE_TYPE - IBF : 2 / 144 ( 1.4%) of all IOs ( 66.7%) of used IOs
IO_USAGE_TYPE - OBF : 1 / 144 ( 0.7%) of all IOs ( 33.3%) of used IOs
IO_USAGE_TYPE - TOBF : 0 / 144 ( 0.0%) of all IOs ( 0.0%) of used IOs
IO_USAGE_TYPE - IOBF : 0 / 144 ( 0.0%) of all IOs ( 0.0%) of used IOs
CPE_USAGE_PHYS - CPE_COMB_ONLY : 73 / 20480 ( 0.4%) of all CPEs ( 60.3%) of occupied CPEs
CPE_USAGE_PHYS - CPE_SEQ_ONLY : 5 / 20480 ( 0.0%) of all CPEs ( 4.1%) of occupied CPEs
CPE_USAGE_PHYS - CPE_BRIDGE_ONLY : 0 / 20480 ( 0.0%) of all CPEs ( 0.0%) of occupied CPEs
CPE_USAGE_PHYS - CPE_CARRY_ONLY : 0 / 20480 ( 0.0%) of all CPEs ( 0.0%) of occupied CPEs
CPE_USAGE_PHYS - CPE_COMB+SEQ : 10 / 20480 ( 0.0%) of all CPEs ( 8.3%) of occupied CPEs
CPE_USAGE_PHYS - CPE_COMB+BRIDGE : 0 / 20480 ( 0.0%) of all CPEs ( 0.0%) of occupied CPEs
CPE_USAGE_PHYS - CPE_COMBSEQ : 21 / 20480 ( 0.1%) of all CPEs ( 17.4%) of occupied CPEs
CPE_USAGE_LOGIC - CPE_COMB : 8 / 20480 ( 0.0%) of all CPEs ( 6.6%) of occupied CPEs
CPE_USAGE_LOGIC - CPE_SEQ : 15 / 20480 ( 0.1%) of all CPEs ( 12.4%) of occupied CPEs
CPE_USAGE_LOGIC - CPE_COMBSEQ : 21 / 20480 ( 0.1%) of all CPEs ( 17.4%) of occupied CPEs
CPE_USAGE_LOGIC - CPE_BRIDGE : 0 / 20480 ( 0.0%) of all CPEs ( 0.0%) of occupied CPEs
CPE_USAGE_OVERALL : 121 / 20480 ( 0.6%) of all CPEs occupied
CPE_USAGE_LOGIC : 94 / 20480 ( 0.5%) of all CPEs used for customer logic
Component Statistics:
AND 32 19%
ADDF 2 1%
ADDF2 60 37%
C_OR 48 29%
Route1 4 2%
CP_route 15 9%
--------
Sum of COMB: 161
D 25 92%
C_0_1 2 7%
--------
Sum of SEQ: 27
Sum of all: 188
Et le bitstream généré est au format *.cfg (ascii) ou *.cfg.bit (binaire).
$ ls -lha blink_00.*
-rw-rw-r-- 1 oem oem 121K May 1 08:38 blink_00.cdf
-rw-rw-r-- 1 oem oem 1.4M May 1 08:38 blink_00.cfg
-rw-rw-r-- 1 oem oem 48K May 1 08:38 blink_00.cfg.bit
-rw-rw-r-- 1 oem oem 465 May 1 08:38 blink_00.pin
-rw-rw-r-- 1 oem oem 6.0K May 1 08:38 blink_00.place
-rw-rw-r-- 1 oem oem 65K May 1 08:38 blink_00.SDF
-rw-rw-r-- 1 oem oem 42K May 1 08:38 blink_00.used
-rw-rw-r-- 1 oem oem 79K May 1 08:38 blink_00.V
Pour configurer le FPGA nous utiliserons openFPGALoader en «natif» :
$ openFPGALoader -b gatemate_evb_jtag blink_00.cfg.bit
Jtag frequency : requested 6.00MHz -> real 6.00MHz
Load SRAM via JTAG: [==================================================] 100.00%
Done
Wait for CFG_DONE DONE
Et la LED clignote :