Interfaces SystemVerilog et Bus Wishbone

Ce cours est l'occasion d'introduire l'utilisation de la  notion d'interface (chapitre 25 de la  norme) en SystemVerilog pour modéliser des bus de communication. Une application est faite à la norme de communication Wishbone, au travers d'un exercice de codage d'un contrôleur de mémoire.

Le cours est ici ..

Création d'un contrôleur mémoire à interface Wishbone.

Il s'agit de coder un module esclave Wishbone pour contrôler une mémoire synchrone interne d'un FPGA.

 

Image du contrôleur de RAM

0 Mise en place de l'environnement de travail

  • Placez vous dans votre dépot  git personnel (cd )
  • Importez les codes de testbench de votre futur bloc  ​​
    • git checkout master
    • git remote add interface_wishbone git@gitlab.enst.fr:se204/interface_wishbone.git   
    • git remote update
    • git merge --allow-unrelated-histories interface_wishbone/master

La hiérarchie chargée est structurée de la façon suivante :

  • Le répertoire controleur_memoire contient
    • Un fichier Makefile permettant de tester votre code
    • Un répertoire wshb_bram_tb_src contenant les sources d'un testbench de votre futur contrôleur.
    • Un répertoire wb_bram contenant les sources d'un squelette de module qui inclura votre futur code
  • Le répertoire wshb_if contient
    • la définition de l'interface Wishbone en SystemVerilog
    • la documentation de l'interface Wishbone
    • des outils nécessaires à la réalisation du testbench

Vous n'avez, pas à intervenir dans le répertoire  wshb_if , sauf pour   lire la documentation..
 

1 Code SystemVerilog du contrôleur de mémoire

ATTENTION : LISEZ IMPERATIVEMENT LES CHAPITRES 1 à 4 AVANT DE CODER QUOI QUE CE SOIT.

Vous disposez d'un squelette (wb_bram.sv) du contrôleur de mémoire. Ses entrées sorties sont réduites au bus Wishbone lui même, car ce module ne communique qu'avec le bus.

Contraintes de codage à respecter impérativement

  • Le code est constitué d'un module unique contenant à la fois le code de l'interface et l'inférence de la mémoire.
  • Le contrôleur est un esclave du bus Wishbone.
  • L'acquittement de l'écriture se fera de manière combinatoire.
  • La mémoire étant synchrone dans les FPGA, l'acquittement de la lecture aura un cycle de retard par rapport à la requête
  • La taille de la mémoire sera paramétrable, sa valeur par défaut sera de 2048 mots (paramètre mem_adr_width égal à 11)
  • Le code devra être évidemment synthétisable.
  • Deux versions du code seront réalisées, et taggées  dans votre dépot GIT :
    • Un esclave Wishbone utilisant des transactions de type "Classic Bus Cycle"  ( tag imposé : simple_wb_bram )
    • Un esclave Wishbone utilisant des transactions de type "Registered FeedBack Cycle"  (tag imposé : pipelined_wb_bram) 
    • Le nom du fichier ne doit pas être changé (usage exclusif des tags)

 

Dans le squelette, l'interface Wishbone est nommée "wb_s". Tous les signaux de l'interface seront donc accessibles par la syntaxe "wb_s.xxx" ou xxx est le nom du signal voulu.

Les  signaux accessibles par l'esclave Wishbone sont, conformément à la norme :

Signaux de l'interface Wishbone esclave
Nom Type bits Commentaire
clk input 1 Horloge du bus 
rst input 1 Initialisation du bus (actif à l'état haut)
adr input 32  Adresse
dat_ms input 32  Donnée écrite par le maître
dat_sm output  32  Donnée renvoyée par l'esclave
sel input 4  Masque de sélection des octets
cyc input 1  Demande d'accès par le maître
stb input  1  Validation d'un accès par le maître
we  input  Sens de l'accès we=1 : écriture par le maître
ack output  Acquittement de la transaction par l'esclave
cti input  Tag : type de transfert (classique, salves,...)
bte  input  Tag : type de salve
rty  output  Demande de repétition par l'esclave
err  output   Signalement d'une erreur par l'esclave

2 Simulation

Le Makefile permet de lancer la simulation qui indique directement les erreurs de transferts. La commande de Makefile permet les choix suivants :

  • compile : compilation des codes (module à tester et testbenchs)
  • simu_batch : simulation en mode terminal, avec simple affichage des résultats des tests
  • simu_gui : simulation en mode graphique pour faire un debug de votre code.
  • all : équivalent à simu_gui
  • clean : nettoyage

Le testbench génère des écritures de paquets de données, suivies de lectures de ces mêmes paquets. La taille et les addresses de ses paquets sont aléatoires. A la première erreur, le testbench affiche le paquet  initial lu, le paquer  écrit et le paquet relu :

#-----Check 1   Failed. Current Check has 25 errors
 : Packet size is          96 bytes
address   Initial read data         Written data              Read data
0000daa8  (1,00)(1,00)(1,00)(1,00)  (0,ae)(0,d4)(0,35)(0,56)  (0,00)(0,00)(0,00)(0,00)
0000daac  (1,00)(1,00)(1,00)(1,00)  (1,e3)(1,05)(0,db)(0,7d)  (1,00)(1,00)(0,00)(0,00)
0000dab0  (1,00)(1,00)(1,00)(1,00)  (0,25)(0,05)(0,e5)(0,20)  (0,00)(0,00)(0,00)(0,00)
0000dab4  (1,00)(1,00)(1,00)(1,00)  (1,58)(1,8a)(1,5d)(1,e9)  (1,58)(1,8a)(1,5d)(1,ea)
0000dab8  (1,00)(1,00)(1,00)(1,00)  (0,b9)(0,c9)(0,56)(1,8b)  (0,00)(0,00)(0,00)(1,00)
...
Sont indiqués :
  • l'adresse d'écriture de chaque mot du paquet de données 
  • la liste des octets lus, de chaque mot ainsi que leur bit de masque à la lecture
  • la liste des octets écrits ainsi que le bit de masque associé
  • la liste des octets re-lus. 

Il y a erreur (en rouge)  dans les 2 cas suivants :

  1. L'octet relu n'est pas identique à l'octet écrit alors que  le bit de masque d'écriture était "1".

  2. L'octet relu n'est pas identique à l'octet lu initialement alors que  le bit de masque d'écriture était "0".

ATTENTION : Les messages d'erreur sont dirigés vers le terminal que la simulation soit en mode batch ou interactive. Vérifiez donc systématiquement les messages apparaissant dans le terminal.

3 Test de Synthèse

N'oubliez pas de tester votre contrôleur en synthèse. Pour cela vous devrez compiler 2 fichiers dans le synthétiseur Précision :

  • La définition de l'interface elle même : fichier wshb_if.sv dans le répertoire wshb_if.
  • Le contrôleur : fichier wshb_bram.sv dans le répertoire wshb_bram.

Le synthétiseur sera configuré de la façon suivante :

  • La cible choisie sera un FPGA Altera EP2C35F672C6.
  • La fréquence cible sera 400 MHz.
  • Les contraintes de délai sur les I/O seront mises à 0.0 ns
  • Dans le menu Options/Optimization décochez "Add IO Pads"  (on ne synthètise qu'un bloc, pas un FPGA complet)

N'oubliez pas de vérifier que votre code infère bien des blocs mémoire du FPGA.

4 Un peu d'aide

Voici quelques conseils et erreurs courantes faites par les élèves :

  • Séparez la gestion de la réponse au protocole Wishbone du traitement effectif de la requête (écrire ou lire dans une RAM). Vous pouvez ainsi supprimer très rapidement les erreurs de timeout (le maître fait une requête mais l'esclave ne répond pas).
  • L'esclave n'a pas à vérifier le respect du protocole par le maître. PAS DE CODE INUTILE DE VERIFICATION
  • Pas de machines à état compliquées qui se traduisent par des retards inutiles dans la réponse du contrôleur.
  • Traitez le problème en partant des signaux à générer et en réfléchissant de manière indépendante signal par signal :
    • Mauvaise méthode : je fais un processus synchrone, et je verrais bien dans ce processus quand tel ou tel signal devra valoir 1 ou 0
    • Bonne méthode : je considère un signal, je détermine ses contraintes (quand vaut il 1 ou 0) et j'en déduit un processus synchrone ou combinatoire adapté.

Enfin les tableaux  suivant présentent les résultats obtenus par un groupe d'étudiants.

Temps de simulation pour le contrôleur classique
Temps obtenu Commentaires
9880570 Ce qu'il faut obtenir
temps attendu+10% Fonctionnel  mais sûrement une petite maladresse dans le code
temps attendu+30% Un peu plus maladroit encore
infini... Code ne répondant même pas au protocole Wishbone

Ce premier tableau correspond au temps nécessaire pour que le tesbench génère et traite tous les paquets de données. Le temps est d'autant plus court que le contrôleur répond de manière efficace au maître wishbone. Vérifiez bien le comportement du contrôleur en simulation (temps de réaction à une requête en nombre de cycles)

 

Fréquence de fonctionnement du contrôleur classique sur CycloneII
Gamme de fréquences Commentaires
supérieure 950MHz L'optimum
Entre 500MHz et 900MHz Code combinatoire sans doute un peu maladroit. Ne pas faire de calculs inutiles.
Inférieur à 500MHz Code sûrement très maladroit
0 Echec à la synthèse. Il faut absolument examiner et comprendre les messages d'erreur du synthétiseur et modifier le code

Ce tableau donne la fréquence maximale de fonctionnement du contrôleur  après synthèse avec l'outil "Precision" sur cible CycloneII EP2C35F672C6.  Examinez bien les WARNING de synthèse et cherchez à en comprendre la signification.

 

Complexité du contrôleur classique sur CycloneII
Complexité Commentaires
Moins de 10 LUT L'optimum
Entre 10 et 50 LUT Trop de choses codées inutilement
Entre 50 et 100 LUT Code sûrement très maladroit
Plus de 100 LUT La mémoire n'est sûrement pas correctement inférée, elle est remplacée par un tableau de bascules D.

Ce tableau indique le nombre de "Look UP Tables" nécessaire pour la synthèse de votre code. Si ce nombre explose, il est vraisemblable que le code comportemental de la RAM est mal écrit.