URL: https://linuxfr.org/users/killruana/journaux/nouvelles-de-kfpga-le-fpga-libre Title: Nouvelles de kFPGA, le FPGA libre Authors: jtremesay Date: 2020年04月12日T09:29:03+02:00 License: CC By-SA Tags: kfpga Score: 30 Bonjour' nal, En novembre, je t'avais [parlé](https://linuxfr.org/users/killruana/journaux/k1g1-le-premier-fpga-libre) de mon projet de [FPGA](https://fr.wikipedia.org/wiki/Circuit_logique_programmable) libre, et je t'avais aussi [montré](https://linuxfr.org/users/killruana/journaux/kfpga-et-del-qui-clignotent) une vidéo où il fait clignoter des LEDs. Aujourd'hui, je te fais un petit point sur l'avancée du projet. Déjà, comme tu peux le constater sur la heatmap ci-dessous, l'activité sur le projet a été assez faible. Cela est dû à une combinaison de facteurs. Il a fallu que je déménage suite à une rupture, je devais préparer une audience au tribunal pour début mars qui a finalement été reporté en septembre suite à la grève des avocats, j'ai reçu une mise en demeure de la part d'un concurrent après la publication de la dépêche parlant du projet, il faut que consacre du temps à ma recherche de taf pour faire plaisir à Pôle emploi et à mon banquier, le confinement à une influence assez néfaste sur ma motivation... Bref, j'avais pas trop la tête à bosser dessus. ![Heatmap du projet](https://i.zcraft.fr/4005761586609719.png) # Mise de côté de OFP (Open FPGA Platform) À la base j'avais décomposé mon idée en deux projets distincts : OFP et kFPGA. OFP devait être un framework gérant tout le cycle de vie des FPGA. Les concepteurs de FPGA s'en serait servis pour créer et mettre à disposition leur architectures FPGA, les intégrateurs pour réaliser les implémentations physiques et les utilisateurs pour programmer leurs FPGA. kFPGA aurait été une architecture parmi d'autres utilisable avec OFP. En cours de route, je me suis rendu compte que _peut-être que j'avais vu un peu trop gros_ pour commencer et que la partie qui m'intéressai le plus était la conception de l'architecture FPGA. Du coup, j'ai mis de côté OFP et je me suis concentré sur kFPGA en y intégrant le travail sur OFP déjà effectué (essentiellement le module générant le code RTL des cœurs). # Simplification de l'architecture kFPGA Concevoir une architecture FPGA, c'est bien beau, mais il faut encore pouvoir la tester. Et pour ça, il faut les outils pour la programmer : un synthétiseur logique, un placeur, un routeur, un générateur de bitstream et éventuellement un analyseur de timings. Tous ces outils existent déjà en opensource mais aucun n'est prévu pour fonctionner avec mon architecture :'(. Il me faut donc les adapter. Pour simplifier ce travail d’adaptation, j'ai décidé de partir de l'architecture FPGA la plus simple possible car comme l'aurait Lapalisse, moins il y a de fonctionnalités dans l'architecture, moins il y a de fonctionnalités à gérer dans les outils. Une fois que j'aurai une chaîne d'outils fonctionnelle, je pourrais complexifier mon architecture de manière incrémentale. À quoi correspond une architecture la plus simple possible ? Juste des LUTs, des registres et de l’interconnexion. Un seul signal d'horloge en entrée, pas de signaux `enable` ou `set`, un seul signal de `reset` et déclenché uniquement sur un front montant, pas de génération interne de signaux d'horloge ou de reset. Bref, le minimum du minimum, voir même moins. Un cœur kFPGA est constitué d'I/O en bordure permettant de communiquer avec l'extérieur, d'une grille de tuiles logiques implémentant les calculs et d'adapteurs entre les I/O et la grille. Le nombre d'IO par adaptateur, les dimensions de la grille et la largeur des canaux de routage sont configurables. ![Vue d'ensemble de l'architecture](https://git.slaanesh.org/kfpga/kfpga/media/branch/master/images/kfpga_architecture.png) Chaque tuile logique contient un élément de routage (switch box) et des éléments logiques. Le nombre d'éléments logiques est configurable. ![Vue d'une tuile logique](https://git.slaanesh.org/kfpga/kfpga/media/branch/master/images/logic_tile.png) Chaque élément logique est composé d'une LUT et d'un registre by-passable. La taille des LUT est configurable. ![Vue d'un élément logique](https://git.slaanesh.org/kfpga/kfpga/media/branch/master/images/logic_element.png) # Synthèse logique J'ai écrit un outil de synthèse logique basé sur [yosys](http://www.clifford.at/yosys/). Plutôt que de forker Yosys pour y inclure une commande de synthèse supportant spécifiquement kFPGA, j'ai préféré faire un wrapper qui génère à la volée le script de synthèse utilisé pour piloter Yosys. De cette manière, il m'est plus facile de supporter d'autres outils de synthèses. Et puis comme ça je n'ai pas à apprendre comment faire pour que `python setup.py install` compile un gros truc en c++ ^^'. Ça s'utilise comme ça : ``` $ kfpga-synthesize -o ``` Exemple avec un additionneur 2 bits ```verilog module Adder2(z, a, b, clk); output reg [2:0] z; input [1:0] a, b; input clk; always @(posedge clk) z <= a + b; endmodule ``` Synthèse à destination d'un cœur kFPGA avec des LUT de taille 2 : ``` $ kfpga-synthesize -o netlist_lut2.v kfpga_lut2.kcf Adder2.v ``` Netlist obtenue : ```verilog /* Generated by Yosys 0.9+2406 (git sha1 7c06cb61, gcc 9.3.0-1 -march=native -O3 -fno-plt -fPIC -Os) */ (* top = 1 *) (* src = "Adder2.v:3.1-8.10" *) module adder2(z, b, a); (* src = "Adder2.v:5.17-5.18" *) input [1:0] a; (* src = "Adder2.v:5.20-5.21" *) input [1:0] b; (* src = "Adder2.v:4.18-4.19" *) output [2:0] z; wire z_KTECH_LUT2_o_data_1_i_data; wire z_KTECH_LUT2_o_data_1_i_data_1; wire z_KTECH_LUT2_o_data_i_data; wire z_KTECH_LUT2_o_data_i_data_1; (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp5zur_vdw/cells_map.v:44.15-47.14" *) KTECH_LUT2 #( .CONFIG(4'h8) ) a_KTECH_LUT2_i_data ( .i_data({ b[0], a[0] }), .o_data(z_KTECH_LUT2_o_data_i_data_1) ); (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp5zur_vdw/cells_map.v:44.15-47.14" *) KTECH_LUT2 #( .CONFIG(4'h8) ) a_KTECH_LUT2_i_data_1 ( .i_data({ b[1], a[1] }), .o_data(z_KTECH_LUT2_o_data_1_i_data) ); (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp5zur_vdw/cells_map.v:44.15-47.14" *) KTECH_LUT2 #( .CONFIG(4'h6) ) a_KTECH_LUT2_i_data_2 ( .i_data({ b[1], a[1] }), .o_data(z_KTECH_LUT2_o_data_i_data) ); (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp5zur_vdw/cells_map.v:44.15-47.14" *) KTECH_LUT2 #( .CONFIG(4'h6) ) z_KTECH_LUT2_o_data ( .i_data({ z_KTECH_LUT2_o_data_i_data, z_KTECH_LUT2_o_data_i_data_1 }), .o_data(z[1]) ); (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp5zur_vdw/cells_map.v:44.15-47.14" *) KTECH_LUT2 #( .CONFIG(4'he) ) z_KTECH_LUT2_o_data_1 ( .i_data({ z_KTECH_LUT2_o_data_1_i_data, z_KTECH_LUT2_o_data_1_i_data_1 }), .o_data(z[2]) ); (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp5zur_vdw/cells_map.v:44.15-47.14" *) KTECH_LUT2 #( .CONFIG(4'h8) ) z_KTECH_LUT2_o_data_1_i_data_1_KTECH_LUT2_o_data ( .i_data({ z_KTECH_LUT2_o_data_i_data, z_KTECH_LUT2_o_data_i_data_1 }), .o_data(z_KTECH_LUT2_o_data_1_i_data_1) ); (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp5zur_vdw/cells_map.v:44.15-47.14" *) KTECH_LUT2 #( .CONFIG(4'h6) ) z_KTECH_LUT2_o_data_2 ( .i_data({ b[0], a[0] }), .o_data(z[0]) ); endmodule ``` Même chose avec un FPGA possédant des LUTs de taille 6 : ``` $ kfpga-synthesize -o netlist_lut6.v kfpga_lut6.kcf Adder2.v ``` ```verilog /* Generated by Yosys 0.9+2406 (git sha1 7c06cb61, gcc 9.3.0-1 -march=native -O3 -fno-plt -fPIC -Os) */ (* top = 1 *) (* src = "Adder2.v:3.1-8.10" *) module adder2(z, b, a); (* src = "Adder2.v:5.17-5.18" *) input [1:0] a; (* src = "Adder2.v:5.20-5.21" *) input [1:0] b; (* src = "Adder2.v:4.18-4.19" *) output [2:0] z; (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp8gt2czyu/cells_map.v:60.15-63.14" *) KTECH_LUT6 #( .CONFIG(64'h0000000000008778) ) z_KTECH_LUT6_o_data ( .i_data({ 2'h0, b[1], a[1], b[0], a[0] }), .o_data(z[1]) ); (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp8gt2czyu/cells_map.v:60.15-63.14" *) KTECH_LUT6 #( .CONFIG(64'h000000000000e888) ) z_KTECH_LUT6_o_data_1 ( .i_data({ 2'h0, b[0], a[0], b[1], a[1] }), .o_data(z[2]) ); (* module_not_derived = 32'd1 *) (* src = "/tmp/tmp8gt2czyu/cells_map.v:44.15-47.14" *) KTECH_LUT6 #( .CONFIG(64'h0000000000000006) ) z_KTECH_LUT6_o_data_2 ( .i_data({ 4'h0, b[0], a[0] }), .o_data(z[0]) ); endmodule ``` # Système de tests automatisés Pour me simplifier la vie et vérifier que je casse pas plus de trucs que je n'en répare, j'ai bricolé un système de tests automatisés. À partir de modèles relativement simples, le bouzin me génère une grande variété d'applications et les testbenchs associés, fait les synthèses logiques à destination de différents cœurs, exécute les tesbenchs et me génère un joli rapport au format HTML. La génération d'un rapport au format JUnit est prévu afin de faire tourner tout ça automatiquement dans Jenkins. J'utilise python et le moteur de template [Jinja](https://jinja.palletsprojects.com/) pour générer les bouzins, make pour organiser l'orchestration et [cocotb](https://cocotb.readthedocs.io/) pour écrire les testbenchs. ![Aperçu du rapport](https://i.zcraft.fr/5893281586614998.png) # Prochaine étape Pouvoir réaliser le placement et le routage. Pour ça, je vais sauvagement gruiker [nextpnr](https://github.com/YosysHQ/nextpnr). # Liens Le projet a déménagé depuis la dernière fois, il se trouve maintenant [ici](https://git.slaanesh.org/kfpga/kfpga). Le README contient une description des autres outils fourni par le projet. Mon espace de travail est [ici](https://git.slaanesh.org/killruana/kfpga_workspace). Il contient le bordel qui n'a pas sa place dans le dépôt principal mais qui improve grave ma productivity, tel que ma R&D, de la doc, des scripts divers...

AltStyle によって変換されたページ (->オリジナル) /