Analyse du HelloWorld

Description de la partie matérielle:

SoC de base

La partie matérielle du système est décrite dans le fichier C++ top.cpp

Le SoC contient deux types de modules:

  • Un interconnect et le LM32 utilisant l'interface WishBone
  • Des modules utilisant l'interface VCI de la bibliothèque SocLib

L'interface VCI:

L'interface utilisée par la majorité des modules de SocLib est une interface VCI. Elle fonctionne sur le principe de requêtes/réponses dissociées:

  • Un initiateur fait une requête (de lecture ou d'écriture) en fournissant l'adresse de la cible (et éventuellement des données en écriture).
  • La requête est maintenue tant qu'elle n'est pas acceptée par la cible.
  • Après que la cible ait accepte la requête, elle répond en indiquant l'identifiant de l'initiateur à l'origine de la requête.
  • La réponse est maintenue tant qu'elle n'est pas acceptée par l'initiateur.

Dans les modèle SystemC de la bibliothèque SocLib, cette interface est paramétrable. Pour le HelloWorld, nous avons une interface 32 bits données/adresse avec jusqu'à 256 initiateurs sans modes spéciaux d'adressage.

La structure structure VciParams, regroupe ce paramètres et sert de "template" aux modules utilisant l'interface VCI.

typedef soclib::caba::VciParams<4,8,32,1,1,1,8,1,1,1> vci_param;

Avec dans l'ordre:

  • cell_size : taille de la cellule 4(octets) => interface 32 bits
  • plen_size : la taille des paquets (transferts multiples/bursts) est codée sur 8 bits
  • addr_size : la taille du bus d'adresse est de 32 bits
  • rerror_size: les messages d'erreurs codés sur sur 1 bit (erreur ou ok)
  • clen_size : nombre de paquets dans une chaine codé sur 1 bit
  • rflag_size : les indicateurs d'erreur sont codés sur 1 bit
  • srcid_size : l'identifiant des sources est codé sur 8bits (jusqu'à 256 initiateurs)
  • pktid_size : l'identifiant des paquets est sur 1bit
  • trdid_size : l'identifiant des threads est sur 1bit
  • wrplen_size: le dernier paramètre correspond à l'adressage circulaire des bursts

La structure vci_param est en suite utilisée pour paramétrer toute les modules et interfaces VCI.

Par exemple, la définition du signal VCI servant à connecter la mémoire ROM:

soclib::caba::VciSignals<vci_param> signal_vci_rom("signal_vci_vcirom");

L'interface WishBone:

C'est l'interface que vous utiliserez pour vos périphériques. Son fonctionnement est plus simple que celui du VCI les requêtes sont bloquantes jusqu'à l'acquittement.

L'interface WishBone peut aussi être paramétrée en définissant la largeur du bus de données et du bus d'adresses. Pour le helloworld, les données et les adresses font 32 bits.

typedef soclib::caba::WbParams<32,32> wb_param;
  • wb_data_width : largeur du bus de données
  • wb_addr_width : largeur du bus d'adresses

Comme pour les paramètres VCI , les paramètres WishBone sont ensuite utilisés pour tous les signaux et toutes les interfaces WishBone.

Par exemple, le signal servant à connecter le processeur au bus:

 soclib::caba::WbSignal<wb_param> signal_wb_lm32("signal_wb_lm32");

La table de d'adressage:

La table de d'adressage permet de décrire les plages de l'espace mémoire réservée à chaque élément du système. C'est un module pour la "simulation" qui permet de vérifier qu'il n'y a pas d'incohérence dans les adresses des différents modules. Il permet aussi de centraliser ces informations.

La table prend 4 arguments à la construction:

  • La taille du bus d'adresse ( nombre de bits)
  • Le nombre de bits utilisés pour router les requêtes VCI
  • Le nombre de bits utilisés pour router les réponses VCI
  • Le masque des adresses cachables.
soclib::common::MappingTable maptab(32, IntTab(8), IntTab(8), 0x80000000);

Dans Cet exemple nous utilisons 32 bits pour les adresses dont les 8 bits de poids fort permettent d'identifier les cibles/esclaves. Si le bit 31 de l'adresse est non nul alors les requêtes vers cette plage mémoire ne passent pas par le cache du processeur.

On à cette table des segments correspondants aux cibles/esclave. On précise un nom, une adresse de base, une taille, un index et un indicateur de "cachabilité" (cet index doit être cohérent avec le masque donné à la définition de la table)

maptab.add(Segment("rom" , ROM_BASE , ROM_SIZE , IntTab(0), true));

Dans cet exemple, on définit un segment correspondant à la mémoire ROM. Le nom de ce segment est "rom", sont adresse de base est ROM_BASE et sa taille est ROM_SIZE. Il sera identifié comme la cible "0" et les requêtes vers cette ROM passeront par le cache du processeur.

Toutes les requêtes à faite une adresse appartenant à l'intervalle [ROM_BASE, ROM_BASE+ROM_SIZE] seront transmise au contrôleur de ROM.

Les constantes utilisée sont toutes définies dans le fichiersegmentation.h.

La cohérence de cette table est vérifiée avant le début de la simulation.

Le processeur:

Nous disposons d'un ISS (Instruction Set Simulator) qui permet de simuler l'exécution d'un flot d'instruction sur un lm32.

Cet ISS est n'est pas un module C++, il n'est donc pas instancié directement dans la plateforme. La bibliothèque SocLib propose des modules génériques (des wrappers d'iss) avec des configurations de cache et des interfaces différentes qui permettent d'encapsuler les ISS. Ces Wrappers permettent de simuler indifféremment un mips, un sparc ou un lm32... Le code responsable de la gestion du cache, et des entrées/sorties des processeurs est ainsi mutualisé.

Wrapper d'ISS

Ici, comme nous allons travailler avec l'interface WishBone et que notre CPU a une cache, nous utilisons le WbXcacheWrapper.

soclib::caba::WbXcacheWrapper
      <wb_param, soclib::common::Iss2Simhelper<soclib::common::LM32Iss<false> > >
      lm32("lm32", 0, maptab,IntTab(0), 2,128,8, 2,128,8);

Dans cet exemple on construit un modèle de LM32 avec les paramètres suivants:

  • Le nom de l'instance, ici lm32
  • l'indice du processeur dans un le cas d'un système multiprocesseurs, ici 0
  • la table de mapping principalement pour définir les zones "cachées"
  • l'indice de l'initiateur correspondant (n'est pas utilisé dans la version WishBone)
  • la configuration des caches instructions et données (ici 2 ways, 128 sets et 8 mots de 32bits par set)
  • L'argument de template du LM32Iss "false" indique que le lm32 est big endian contrairement à la convention SocLib.

Interconnexion:

Nous utiliseront le WbInterc (WishBone interconnect). Ce module simule le comportement d'une interconnexion à bus multiplexé avec arbitrage à priorité tournante (round robin) .

soclib::caba::WbInterco<wb_param> wbinterco("wbinterco",maptab, 1, 3);

Les paramètres du constructeur sont:

  • Le nom de l'instance, ici "wbinterco"
  • La table de mapping
  • Le nombre de maîtres, ici 1 (le lm32)
  • Le nombre d'esclaves, ici 3 (la rom, la ram et l'uart)

Connecter les différents éléments:

Le WbInterco possède, en plus d'un port d'horloge (p_clk) et d'un port de remisee à zéro (p_resetn), un port pour relier les maîtres (p_from_master) et les esclaves (p_to_slave). Ces deux derniers ports sont des vecteurs où l'indice de chaque connexion doit correspondre à l'indice du périphérique dans la table d'adressage. Ces ports sont reliés à des signaux WishBone qui sont reliés aux ports des éléments respectifs.

wbinterco.p_clk(signal_clk);
wbinterco.p_resetn(signal_resetn);
wbinterco.p_from_master[0](signal_wb_lm32);
wbinterco.p_to_slave[0](signal_wb_rom);
wbinterco.p_to_slave[1](signal_wb_ram);

Ici, nous avons le signal venant du lm32 relié au port maître 0, la rom au port esclave 0 et la ram au port esclave 1.

Connecter les modules VCI à l'interconnect WishBone:

Les éléments VCI ne peuvent pas être connectés directement au bus WishBone. Nous devons utiliser un adaptateur (wrapper) qui converti les requêtes venant des maîtres WishBone en transaction VCI.

Ce wrapper se comporte comme esclave WishBone et maître VCI. Il possède un port d'horloge (p_clk), un port de reset (p_resetn), un port WishBone esclave pour se connecter à l'interconnect et un port VCI maître pour se connecter au module VCI.

soclib::caba::WbSlaveVciInitiatorWrapper<vci_param, wb_param> tty_w ("tty_w") ;
tty_w.p_clk            (signal_clk);
tty_w.p_resetn         (signal_resetn);
tty_w.p_vci            (signal_vci_tty);  // Vers le module tty
tty_w.p_wb             (signal_wb_tty);   // Vers WbInterco

Le wrapper a comme arguments de template les paramètres WishBone et VCI et comme argument de constructeur le nom du module SystemC.

Commencer la simulation:

La simulation est initiée en utilisant la fonction sc_start().

  • Si cette fonction est appelés avec un argument, cet argument représente la durée en temps du simulateur de l'exécution.
  • Si elle est appelée sans argument, la simulation est lancée jusqu'à l'exécution de la fonction sc_stop().
sc_start(SC_ZERO_TIME);               // démarre la simulation mais ne fait pas avancer le temps
signal_resetn = false;                // Remise à zéro du système
sc_start(sc_core::sc_time(1, SC_NS)); // avance la simulation de "1ns"
signal_resetn = true;                 // Fin de la remise à zéro du système
sc_start();                           // lance la simulation
                                      // La simulation s'arrêtera à l'appel de sc_stop()