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.
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.
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 :
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 | 1 | Sens de l'accès we=1 : écriture par le maître |
ack | output | 1 | Acquittement de la transaction par l'esclave |
cti | input | 3 | Tag : type de transfert (classique, salves,...) |
bte | input | 2 | Tag : type de salve |
rty | output | 1 | Demande de repétition par l'esclave |
err | output | 1 | 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 :
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)
...
- 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 :
-
L'octet relu n'est pas identique à l'octet écrit alors que le bit de masque d'écriture était "1".
-
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 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)
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é | 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.
Fichier attaché | Taille |
---|---|
![]() | 336 octets |
![]() | 4.13 Ko |
![]() | 643.98 Ko |