Version 46 (modified by 15 years ago) (diff) | ,
---|
TP4 : Outil soclib-cc & communications par interruption
1 Objectif
Le but de ce quatrième TP est principalement d'introduire la chaîne de compilation soclib-cc, qui permet d'automatiser la génération du (des) simulateurs. On en profitera pour introduire dans l'architecture de nouveaux composants matériels supportant la communication par interruption entre le(s) processeurs(s) et les périphériques.
2 Outil soclib-cc
L'architecture matérielle qui a été modélisée dans le TP3 était très simple (un seul processeur et 4 cibles), mais il a fallu compiler une cinquantaine de fichiers source (.cpp) et un nombre encore plus grans de fichiers d'en-tête (.h) pour générer le simulateur.
Tous ces fichiers proviennent du serveur WEB SoCLib, qui contient lui-même un serveur SVN permettant d'archiver les différents modèles de simulation. Ce serveur SVN fournit un service de gestion de versions et supporte le développement coopératif de la plate-forme.
Mais l'exploitation de cette bibliothèque de modèles de simulation pose (au moins) deux problèmes :
- Il faut identifier et localiser tous les fichiers nécessaires pour générer le simulateur d'une architecture particulière. L' archive qui vous a été fournie pour le TP3 rassemblait dans un seul répertoire la centaine de fichiers nécessaires, et le Makefile vous était fourni. Mais dans le cas général, l'identification des fichiers nécessaires à la compilation est un travail non négligeable, à cause des dépendances entre composants logiciels (le fichier A fait référence à des objets définis dans le fichier B, qui lui-même fait appel au fichier C, etc.). De ce fait, la construction du Makefile est généralement un exercice laborieux.
- Par ailleurs, la plupart des modèles ont des paramètres templates (puisque la plupart des composants ont des interfaces VCI, et que les largeurs des champs VCI sont paramétrables). Pour chaque composant possédant un (ou plusieurs) paramètre(s) template, il faut donc modifier le fichier .cpp pour préciser la valeur des paramètres template avant de lancer la compilation de ce composant (on dit qu'on instancie les template). Vous avez fait ce travail dans le TP2, et c'est un travail très fastidieux dès que les architectures modélisées deviennent complexes.
La chaîne de compilation soclib-cc a pour but de résoudre ces deux problèmes dans le cas général,
en automatisant la recherche des dépendances, l'instanciation des templates, et l'appel du compilateur.
Pour permettre cette automatisation, tout composant logiciel de SoCLib doit être accompagné d'un fichier
de metadata (fichier possédant le suffixe .sd
) qui contient les informations suivantes:
- le nom de la classe C++
- les paramètres templates associés, avec leurs types et les valeurs par défaut (si applicable)
- les chemins d'accès aux fichiers d'en-tête (.h) et d'implémentation (.cpp)
- la liste des ports d'interface du composant
- la liste des dépendances vers d'autres composants
- les paramètres du constructeur, avec leurs types
Ce fichier est écrit en un langage ad-hoc (mais que Python peut parser nativement), et on trouvera ci-dessous, à titre d'exemple, le fichier vci_simple_ram.sd:
Module('caba:vci_simple_ram', classname = 'soclib::caba::VciSimpleRam', tmpl_parameters = [parameter.Module('vci_param', default = 'caba:vci_param')], header_files = ['../source/include/vci_simple_ram.h',], implementation_files = ['../source/src/vci_simple_ram.cpp'], ports = [ Port('caba:vci_target', 'p_vci'), Port('caba:bit_in', 'p_resetn', auto = 'resetn') Port('caba:clock_in', 'p_clk', auto = 'clock')], uses = [ Uses('caba:base_module'), Uses('common:linked_access_buffer', addr_t = parameter.StringExt('sc_dt::sc_uint<%d>', parameter.Reference('addr_size')), id_t = parameter.StringExt('sc_dt::sc_uint<%d>', parameter.Reference('srcid_size'))), Uses('common:loader'), Uses('common:mapping_table',], instance_parameters = [ parameter.IntTab('ident'), parameter.Module('mt', 'common:mapping_table', auto='env:mapping_table'), parameter.Module('loader', 'common:loader', auto='env:loader'), parameter.Int('latency')], extensions = [ 'dsx:addressable=ident', 'dsx:get_ident=ident:p_vci', 'dsx:mapping_type=memory'], )
Il faut par ailleurs définir les caractéristiques de la top-cell dans un fichier de directives pour soclib-cc. Ce fichier est habituellement nommé platform.desc, mais le nom n'est pas imposé. Ce fichier est également en langage parsable par Python, et contient : le nom de fichier de la top-cell SystemC, la liste des modèles des composants instanciés et les valeurs des paramètres template VCI. Vous trouverez ci-dessous, à titre d'exemple, le fichier tp3.desc décrivant l'architecture du TP3:
todo = Platform('caba', 'tp3_top.cpp', uses = [ Uses('caba:vci_xcache_wrapper', iss_t = 'common:mips32el'), Uses('caba:vci_simple_ram'), Uses('caba:vci_multi_tty'), Uses('caba:vci_vgsb'), Uses('caba:vci_gcd_coprocessor'), Uses('common:mapping_table'), Uses('common:elf_file_loader')], cell_size = 4, plen_size = 8, addr_size = 32, rerror_size = 1, clen_size = 1, rflag_size = 1, srcid_size = 12, pktid_size = 1, trdid_size = 1, wrplen_size = 1 )
3 Communications par interruption =
La plate-forme matérielle du TP3 utilisait une technique de scrutation (polling) pour lire des caractères en provenance du terminal TTY. Cette technique n'est pas très efficace, et on souhaite remplacer ce mécanisme de scrutation par un mécanisme d'interruption, en utilisantla capacité du contrôleur TTY à générer une interruption lorsque qu'un caractère est frappé sur le clavier. Ceci nécessite d'introduire un nouveau composant matériel dans l'architecture : Le composant vci_icu est contrôleur d'interruptions vectorisé. C'est une cible VCI dont vous trouverez la spécification fonctionnelle ici.
On en profite pour introduire un autre périphérique : Le composant vci_multi_timer est également une cible VCI contenant un nombre queconque de timers programmables capables de générer des interruptions périodiques à destination du processeur. Vous trouverez la spécification fonctionnelle de ce composant ici.
On obtient ainsi une architecture possédant un initiateur VCI et 6 cibles VCI, conformément au schéma ci-dessous. La line d'interruption en provenance du composant TIMER sera connectée au port p_irq_in[0] du composant ICU et la ligne d'interruption en provenance du contrôleur TTY sera connectée au port p_irq_in[1] du composant ICU.
On associe à chaque ligne d'interruption une routine de traitement spécifique, appelée ISR (Interrupt Service Routine), qui est exécutée par le processeur lorsque la ligne d'interruption est activée par le périphérique, et que les interruptions ne sont pas masquées. Il s'agit donc pour le périphérique de "voler" quelques cycles du processeur pour lui permettre d'exécuter un peu de code. L'ISR permet généralement au périphérique de signaler un événement en allant écrire à certains emplacements prédéfinis en mémoire.
Pour communiquer avec un périphérique, un programme utilisateur peut donc utiliser un tampon mémoire partagé DATA, protégé par une variable de synchronisation SYNC. Supposons qu'un programme utilisateur souhaite lire un caractère sur un terminal TTY. Plutôt que d'effectuer un appel système bloquant (qui effectue une scrutation directement sur le registre STATUS du TTY), le programme utilisateur va appeler une fonction de communication qui s'exécute en mode user, et qui effectue une scrutation sur la variable SYNC. Le tampon est partagé entre le périphérique TTY et le programme utilisateur :
- Le périphérique TTY écrit dans le tampon DATA et active la variable SYNC (en déclenchant l'exécution de la routine d'interruption).
- Le programme utilisateur lit dans le tampon DATA et désactive la variable SYNC.
Il existe évidemment un mécanisme symétrique pour l'écriture d'un caractère vers le contrôleur TTY.
Question: Que fait la routine d'interruption déclenchée par le périphérique TTY lors de la frappe d'un caractère lorsque la variable SYNC est déjà activée ? (ceci signifie que le précédent caractère écrit dans le tampon DATA n'a pas été lu par le programme utilisateur). La réponse se trouve dans le fichier isr.c. Expliquez ce comportement.
Question: Quel est l'avantage de ce type de communication par interruption, comparé au mécanisme de scrutation utilisé dans le TP3 ?
4 Travail à réaliser
L'archive soclib_tp4.tgz contient différents fichiers dont vous aurez besoin pour ce TP. Elle contient également un sous-répertoire soft qui est utilisé pour la génération du logiciel embarqué. Attention: ce répertoire soft de l'archive du TP4 contient des fichiers différents de ceux qui étaient fournis pour le TP3.
Créez un répertoire de travail spécifique TP4, recopiez l'archive dans ce répertoire TP4, et décompressez-la:
$ tar xzvf soclib_tp4.tgz
4.1 Utilisation de soclib-cc
On va commencer par regénérer le simulateur utilisé dans le TP3, en utilisant soclib-cc.
Comme vous pouvez le constater, le répertoire principal de l'archive ne contient plus que deux fichiers : le fichier tp3_top.cpp décrivant l'architecture, et le fichier tp3.desc, puisqu'on utilise directement les modèles de composants enregistrés dans l'arbre SVN SoCLib.
Il faut vérifier que le chemin d'accès à à soclib-cc est bien dans votre PATH en exécutant:
$ source /users/outil/soc/env_soclib.sh
Puis lancer la compilation avec la commande :
$ soclib-cc -p tp3.desc -o tp3.simulator.x
Vérifiez que le simulateur tp3_simulator.x qui vient d'être généré exécute toujours correctement l'application logicielle du TP3. Vous pouvez pour cela donner explicitement le cheminom (pathname) du fichier contenant le code binaire comme argument sur la ligne de commande :
$ ./tp3_simulator.x ../TP3/soft/bin.soft
4.2 Communication par interruptions
Modifiez le fichier tp3_top.cpp pour instancier et connecter les deux nouveaux composants ICU et TIMER. On instanciera un seul terminal TTY et un seul TIMER. Renommez tp4_top.cpp le fichier ainsi modifié. Complètez également le fichier tp3_desc et renommez le tp4_desc
Utilisez soclib-cc pour générer le simulateur tp4_simulator.x.
Le logiciel doit également être modifié pour supporter la communication par interruption entre un programme utilisateur et un périphérique:
- le fichier isr.s contient le codes des routines d'interruption associées aux différentes requêtes d'interruption générées par les périphériques. Il y a une routine par ligne d'interruption. Ce code est écrit en assembleur, et s'exécute en mode kernel.
- Le fichier userio.c contient les fonctions C permettant à un programme utilisateur de communiquer par interruption (en lecture ou en écriture) avec les périphériques. Pour l'instant seul les fonctions d'accès au TTY sont disponibles.
- Le code de boot défini dans le fichier reset.s doit maintenant initialiser le vecteur d'interruption
(c'est à dire le tableau indexé par le numéro d'interruption, et contenant les adresses des différentes ISR).
Modifiez le fichier reset.s pour initialiser les routines d'interruption correspondant au à la ligne IRQ[0] du composant vci_timer, et à la ligne IRQ[0] du contrôleur TTY (lecture d'un caractère).
Modifiez le fichier main.c du TP3 (fourni dans l'annexe) pour qu'il utilise la fonction utilisateur user_getc() au lieu de l'appel système tty_getc(). Noubliez pas d'introduire au début du programme main() l'appel système qui permet d'activer les entrées d'interruption IRQ_IN[0] et IRQ_IN[1] du concentrateur d'interruption ICU.
Pour terminer ce TP, modifiez le programme main() (dans le fichier main.c), pour activer le composant vci_timer en programmant ce composant pour qu'il génère une interruption périodique tous les 50000 cyles. On utilsera pour cela les fonctions définies dans le fichier stdio.c.
4 Compte-rendu
Il ne vous est pas demandé de compte-rendu pour ce TP, mais on vous demandera une démonstration au début du TP de la semaine suivante...
Attachments (3)
- soclib_tp4_mono.png (35.2 KB) - added by 14 years ago.
- images.tgz (230.9 KB) - added by 14 years ago.
- soclib_tp4.tgz (6.7 KB) - added by 10 years ago.
Download all attachments as: .zip