Archives de catégorie : outils

Sortie de la version 0.6.0 du configurateur de FPGA openFPGALoader

[Dépêche parue initialement sur LinuxFR]

openFPGALoader est un utilitaire en ligne de commande, écrit en C++ et sous licence Apache 2.0. Il permet de configurer des FPGA de toutes marques. L’objectif du projet est de pouvoir prendre en charge tous les FPGA du marché ainsi que tous les adaptateurs et sondes de configuration.

Sommaire

La chaîne de développement sur FPGA

Pour développer sur un FPGA, nous avons besoin d’un ensemble de logiciels et de formats spécifiques. La chaîne de développement sur FPGA peut se résumer par la figure ci-dessous:

Chaîne de développement FPGA

L’architecture du composant est décrite dans un langage de description (HDL pour Hardware Description Language) matériel. Cette description est convertie en un schéma électronique (Netlist) par un procédé appelé «synthèse». Les composants de la Netlist sont ensuite placés dans la matrice du FPGA (placement) puis connectés ensemble (Routage) pour former le composant décrit au début.
Toutes ces informations sont ensuite décrites dans un fichier de configuration appelé bitstream (propriétaire). Et enfin, le fichier est transféré au FPGA pour le configurer.

À l’origine, toutes ces opérations sont réalisées par des logiciels privateurs, et les formats sont verrouillés. Quand on parle de libération des FPGA on aimerait bien sûr que toute la chaîne puisse être réalisée avec des logiciels libres et des formats ouverts. Mais le point le plus bloquant évoqué est souvent le format du bitstream, qui est LE maillon le plus critique de la chaîne jalousement gardé secret par (presque) tous.

Toutes ces étapes ont désormais des projets open source qui sont suffisamment avancés pour pouvoir développer sur FPGA librement. À condition de bien choisir le modèle.

Chargement du bitstream ou « configuration »

On en oublie souvent la dernière étape consistant à télécharger le bitstream dans le FPGA. Pourtant cette étape est également dépendante du constructeur qui propose l’adaptateur à vil prix (souvent une sonde USB-JTAG). Et le logiciel est en général intégré au lourd IDE du constructeur (binaire x86) qu’il n’est pas toujours facile de configurer sur sa distribution Linux et encore moins sur une architecture exotique (raspberryPi, Risc-V, …).

Le dessein d’openFPGALoader est donc d’être « l’anneau pour les programmer tous ». Pour cela il faut :

Avec cette version 0.6.0, le logiciel peut être considéré comme mature. C’est tellement devenu une référence qu’il est même intégré dans quelques distributions Linux, dans buildroot. Le logiciel fonctionne également sur Mac et Windows avec cependant plus de problème du fait du passage par le pilote usb zadig.

C’est aujourd’hui un automatisme pour configurer un FPGA, de le tester d’abord avec openFPGALoader. Avant même d’utiliser l’outil constructeur. Le logiciel apporte un confort d’utilisation et de configuration qui n’a rien à envier aux autres.

Quelques exemples

Pour illustrer, un peu l’utilisation d’openFPGALoader, supposons que nous ayons notre bitstream permettant de faire clignoter la led de la carte Tang Nano 4K. L’avantage de cette carte est que l’adaptateur de programmation est inclus et que tout passe par le même port USB.
Une fois la carte branchée on peut commencer par détecter le FPGA avec --detect :

    $ openFPGALoader --detect
    write to ram
    Jtag frequency : requested 6.00MHz   -> real 6.00MHz  
    index 0:
        idcode 0x100981b
        manufacturer Gowin
        family GW1NSR
        model  GW1NSR-4C
        irlength 8

Le format de bitstream pour les gowin possède l’extension fs, on peut le configurer directement en donnant simplement le nom du fichier en argument :

    $ openFPGALoader led_test/project/impl/pnr/led_test.fs
    write to ram
    Jtag frequency : requested 6.00MHz   -> real 6.00MHz  
    Parse file Parse led_test/project/impl/pnr/led_test.fs: 
    Done
    DONE
    Jtag frequency : requested 2.50MHz   -> real 2.00MHz  
    erase SRAM Done
    Flash SRAM: [==================================================] 100.00%
    Done
    SRAM Flash: Success

Et si le bitstream nous satisfait on l’écrira dans la mémoire « flash » avec l’option -f pour qu’il se reconfigure à chaque allumage.

    $ openFPGALoader ide/gbhdmi/impl/pnr/gbhdmi.fs -f
    write to flash
    Jtag frequency : requested 6.00MHz   -> real 6.00MHz  
    Parse file Parse ide/gbhdmi/impl/pnr/gbhdmi.fs: 
    Done
    DONE
    Jtag frequency : requested 2.50MHz   -> real 2.00MHz  
    erase SRAM Done
    erase Flash Done
    write Flash: [==================================================] 100.00%
    Done
    CRC check: Success

Les fichiers de configuration à télécharger dans le FPGA peuvent être assez volumineux pour certain gros FPGA. Les sondes de configuration n’étant pas toujours très rapide, il est intéressant de pouvoir envoyer le bitstream compressé.
Cette option est bien sûr supporté par openFPGALoader.

Plutôt que de prendre le nom du fichier bitstream en argument, il est également possible de récupérer un «flux» sur l’entrée standard:

    cat /path/to/bitstream.ext | openFPGALoader --file-type ext [options]

Méthode très pratique si l’on souhaite configurer son FPGA via le réseau par exemple:

    # Carte connectée au FPGA
    nc -lp port | openFPGALoader --file-type xxx [option

    # Ordinateur distant
    nc -q 0 host port < /path/to/bitstream.ext

Et si vous trouvez que cette dépêche manque (scandaleusement) de TapTempo, sachez qu’openFPGALoader fonctionne très bien sur le FPGA ECP5 présent sur la carte colorlight pour y configurer le bitstream TapTempo en VHDL :

    $ openFPGALoader taptempo.bit 
    Open file taptempo.bit DONE
    Parse file DONE
    Enable configuration: DONE
    SRAM erase: DONE
    Loading: [==================================================] 100.000000%
    Done
    Disable configuration: DONE

Pour conclure

À l’heure où cette dépêche est mise sous presse, openFPGALoader a sorti une version mineure 0.6.1 (principalement pour réduire le nombre d’« assets » dans l’archive.

openFPGALoader est maintenant bien installé dans la constellation des logiciels libres pour développer sur FPGA. Même s’il n’a pas encore atteint la version 1.0, il est désormais tout à fait mature pour une utilisation en « production ». Il méritait bien une dépêche sur LinuxFR.

Aller plus loin

Sortie de GHDL version 1.0.0

[Dépêche initialement parue sur LinuxFR]

GHDL est un logiciel écrit en ADA permettant de faire l’analyse, la compilation, la simulation ainsi que la synthèse du VHDL. Le VHDL, quant à lui, est un langage de description matériel très utilisé dans le développement sur FPGA ou ASIC. À l’origine, GHDL est un « side-project » de Tristan Gingold lui permettant de se faire la main avec ADA.

GHDL est devenu l’outil indispensable pour faire de la simulation VHDL aujourd’hui. Après presque 20 ans de développement, voici que sort en version 1.0.0 le logiciel de simulation VHDL nommé GHDL. En prime, GHDL s’offre un nouveau logo:

logo GHDL

Peu d’informations ont filtré sur cette sortie pour le moment. On peut soupçonner que ce soit une sortie anniversaire pour marquer les 20 ans du logiciel. Il n’en reste pas moins que GHDL est devenu un maillon indispensable dans l’écosystème opensource du monde FPGA et des ASIC.

Cette version 1.0.0 supporte désormais complètement les standards 1987, 1993 et 2002 du langage défini par l’IEEE. Le support de VHDL 2008 est noté comme partiel pour le moment.

Depuis quelques années, le développement du projet s’est accéléré et supporte de mieux en mieux les projets tierces comme Yosys bien sûr mais également CocoTB pour les testbenchs écrit en Python ainsi que les standards de vérification comme UVVM, OSVVM, VUnit issues du standard d’accelera.

Un support partiel d’un langage de PSL (Properties Specification Language) est également inclus. Il permet de décrire les propriétés du système pour faire de la vérification formelle.

Et surtout, il est possible de faire de la Synthèse. Certes, l’extension ghdl-yosys-plugin est encore en développement, mais l’exemple TapTempo l’a montré : Il est tout à fait possible de faire de la synthèse VHDL avec.

Cette version mature est surtout une occasion de mettre en valeur cet outil indispensable dans le monde du développement numérique (gateware).

Aller plus loin

CocoTB 1.4.0, la maturité

[Dépêche publiée initialement sur LinuxFR]

C’est dans la soirée du 8 juillet que l’annonce est tombée : la version 1.4.0 de CocoTB est sortie. Cette nouvelle version est une belle évolution de Cocotb avec une bonne intégration dans le système de paquets de Python ainsi que l’abandon de la prise en charge de Python 2. On peut aujourd’hui dire que CocoTB est une alternative sérieuse pour écrire ses bancs de test HDL.

Sommaire

Mais qu’est‑ce que c’est ?

CocoTB est une bibliothèque de cosimulation permettant d’écrire (en Python) des bancs de test pour la simulation numérique HDL (Hardware Description Language). Historiquement, les deux langages de descriptions HDL que sont Verilog et VHDL embarquent tout le nécessaire pour écrire des stimuli permettant de tester le composant en simulation. Cela permet d’avoir un seul langage pour décrire le composant et le tester. Le simulateur exécutera tout cela sans problème.

Mais cela amène beaucoup de confusion entre la partie du langage utilisable pour la simulation uniquement et la partie « description du matériel ». Dans le cas de la partie « matériel » on parle alors de code « synthétisable ». Cette confusion entre du code synthétisable ou non est source de grandes frustrations au moment de passer à la synthèse. En effet, cette belle structure de données que l’on aura développée et testée aux petits oignons s’écroulera au moment de la synthèse quand on se rendra compte que le code n’est pas synthétisable. Il faudra tout reprendre.

Une des idées derrière CocoTB est donc de changer de langage pour la simulation, comme cela les choses sont claires : on utilise le VHDL ou Verilog pour la partie du composant qui est synthétisable, et on passe au Python pour le banc de test. Ce n’est pas le seul logiciel à proposer ce genre d’approche. Avec Verilator, par exemple, on va écrire toute la partie banc de test en C++ ou en SystemC. La partie synthétisable sera écrite en Verilog et convertie en un objet C++ par Verilator.

La seconde idée de CocoTB est de ne pas réinventer la roue en réécrivant un énième simulateur HDL. Ce qui évite également d’avoir à choisir son camp entre Verilog et VHDL ou les deux (simulation mixte). Non, CocoTB va se contenter de piloter les simulateurs disponibles sur le marché. Les simulateurs libres que sont GHDL, Icarus et Verilator sont naturellement pris en charge, même si dans le cas de Verilator c’est très récent. La plupart des simulateurs commerciaux le sont également, ce qui est un argument pour l’introduire dans son bureau d’étude. En effet, les managers sont en général moyennement chauds pour virer un logiciel acquis à grands frais. Et l’on peut continuer à profiter des interfaces proposées par notre simulateur habituel pour exécuter le simulateur, visionner les chronogrammes, faire de la couverture de tests, etc.
La version 1.4 de CocoTB introduit la gestion complète du simulateur Aldec Active HDL qui vient s’ajouter aux classiques de Cadence et de Mentor, Modelsim…

Les changements dans le code

Un gros changement initié depuis quelque versions déjà est l’utilisation du mot clef async en lieu et place du yield et du décorateur @coroutine. Python 3 gérant désormais l’asynchronisme, CocoTB l’utilise et le prend désormais complètement en charge. L’exemple donné dans le courriel de la publication est le suivant :

    @cocotb.test()
    async def my_first_test(dut):
         """Try accessing the design."""

         dut._log.info("Running test!")
         for cycle in range(10):
             dut.clk <= 0
             await Timer(1, units='ns')
             dut.clk <= 1
             await Timer(1, units='ns')
         dut._log.info("Running test!")

Qui se serait écrit comme cela dans « l’ancien système » :

    @cocotb.test()
    def my_first_test(dut):
        """Try accessing the design."""
         dut._log.info("Running test!")
         for cycle in range(10):
             dut.clk <= 0
             yield Timer(1, units='ns')
             dut.clk <= 1
             yield Timer(1, units='ns')
         dut._log.info("Running test!")

Cette écriture restant cependant valable.

Le gros avantage de cette nouvelle écriture est de ne plus avoir a réinventer la roue avec des décorateurs inutiles. Avec async et await, on utilise des interfaces intégrées à Python 3, ce qui évite tout un travail de gestion.

Installation

CocoTB est, depuis maintenant un certain temps, partie intégrante du système de gestion de paquets de Python pip. Et vous pouvez dès à présent l’installer sur votre système via la commande pip install :

    $ python -m pip install cocotb
    # Pour celles et ceux qui ont installé la version précédente n’oubliez pas le --upgrade
    $ python -m pip install --upgrade cocotb

Et on peut vérifier la version grâce à la commande cocotb-config suivante :

cocotb-config --version
1.4.0

En plus de votre composant écrit en VHDL ou Verilog, deux fichiers supplémentaires sont nécessaires pour tester avec CocoTB : le Makefile et le script Python de test proprement dit.

Avec cette nouvelle version, le Makefile a encore été simplifié puisqu’il n’est plus nécessaire d’intégrer les en‑têtes C++. Ces en‑têtes sont nécessaires pour compiler les interfaces VPI/VHPI/FLI qui permettent de piloter les simulateurs. On compile désormais cette partie à l’installation de CocoTB. Dans les précédentes version, cette compilation ce faisait à chaque fois que l’on relançait les tests.

Si l’on prend l’exemple de l’antirebond en Verilog du Blinking Led Project, nous avons le Makefile suivant :

    SIM=icarus                                   # Nom du simulateur
    export COCOTB_REDUCED_LOG_FMT=1              # Pour avoir des traces de log qui rentre dans l’écran
    VERILOG_SOURCES = $(PWD)/../src/button_deb.v # Inclusion des fichiers HDL
    TOPLEVEL=button_deb                          # Nom de l’entité 
    MODULE=test_$(TOPLEVEL)                      # Nom du script Python de test
    include $(shell cocotb-config --makefile)/Makefile.sim

L’exemple est un composant permettant de ne pas compter les rebonds d’un bouton comme des appuis successifs.
Le script de test en Python se trouve dans le dépôt Git du projet et se nomme test_buton_deb.py. Pour le lancer, il suffit de se rendre dans le répertoire blp/verilog/cocotb/ et de taper make :

     $ make
     [...]
     0.00ns INFO     Running test!
     0.00ns INFO     freq value : 95000 kHz
     0.00ns INFO     debounce value : 20 ms
     0.00ns INFO     Period clock value : 10000 ps
     0.02ns INFO     Reset complete

Un fichier de traces (chronogrammes) button_deb.vcd au format VCD est créé. Il peut être visionné en « temps réel » alors même que la simulation n’est pas terminée, grâce au visualiseur gtkwave :

   $ gtkwave button_deb.vcd
Vue de traces VCD avec GTKWave

Une organisation qui tourne

Le projet CocoTB est chapeauté par la FOSSi foundation qui fournit le « chef de projet » Philipp Wagner ainsi que des moyens financiers pour faire tourner des machines virtuelles de tests ainsi que pour payer les licences des simulateurs commerciaux.

Les statistiques de modification de cette version sont les suivantes :

  • 346 fichiers modifiés, 14 012 insertions (+), 10 356 suppressions (−) ;
  • 554 commits ;
  • 31 contributeurs ;
  • 2 nouveaux mainteneurs : Colin Marquardt et Kaleb Barrett.

Ces chiffres montrent que CocoTB est un projet qui fédère désormais une grosse communauté. C’est un projet mature qui compte dans le paysage des logiciels libres pour le matériel (FPGA et ASIC).

EOS S3, le bitstream libéré !

[Dépêche initialement paru sur LinuxFR]

Pour configurer les différentes connexions des blocs de logiques contenus dans un FPGA il faut lui fournir un fichier de configuration appelé «bitstream». Quand on parle de libération des FPGA, on pense principalement à la publication de ces spécifications .
Jusqu’à présent, cette « libération » s’est faite, pour une poignée de FPGA (majoritairement Lattice), par ingénierie inverse. Donc jamais à l’initiative du constructeur, ce dernier n’ayant même pas toujours connaissance de projet d’ingénierie inverse à destination de ses produits. Et il faut aller fouiller dans d’obscurs fils Twitter et autre forums de bidouilleurs pour les découvrir.

Mais la libération s’accélère, et une petite société peu connue dans le monde du FPGA vient de lancer un produit basé sur des outils opensource pour le développement : l’EOS S3.

Comme on peut le voir dans le diagramme bloc ci-dessous, le produit est en fait un microcontrôleur Cortex-M4 qui possède une zone périphérique «de FPGA» appelé eFPGA.

EOS S3 Block Diagram

La société Quicklogic a considéré que développer des logiciels de synthèse et de placement routage n’était pas son métier. Elle s’est donc « contenté » de l’adapter aux logiciels open source de la suite symbiflow.

Pour la première fois dans l’histoire des FPGA, nous avons donc une société qui affirme documenter son « bitstream » et qui propose des outils libres pour le développement. C’est un événement que beaucoup attendaient depuis des dizaines d’années !

Bon le (tout petit) FPGA ne concerne qu’une partie du composant. Mais c’est un bon début, et l’utilisation de logiciels libres reste la philosophie de la société pour le développement de ce produit. Comme dit dans les avantages de la fiche marketing du kit de développement :

« No more multi Gigabyte software installs, no more of the hassles associated with proprietary tools, no more vendor-specific hardware incompatible with the industry. »

eFPGA

La datasheet nous dit que la partie FPGA (celle qui nous intéresse ici) est composée de :

  • 891 cellules logiques
  • 8 blocs de RAM double ports de 8Kbits
  • 2 multiplieurs câblés de 32×32 bits
  • 32 I/O configurables

Alors certes, on est très très bas dans la gamme des FPGA du marché. Mais on peut déjà envisager faire des petites choses intéressantes avec. Surtout qu’il n’y a pas que le FPGA dans ce microcontrôleur.

Kit de développement QuickFeather

Le kit est encore en phase de lancement, même s’il semble que certaines développeuses aient déjà reçu la carte pour faire des tests. Le tarif de $50 n’est pas prohibitif pour en envisager l’acquisition à des fin de tests. Les frais de port de $80 par contre posent problème, surtout s’il faut ajouter des frais de douane.

Bref, ça n’est pas du vaporware puisque les composants existent, mais il est pour l’instant difficile d’en dire plus concernant les outils. Dans tous les cas une nouvelle très rafraîchissante, et une accélération de la libération des FPGA qui fait plaisir !

[Édition le 17 juin 2020]

L’entreprise qui est derrière ce nouveau produit est Antmicro. Une entreprise qui fait de la conception FPGA/ASIC à base de logiciel libre.
Il semble également qu’ils aient été aidé par google.

Le communiqué de Antmicro.

Et en plus du EOS S3, Quicklogic lance une gamme de FPGA «discret» : le PolarPro 3E. Également basé sur une chaîne de développement libre \o/

openFPGALoader: One program to configure them all.

openFPGALoader is an open source C++ utility prog used to program/configure FPGA.

The goal of this project is to have one command line program to configure all types of FPGA regardless of probe or development kit is used.

For the moment the following FPGA are supported :

But the project is growing fast, no doubt that other FPGA will be supported soon.

Not only it’s easier to use than GUI, but it really fastest. With a MachXO3 6900 and digilent HS3 probe it take about 10 seconds on my computer :

$ time openFPGALoader -cdigilent_hs3 bitstream.jed
Open file bitstream.jed DONE
Parse file DONE
Enable configuration: DONE
SRAM erase: DONE
Enable configuration: DONE
Flash erase: DONE
Writing: [==================================================] 100.000000%
Done
Verifying: [==================================================] 100.000000%
Done
Write program Done: DONE
Disable configuration: DONE
Refresh: DONE

real	0m10,274s
user	0m0,728s
sys	0m1,676s

With official lattice diamond programer it take me 50 seconds.

Cocotb Tips

Some tips for python HDL test module Cocotb.

Read and Write signal

Write:

clk.value = 1
dut.input_signal <= 12
dut.sub_block.memory.array[4] <= 2

Read:

count = dut.counter.value
print(count.binstr)
print(count.integer)
print(count.n_bits)
print(int(dut.counter))

See it under the official documentation.

Yielding a coroutine in a select list fashion

Question asked on stackoverflow.

Using latest python version with virtualenv

If you compile python yourself, don’t forget to add option --enable-shared at configure time (./configure --enable-shared)

$ virtualenv --python=/usr/local/bin/python3.7 ~/envp37
$ source ~/envp37/bin/activate
$ python -m pip install cocotb

Do not forget to re-source your environnement each time you open a new terminal :

$ source ~/envp37/bin/activate

Logging messages and main test class template

This is a template for declaring a class used for test in function @cocotb.test() :

import logging
from cocotb import SimLog
...

class MyDUTNameTest(object):
    """ Test class for MyDUTName"""
    LOGLEVEL = logging.INFO
    # clock frequency is 50Mhz
    PERIOD = (20, "ns")

    def __init__(self):
        if sys.version_info[0] < 3: # because python 2.7 is obsolete
            raise Exception("Must be using Python 3")
        self._dut = dut
        self.log = SimLog("RmiiDebug.{}".format(self.__class__.__name__))
        self.log.setLevel(self.LOGLEVEL)
        self._dut._log.setLevel(self.LOGLEVEL)
        self.clock = Clock(self._dut.clock, self.PERIOD[0], self.PERIOD[1])
        self._clock_thread = cocotb.fork(self.clock.start())

# ....

@cocotb.test()
def my_test(dut):
    mdutn = MyDUTNameTest()
    mdutn.log.info("Launching my test")

Déballage du kit de développement Lichee Tang muni d’un FPGA Chinois Anlogic

La société chinoise SiPeed propose un kit de développement permettant d’évaluer le FPGA chinois EG4S20BG256 produit par Anlogic. Le kit peut être commandé pour une vingtaine de dollars sur le site de vente en ligne Seeed spécialisé dans les kits de développement en électronique «grand public».

Contenu du kit SiPeed coté FPGA
Contenu du kit Lichee Tang botto

Au branchement du kit Debian/Linux détecte un convertisseur USB-JTAG de chez Anlogic:

$ sudo dmesg -c
[30017.300586] usb 3-2: new full-speed USB device number 5 using xhci_hcd
[30017.441796] usb 3-2: New USB device found, idVendor=0547, idProduct=1002
[30017.441801] usb 3-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[30017.441804] usb 3-2: Product: USB-JTAG-Cable
[30017.441807] usb 3-2: Manufacturer: Anlogic

L’environnement de développement est disponible en téléchargement (~100Mo) sous forme d’une archive rar ici. Le fichier se décompresse avec la commande unrar:

$ unrar x ../TD_RELEASE_SEPTEMBER2018_RHEL.rar

Il faut ensuite mettre en exécutable le répertoire bin:

$ chmod +x bin/*

Et on peut ensuite lancer l’IDE:

$ cd bin ; ./td -gui

La fenêtre suivante s’ouvre alors :

L’environnement de développement Tang Dynasty lancé sur Debian

C’est l’environement de développement le plus simple à installer que j’ai pu voir depuis que je bricole des FPGA. Même si la procédure d’installation est quand même étrange (un obscure .rar à télécharger puis à décompresser).

Pour synthétiser un premier design on va avoir besoin d’un minimum de documentation sur la schématique de la carte ainsi que sur le pinout du FPGA. On trouvera les schémas du kit en format pdf ici.

On trouve des exemples de code pour le kit sur github, notamment pour faire clignoter une led. La base du Hello World en électronique.

Pour tester la led qui clignote on crée un nouveau projet avec le fpga EG4S20BG256. On ajoute ensuite le source pour la led se trouvant dans le répertoire Tang_FPGA_Examples/0.LED/src/led.v

L’extension du fichiers de contrainte est en *.adc pour l’exemple de led le fichier se trouve dans le répertoire Tang_FPGA_Examples/0.LED/constraint/io.adc

Une fois les deux fichiers ci-dessus ajouté à notre projet on peut lancer la procédure complète pour générer le bitstream en double-cliquant sur l’icône «Generate Bitstream» dans l’encart «FPGA Flow» de l’ide.

La génération du bitstream est très rapide. Pour le télécharger ensuite dans le FPGA il faut bien sûr que le kit soit connecté à l’usb.

Le configurateur se lance en allant dans le menu Tools -> Download.

Chez moi j’ai du lancer l’ide en sudo pour éviter un plantage fatal, à ce moment. Le configurateur se présente comme ci-dessous :

Il faut ajouter le fichier bitstream au moyen du bouton de gauche «Add» puis cliquer sur la ligne du tableur pour «dégriser» le bouton «run», qui permet de télécharger le bitstream pour configurer le FPGA.

Pour conclure, je pensais beaucoup plus souffrir à mettre en route ce kit à la documentation majoritairement en chinois. Mais la note de blog de JAEB et le projet d’exemples sur github m’ont beaucoup aidé à faire clignoter cette led tricolore rapidement. À l’avenir il faudra regarder si ce FPGA est vraiment nouveau ou si ça n’est pas une copie d’un constructeur bien connu. On doit pouvoir vérifier ça avec le bitstream généré.

Au bout de quelques temps, la licence du logiciel expire. Il n’est plus possible de synthétiser avec. Un site chinois donne le truc pour que ça remarche. Pour éviter ce piratage, il semble être maintenant possible d’utiliser Yosys pour la partie synthèse !

Pour aller plus loin:

Installing Libero on Debian 9

This is just an install success story of Libero on Debian 9 (stretch).  For the Risc-V contest, I recently acquired the Microsemi IGLOO2 development kit named FUTUREM2GL-EVB  distributed by Futur-Electronic.

The development software for the IGLOO2 is named Libero and according to Microsemi, should works on Linux. But officially support only RedHat, CentOS and SuSE … not Debian. Microsemi provide a Linux installation guide to install it. It’s useful but should be adapted for Debian.

Download and install Libero

The first thinks to do is to download the installing file for Linux (and not the SP1 file which is only an update).  Once downloaded we just have to launch it, if it’s not executable we can change rights with chmod command.

$ chmod 666 Libero_SoC_v11.9_Linux.bin
$ ./Libero_SoC_v11.9_Linux.bin

An install windows will raise and we can follow directives.

Licensing

Once installed, we need to install the license. For that, we need to know our mac address :

$ ip addr show dev eth0
[...]
link/ether 12:34:56:78:9a:bc [...]

The key that should be given to Microsemi is in upper case without ‘:’ :

$ ipython

In [1]: "12:34:56:78:9a:bc".replace(':','').upper()                                                                                                                                                             
Out[1]: '123456789ABC'

With this key we can then ask for a license file on microsemi website. The official Linux guide talk about license.dat file, but for me it was license.zip … Both are zip file in fact. We can then unflat it with unzip command:

$ unzip License.zip 
Archive:  License.zip
  inflating: License.dat

The unflated file is a text file that should be edited with you text edito as explained in guide (page 6).

License server

The license server deamon must be downoaded on official microsemi website. Choose «Linux deamon» in table. It’s an archive of several binaries that should be unflated :

$ cd
$ tar -zxvf Linux_Licensing_Daemon.tar.gz
Linux_Licensing_Daemon/
Linux_Licensing_Daemon/actlmgrd
Linux_Licensing_Daemon/lmgrd
Linux_Licensing_Daemon/lmhostid
Linux_Licensing_Daemon/lmutil
Linux_Licensing_Daemon/mgcld
Linux_Licensing_Daemon/snpslmd
Linux_Licensing_Daemon/syncad
Linux_Licensing_Daemon/synplctyd

Export shell variables

Before launching software, we have to export some paths in our .bashrc :

#Libero 
LIBERO_LICENSE_FOLDER=/home/giselle/flexlm
LD_LIBRARY_PATH=/usr/lib/i386-linux-gnu/:/usr/lib/x86_64-linux-gnu/
# For Floating License from a License Server
export LM_LICENSE_FILE=1702@gisellelaptop:$LM_LICENSE_FILE
export SNPSLMD_LICENSE_FILE=1702@gisellelaptop:$SNPSLMD_LICENSE_FILE
# <1702> is the port number
# martonilp is the license server host name
#For Node-Locked License
export LM_LICENSE_FILE=$LIBERO_LICENSE_FOLDER/license.dat:$LM_LICENSE_FILE
export SNPSLMD_LICENSE_FILE=$LIBERO_LICENSE_FOLDER/license.dat:$SNPSLMD_LICENSE_FILE
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib
export DISPLAY=:0
export PATH=/opt/microsemi/Libero_SoC_v11.9/Libero/bin:$PATH

On my computer, Microsemi softwares are installed in /opt/ directory.

Launching Libero

First launch license server :

$ cd
$./flexlm/lmgrd -c ~/flexlm/License.dat -log /tmp/lmgrd.log

Once license server launched we can run Libero :

$ libero
/opt/microsemi/Libero_SoC_v11.9/Libero/bin/libero_bin: /opt/microsemi/Libero_SoC_v11.9/Libero/lib/libz.so.1: no version information available (required by /usr/lib/i386-linux-gnu/libpng16.so.16)

I had a little problem with libz provided with libero package, then I removed it and linked libz of my distribution :

$ apt-file search libz.so
lib32z1: /usr/lib32/libz.so.1
lib32z1: /usr/lib32/libz.so.1.2.8
lib32z1-dev: /usr/lib32/libz.so
zlib1g: /lib/x86_64-linux-gnu/libz.so.1
zlib1g: /lib/x86_64-linux-gnu/libz.so.1.2.8
zlib1g-dev: /usr/lib/x86_64-linux-gnu/libz.so
...
$ cd /opt/microsemi/Libero_SoC_v11.9/Libero/lib
$ mv libz.so.1 oldlibz.so.1
$ ln -s /lib/x86_64-linux-gnu/libz.so.1 libz.so.1

And then managed to launch it :

$ libero

Hurrah \o/ that works

But it’s unfortunately not finished.

First, when I tryied to synthesize I had this message in error window :

/opt/microsemi/Libero_SoC_v11.9/Synplify/bin/synplify_pro: 137: [: unexpected operator
/opt/microsemi/Libero_SoC_v11.9/Synplify/bin/synplify_pro: 151: [: !=: argument expected
/opt/microsemi/Libero_SoC_v11.9/Synplify/bin/synplify_pro: 324: /opt/microsemi/Libero_SoC_v11.9/Synplify/bin/config/execute: Syntax error: "(" unexpected (expecting ";;")

The problem come from the shell Debian uses by default :

$ ls -lha /bin/sh
lrwxrwxrwx 1 root root 4 oct.  29 20:50 /bin/sh -> dash

This shell doesn’t work like bash and generate some error in synplify scripts. To solve it I simply changed the /bin/sh link to /bin/bash :

$ cd /bin/
$ sudo mv sh shold
$ sudo ln -s bash sh

And I managed to synthesize my design.

But it’s not finished ! Once my bitstream generated I would like to download it on the IGLOO2 on kit. For that, we have to install correctly drivers for FlashPro5.
Directives are given in the official Microsemi Linux install guide, but udev syntax is false on Debian :

BUS=="usb",SYSFS{idProduct}=="2008",SYSFS{idVendor}=="1514",MODE="0660",GROUP="",SYMLINK+="FlashPro5"
BUS=="usb",SYSFS{idProduct}=="6001",SYSFS{idVendor}=="0403",MODE="0660",GROUP="",SYMLINK+="FTDI232"

Right rules are following :

# FlashPro5
SUBSYSTEM=="usb", ATTR{idVendor}=="1514", ATTR{idProduct}=="2008", MODE="0666", GROUP="plugdev"
SUBSYSTEM=="usb", ATTR{idVendor}=="0403", ATTR{idProduct}=="6001", MODE="0666", GROUP="plugdev"

Should be written in /etc/udev/rules.d/70-microsemi.rules file.

Then fully works  and they lived happily and urged a lot of children

Verilator 4.002

La version 4.002 de Verilator a été annoncée à la conférence ORConf2018 en Pologne.

Verilator est sans conteste le simulateur HDL open source le plus rapide du « marché ». Il permet de simuler des porte‐grammes écrits en Verilog synthétisable.

Le nouveau logo de Verilator

La suite sur la dépêche linuxfr

Un composant électronique TapTempo avec Chisel3

Le «défi TapTempo» a été lancé sur LinuxFr il y a quelques semaines. L’objectif est de réaliser la mesure du tempo de l’appui sur une touche et de l’afficher simplement dans la console le résultat. La mesure du tempo s’effectue par défaut sur 5 appuis consécutif et affiche une moyenne en bpm (Beats Per Minute). L’idée est de réaliser la fonction dans divers langages informatiques pour que chacun puisse promouvoir son langage favoris. Beaucoup de langages ont été représenté jusqu’à présent, mais aucun langages de description matériel n’avait encore été proposé.

Pour palier ce gros manquement dans les langages représenté je vous propose ici de réaliser TapTempo en Chisel (version 3).

Architecture générale

L’idée ici n’est donc plus d’écrire un programme pour calculer le tempo mais de décrire l’architecture d’un composant matériel permettant de réaliser la fonction. Le matériel visé sera un FPGA, nous laissons de coté le développement sur ASIC. Même si une fois terminé il ne devrait pas y avoir de problème pour être porté sur un ASIC, si quelqu’un a suffisamment d’argent pour le claquer dans ce genre d’ânerie 😉

Le bloc fonctionnel de notre composant sera donc constitué d’une entrée button recevant le signal de l’appui sur un bouton permettant de faire le tempo. Dans un premier temps nous laisserons de coté les problèmes de métastabilité ainsi que de rebond. L’implémentation réel dans un FPGA nécessitera obligatoirement l’ajout d’un étage de synchronisation du signal d’entrée avec l’horloge ainsi que d’un bloc «anti-rebond», aucun bouton réel n’étant capable de faire un signal vraiment propre.

La sortie du bloc sera constitué d’un entier non signé bpm dont nous allons discuter la taille ci-dessous.

Et comme nous somme dans un FPGA il est indispensable de concevoir notre fonction synchrone d’une horloge, et souhaitable d’avoir un reset général.

Structure interne

La structure interne de TapTempo est donnée ci-dessous:

L’idée est de compter des ticks générés par timepulse au moyen du compteur count. Quand un appui sur le bouton est détecté, le compteur se remet à zéro et la valeur est enregistrée dans le tableau countx. À chaque coup d’horloge l’addition des 4 valeurs count est réalisée puis on divise par 4. La division par 4 est réalisable dans un FPGA au moyen d’un simple décalage à droite de 2. Vient la partie la plus compliqué : se servir de cette période moyenne pour diviser TMINUTE et obtenir la valeur du tempo en bmp.

Un peu de dimensionnement

On ne fonctionne pas dans un FPGA comme on fonctionne avec un pc, quand on fait des opérations sur des nombres il faut les dimensionner. Et il est fortement recommander d’utiliser des entiers, car le calcul flottant nécessite tout de suite une quantité de ressources phénoménale.

Notre objectif est de mesurer une cadence musicale en bpm que l’on puisse «taper à la main», si l’on regarde l’article wikipedia consacré au Tempo, on se rend vite compte qu’attendre les 200bpm est déjà pas mal. Disons que pour prendre une très large marge nous mettons la marge supérieur à 270bpm. Nous aurons donc en sortie une variable entière sur 9bits ( int(ln2(270))+1).

À 270bpm, le temps entre deux tempos est de ~222ms ce qui nous donnerais une fréquence de pulse de 4.5Hz. Cependant, si nous voulons une précision de 1bpm il va falloir augmenter cette fréquence , pour avoir un chiffre rond nous prendrons un temps de 1ms, soit une fréquence de 1kHz. Ce qui est un peu juste pour 270bpm, mais conviendra à la démonstration.

Décomposons le code

Le code se trouve sur le dépôt github suivant.  Nous allons décrire la description du module à proprement parlé qui se trouve ici.

Dans l’entête du module nous allons retrouver le port d’entrée button ainsi que le port de sortie bpm. Point d’horloge ni de reset ici puisqu’en Chisel ces signaux sont implicite.

// default clock 100Mhz -> T = 10ns
class TapTempo(tclk_ns: Int, bpm_max: Int = 270) extends Module {
val io = IO(new Bundle {
// val bpm = Output(UInt(8.W))
val bpm = Output(UInt(9.W))
val button = Input(Bool())
})

Quelques constantes qui nous servirons ensuite :

  /* Constant parameters */
  val MINUTE_NS = 60*1000*1000*1000L
  val PULSE_NS = 1000*1000
  val TCLK_NS = tclk_ns
  val BPM_MAX = bpm_max

  /* usefull function */
  def risingedge(x: Bool) = x && !RegNext(x)

Pour notre générateur de pulses il suffit d’utiliser une classe présente dans la bibliothèque «util» de chisel : Counter. Qui comme son nom l’indique … compte !

import chisel3.util.Counter
[...]
  val (pulsecount, timepulse) = Counter(true.B, PULSE_NS/tclk_ns)
[...]

Ce compteur prend en paramètre un signal de comptage (ici true.B -> compte tout le temps) ainsi que la valeur max à atteindre.
L’instanciation de l’objet retourne un compteur ainsi qu’un signal qui passe à ‘1’ quand le compteur se remet à zero (quand il dépasse la valeur max).

Ce signal timepulse sera ensuite utilisé par un deuxième compteur 16 bits tp_count que nous allons écrire «à la main» cette fois.
On défini d’abord le registre de 16bits que l’ont initialise à 0 (0.asUInt(16.W))

  val tp_count = RegInit(0.asUInt(16.W))

Puis on écrit le code décrivant le «comptage»:

  when(timepulse) {
    tp_count := tp_count + 1.U
  }
  when(risingedge(io.button)){
    // enregistrement de la valeur du compteur.
    countx(count_mux) := tp_count
    count_mux := Mux(count_mux === 3.U, 0.U, count_mux + 1.U)
    // remise à zéro du compteur
    tp_count := 0.U
  }

Ce deuxième compteur compte les pulse «timepulse» et se remet à 0 lorsqu’un front montant est détecté sur le bouton (quand on appuis sur le bouton).

Pour stocker les 4 valeurs permettant de réaliser une valeurs nous déclarons un vecteur de registres de 19 bits (pour gérer les retenues quand nous ferons l’addition):

  val countx = RegInit(Vec(Seq.fill(4)(0.asUInt(19.W))))

Ainsi que le «pointeur» :

  val count_mux = RegInit(0.asUInt(2.W))

La gestion de l’incrémentation du pointeur ainsi que de l’enregistrement du compteur se trouve dans le code du «compteur de pulse» que nous avons vu plus haut:

    // enregistrement de la valeur du compteur.
    countx(count_mux) := tp_count
    count_mux := Mux(count_mux === 3.U, 0.U, count_mux + 1.U)

Pour faire la somme rien de plus simple, il suffit de faire ‘+’ :

  val sum = Wire(UInt(19.W))
[...]
  sum := countx(0) + countx(1) + countx(2) + countx(3)

Et la division par 4 se résume à un décalage:

  val sum_by_4 = sum(18, 2)

Et nous arrivons à la partie la plus compliquée du design : diviser. Diviser est quelque chose de très compliqué dans un FPGA, on peut réaliser un design permettant d’effectuer une divisions en plusieurs cycles d’horloge, mais c’est tout de suite une très grosse usine à gaz.

Pour la division permettant de faire la moyenne des échantillons nous nous en étions sortie en faisant une division par une puissance de 2, qui se résume de fait à un simple décalage. Mais cette fois on ne pourra pas s’en sortir avec ce genre de pirouette. Car notre division à réaliser est la suivante :

   Nombre de pulse dans une minute
-------------------------------------  = valeur en bpm
moyenne des pulses mesuré (sum_by_4)

Pour nous en sortir la première idée serait de faire une table de valeurs pré-calculée pour chaque valeurs de  sum_by_4. Ce qui se fait très simplement en scala avec une séquence :

val x = Seq.tabulate(pow(2,16).toInt-1)(n => ((MINUTE_NS/PULSE_NS)/(n+1)).U)

Sauf que le nombre de valeurs est particulièrement grand (2^16) et qu’on pourrait certainement factoriser un peut tout ça.

Pour réduire la taille ne notre tableau il faut prendre le problème à l’envers: combien de valeurs possible puis-je avoir en sortie ?

La réponse est simplement 269 puisque je peux aller de 1 à 270bpm. Nous allons donc réaliser un vecteur de 270 valeurs contenant la valeurs minimum du compteurs permettant d’atteindre notre résultat. Et nous mettrons ces valeurs dans 270 registres.

  val bpm_calc = RegInit(Vec(x(0) +: Seq.tabulate(bpm_max)(n => x(n))))

Pour obtenir la valeur finale il faut ensuite générer 270 inéquations ayant pour résultat un vecteur de 270 bits :

  for(i <- 0 to (bpm_max-1)) {
    bpm_ineq(i) := Mux(sum_by_4 < bpm_calc(i), 1.U, 0.U)
  }

Le résultat correspondra ensuite à l’index du dernier bit à 1 dans ce vecteur.

Pour récupérer cet index, une fonction très utile est fournie dans la bibliothèque «util» de chisel : le PriorityEncoder. Qui permet d’obtenir l’index du plus petit bit à 1 dans un vecteur… sauf que nous on veut le plus grand !

Mais ce n’est pas très grave, il suffit de retourner le vecteur avec Reverse puis de faire une soustraction pour avoir le résultat :

  io.bpm := bpm_max.U - PriorityEncoder(Reverse(bpm_ineq.asUInt()))

Simulation

Le test permettant de simuler le design se trouve dans le fichier TapTempoUnitTest.scala

Il peut être lancé avec la commande sbt suivante :

sbt 'test:runMain taptempo.TapTempoMain --backend-name verilator'

Et les traces VCD générées sont disponible dans le répertoire ./test_run_dir/taptempo.TapTempoMain962904038/TapTempo.vcd

Visualisable simplement avec gtkwave.

gtkwave ./test_run_dir/taptempo.TapTempoMain962904038/TapTempo.vcd

Trace vcd de la simulation TapTempo

À suivre

Pour être vraiment complet il faudrait ajouter la gestion des rebonds ainsi que la synchronisation du signal d’entrée puis tester la synthèse. Mais ce sont de nouvelles aventure qui continuerons peut-être dans un prochaine épisode 🙂 .