TP4 : Interruptions et architectures multi-processeurs
}}}
[[PageOutline]]
= 1 Objectif =
Le but de ce quatrième TP est double :
D'un côté, on souhaite introduire de nouveaux
composants matériels supportant la communication par interruption,
et analyser les mécanismes de communication entre un programme utilisateur et un périphérique.
D'un autre côté, on souhaite modéliser des architectures comportant plusieurs processeurs programmables.
= 2 Communications par interruption =
Tous les périphériques utilisent les interruptions, mais il existe deux types de périphériques:
* Un contrôleur TTY est un périphérique ''caractère'' car il supporte des requêtes de lecture ou d'écriture d'un seul caractère. Ce type de périphérique est généralement une cible sur le bus, puisqu'il ne peut que recevoir des commandes provenant d'un processeur, et qu'il n'a pas la possibilité de lire ou d'écrire lui-même en mémoire.
* Par opposition un périphérique ''bloc'', tel qu'un contrôleur de disque, (ou un contrôleur réseau) doit tranférer de grosses quantités de données entre la mémoire et le disque (ou le réseau). Les transferts se font par blocs (un bloc contenant généralement 512 octets), et ces périphériques ont généralement une capacité DMA : Ils sont à la fois maître et cible sur le bus, et peuvent directement lire ou écrire en mémoire.
== 2.1 Interruptions vectorisées ==
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 utilisant la 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
[https://www.soclib.fr/trac/dev/wiki/Component/VciIcu ici].
On en profite pour introduire d'autres périphériques : 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
[https://www.soclib.fr/trac/dev/wiki/Component/VciMultiTimer ici].
Le composant '''vci_block_device'''
Le composant '''vci_frame_buffer'''
On obtient ainsi une première 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.
[[Image(soclib_tp4_cluster.png)]]
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.
Dans le TP3, le programme utilisateur utilisait l'appel système ''tty_getc()'' pour lire un caracère saisi au
clavier. Cet appel système bloquant réalise une boucle de scrutation dans laquelle, à chaqur tour de boucle,
on effectue une transaction sur le bus pour lire la valeur du registre STATUS du terminal concerné.
On ne sort de cette boucle que lorsqu'un caractère aeffectivement été saisi. au clavier.le système lit la valeur
Dans un mécanisme interruptif, le programme utilisateur utilise l'appel système ''tty_get_irq()''.
Cet appel système utilise lui-même un tampon mémoire partagé '''_tty_get_buf''', protégé par une variable de synchronisation '''-tty_get_full'''.
Ces deux variables appartiennent au système d'exploitation et sont stockées dans le segment ''seg_kunc'',
qui est à la fois protégé (non accessible par les programmes utilisateur) et non cachable.
Plutôt que d'effectuer une scrutation sur le registre STATUS du contrôleur TTY, l'appel système ''tty_get_irq()''
teste la variable '''_tty_get_full''', ce qui permet (en principe) au système d'exploitation d'attribuer le processeur
à un autre programme utilisateur si te tampon est vide. C'est la routine d'interruption (ISR) associée au
terminal TTY qui se charge d'écrire le code ASCII du caractère dans le tampon '''_tty_get_buf''', et de
forcer à 1 la variable de synchronsation '''_tty_get_full'''. Cette variable de synchronisation est remise à 0
par l'appel système ''tty_getc_irq()'' lorsque le caractère est transféré du tampon système '''tty_get_buf'''
vers le tampon mémoire défini par l'utilisateur.
Dans une architecture monoprocesseur, le processeur peut exécuter plusieurs tâches (plusieurs programmes utilisateurs) en pseudo-paralléliseme, par multiplexage temporel. Chaque tâche possède alors son propre terminal écran/clavier, mais il n'y a qu'un seul contrôleur TTY.
Dans une architecture multi-processeurs, on aura un contrôleur TTY pour chaque processeur, et chaque
processeur peut exécuter plusieurs tâches.
Le GIET supporte au plus 8 processeurs, et au plus 4 tâches par processeur. Le GIET supporte donc au plus
32 terminaux ecran/clavier, et définit donc deux tableaux '''_tty_get_buf[32]''' et '''_tty_get_full[32]''', indexés par le numéro du terminal concerné.
'''Question''' : Comment l'écrivain (l'ISR) calcule-t-il l'index du terminal concerné ? Comment le lecteur
(l'appel système ''tty_get_irq()'' détermine-t-il cet index ? La réponse se trouve dans les fichier ''drivers.c'' et ''isr.s''.
'''Question:''' Que fait la routine d'interruption ISR déclenchée par le périphérique TTY lors de la frappe
d'un caractère lorsque la variable '''_tty_get_full[i]''' vaut 1 ? Ceci signifie que le précédent caractère écrit
dans le tampon '''_tty_get_buf[i]''' n'a pas été lu par le programme utilisateur. La réponse se trouve dans le fichier ''isr.s''.
'''Question:''' Quel est l'avantage de ce type de communication par interruption, comparé au mécanisme de scrutation utilisé dans le TP3 ?
'''Question''' : 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.
Le logiciel doit également être modifié. En particulier, 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 routines d'interruption).
'''Question''' : En ouvrant le fichier ''isr.s'', déterminez le nom des deux ISRs associées au TTY et au Timer. 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).
'''Question''' Modifiez le fichier '''main.c''' du TP3 pour qu'il utilise la fonction utilisateur ''tty_getc_irq()'' au lieu de l'appel système ''tty_getc()''.
== 2.2 Contrôleur de disque ==
Le contrôleur de disque disponible dans SoCLib
= 3. Architecture multi-processeurs générique =
On va dans cette section modéliser une architecture matérielle comportant un nombre variable de processeurs programmables, telle que le nombre de processeurs effectivement instanciés est un paramètre ; défini sur la ligne de commande au lancement du simulateur.
= 4 Travail à réaliser =
L'archive [attachment:soclib_tp4.tgz 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.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()''. N''oubliez 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...