Ce travail pratique vaut 3% de la note totale du cours. À faire individuellement, il est à remettre au plus tard lundi le 21 mars 2016 à 23h59.
Ce travail pratique vise les objectifs suivants:
Pour ce travail pratique, nous réutiliserons l'environnement « IAR Embedded Workbench ». Si vous n'êtes pas familier avec ce système, ou si vous n'êtes plus certain des étapes à effectuer pour créer un nouveau projet, il est important que vous consultiez les notes pour le travail pratique 2 afin d'assurer que vous démarrez le TP dans un environnement adéquat.
En plus des modifications usuelles au projet énumérées dans l'énoncé du TP2, nous allons mettre en place une interruption périodique dans IAR. Cela permettra de simuler l'utilisation d'une horloge interne au processeur, capable d'interrompre régulièrement son travail. Pour ce faire, une fois le projet créé et configuré, allez dans le menu Simulator
et cliquez sur l'item Interrupt Setup
:
Vous devriez alors voir apparaître la fenêtre suivante. Cliquez alors sur le bouton New
:
Une nouvelle fenêtre s'ouvrira. Vous devez sélectionner les options suivantes :
Interrupt
, sélectionnez FIQ;First activation
, écrivez 250;Repeat interval
, écrivez 90.Laissez les autres options à leur valeur par défaut. Votre fenêtre devrait alors présenter exactement le contenu de celle-ci :
Finalement, cliquez sur Ok pour fermer les deux fenêtres en sauvegardant les changements. Cette procédure fait en sorte que lors de la simulation, une interruption FIQ surviendra après 250 cycles processeurs (la valeur cyclecounter dans la vue des registres dans le débogueur), puis à tous les 90 cycles.
Afin de faciliter le débogage de ce TP, nous vous suggérons d'activer les views
Breakpoints, Disassembly, Register et Memory. Au final, votre espace de travail pourrait ressembler à quelque chose du genre :
Ce TP s'effectue en deux étapes, qui vous demanderont respectivement d'écrire du code (pour 70% de la note du TP), et de répondre à des questions (pour 30% de la note).
Premièrement, il vous faudra coder un système d'exploitation (très) rudimentaire, capable de gérer l'exécution alternative de deux processus distincts, sans que ces derniers ne soient affectés. Pour ce faire, le processeur génère périodiquement une interruption, indépendamment de ce que font les processus. Cette interruption est gérée par le système d'exploitation, qui peut alors décider d'arrêter temporairement un processus pour laisser la place à un autre. Ce système est qualifié de préemptif, puisqu'il peut interrompre un processus à n'importe quel moment, même si ce dernier est dans une boucle infinie. Nous verrons plus en détail les notions reliées à l'ordonnancement des processus dans la suite du cours, mais sachez pour l'instant que cette gestion des processus est tout à fait similaire à ce que fait votre ordinateur lorsque plusieurs programmes requièrent simultanément du temps de calcul.
Vous devrez coder trois sections de code distinctes :
Vous trouverez plus d'informations sur chacune de ces sections dans la section détails ci-bas.
Le fichier asm.s
fourni contient plus de précisions quant à la tâche exacte qui vous est demandée pour chacune de ces sections.
Téléversez votre fichier asm.s
qui contient votre réponse dans la boîte de dépôt qui est disponible dans la section « Évaluations et résultats » du portail des cours.
Deuxièmement, une fois votre code implanté et testé (nous verrons comment vous pouvez tester son bon fonctionnement), vous devez répondre à dix (10) questions sur le portail des cours. Notez que contrairement aux travaux pratiques précédents, ces questions ne portent pas sur des lignes en particulier, mais bien sur le fonctionnement global de votre programme et des interruptions en ARM.
Ces questions sont disponibles dans la section « Questionnaires » du portail des cours.
La politique des retards mentionnée dans le plan de cours sera appliquée. Comme il y a un fichier à téléverser et des questions à répondre, la date la plus tardive d'entre les deux sera utilisée pour le calcul des retards. Pour toutes questions concernant la procédure de remise ou le travail lui-même, posez vos questions sur le forum!
Comme beaucoup d'architectures, l'ARM utilise une table des vecteurs d'interruption pour permettre au programmeur de spécifier quoi faire pour chaque type d'interruption. Cette table est située au tout début de la mémoire, à partir de l'adresse 0x00
. Le tableau suivant présente le détail de ces vecteurs d'interruption.
Adresse | Correspond à l'interruption... |
---|---|
0x00000000 | Reset |
0x00000004 | Instruction invalide |
0x00000008 | SWI ou SVC (interruption logicielle) |
0x0000000C | Prefetch Abort |
0x00000010 | Data Abort |
0x00000014 | Inutilisé |
0x00000018 | IRQ (Interruption Request) |
0x0000001C | FIQ (Fast Interrupt Request) |
Comme vous pouvez le constater, vous utilisiez déjà une interruption sans le savoir, soit l'interruption Reset, en écrivant B main
au tout début du programme. Cette instruction se retrouvait à l'adresse 0x00
et indiquait au processeur quoi faire lors d'un reset, à savoir aller à l'étiquette main
.
Dans ce TP, nous avons implanté l'entrée de la table pour l'interruption Reset (voir B moninitialisation
). Vous devrez écrire le code correspondant à l'interruption FIQ, qui devrait brancher vers votre routine de traitement de l'interruption, soit l'étiquette moninterruption
.
Lorsqu'une interruption survient, le processus en cours d'exécution peut être n'importe où dans son code assembleur. Il nous faut par conséquent être capables d'enregistrer l'état du processus afin d'être en mesure de le restaurer plus tard, sans que ce dernier ne « remarque » qu'il a été interrompu. Plus précisément, dans ce TP, vous devrez sauvegarder :
Pour sauvegarder ces données, votre système dispose de deux piles différentes : Pile0
, qui contient les informations nécessaires au processus 0, et Pile1
pour le processus 1. La figure suivante montre l'organisation mémoire déjà préparée pour vous dans le fichier asm.s
. Sur la pile de chaque processus se trouve l'adresse de retour, suivie de l'état des drapeaux, suivi des registres R7 à R0, dans cet ordre. R0 est donc le registre qui est le premier élément de la pile lorsque cette dernière est remplie. N'oubliez pas que la pile fonctionne de bas en haut!
Il vous faudra tout d'abord initialiser les piles Pile0
et Pile1
. Pour ce faire, vous devrez accomplir les trois étapes suivantes:
ProcessusCourant
pour indiquer au système que c'est le processus 0 qui est exécuté en premier.Pour les deux premières étapes, utilisez la fonction initialiseProcessus
, qui fait tout le travail pour vous. Vous n'avez qu'à l'appeler avec les bons paramètres (voyez sa documentation dans le fichier asm.s
pour plus de détails).
Votre routine de traitement de l'interruption correspond à l'étiquette moninterruption
. Lors d'une interruption, votre routine doit, dans l'ordre :
ProcessusCourant
pour mémoriser cette valeur;Comme nous utilisons une interruption de type FIQ, votre routine de traitement de l'interruption peut utiliser les registres R8 à R15 sans interférer avec les processus. Pour vous simplifier la vie, servez-vous de ces registres comme registres de travail dans votre fonction moninterruption
, ce qui vous évitera d'avoir à sauvegarder les registres que vous utiliserez dans moninterruption
.
Afin de vous aider à déboguer votre code, il est recommandé d'utiliser les points d'arrêt (« breakpoints »), comme au TP3. Vous pouvez par exemple mettre un de ces points d'arrêt dans la routine d'interruption elle-même, afin de vérifier son bon fonctionnement. Une autre vérification simple est de vous assurer que les blocs correspondant aux processus 0 et 1 sont bel et bien exécutés en alternance à chaque interruption.
En ce qui concerne la validation de votre code, le fichier asm.s
prévoit un système capable de détecter certaines erreurs. Il fonctionne en écrivant un code correspondant à cette erreur dans le registre R7, nous vous demandons donc de vous abstenir d'utiliser ce registre. Au début du programme, la valeur de R7 est non-nulle, mais doit le devenir et le rester après la première exécution des deux processus. Si, après plusieurs millions de cycles, la valeur de R7 est toujours à 0, vous pouvez considérer votre système comme suffisamment stable. Dans le cas contraire, cela indique un problème dans votre procédure de sauvegarde/restauration de l'état des processus.
asm.s
original.Merci à Marc-André Gardner pour la création de ce TP!