Apicula : lancement de la libération du FPGA Gowin GW1N

Posté par  (site Web personnel) . Édité par BAud, Davy Defaud, zurvan, Ysabeau, Pierre Jarillon, theojouedubanjo et Benoît Sibaud. Modéré par Davy Defaud. Licence CC By‑SA.
Étiquettes :
18
14
mar.
2020
Matériel

Le lecteur assidu de LinuxFr.org sait déjà sans doute ce qu’est un FPGA. Rappelons‑en cependant brièvement la définition.

Les FPGA sont des composants constitués de « champs de portes programmables ». L’idée est de graver un certain nombre d’éléments logiques simples sous forme de matrice et de laisser au développeur le loisir de reconfigurer à l’infini les connexions entre ces portes. Une fois les connexions configurées, on se retrouve avec un composant numérique sur mesure qui ne ressemble à aucun composant disponible chez les fournisseurs classiques. C’est très pratique quand on a besoin d’architectures bâtardes, ou quand justement on développe un composant numérique : ça permet de reconfigurer à l’infini pour déverminer et évaluer les performances.

Pepijn de Vos a effectué un stage pour Symbiotic EDA. Et l’ingénierie inverse du GW1N était son sujet de stage. Il a rendu son rapport avant Noël sur GitHub et a publié le code source du projet Apicula.

Vous voulez en savoir plus, lisez la suite…

Sommaire

Parlons maintenant du grand drame des FPGA : ils sont complètement verrouillés car, pour reconfigurer ces fameuses connexions, il faut leur téléverser un fichier nommé bitstream qu’aucun constructeur de FPGA ne documente. Ce drame conduit les libristes que nous sommes à se taper des installations d’outils propriétaires particulièrement volumineux (surtout dans le cas de Xilinx et Altera) et pas toujours très stables. Tout ça pour générer le fameux bitstream.

Le format du bitstream n’est pourtant pas chiffré. Depuis plus d’une décennie, on sait qu’il est parfaitement possible d’en faire l’ingénierie inverse. Mais rien n’avait bougé jusqu’en 2015 quand Clifford (qui se prénomme maintenant Claire) Wolf a sorti sa suite open source pour le Lattice iCE40 : IceStorm. Le projet IceStorm avait pour but d’analyser toute la gamme des FPGA iCE40 pour en documenter le format du bitstream. Projet qui a parfaitement abouti et essaimé : toute la gamme des iCE40 est désormais accessible au moyen d’outils open source, ainsi que la gamme des ECP5 avec le Projet Trellis.

Presque tous les modèles de FPGA ont leur projet d’ingénierie inverse aujourd’hui. Tous ne sont pas terminés, loin s’en faut. Néanmoins, quelques‑uns avancent, comme le projet Apicula de Pepijn de Vos ciblant les FPGA du constructeur chinois Gowin. Dire que le projet Apicula est abouti serait un raccourci un peu rapide, il manque encore en effet un certain nombre de blocs à décoder. Cependant, il est possible aujourd’hui de réaliser un projet très simple (UNE LED QUI CLIGNOTE \o/) grâce au travail effectué.

Le Gowin GW1N

Voici l’architecture du GW1N donnée dans la documentation du composant :
Architecture global du GW1NOui, toi aussi, cher lecteur, tu te demandes bien l’intérêt de ce zoom. ;)

On voit différents éléments dans ce schéma, de la mémoire vive, des PLL pour générer les horloges, des multiplieurs câblés (DSP), des blocs d’entrées‑sorties (IOB) et surtout — ce que l’on voit le plus — des CFU (Configurable Function Unit).

Chez Gowin, le CFU est l’élément de base constitué ainsi :
Schéma d’architecture CFU

Les deux éléments qui nous intéressent ici sont : la LUT (Look Up Table) et le REG (registre). Ces deux éléments sont la base de la logique synchrone.

Le registre recopie son entrée sur la sortie au front montant de l’horloge, la sortie restant stable le reste du temps.

La LUT, comme son nom anglais l’indique, est une table de vérité, qui, dans le cas de ce petit FPGA, comporte quatre entrées binaires et une sortie. La configuration du FPGA viendra remplir cette table de vérité pour réaliser une fonction logique. Le registre se trouvant derrière se charge ensuite de verrouiller le résultat au rythme de l’horloge.

Si l’on arrive à déchiffrer le bitstream pour pouvoir configurer ces LUT, ces registres ainsi que les blocs d’entrées‑sorties (IOB), alors on a (presque) gagné : on peut réaliser un composant simple mais fonctionnel.

Et c’est ce qu’a réalisé Pepijn de Vos, on peut donc dire qu’il a amorcé la libération du GW1N de Gowin !

Le projet n’est cependant pas terminé, il faut encore déchiffrer les autres blocs pour permettre l’utilisation complète du FPGA. Il faut également réussir à documenter les temps de propagation des signaux entre les différents blocs. L’information de ces temps de propagation permet au logiciel de placement routage (nextpnr, pour ne citer que le plus célèbre en libre) de faire son travail correctement.

Mais alors, cette LED clignotante, elle vient ?

Minute, papillon ! Dans un premier temps, il va falloir trouver une carte électronique munie d’un FPGA de Gowin. Nous allons ensuite nous servir des données déjà produites par le projet Apicula pour faire la synthèse avec Yosys, puis le placement‐routage avec nextpnr.

Pour le moment, deux kits de développement ont été utilisés dans le projet Apicula :

Nous allons tester avec le kit allemand TEC0117, mais le Tang Nano ne change pas grand’chose à la procédure (et il est moins cher).

On doit installer :

  • Yosys, le logiciel de synthèse Verilog. Pour le détail des dépendances et autres subtilités d’installation, voir le site officiel. Sinon, pour résumer :

    git clone https://github.com/YosysHQ/yosys.git
    cd yosys
    make
    sudo make install
  • nextpnr, le logiciel de placement routage. Il faut le compiler avec le paramètre «generic». Les deux autres paramètres possible à ma connaissance sont ice40 et ecp5 (les deux gammes de FPGA vraiment prises en charge par nextpnr) :

    git clone https://github.com/YosysHQ/nextpnr.git
    cd nextpnr/
    cmake -DARCH=generic .
    make
    sudo make install

    Dans mon cas, j’ai dû forcer l’utilisation de Python 3.7 dans le fichier CMakeLists.txt : find_package(PythonInterp 3.7 REQUIRED); pour pouvoir exécuter les scripts en argument avec Python 3.7.

  • Apicula, dont il faut cloner le dépôt Git :

    git clone https://github.com/pepijndevos/apicula.git
    cd apicula
  • pour l’instant la « base de données » des éléments trouvés par ingénierie inverse n’est pas « commité » dans le projet Apicula, il faut donc avoir une installation de l’EDI officiel de Gowin ; les scripts du projet Apicula iront fouiller dans les données de l’IDE pour générer un fichier intelligible en JSON et pickle (Python), il n’est cependant pas nécessaire d’avoir la licence ;

  • il faut également aller chercher le « pinout » de nos FPGA sur le site officiel de Gowin et le mettre dans son répertoire local nommé ~/Documents/gowinsemi :

Maintenant que nous avons les outils installés, lançons l’exemple générique du projet Apicula :

  • d’abord, on génère la base de données des éléments du FPGA :

    export GOWINHOME=/chemin/de/linstallation/gowin/IDE/
    export DEVICE="GW1NR-9" # TEC0117
    python dat19_h4x.py # makes $DEVICE.json
    python tiled_fuzzer.py # makes $DEVICE.pickle
  • muni de cette base de données, on peut se lancer dans la synthèse du (pas si) simple porte‑gramme de clignotement de LED donné en Verilog ci‑dessous :

    module top;
        wire clk;
        (* BEL="R29C29_IOBA", keep *)
        GENERIC_IOB #(.INPUT_USED(1), .OUTPUT_USED(0)) clk_ibuf (.O(clk));
        wire [7:0] leds;
        (* BEL="R1C8_IOBA", keep *)
        GENERIC_IOB #(.INPUT_USED(0), .OUTPUT_USED(1)) led7_obuf (.I(leds[7]));
        (* BEL="R1C8_IOBB", keep *)
        GENERIC_IOB #(.INPUT_USED(0), .OUTPUT_USED(1)) led6_obuf (.I(leds[6]));
        (* BEL="R1C10_IOBA", keep *)
        GENERIC_IOB #(.INPUT_USED(0), .OUTPUT_USED(1)) led5_obuf (.I(leds[5]));
        (* BEL="R1C10_IOBB", keep *)
        GENERIC_IOB #(.INPUT_USED(0), .OUTPUT_USED(1)) led4_obuf (.I(leds[4]));
        (* BEL="R1C11_IOBA", keep *)
        GENERIC_IOB #(.INPUT_USED(0), .OUTPUT_USED(1)) led3_obuf (.I(leds[3]));
        (* BEL="R1C11_IOBB", keep *)
        GENERIC_IOB #(.INPUT_USED(0), .OUTPUT_USED(1)) led2_obuf (.I(leds[2]));
        (* BEL="R1C12_IOBA", keep *)
        GENERIC_IOB #(.INPUT_USED(0), .OUTPUT_USED(1)) led1_obuf (.I(leds[1]));
        (* BEL="R1C12_IOBB", keep *)
        GENERIC_IOB #(.INPUT_USED(0), .OUTPUT_USED(1)) led0_obuf (.I(leds[0]));
    reg [25:0] ctr;
    always @(posedge clk)
        ctr <= ctr + 1'b1;
    assign leds = ctr[25:18];
    endmodule

    Un habitué des LED qui clignotent en Verilog reconnaîtra tout de suite le compteur dans les dernières lignes (always, reg…) mais sera peut‑être perturbé par la déclaration des entrées‑sorties. Il faut juste avoir en tête que le projet n’est pas terminé et qu’il faut se taper le placement‐routage des entrées‑sorties « à la main », d’où les directives (* ... *) et les modules GENERIC_IOB().

  • le script pour la synthèse et le placement routage est donné dans l’exemple :

    $ cd generic
    $ bash simple.sh blinky.v # TEC0117
    $ cd ..
    $ python gowin_pack.py generic/pnrblinky.json
    $ python gowin_unpack.py pack.fs
    $ yosys -p "read_verilog -lib +/gowin/cells_sim.v; clean -purge; show" unpack.v
  • on doit se retrouver avec un bitstream nommé pack.fs que l’on peut téléverser dans le FPGA au moyen de l’utilitaire libre openFPGALoader maintenu par Trabucayre (Gwenhael Goavec‑Merou) :

    openFPGALoader -m -b littleBee pack.fs # FOSS programmer
    Parse pack.fs: 
    Done
    erase SRAM Done
    Flash SRAM: [==================================================] 100.000000%
    Done
    SRAM Flash: FAIL
    

    Le FAIL est connu et vient d’une sombre histoire de somme de contrôle que openFPGALoader ne sait pas encore calculer et qu’Apicula ne fournit pas. Un ticket est ouvert sur le sujet dans le projet, Trabucayre sera ravi d’accepter des correctifs.

Et les huit LED doivent clignoter. Enfin, disons plutôt qu’elles comptent en binaire. Pour voir la vidéo des LED clignotantes, c’est sur YouTube.

Architectures de développement hétéroclites

Comme nous avons des outils open source, il est possible de développer sur des ordinateurs à base d’architectures différentes de x86. Voici un petit exemple de téléchargement d’un bitstream sur Tang Nano au moyen d’un Raspberry Pi (architecture ARM). Le bitstream en question permet de piloter un écran à cristaux liquides.

Chose impossible à faire avec les Vivado, Diamond et autres Quartus.

LCD sur Tang Nano

C’est encore très expérimental

Comme nous venons de le voir, le projet Apicula est encore très expérimental. Cependant, tous les ingrédients sont là et la preuve de fonctionnement est faite. Donc, à condition de mettre un minimum les mains dans le cambouis, on peut désormais générer des bitstreams pour les GW1Nx avec des outils open source.

Super ! Comment je fais pour contribuer ?

Autant d’enthousiasme fait plaisir à voir. Pour contribuer, le mieux est d’acquérir l’une des deux cartes citées dans cette dépêche et d’installer le logiciel officiel de Gowin.
Ensuite, différentes commandes permettant de mettre le pied à l’étrier de l’ingénierie inverse sont données sur le README.md du projet Apicula.

Sinon, n’hésitez pas à laisser une issue sur le projet GitHub ou d’interpeller Pepijn directement sur le « silo social Twitter ». Pepijn est super content de voir des gens s’intéresser au projet et répond très vite.

Aller plus loin

  • # Rêvons un peu.

    Posté par  . Évalué à 3.

    Je pose une hypothèse de réflexion :
    Un fabricant de FPGA qui documenterait complètement le format de son "bitstream" ne gagnerait-il pas des parts de marché ?

    • [^] # Re: Rêvons un peu.

      Posté par  (site Web personnel) . Évalué à 3.

      J'en suis convaincu. Surtout dans le cas d'un nouveau venu dans le monde du FPGA qui n'aurai pas le budget pour écrire un nième IDE mal foutu.
      Il y a des rumeurs sur le web parlant d'un constructeurs qui va s'y mettre. Mais pour l'instant rien de très clair ;)

    • [^] # Re: Rêvons un peu.

      Posté par  . Évalué à 3.

      On peut faire un parallèle avec le monde du microcontroleur : Atmel et STMicro ont le vent en poupe, même pour des projets professionnels n'utilisant pas Arduino IDE, parce que leurs stacks libres sont matures et pas aussi lourdes et buggées que, par exemple, l'IDE proprio de Microchip indispensable pour programmer les PIC.

  • # Lien youtube pété

    Posté par  (site Web personnel) . Évalué à 4.

    Juste pour correction, le lien pour les leds cligotantes est : https://www.youtube.com/watch?v=yc2yBYlCCI4

  • # et au delà !

    Posté par  . Évalué à 3.

    ça permet de reconfigurer à l’infini

    Non, sauf si j'ai mal compris.
    Il y a un nombre déterminé d'éléments logiques, on les combine entre eux, il y a donc un nombre fini de façons de les combiner.
    Non ?

    • [^] # Re: et au delà !

      Posté par  . Évalué à 3.

      Oui, mais tu peux le faire plusieurs fois

    • [^] # Re: et au delà !

      Posté par  (site Web personnel) . Évalué à 4.

      On peut configurer le FPGA un nombre infini de fois.

      Le nombre de portes gravées dans le FPGA étant fixe, le nombre de configuration possible est en effet limité … mais particulièrement grand ;)

      • [^] # Re: et au delà !

        Posté par  . Évalué à 2.

        "on peut configurer 1000 fois 1 fpga, on peut configurer 1 fois 1000 fpga, mais on peut pas configurer 1000 fois 1000 fpga !"
        Émile Gravier (ou pas)

        • [^] # Re: et au delà !

          Posté par  . Évalué à 1.

          Il dit qu'il voit pas le rapport.
          Mille réécritures c'est rien du tout même pour une mémoire NAND Flash en QLC. Et ici c'est directement la SRAM qu'on met le programme donc il n'y a vraiment aucune usure.

  • # somme de contrôle

    Posté par  (site Web personnel) . Évalué à 1.

    Comme le problème avec la somme de contrôle est mentionné dans cet article, je souhaitais signaler que celui-ci vient d'être réglé à la fois dans Apicula et openFPGALoader.
    Maintenant plus de "fausse erreur"!

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n’en sommes pas responsables.