Aller au contenu

Codage d'un contrôleur mémoire simple

ATTENTION : LISEZ IMPERATIVEMENT LES PARAGRAPHES 1 à 3 AVANT DE CODER QUOI QUE CE SOIT.

TAG à placer sur le dépot à la fin de ce travail: avalon_single_bram

Il s'agit de coder un contrôleur simple ne pouvant traiter que des transactions d'une seule donnée à la fois (burstcount=1).

Contraintes de codage à respecter impérativement

  1. Le code est constitué d’un module unique contenant à la fois le code de l’interface et l’inférence de la mémoire. Pas de sous-modules
  2. Le contrôleur utilise le mode pipelined du bus Avalon (voir chapitre 3.5.4 de la documentation), c’est à dire que l' agent demande à l' hôte d’attendre via le signal waitrequest
  3. Pendant l’initialisation (reset=1), le signal waitrequest doit être égal à 1 (voir norme Avalon). Après l’initialisation, l' agent devra être prêt à recevoir des requêtes( waitrequest=0 )
  4. Pour les opérations de lecture, la mémoire étant synchrone dans les FPGA, l' agent devra bloquer l' hôte pendant 1 cycle.
  5. Pour les opérations d' écriture, l' agent ne bloquera pas l’hôte: les requêtes peuvent s'enchaîner à chaque cycle.
  6. La taille de la mémoire sera calculée en se basant sur le paramètre RAM_ADD_W qui précise le nombre de bits nécessaires pour encoder l’addresse en mémoire. Attention, les adresses AVALON sont des adresses d'octets, alors que les adresses de la mémoire sont des adresses de mots.
  7. Le code devra être synthétisable.
  8. Le nom du fichier ne doit pas changer d’une version à l’autre. Vous devez exclusivement utiliser les tags pour différencier les deux versions.

Chronogramme attendu pour les transactions

Le chronogramme présente 3 transactions en lecture suivies de 3 transactions en écriture avec des attentes variables entre transactions.

Chronogrammes pour des transactions simples

  • On remarque que le contrôleur bloque systématiquement les transactions en lecture pendant un cycle (le temps nécessaire à la mémoire pour retourner la donnée).
  • On remarque que le contrôleur ne bloque pas les transactions en écriture.

Conseils

  1. Commencez par gérer la réponse au protocole Avalon (gestion des signaux waitrequest et readdatavalid) sans coder le comportement de la mémoire. Les résultats de simulation seront incorrects mais le respect du protocole sera testé.
  2. Le protocole impose de traiter les 4 octets d’un même mot séparément pour l’écriture. Cela engage, soit à déclarer 4 mémoires indépendantes, soit à définir la mémoire de façon "bidimensionnelle". Cette deuxième option a le mérite de simplifier l’écriture du code mais n’est pas supportée par tous les outils de synthèse: on ne la retiendra pas.
  3. L’agent n’a pas à vérifier le respect du protocole par l’hôte. PAS DE CODE INUTILE DE VERIFICATION
  4. Pas de processus synchrones compliqués qui se traduisent par des retards inutiles dans la réponse du contrôleur.
  5. 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 (dans quelle situation vaut-il 1 ou 0) et j’en déduis un processus synchrone ou combinatoire adapté.
  6. N’hésitez pas à multiplier les processus (synchrones ou non): le code est plus clair quand les traitements des différents signaux ne sont pas entrelacés.

Simulation

Remarque: Le banc de test proposé est unique pour l'ensemble des tests effectués:

  • Une série de tests en mode pipelined
  • Une série de tests en mode pipelined burst
  • Une série de tests pour évaluer la bonne configuration de la mémoire.

Il est normal qu'a ce stade, même si le mode pipeline simple est correctement codé, il y ait des erreurs dans la partie rafale du code, ainsi que dans le test de configuration de la mémoire qui utilise le mode rafale.

  • Dès que vous pensez avoir codé (même partiellement) votre contrôleur, lancez une compilation en utilisant la commande make compile. Corrigez les erreurs éventuelles.
  • Lancez la simulation par la commande make simu_batch. Vous obtenez des messages d'erreur, soit concernant le respect du protocole, soit concernant le transfert des paquets de données. Si les messages vous semblent compréhensibles, corrigez votre code.
  • Si les erreurs ne sont pas liées au protocole mais à la mémorisation des données, utilisez la commande make exam_packets pour avoir le détail des erreurs dans les paquets.
  • Si vous ne parvenez pas à comprendre les erreurs, vous pouvez lancer une simulation interactive par la commande make simu_gui:
    • Affichez tous les signaux de l'interface Avalon (instance avalon_if_0) et de votre contrôleur (instance dut_0)
    • Lancez la simulation
    • La ligne supérieure de la fenêtre de chronogrammes montre des petits drapeaux rouge ou vert correspondant aux différents messages d'erreur ou d'information. En passant la souris sur ces drapeau l'outil affiche le message correspondant.

Votre code sera correct du point de vue de cette étape si vous n'avez pas d'erreur dans la première série de tests. Vous devriez alors avoir le message:

#            0.00000ns:  verbosity_pkg.set_verbosity: Setting Verbosity level=3 (VERBOSITY_WARNING)
# 
#            390.000ns: INFO:  Starting FIRST sequence of packets read/write/verify
#          23230.000ns: INFO:  Finished FIRST packet read/write/read sequences
#          23230.000ns: INFO:  Total time for simple Pipelined packet transfer sequences:  22840
# 
#          23430.000ns: INFO:  Starting SECOND second sequence of packets read/write/verify
#       500000.00000ns: FAILURE: Simulation didn't finish before the expected time, probable stalled process waiting for something...
Si le temps total calculé pour ce premier test est très différent de la valeur proposée (22840), voici quelques pistes de réflexion:

  • Temps trop court: en lecture, votre agent ne bloque pas l' hôte pendant exactement un cycle.
  • Temps trop long(1): en lecture, votre agent bloque l' hôte pendant plus d'un cycle.
  • Temps trop long(2): en écriture votre agent bloque l' hôte alors qu'il doit être capable de recevoir une requête à chaque cycle.

Synthèse

Nous devons vérifier que votre code est synthétisable, ainsi que ses performances. Pour cela, exécutez la commande make syn

  • Si vous avez des messages d'erreur, il est probable que votre code ne soit pas synthétisable. Corrigez votre code, sans oublier de le simuler.

S'il n'y a pas d'erreurs de synthèse, cela ne signifie pas forcément que votre code soit de "qualité". Examinez les messages pour estimer la qualité de votre conception.

Estimation de la complexité:

Le nombre d'éléments utilisés dans le FPGA est indiqué. Si votre code est correct, vous devriez avoir un résultat de ce type:

## Synthesis stats
MISTRAL_MLAB             0
MISTRAL_M10K             8
MISTRAL_ALUT_ARITH       0
MISTRAL_ALUT             4
MISTRAL_FF               2
  • MISTRAL_MLAB: nombre de mémoires basées sur les LUT du FPGA.
    • Si ce n'est pas 0, il est probable que le code du comportement de la mémoire soit maladroit.
  • MISTRAL_M10K: nombre de mémoires de 10Kbits.
    • Suivant le style de codage de la mémoire, vous pouvez en avoir 8 (optimal) ou 16 (résultat non optimal du synthétiseur)
  • MISTRAL_ALUT_ARITH: nombre de LUT configurées pour des calculs arithmétiques.
    • Devrait être 0. Il n'est pas nécessaire de faire des calculs arithmétiques dans ce code.
  • MISTRAL_ALUT: LUT configurées pour des calculs combinatoires.
    • Quelques équations logiques, en tous cas moins de 10.
  • MISTRAL_FF: bascules D
    • Cela peut varier, d'un code à l'autre, pas plus de 5.

Estimation de la vitesse de fonctionnement

Après placement/routage, la vitesse maximale de fonctionnement est estimée.

  • Un résultat autour de 200Mhz est correct.
  • Un résultat autour de 100Mhz est suspect (trop de logique inutile ?)
  • Un résultat autour de 300Mhz est suspect (votre code contient il vraiment quelque chose ?)