Intel HLS

La programmation d’un FPGA peut se faire de différentes manières ainsi qu’à différents niveaux :

  • Bas niveau : Description du fonctionnement voulu à bas niveau en VHDL/Verilog.
  • Plus haut niveau : Utilisation d’IP propriétaires intégrées au sein d’un design.
  • Encore plus haut niveau : Génération d’IP à l’aide du moteur de compilation High Level
    Synthesis (HLS) d’Intel (programmation en C++).

En utilisant Intel HLS, on accepte de perdre un peu de contrôle sur ce qui est généré au niveau RTL au profit d’un temps de développement nettement réduit.

Principe de fonctionnement

Le développement HLS se fait au niveau software, pas besoin d’avoir de compétences particulières en électronique pour s’approprier l’outil :

  • Développement en C++ légèrement revisité.
  • Intel HLS s’utilise uniquement en ligne de commande (commande i++).

Du code c++ à l’IP

Voici une analogie entre le code écrit et ce qui est généré in fine :

Compilations avec i++

i++ est le pendant de g++ mais appliqué à la génération d’IP intégrable dans quartus.

Il existe 2 modes de fonctionnements distincts :

  • Une compilation pour le débogage : permet de vérifier le bon fonctionnement du composant décrit (possibilité d’utiliser des outils comme printf, cout ou gdb).

Le graphique ci-dessus décrit une manière simple d’utiliser le mode de débogage :

Compilation x86-64
  • Une compilation qui cible un FPGA : Une fois que le composant fonctionne correctement on synthétise un « projet » c’est à dire une suite de dossier contenant l’IP, les rapports, les simulations etc.. :

Le graphique ci-dessus décrit une compilation qui cible un FPGA Arria 10 :

Compilation pour un Arria 10

Optimisations du code

Un réseau de neurones est composé de très nombreux neurones agencés en couches. Lorsque l’on va décrire tout cela en C++ il va falloir porter une attention toute particulière à différents points :

  • La taille des variables que l’on manipule : Intel HLS met à notre disposition des types particuliers (ac_fixed, ac_int), ils permettent de gérer très précisément le nombre de bits alloués à tel ou tel paramètre.
  • La manière de décrire les boucles de calculs : Afin d’obtenir un code optimisé, Intel a établi une liste des pièges à éviter ainsi qu’un guide des bonnes pratiques de codages. En effet, bien que l’on travaille en C++ c’est du code VHDL/Verilog qui est généré.
  • Utilisation des pragmas : Il est possible de contraindre l’exécution d’une boucle de telle ou telle manière. Pour cela, il faut placer un petit morceau de code en entête de la boucle (c’est ce qu’on appelle les pragmas).

Performances sur les réseaux « challenges »

Les résultats présentés ci-dessous sont le fruit de 4 implémentations différentes (horloge à 240MHz) :

  • Vanilla : Une implémentation qui ne contient pas d’optimisations dans le code.
  • Pipeline : Une implémentation dans laquelle on pipeline le réseau.
  • Unroll : Une implémentation dans laquelle on unroll la totalité des boucles.
  • U+p : Une implémentation dans laquelle on unroll une partie des boucles (les boucles imbriquées) + pipeline du réseau.
ALUTSFFsRAMsMLABsDSPsDébit (FPS)
Ch1 vanilla602547421.55 217 391
Ch1 pipeline610624451.526 666 667
Ch1 unroll515245410240 000 000
Ch1 u+p515245410240 000 000
ALUTSFFsRAMsMLABsDSPsDébit (FPS)
Ch3 vanilla1 4081 80930122.59 383
Ch3 pipeline2 0934 46032482.511 988
Ch3 unroll118 04136 7375370240 000 000
Ch3 u+p27 52442 5461 855298752 376 237
ALUTSFFsRAMsMLABsDSPsDébit (FPS)
Ch4 vanilla4 4426 415355203.5364
Ch4 pipeline5 55510 8993621133.5480
Ch4 unrollXXXXXXXXXXXXXXXXXXXXXXXX
Ch4 u+pXXXXXXXXXXXXXXXXXXXXXXXX
ALUTSFFsRAMsMLABsDSPsDébit (FPS)
Ch5 vanilla1 6692 19332162.52 556
Ch5 pipeline2 6176 07435762.53 839
Ch5 unroll569 249196 0516400240 000 000
Ch5 u+p17 56023 24450723750.5952 380

Conclusion

Avantages :

  • Permet d’attendre des débits très élevés : sur des réseaux petits ou bien optimisés.
  • Possibilité d’implémenter facilement des réseaux en parallèle sur un FPGA : en effet, ce sont des IP qui sont facilement interfaçable en parallèle au sein d’un même design.
  • Il est beaucoup plus facile de voir l’influence de tel ou tel paramètre avec HLS qu’avec du VHDL/Verilog classique : une compilation peut prendre du temps mais changer une ligne de code reste beaucoup plus simple que de réécrire du code VHDL/Verilog.
  • Les test/simulations sont aussi grandement facilités : Le main du code C++ devient le testbench du composant. Beaucoup plus simple d’exécuter un programme que de faire des simulations Quartus.

Inconvénients :

  • Perte de contrôle sur ce qui est généré au final : même en utilisant tous les outils à notre disposition il n’est pas possible d’écrire un code aussi optimisé que ce que nous pouvons réaliser en VHDL/Verilog.
  • Il est possible d’avoir des mauvaises surprises lors de la synthèse des projets : la compilation x86-64 et la compilation pour un FPGA peuvent donner des résultats différents lors de l’exécution. Pour éviter cela, il est conseillé de suivre les recommandations fournies par Intel.
  • Une méthode adaptée pour les réseaux simples et de petites tailles : pour les réseaux plus conséquents (traitement d’images), privilégier des solutions adaptées (Brainchip, Vitis AI, FPGA AI Suite)