wiki:SoclibCourseTp2

Version 3 (modified by alain, 16 years ago) (diff)

--

TP2: Protocole de communication VCI

1. Objectif

L'objectif de ce second TP est d'introduire la modélisation du protocole de communication VCI. Pour des raisons d'inter-opérabilité, tous les composants matériels de la plate-forme de prototypage SoCLib respectent le protocole de communication VCI, qui a été présenté en cours. On va donc modifier les deux composants matériels du TP1, pour qu'ils utilisent des ports de communication VCI plutôt que des ports FIFO. Ceci va permettre d'interconnecter plusieurs composants initiateurs et plusieurs composants cibles à travers un micro-réseau à commutation de paquets intégré sur puce.

2. Architecture matérielle

L'architecture matérielle pour de ce second TP instancie trois types de composants matériels. Les deux composants VciLcdCoprocessor et VciLcdMaster ont des fonctionnalités identiques à celles des composants utilisés dans le premier TP, mais ces composants possèdent maintenant des ports de communication qui respectent le protocole VCI/OCP. Le troisième composant VciGbs est un composant matériel modélisant un bus système respectant le protocole VCI/OCP, et permettant aux différents composants matériels de communiquer entre eux.

Le composant VciGsb se comporte comme un bus, car il ne traite qu'une seule transaction à la fois. Si plusieurs initiateurs ...

3. Protocole VCI/OCP

Le protocol de communication VCI permet de construire des architectures matérielle multi-processeurs à memoire partagée. Dans ce type de d'architecture, les différents composants matérielles utilisent des transactions pour communiquer entre eux. Une transaction est un couple (commande / réponse). Une transaction est initiée par composant initiateur est chargé de démarrer la transaction, et un composant cible est chargé de répondre à la commande qu'il a reçue.

  • paquet commande un paquet commande contient principalement une adresse

En principe, n'importe quel initiateur est capable de communiquer avec n'importe quelle cible. La cible est désignée par les bits de poids fort de l'adresse.

L'adreentre un intitiateur et utilsentUn système de ce type possède trois types de composants :

  • des composants initiateurs", capable de

d'adressage partagé implante un protocole de communication très simple supportant le contrôle de flux.

No image "soclib_tp2_fig1_archi.png" attached to SoclibCourseTp2

2.1 Canal de communication VCI

La figure ci-dessous détaille les signaux utilisés par le protocole VCI.

No image "soclib_tp2_fig2_fifo.png" attached to SoclibCourseTp2

La plupart des champs VCI on des largeurs paramètrables (en nombre de bits) :

  • le paramètre X définit le nombre de bits du champs ADDRESS. Les adresses VCI sont des adresses octets,

mails elles doivent être alignées sur des frontières de mot.

  • le paramètre B définit le nombre d'octets d'un mot de donnée VCI. Ce paramètre définit le largeur des trois

champs WDATA, RDATA et BE.

  • le paramètre K définit le nombres de bits termettant de coder la longueur PLEN d'un paquet (en nombre d'octets).

La valeur PLEN doit également être un multiple du paramètre B.

  • le paramètre S définit le nombre de bits du champs SRCID, qui permet de coder le numéro de l'initiateur

VCI qui a démarré la transaction. Ce paramètre définit donc le nombre maximum d'initiateurs dans le système.

  • Le paramètre E définit le nombre de bits permettant de coder le type d'erreur dans le champs RERROR

du paquet commande. La valeur 0 signifie "pas d'erreur".

  • Les deux paramètres T et P définissent le nombre de bits des deux champs TRDID et PKTID. Ces deux champs permettent d'étiqueter une commande VCI par une numéro de thread et/ou par un numéro de transaction. Ceci

permet à un même initiateur d'envoyer une commande n+1 sans attendre d'avoir reçu la réponse à la commande n.

Bien sûr les valeurs de ces paramètres VCI doivent être les mêmes pour tous les composants matériels d'une même architecture.

Cette généricité des interfaces de communication VCI est évidemment une souplesse très utile, mais elle crée une difficulté pour la modélisation des composants matériels, puisqu'ilfaut écrire des modèles de simulation génériques, capable de s'adapter à différentes largeurs d'adresse ou de donnée. On utilise pour cela la techique des templates du langage C++ : on regroupe toutes les valeurs de ces paramêtres dans un oblet C++ de type VciParams?, qui est utilisé comme paramètre template par tous les composants matériels qui possèdent des ports de communication VCI.

On définit également trois autres objets, qui facilitent l'écriture des modèles de simulation CABA :

  • l'objet VciSignals? regroupe tous les signaux (commande et réponse) d'un canal VCI.
  • l'objet VciInitiator? regroupe tous les ports utilisés par un initiateur VCI pour émettre une commande,

et recevoir la réponse.

  • l'objet VciTarget? regroupe tous les ports utilisés par une cible VCI pour émettre une réponsee,

et recevoir une commande. Ces trois objets utilisent évidemment un paramètre template de type VciParams?.

4. Segmentation de l'espace adressable

5. Travail à réaliser

L'archive attachement:soclib_tp1.tgz contient différents fichiers dont vous aurez besoin pour ce premier TP. Créez un répertoire de travail spécifique TP1 pour ce TP, recopier l'archive dans ce répertoire TP1, et décompressez-la:

$ tar xzvf soclib_tp1.tgz

Cette archive contient les fichiers suivants :

4.1 Composant VciLcdCoprocessor

Le composant VciLcdCoprocessor se comporte comme un périphérique adressable, et doit donc être modélisé comme une cible VCI. Il possède donc un seul port de type VciTarget, et 4 registres (ou pseudo-registres) implantés dans l'espace addressable, qui peuvent donc - en principe - être lus ou écrits par n'importe quel initiateur du sytème. Chacun de ces registres a une largeur de 4 octets. Par conséquent, le segment occupé par ce périphérique dans l'espace adressable a une taille de 4*4 = 16octets.

Pour simplifier le décodage des adresses, on impose la contrainte que l'adresse de base de ce segment est un multiple de sa longueur (on dit que le segment est aligné). La carte d'implantation des registres est définit comme suit :

Nom du registre Offset Mode
r_opa 0x0 Write Only
r_opb 0x4 Write Only
r_start 0x8 Write Only
r_res 0xc Read Only

Attention : Il n'existe pas réellement de registre r_start dans le composant matériel. Lorsque le composant VciLcdCoprocessor reçoit une commande d'écriture à l'adresse correspondant à l'adresse de r_start, la donnée WDATA correspondante n'est écrite nulle part, mais la commande est interprêtée par le coprocesseur comme un ordre de démarrage du calcul.

Une erreur est signalée si le coprocesseur reçoit une commande longueur supérieure à un mot, ou si l'adresse reçue n'appartient pas au segment qui a été défini pour le coprocesseur, ou si le mode d'accès (Read ou write) ne respecte pas les contraintes ci-dessus.

Question : à quoi servent ces vérifications ?

Les fichiers

4.2 Composant VciLcdMaster?

Le composant VciLcdMaster est un initiateur VCI, qui exécute une boucle infinie dans laquelle il exécute successivement les 6 actions suivantes:

  • calcul de deux valeurs aléatoires (entiers positifs codés sur 32 bits)
  • écriture

La figure ci-dessous décrit la structure de l'automate de contrôle du composant VciLcdMaster.

Le fichier vci_lcd_coprocessor.h contient une description complête du composant VciLcdMaster. Le fichier vci_lcd_coprocessor.cpp contient une description incompête des méthodes associées à ce composant. Complêtez le code des méthodes transition() et genMoore(), pour traiter les états de l'automate qui ne le sont pas. incomp

L'algorithme de calcul du PGCD implanté par cet automate cablé peut être décrit par le code C suivant :

uint32_t lcd( uint32_t opa, uint32_t opb)
{
    while (opa != opb )
        {
        if ( opa > opb ) opa = opa - opb;  
        if ( opa < opb ) opb = opb - opa 
        }
    return( opa );
}

Le chemin de donnée permettant de réaliser ce calcul doit donc comporter deux registres r_opa et r_opb pour stocker les valeurs opa et opb qui évoluent au cours du calcul, ainsi qu'un comparateur et un soustracteur sur 32 bits.

Par ailleurs l'automate cablé reçoit les deux valeurs des opérandes OPA et OPB sur son port FIFO d'entrée, et renvoie le résultat sur son port FIFO de sortie.

Finalement, l'automate qui contrôle le composant fifo_lcd_coprocesseur exécute un boucle infinie, dans laquelle il effectue successivement les 4 opérations suivantes:

  1. lecture de l'opérande A sur son port FIFO d'entrée
  2. lecture de l'opérande B sur son port FIFO d'entrée
  3. calcul effectif du PGCD
  4. écriture du résultat sur son port FIFO de sortie

Ces quatres opérations ont des durées d'exécution variables, puisque le nombre de cycles pour effectuer le calcul (étape 3) dépend de la valeur des opérandes, et que les opérations de communications (étapes 1, 2 ou 4) ont des durées qui dépendent de la disponibilité du composant fifo_lcd_master.

No image "soclib_tp1_fig3_coprocessor.png" attached to SoclibCourseTp2

Outre le registre d'état de l'automate r_fsm, cet automate contrôle donc deux autres registres r_opa et r_opb utilisés pour le calcul :

  • Dans l'état READ_OPA (resp. READ_OPB), on écrit dans le registre r_opa (resp r_opb) la valeur de l'opérande OPA (resp. OPB) lue sur le port FIFO d'entrée (champs p_in.data). On ne sort de cet état que si la donnée est valide (condition p_in.rok = true).
  • Dans l'état WRITE_RES, on écrit le contenu du registre r_opa sur le port FIFO de sortie p_out.data. On ne sort de cet état que si la donnée est acceptée (condition p_out.wok = true).
  • Dans l'état COMPARE, on effectue la comparaison entre les contenus des registres r_opa et r_opb. On n'écrit pas dans les registres r_opa et r_opb, mais les conditions de sortie dépendent du résultat de la comparaison.
  • Dans l'état DECR_A (resp. DECR_B), on écrit le dans le registre r_opa (resp. r_opb). On ne reste qu'un cycle dans ces états, puisque la décrémentation ne dépend d'aucune condition extérieure.

2.3 Composant fifo_lcd_master

Ce composant matériel effectue le travail normalement effectué par un processeur programmable, consistant à générer les valeurs des deux opérandes, à transmettre ces valeurs d'entrée au coprocesseur, à récupérer le résultat calculé par le coprocesseur, et à afficher ce résultat sur un terminal. L'utilisation de processeurs programmables suppose qu'on est capable de déployer le code binaire exécutable par le processeur programmable sur l'architecture matérielle simulée. Ce problème sera traité dans la suite de ce cours, mais dans ce premier TP, on se contente d'utiliser un processeur cablé, qui exécute en boucle le programme suivant:

  1. génération (pseudo-aléatoire) de deux valeurs OPA et OPB.
  2. écriture de l'opérande OPA sur son port FIFO de sortie.
  3. écriture de l'opérande OPB sur son port FIFO de sortie
  4. lecture du du résultat sur son port FIFO d'entrée.
  5. affichage des valers sur le terminal.

Pour modéliser la génération aléatoire, on utilise la fonction rand() fournie par la libc de la station de travail qui exécute la simulation. On génère évidemment des valeurs aléatoires différentes à chaque itération de la boucle, mais pour faciliter le deboguage, on garantit un fonctionnement reproductible, en contrôlant la valeur initiale du générateur aléatoire grace à la fonction srand() utilisée dans le constructeur du modèle.

Le composant fifo_lcd_master est donc un composant matériel paramètrable (un paramètre permettant de contrôler la séquence de valeurs aléatoires), modélisé comme un automate à 5 états :

No image "soclib_tp1_fig4_master.png" attached to SoclibCourseTp2

Outre le registre d'état de l'automate r_fsm, cet automate contrôle 5 autres registres : les registres r_opa, r_opb, et r_res permettent de stocker respectivement les deux opérandes et le résultat du calcul. Le registre r_cyclecount est incrémenté à chaque cycle, et contient donc la date (en nombre de cycles) depuis l'initialisation du système. Le registre r_iterationcount est incrémenté à chaque itération, et contient donc le numéro de l'itération courante.

  • dans l'état RANDOM on écrit les valeurs pseudo-aléatoires OPA et OPB dans les registres r_opa et r_opb. On ne reste qu'un cycle dans cet état.
  • dans l'état WRITE_OPA (resp. WRITE_OPB) on écrit le contenu du registre r_opa (resp r_opb) sur le port FIFO de sortie (champs p_out.data). On ne sort de ces états que si la donnée est acceptée (condition p_out.wok = true).
  • dans l'état READ_RES, on écrit dans le registre r_res la valeur lue sur le port FIFO d'entrée (champs p_in.data). On ne sort de cet état que si la donnée lue est valide (condition p_in.rok = true).
  • Dans l'état DISPLAY, on ne modifie pas le contenu des registres r_opa, r_opb, et r_res, mais on affiche la date

courante ainsi que les valeurs des opérandes et du résultat sur le terminal standard de la station de travail qui exécute la simulation. On ne reste qu'un cycle dans cet état.

3. Travail à réaliser

L'archive attachement:soclib_tp1.tgz contient différents fichiers dont vous aurez besoin pour ce premier TP. Créez un répertoire de travail spécifique TP1 pour ce TP, recopier l'archive dans ce répertoire TP1, et décompressez-la:

$ tar xzvf soclib_tp1.tgz

Cette archive contient les fichiers suivants :

  • fifo_signals.h : fichier définissant l'objet C++ FifoSignal représentant les signaux d'un canal FIFO. Ce fichier est complet et ne doit pas être modifié.
  • fifo_ports.h : fichier définissant les objets C++ FifoInput et FifoOutput représentant les ports d'accès à un canal FIFO. Ce fichier est complet et ne doit pas être modifié.
  • fifo_lcd_master.h : fichier définissant l'objet C++ FifoLcdMaster représentant le modèle du master. Ce fichier est complet et ne doit pas être modifié.
  • fifo_lcd_master.cpp : fichier contenant l'implémentation C++ des méthodes utilisées par le composant master. Ce fichier est complet et ne doit pas être modifié.
  • fifo_lcd_coprocessor.h : fichier définissant l'objet C++ FifoLcdCoprocessor représentant le modèle du coprocesseur. Ce fichier ne contient qu'une carcasse vide et devra être complété.
  • fifo_lcd_master.cpp : fichier contenant l'implémentation C++ des méthodes utilisées par le composant master. Ce fichier ne contient qu'une carcasse vide et devra être complété.
  • tp1_top.cpp : fichier C++ décrivant l'architecture matérielle du système, dont la compilation générera le simulateur proprement dit. Ce fichier est partiellement incomplet, et devra être complété.

3.1 Ecriture du modèle CABA du coprocesseur

Pour une présentation détaillée des règles d'écriture des modèles de simulation au niveau CABA, vous pouvez consulter la documention disponible en ligne sur le site sur le site WEB du projet SoCLib : https://www.soclib.fr/trac/dev/wiki/WritingRules/Caba.

Le modèle de simulation d'un composant matériel (appelé module en SystemC) nécessite la définition d'une classe C++ dont le nom correspond au nom du module matériel modélisé. En vous inspirant du code fourni pour le composant master, complêter les deux fichiers fifo_lcd_coprocessor.h et fifo_lcd_coprocessor.cpp.

Comme pour tout modèle CABA SoCLib, les variables membres de la classe FifoLcdCoprocessor sont de trois types :

  • ports : les variables membres représentant les ports d'entrée sortie sont de type sc_core::sc_in ou sc_core::sc_out, ou des objets plus complexe (possédant éventuellement un paramètre template) représentant des regroupements de plusieurs ports élémentaires : c'est la cas des types soclib::caba::FifoOutput<typename> et soclib::caba::FifoInput<typename> utilisés pour accéder à un cana FIFO. Pour des raisons de lisibilité, il est recommandé que les noms de registre soient préfixé par p_. On définira 2 ports simples (p_ck, p_resetn), et deux ports FIFO (p_in et p_out). Ce sont évidemment des variables publiques.
  • registres : les variables membres représentant les registres sont de type sc_core::sc_signal. Pour des raisons de lisibilité, il est recommandé que les noms de registre soient préfixé par r_. On définira trois registres r_fsm, r_opa et r_opb. Ce sont des variables privées.
    • constantes : ces variables membres sont en fait des constantes permettant de stocker les valeurs des paramètres définis comme arguments du constructeur pour les composants matériels génériques. Ces variables membres sont initialisées dans le constructeur, et leur valeur reste constante au cours de la simulation. Pour des raisons de lisibilité, il est recommandé que les noms de constantes soient préfixé par m_. Ces variables sont toujours privées. Le coprocesseur n'étant pas paramètrable, on ne définira aucune variable de ce type.

Le constructeur du coprocesseur LCD ne possède qu'un seul argument, qui est le nom d'instance (on a besoin d'un nom d'instance, car il est possible d'avoir plusieurs instances du même coprocesseur dans une architecture). Ce nom d'instance est de type sc_core::sc_module_name, et il est stoké dans une variable membre de la classe sc_module, qui est une classe générique dont héritent tous les modèles de composant SoCLib.

Enfin, comme tous les modèles CABA de SoCLib, le coprocesseur LCD possède des fonctions membres définissant le comportement du composant, qui sont de trois types :

  • la fonction transition() est sensible au front montant du port d'etrée CK, et permet de calculer la valeur future des

registres en fonction de la valeur courante des registres et des valeurs présentes sur les autres ports d'entrée.

  • la fonction genMoore() est sensible au front descendant du port d'entrée CK, et permet de calculer la valeur des ports de sortie qui ne dépendent que des valeurs stockées dans les registres.
  • les fonctions genMealy() (une ou plusieurs fonction). Chacune de ces fonction est sensible au front descendant du port CK, et à un ensemble particulier de port d'entrée. Elle permettent de calculer la valeur des ports de sorties qui dépendent de façon combinatoire des ports d'entrée.

Les noms de fonction ne sont pas imposés, mais il est recommandé de respecter les noms proposés ci-dessus. Le coprocesseur LCD se comportant globalement comme un automate de Moore, on n'a pas besoin de définir de fonctions de type genMealy().

Les architectures matérielles modélisées avec SoCLib peuvent comporter plusieurs dizaines de modèles différents. Pour réduire les temps de compilation la plate-forme de modélisation SoCLib exploite le principe de la compilation séparée: Chaque modèle de composant matériel est compilé séparément.

A titre d'exemple, compilez le modèle du composant FifoLcdMaster, en utilisant le compilateur g++. Il faut lancer la commande suivante dans votre répertoire de travail TP1 :

$ g++ -Wno-deprecated -I. -I/users/outils/dsx/cctools/include -c -o fifo_lcd_master.o fifo_lcd_master.cpp

Cette commande doit créer fichier objet fifo_lcd_master.o dans le répertoire TP1.

Vous pouvez utiliser la même commande (en changeant les noms des fichiers) pour compiler... et déboguer le modèle du composant FifoLcdCoprocessor.

3.2 Ecriture du modèle CABA de la top-cell

On appelle généralement top-cell la description structurelle decrivant l'interconnexion des différents composants matériels constituant l'architecture matérielle qu'on souhaite simuler. Editez le fichier tp1_top.cpp, qui décrit l'architecture, ainsi que les directives de simulation. Ce fichier est volontairement incomplet pour vous obliger à analyser en détail les différentes sections :

  • arguments : On définit dans cette section les arguments qui pourront être passés en lgne de commande lors du lancement de la simulation. On prévoit ici de passer en premier argument le nombre de cycles à simuler, et comme deuxième argument la valeur d'initialisation du générateur aléatoire utilisé dans le composant master. cette section n'a pas besoin d'être modifiée.
  • Signals : On définit dans cette section les différents signaux qui seront utilisés pour connecter entre eux les ports d'entrée sortie des différents composants. On a besoin de 4 signaux : les deux signaux signal_ck et signal_resetn

devront être connectés aux ports correspondants des deux composants matériels. Les deux signaux signal_fifo_m2c et signal_fifo_c2m sont des signaux composites représentant les deux canaux de communication entre les deux composants. On utilise un type générique, en ce sens que le type de la donnée transférée à chaque cycle doit être défini par un paramètre template : dans le cas présent, on transfère un entier 32 bits uint32-t. Le signal signal_clk est également un objet complexe de type sc_core::sc_clock, dont on peut définir la période (sc_time(1,SC_NS) signifie 1 ns), ainsi que le rapport cyclique. Vous devez ajouter le signal manquant dans cette section.

  • Components : Dans cette section on appelle les constructeurs des différents composants instanciés, en définissant les paramètres. Le nom d'instance est un paramètre obligatoire. Le composant master possède un second paramètre qui est la valeur d'initialisation du générateur aléatoire. Vous devez aouter l'appel au constructeur du composant coprocesseur.
  • Net-List : On décrit dans cette section les connexions entre les composants. La syntaxe utilisée pour connecter un signal s au port p d'un composant c est : c.p(s). Vous devez ajouter les connexions concernant les ports du coprocesseur.
  • Simulation : Cette section décrit les directives de simulation. Le mécanisme de RESET étant synchrone, On commence par exécuter un cycle en forçant signal_resetn à l'état bas (actif), pour initialiser les registres internes de tous les composants, puis on exécute le nombre de cycles spécifié en forçant signal_resetn à l'état haut (inactif).

Vous pouvez compiler ce fichier tp1_top.cpp pour générer le fichier objet correspondant en utilisant la commande:

$ g++ -Wno-deprecated -I. -I/users/outils/dsx/cctools/include -c -o  tp1_top.o  tp1_top.cpp

Cette commande doit créer fichier objet tp1_top.o dans le répertoire TP1.

2.3 génération et lancement du simulateur

Vous pouvez maintenant créer le programme exécutable simulator.x en effectuant l'édition de liens entre les trois fichiers objet précédemment créés :

$ g++ -Wno-deprecated -L. -L/users/outils/dsx/cctools/lib-linux -o simulator.x fifo_lcd_master.o fifo_lcd_coprocessor.o tp1_top.o -lsystemc 2>&1 | c++filt

Cette commande doit créer fichier objet simulator.x dans le répertoire TP1.

On lance l'exécution du simulateur pour 10000 cycles avec la commande :

$ ./simulator.x 10000

Quelle est la duréee moyenne d'une itération?

Regroupez toutes les commandes de compilation dans un fichier Makefile, en explicitant les dépendances entre les fichiers.

2.4 Simulation avec SystemCASS

Comme cela a été expliqué en cours, le style d'écriture des modèles de simulation CABA utilisé dans SoCLib permet une simulation rapide - même en utilisant le moteur de simulation SystemC2.0 fourni par le consortium OSCI - puisque dans le cas où tous les composants matériels se comportent comme des automates de Moore, les deux fonctions transition et genMoore de chaque composant ne sont exécutées qu'une seule fois par cycle.

Le moteur de simulation SystemC2.0 utilise une technique d'ordonnancement dynamique (avec gestion d'un échéancier), qui a le mérite d'être très générale, et de s'adapter à à peuprès n'importe quel style d'écriture des modèles SystemC. Mais il est possible de gagner un facteur 10 sur la vitesse de simulation en utilisant le moteur de simulation SystemCASS (développé par le laboratoire LIP6), qui utilise une technique d'ordonnancement statique (sans échéancier) pour exploiter les caractéristiques particulières des modèles SoCLib.

Pour utiliser SystemCASS, il n'est pas nécessaire de modifier le code SystemC des composants instanciés, ni le code SystemC décrivant la top_cell, mais il faut recompiler l'ensemble des fichiers sources, en modifiant les chemins d'accès aux fichiers d'include et aux bibliothèques de SystemC.

La génération des fichiers objets utilise la commande suivante :

$ g++ -Wno-deprecated -I. -I/users/outils/dsx/systemcass/include -c -o filename.o filename.cpp

La génération de l'exécutable utilise la commande suivante :

$ g++ -Wno-deprecated -L. -L/users/outils/dsx/systemcass/lib -o  fast_simulator.x fifo_lcd_master.o fifo_lcd_coprocessor.o tp1_top.o -lsystemc 2>&1 | c++filt

Modifiez le fichier Makefile de la question précédente pour générer un exécutable fast_simulator.x et comparez les vitesses des deux simulateurs.

4. Compte-rendu

Il ne vous est pas demandé de compte-rendu pour ce TP, mais on vous demandera une démonstration de votre simulateur au début du TP de la semaine suivante...

Attachments (8)

Download all attachments as: .zip