Changes between Version 34 and Version 35 of Archi-1-TP11
- Timestamp:
- Dec 11, 2021, 8:12:12 PM (3 years ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
Archi-1-TP11
v34 v35 43 43 Les IRQ sont des signaux d'état qui doivent rester levés/activés tant qu'ils n'ont pas été acquittés par une ISR. Quand une IRQ se lève, la conséquence est que le programme en cours d'exécution sur le processeur recevant l'IRQ est interrompu et qu'il est dérouté vers le noyau pour que ce dernier exécute l'ISR prévue pour l'IRQ. Notez que ce n'est pas le processeur qui est interrompu, c'est bien le programme, car le processeur est seulement dérouté vers le noyau, mais il continue à travailler. 44 44 45 Sur le schéma de la plateforme des TP, on peut voir que ce sont seulement les composants TTY et TIMER quipeuvent lever des IRQ. Les IRQ de ces contrôleurs de périphériques sont envoyés au composant ICU qui va les combiner pour produire un unique signal IRQ pour le processeur.45 Sur le schéma de la plateforme des TP, on peut voir que seuls les composants TTY et TIMER peuvent lever des IRQ. Les IRQ de ces contrôleurs de périphériques sont envoyés au composant ICU qui va les combiner pour produire un unique signal IRQ pour le processeur. 46 46 47 47 [[Image(htdocs:img/Archi_TP11.png,nolink,height=250)]] … … 51 51 [[Image(htdocs:img/IRQ_routage.png,nolink,height=200)]] 52 52 53 Sur le schéma ci-dessus, on voit que l'IRQ du TTY0 e ntre sur l'entrée n°`10` de l'ICU, c'est un choix matériel qui n'est pas modifiable par logiciel. Son état est donc enregistré dans le bit n°10 du registre `ICU_STATE`. Il y a un `AND` avec le bit `10` du registre `ICU_MASK`. Si le bit `10` du registre `ICU_MASK` est à `0`, alors la sortie du `AND` est `0` et l'IRQ est masquée (donc invisible pour le processeur). Le registre `ICU_HIGHEST` contient toujours le numéro de l'IRQ active la plus prioritaire, comme il n'y en a qu'une dans cet exemple, `ICU_HIGHEST` contient `10` (l'IRQ prioritaire, pour cette ICU, est l'IRQ active dont le numéro est le plus petit). L'IRQ de l'ICU entre sur l'entrée `0` des 6 IRQs possibles du MIPS et sa valeur s'inscrit dans le registre `HWI0` du registre `c0_cause`. Il y a un `AND` avec le bit `HWI0` du registre `c0_status`. Si le bit `HWI0` du registre `c0_status` est à 0, alors la sortie du `AND` est `0` et l'IRQ est aussi masquée. Enfin, il y a encore un `AND` qui permet de masquer globalement les IRQ avec le bit `0` de `c0_status` (c'est le bit `IE` pour Interrupt Enable) et le `NOT` du bit `1` de `c0_status` (c'est lebit `EXL` EXception Level).53 Sur le schéma ci-dessus, on voit que l'IRQ du TTY0 est reliée à l'entrée n°`10` de l'ICU, c'est un choix matériel qui n'est pas modifiable par logiciel. Son état est donc enregistré dans le bit n°10 du registre `ICU_STATE`. Il y a un `AND` avec le bit `10` du registre `ICU_MASK`. Si le bit `10` du registre `ICU_MASK` est à `0`, alors la sortie du `AND` est `0` et l'IRQ est masquée (donc invisible pour le processeur). Le registre `ICU_HIGHEST` contient toujours le numéro de l'IRQ active la plus prioritaire, comme il n'y en a qu'une dans cet exemple, `ICU_HIGHEST` contient `10` (l'IRQ prioritaire, pour cette ICU, est l'IRQ active dont le numéro est le plus petit). L'IRQ de l'ICU est reliée à l'entrée `0` des 6 IRQs possibles du MIPS et sa valeur s'inscrit dans le registre `HWI0` du registre `c0_cause`. Il y a un `AND` avec le bit `HWI0` du registre `c0_status`. Si le bit `HWI0` du registre `c0_status` est à 0, alors la sortie du `AND` est `0` et l'IRQ est aussi masquée. Enfin, il y a un dernier `AND` avec le bit `0` de `c0_status` (correspondant au bit `IE` pour Interrupt Enable) qui permet de masquer globalement les IRQ et avec le `NOT` du bit `1` de `c0_status` (correspondant au bit `EXL` EXception Level). 54 54 55 55 Quand le signal IRQ vue par le MIPS s'active (passe à 1), c'est que l'IRQ levée par le contrôleur de périphérique doit être prise en charge. Le programme en cours d'exécution est interrompu et dérouté vers `kentry` à l'adresse `0x80000180` et __en même temps__ `C0_EPC ← PC+4`, `c0_cause.XCODE ← 0`, `c0_status.EXL ← 1`. Notez que le nom officiel de `c0_status` est `C0_SR`, mais dans ce document, on utilise `c0_status` pour plus de clarté. … … 60 60 61 61 - À gauche, on voit que les IRQ venant des contrôleurs de périphériques sont connectés aux entrées d'IRQ de l'ICU. Il y a 32 entrées possibles. Sur notre plateforme, par exemple l'IRQ du TTY2 est connectée à l'entrée `12` de l'ICU. Ce numéro d'entrée est le numéro qui identifie le contrôleur de périphérique. Notez que le registre `ICU_MASK` est en lecture seul, c'est-à-dire qu'il ne peut pas être écrit directement. Pour modifier le contenu du registre `ICU_MASK`, il faut utiliser deux autres registres de l'`ICU`: `ICU_SET` et `ICU_CLEAR`. `ICU_SET` permet de mettre à `1` les bits de `ICU_MASK`, et `ICU_CLEAR` permet de les mettre à `0`. Pour mettre à `1` le bit `i` du registre `ICU_MASK`, il faut écrire `1` dans le bit `i` du registre `ICU_SET`. Pour mettre à `0` le bit `j` du registre `ICU_MASK`, il faut aussi écrire `1`, mais dans le bit `j` du registre `ICU_CLEAR`.\\\\ 62 - À droite, il y a les deux tableaux que le noyau utilise pour connaitre l'ISR à exécuter pour chaque numéro IRQ. Ce couple de tableaux se nomme **vecteur d'interruption** et comme il y a 32 entrées d'IRQ dans l'ICU, ces tableaux ont 32 cases chacun. Ici, le vecteur d'interruption est composé des tableaux `IRQ_VECTOR_ISR[]` et `IRQ_VECTOR_DEV[]`. Le vecteur d'interruption est indexé par les numéros d'IRQ. Il contient deux informations: (1) Dans la case n°`i` du tableau `IRQ_VECTOR_ISR[]`, on trouve le pointeur sur la fonction ISR à appeler si l'IRQ n°`i` est levée, et (2) dans la case n°`i` du tableau `IRQ_VECTOR_DEV[]`, on trouve le numéro de l'instance du périphérique. Cette dernière information est nécessaire dans le cas des contrôleurs de périphérique multi-instances comme le TTY afin de savoir quel jeu de registres la fonction ISR doit utiliser. En effet, il y a une fonction ISR unique à exécuter quelque-soit le numéro du TTY, l'adresse de cette fonction est placée dans les cases `10`, `11`, `12`, et `13` du tableau `IRQ_VECTOR_ISR[]` (si on a 4 TTYs) et dans les cases `10`, `11`, `12`, et `13` du tableau `IRQ_VECTOR_DEV[]`, on a les valeurs `0`, `1`, `2` et `3` qui correspondent bien au numéro d'instance des TTYs.63 64 Enfin, nous vous rappelons les 3 registres du coprocesseur système (`c0`) qui sont utilisés au moment de l'entrée dans le noyau, quelque soit la cause : syscall (vu la semaine dernière), interruption (TD de cette semaine) et exception (dans le cas de problèmes lors de l'exécution du programme comme la division par 0). On rappelle aussi que les seules instructions qui peuvent manipuler ces registres sont `mtc0` et `mfc0` pour, respectivement, les écrire et les lire.62 - À droite, il y a les deux tableaux que le noyau utilise pour connaitre l'ISR à exécuter pour chaque numéro d'IRQ. Ce couple de tableaux se nomme **vecteur d'interruption** et comme il y a 32 entrées d'IRQ dans l'ICU, ces tableaux ont 32 cases chacun. Ici, le vecteur d'interruption est composé des tableaux `IRQ_VECTOR_ISR[]` et `IRQ_VECTOR_DEV[]`. Le vecteur d'interruption est indexé par les numéros d'IRQ. Il contient deux informations: (1) dans la case n°`i` du tableau `IRQ_VECTOR_ISR[]`, on trouve le pointeur sur la fonction ISR à appeler si l'IRQ n°`i` est levée, et (2) dans la case n°`i` du tableau `IRQ_VECTOR_DEV[]`, on trouve le numéro de l'instance du périphérique. Cette dernière information est nécessaire dans le cas des contrôleurs de périphérique multi-instances comme le TTY afin de savoir quel jeu de registres la fonction ISR doit utiliser. En effet, il y a une fonction ISR unique à exécuter quel que soit le numéro du TTY, l'adresse de cette fonction est placée dans les cases `10`, `11`, `12`, et `13` du tableau `IRQ_VECTOR_ISR[]` (si on a 4 TTYs) et dans les cases `10`, `11`, `12`, et `13` du tableau `IRQ_VECTOR_DEV[]`, on a les valeurs `0`, `1`, `2` et `3` qui correspondent bien au numéro d'instance des TTYs. 63 64 Enfin, nous rappelons les 3 registres du coprocesseur système (`c0`) qui sont utilisés au moment de l'entrée dans le noyau, quelle que soit la cause : syscall (vu la semaine dernière), interruption (TD de cette semaine) et exception (dans le cas de problèmes lors de l'exécution du programme comme la division par 0). On rappelle aussi que les seules instructions qui peuvent manipuler ces registres sont `mtc0` et `mfc0` pour, respectivement, les écrire et les lire. 65 65 66 66 [[Image(htdocs:img/C0_registers.png,nolink,height=300)]] 67 67 68 Les bits `HWI0` des registres `c0_status` (aussi nommé `c0_sr`) et `c0_cause` contiennent respectivement le mask et le l'état de l'entrée n°`0` d'interruption du MIPS. Les bits `UM`, `IE` et `EXL` sont liés au mode d'exécution du MIPS: `UM` est le bit de mode du MIPS (`1`=`User Mode`, `0`=`Kernel Mode`), `IE` est le bit de masque général des interruptions (`1`=autorisées, `0`=masquées) et enfin `EXL` est le bit que le MIPS met à `1` à l'entrée dans le noyau pour informer d'un niveau exceptionnel et dans ce cas les bits `UM` et `IE` ne sont plus significatifs, si `EXL` est à `1` alors le MIPS est en mode kernel, interruptionsmasquées.68 Les bits `HWI0` des registres `c0_status` (aussi nommé `c0_sr`) et `c0_cause` contiennent respectivement le mask et le l'état de l'entrée n°`0` d'interruption du MIPS. Les bits `UM`, `IE` et `EXL` sont liés au mode d'exécution du MIPS: `UM` est le bit de mode du MIPS (`1`=`User Mode`, `0`=`Kernel Mode`), `IE` est le bit de masque général des interruptions (`1`=autorisées, `0`=masquées) et enfin `EXL` est le bit que le MIPS met à `1` à l'entrée dans le noyau pour informer d'un niveau exceptionnel et dans ce cas les bits `UM` et `IE` ne sont plus significatifs, si `EXL` est à `1` alors le MIPS est en mode kernel, et les interruptions sont masquées. 69 69 70 70 … … 77 77 78 78 79 1. A quelles adresses dans l'espacesd'adressage sont placés les registres des 3 contrôleurs de périphériques de la plateforme et comment le kernel les connaît ?79 1. À quelles adresses dans l'espace d'adressage sont placés les registres des 3 contrôleurs de périphériques de la plateforme et comment le kernel les connaît ? 80 80 {{{#!protected ------------------------------------------------------------------------------------ 81 81 '' … … 95 95 {{{#!protected ------------------------------------------------------------------------------------ 96 96 '' 97 * C'est un signal à 2 états, c'est binaire. Il y a l'état `ON` (on dit aussi levé ou actif) pour dire que l'interruption est demandée et il y a l'état `OFF` (on dit aussi baissé ou inactif) pour di te que l'interruption n'est pas demandée).97 * C'est un signal à 2 états, c'est binaire. Il y a l'état `ON` (on dit aussi levé ou actif) pour dire que l'interruption est demandée et il y a l'état `OFF` (on dit aussi baissé ou inactif) pour dire que l'interruption n'est pas demandée). 98 98 '' 99 99 }}} … … 101 101 {{{#!protected ------------------------------------------------------------------------------------ 102 102 '' 103 * c'est un événement matériel sur le contrôleur de périphérique, comme la fin d'une commande ou l'arrivée d'une donnée.104 '' 105 }}} 106 1. Les IRQ relient des composants source et des composants destinataires, quels sont ces composants ? Donnez un exemple.103 * C'est un événement matériel sur le contrôleur de périphérique, comme la fin d'une commande ou l'arrivée d'une donnée. 104 '' 105 }}} 106 1. Les IRQ relient des composants sources et des composants destinataires, quels sont ces composants ? Donnez un exemple. 107 107 {{{#!protected ------------------------------------------------------------------------------------ 108 108 '' … … 137 137 {{{#!protected ------------------------------------------------------------------------------------ 138 138 '' 139 * Les 4 IRQ de TTYs sont branché s sur les entrées `10`, `11`, `12` et `13` de l'ICU et l'IRQ du TIMER est sur l'entrée `0`.140 '' 141 }}} 142 1. Quelle valeur mettredans le registre `ICU_MASK` si on veut recevoir seulement les IRQ venant des 4 TTYs, dans le cas de la plateforme utilisée en TP ? Donnez le nombre en binaire et en hexadécimal.139 * Les 4 IRQ de TTYs sont branchées sur les entrées `10`, `11`, `12` et `13` de l'ICU et l'IRQ du TIMER est sur l'entrée `0`. 140 '' 141 }}} 142 1. Quelle valeur faut il avoir dans le registre `ICU_MASK` si on veut recevoir seulement les IRQ venant des 4 TTYs, dans le cas de la plateforme utilisée en TP ? Donnez le nombre en binaire et en hexadécimal. 143 143 {{{#!protected ------------------------------------------------------------------------------------ 144 144 '' … … 152 152 '' 153 153 }}} 154 1. Sur une plateforme (autre que celle des TP) sur laquelle on aurait un TTY0 sur l'entrée 5, un TIMER sur l'entrée 2, et un autre TTY1 sur l'entrée 14. Que doit-on faire pour que seuls le s TTY1 et le TIMER soient démasqués et que TTY0 soit masquée?\\Si les 3 IRQ se lèvent au même cycle, quelles seront les valeurs des registres `ICU_STATE`, `ICU_MASK` et `ICU_HIGHEST` ?154 1. Sur une plateforme (autre que celle des TP) sur laquelle on aurait un TTY0 sur l'entrée 5, un TIMER sur l'entrée 2, et un autre TTY1 sur l'entrée 14. Que doit-on faire pour que seuls le TTY1 et le TIMER soient démasqués et que TTY0 soit masqué ?\\Si les 3 IRQ se lèvent au même cycle, quelles seront les valeurs des registres `ICU_STATE`, `ICU_MASK` et `ICU_HIGHEST` ? 155 155 {{{#!protected ------------------------------------------------------------------------------------ 156 156 '' 157 157 * on doit écrire `1` dans les bits 2 et 14 du registre `ICU_SET` donc `0b00000000.00000000.01000000.00000100` = `0x00004004` 158 * on doit écrire `1` dans le bit 4 du registre `ICU_CLEAR` donc `0b00000000.00000000.00000000.00100000` = `0x00000020` pour être sûr que le bit 5 de `ICU_MASK` soit à 0. (au reset, tous les bits de `ICU_MASK` sont à 0, mais là on ne sait pas si c'est juste après le reset)159 * Si les 3 IRQ s'activent alors `ICU_STATE` ← `0x00000000.00000000.01000000.00 010100` = `0x00004014`\\158 * on doit écrire `1` dans le bit 5 du registre `ICU_CLEAR` donc `0b00000000.00000000.00000000.00100000` = `0x00000020` pour être sûr que le bit 5 de `ICU_MASK` soit à 0. (Au reset, tous les bits de `ICU_MASK` sont à 0, mais là on ne sait pas si c'est juste après le reset) 159 * Si les 3 IRQ s'activent alors `ICU_STATE` ← `0x00000000.00000000.01000000.00100100` = `0x00004024`\\ 160 160 on ne sait pas ce qu'il y a dans `ICU_MASK`, sauf pour les bits 2, 5 et 14 mais on sait qu'il ne change pas de valeur et `ICU_HIGHEST ← 2` (le plus petit numéro d'IRQ). 161 161 '' … … 213 213 {{{#!protected ------------------------------------------------------------------------------------ 214 214 '' 215 * C'est l'adresse de retour dans le programme interrompu. Quand le processeur reçoit une IRQ alors qu'il est en train d'exécuter l'instruction n°`i` à l'adresse `PC` (Program Counter), alors le MIPS termine l'exécution de l'instruction `i`, puis il enregistre `PC+4` (adresse de l'instruction n°`i+1`) dans `c0_EPC` et il saute à l'adresse `0x80000180`. 216 '' 217 }}} 218 1. Que se passe-t-il dans le registre `c0_sr` à l'entrée dans le noyau en cas d'interruption et quelle est la conséquence ? 219 {{{#!protected ------------------------------------------------------------------------------------ 220 '' 221 * Le bit `EXL` passe à 1 et la conséquence est que le MIPS passe en mode kernel, toutes les sont interruptions masquées quelque-soit les valeurs de `c0_status.UM` et `c0_status.IE` (respectivement le mode d'exécution et le masque d'interruption général). 222 '' 223 }}} 224 1. Le routine `kentry` (entrée du kernel à l'adresse `0x80000180`) appelle le gestionnaire d'interruption quand le MIPS reçoit une IRQ non masquée, que fait ce gestionnaire d'interruption ? 225 {{{#!protected ------------------------------------------------------------------------------------ 226 '' 227 * Le gestionnaire d'interruption doit déterminer le numéro de l'IRQ en lisant dans le registre `ICU_HIGHEST` de l'ICU et il doit appeler la fonction ISR trouvée dans le tableau `IRQ_VECTOR_ISR[]` du vecteur d'interruption à la case du numéro de l'IRQ, en lui donnant en argument le numéro du périphérique (DEVice) trouvé dans le tableau `IRQ_VECTOR_DEV[]` à la case du numéro de l'IRQ. 215 * C'est l'adresse de retour dans le programme interrompu. Quand le processeur reçoit une IRQ alors qu'il est en train d'exécuter l'instruction `i` à l'adresse `PC` (Program Counter), alors le MIPS termine l'exécution de l'instruction `i`, puis il enregistre `PC+4` (adresse de l'instruction qui suit `i`) dans `c0_EPC` et il saute à l'adresse `0x80000180`. 216 * Question de Karine : et si `i` est un saut (ou l'instruction dans le delayed slot d'un saut pris ?) 217 '' 218 }}} 219 1. Que se passe-t-il dans le registre `c0_status` à l'entrée dans le noyau en cas d'interruption et quelle est la conséquence ? 220 {{{#!protected ------------------------------------------------------------------------------------ 221 '' 222 * Le bit `EXL` passe à 1 et la conséquence est que le MIPS passe en mode kernel, toutes les sont interruptions masquées quelles que soient les valeurs de `c0_status.UM` et `c0_status.IE` (respectivement le mode d'exécution et le masque d'interruption général). 223 '' 224 }}} 225 1. La routine `kentry` (entrée du kernel à l'adresse `0x80000180`) appelle le gestionnaire d'interruption quand le MIPS reçoit une IRQ non masquée, que fait ce gestionnaire d'interruption ? 226 {{{#!protected ------------------------------------------------------------------------------------ 227 '' 228 * Le gestionnaire d'interruption doit déterminer le numéro de l'IRQ en lisant dans le registre `ICU_HIGHEST` de l'ICU et il doit appeler la fonction ISR trouvée dans le tableau `IRQ_VECTOR_ISR[]` du vecteur d'interruption dans la case du numéro de l'IRQ, en lui donnant en argument le numéro du périphérique (DEVice) trouvé dans le tableau `IRQ_VECTOR_DEV[]` dans la case du numéro de l'IRQ. 228 229 '' 229 230 }}} … … 240 241 sw $1, 1*4($29) // save all temporary registers including HI and LO 241 242 sw $2, 2*4($29) 242 [etc. pour les autres s w deregistres temporaires]243 [etc. pour les autres sauvegardes des registres temporaires] 243 244 244 245 jal irq_handler // call the irq handler fontion écrite en C … … 246 247 lw $1, 1*4($29) // restore all temporary registers including HI and LO 247 248 lw $2, 2*4($29) 248 [etc. pour les autres lw deregistres temporaires]249 [etc. pour les autres restaurations des registres temporaires] 249 250 lw $26, 20*4($29) // get old SR 250 251 lw $27, 21*4($29) // get return address of syscall … … 261 262 '' 262 263 }}} 263 1. La fonction `irq_handler()` a pour mission d'appeler la bonne ISR. Dans le code qui suit (extrait du fichier `kernel/harch.c`), on voit d'abord la déclaration de la structure qui décrit les registres présents dans l'ICU. En fait c'est un tableau de structure parce qu'il y a autant d'instances d'ICU que de processeurs (donné par NCPUS), ici, il y a un seul processeur MIPS, donc NCPUS=1.264 1. La fonction `irq_handler()` a pour mission d'appeler la bonne ISR. Dans le code qui suit (extrait du fichier `kernel/harch.c`), on voit d'abord la déclaration de la structure qui décrit les registres présents dans l'ICU. En fait c'est un tableau de structures parce qu'il y a autant d'instances d'ICU que de processeurs (donné par NCPUS), ici, il y a un seul processeur MIPS, donc NCPUS=1. 264 265 {{{#!c 265 266 struct icu_s { … … 287 288 288 289 }}} 289 La déclaration `extern volatile struct icu_s __icu_regs_map[NCPUS];` informe le compilateur que le symbole `__icu_regs_map` est défini ailleurs et que c'est un tableau de structures de type `struct icu_s`. Ainsi, `gcc` sait comment utiliser cettevariable `__icu_regs_map`.\\\\290 Rappelez dans quel fichier est défini `__icu_regs_map` ?\\290 La déclaration `extern volatile struct icu_s __icu_regs_map[NCPUS];` informe le compilateur que le symbole `__icu_regs_map` est défini ailleurs et que c'est un tableau de structures de type `struct icu_s`. Ainsi, le compilateur `gcc` sait comment utiliser la variable `__icu_regs_map`.\\\\ 291 Dans quel fichier est défini `__icu_regs_map` ?\\ 291 292 Que font les fonctions `icu_get_highest()`, `icu_set_mask()` et `irq_handler()`?\\ 292 293 Comment s'appelle le couple de tableaux `irq_vector_isr[irq]` et `irq_vector_dev[irq]` ?\\ … … 294 295 {{{#!protected ------------------------------------------------------------------------------------ 295 296 '' 296 * Ce symbole est défini dans le fichier ldscript du kernel `kernel/kernel.ld`297 * Ce symbole est défini dans le fichier ldscript du kernel `kernel/kernel.ld` 297 298 * `icu_get_highest()` lit le registre `ICU_HIGHEST` de l'ICU et rend donc le numéro de l'IRQ la plus prioritaire. 298 * `icu_set_mask()` met 1 dans le bit n°`irq` du registre `ICU_SET` de l'ICU n°`icu` (ici `icu` est à 0 parce qu'il faut une ICU par MIPS et qu'il n"y a qu'un seul MIPS). Cela a pour effet de mettre à `1` dans le bit n *`irq` du registre `ICU_MASK`.299 * `icu_set_mask()` met 1 dans le bit n°`irq` du registre `ICU_SET` de l'ICU n°`icu` (ici `icu` est à 0 parce qu'il faut une ICU par MIPS et qu'il n"y a qu'un seul MIPS). Cela a pour effet de mettre à `1` dans le bit n°`irq` du registre `ICU_MASK`. 299 300 * `irq_handler()` va chercher dans l'ICU le numéro de l'IRQ la plus prioritaire et la copie dans la variable `irq` (cette notion de priorité n'a de sens que dans le cas où au moins deux IRQ sont actives en même temps). `irq_handler()` appelle la fonction ISR qui est dans la case n°`irq` du tableau `irq_vector_isr[]` et lui donne en argument le numéro d'instance qui est dans la case n°`irq` du tableau `irq_vector_dev[]`. 300 301 * Les deux tableaux constituent le vecteur d'interruption et ils ont autant de cases que l'ICU prend d'IRQ, c.-à-d. 32. … … 304 305 {{{#!protected ------------------------------------------------------------------------------------ 305 306 '' 306 * Si `ICU_HIGHEST` contient 10, c'est que c'est une IRQ du TTY0 et donc il faut appeler l' isrdu TTY en lui passant 0 en argument.307 * Si `ICU_HIGHEST` contient 10, c'est que c'est une IRQ du TTY0 et donc il faut appeler l'ISR du TTY en lui passant 0 en argument. 307 308 '' 308 309 }}} … … 310 311 {{{#!protected ------------------------------------------------------------------------------------ 311 312 '' 312 * Elle met à `1` le bit `irq` du registre `ICU_MASK` de l'ICU n°`icu` (ici c'est nécessaire `0` puisqu'il n'y a qu'un seul MIPS donc une seule ICU).313 * Elle met à `1` le bit `irq` du registre `ICU_MASK` de l'ICU n°`icu` (ici c'est nécessairement `0` puisqu'il n'y a qu'un seul MIPS donc une seule ICU). 313 314 '' 314 315 }}} … … 323 324 extern volatile struct timer_s __timer_regs_map[NCPUS]; 324 325 }}} 325 Ecrivez le code de la fonction `static void timer_init (int timer, int tick)` qui initialise la période avec du timer n° `timer` avec le nombre de période nommé `tick`.326 Écrivez le code de la fonction `static void timer_init (int timer, int tick)` qui initialise la période du timer n° `timer` avec l'entier nommé `tick` et active les IRQ si la période donnée est non nulle. 326 327 {{{#!protected ------------------------------------------------------------------------------------ 327 328 '' … … 334 335 }}} 335 336 }}} 336 1. La configuration des périphériques et des interruptions est faite s dans la fonction `arch_init()` appelée par `kinit()`.\\Ecrivez les instructions C permettant d'ajouter le TIMER dans le noyau avec un tick de 1000000 (1 milion de cycle). Il faut (1) Démasquer l'IRQ venant du timer dans l'ICU, laquelle est connectée sur son entrée n°0 ; (2) initialiser le timer,(3) initialiser le vecteur d'interruption avec la fonction `timer_isr` pour ce timer `0`.337 1. La configuration des périphériques et des interruptions est faite dans la fonction `arch_init()` appelée par `kinit()`.\\Écrivez les instructions C permettant d'ajouter le TIMER dans le noyau avec un tick de 1000000 (1 million de cycles). Il faut (1) initialiser le timer ; (2) démasquer l'IRQ venant du timer dans l'ICU, elle connectée sur son entrée n°0 ; (3) initialiser le vecteur d'interruption avec la fonction `timer_isr` pour ce timer `0`. 337 338 {{{#!protected ------------------------------------------------------------------------------------ 338 339 '' 339 340 * Il faut une séquence de 4 instructions : 340 341 {{{#!c 342 int tick = 1000000; 341 343 timer_init (0, tick); // sets period of timer n'0 (thus for CPU n'0) and starts it 342 344 icu_set_mask (0, 0); // [CPU n'0].IRQ <-- ICU.PIN[0] <- Interrupt signal timer n'0 … … 353 355 354 356 355 Dans le premier TME, vous avez réalisé un petit jeu dans lequel vous deviez deviner un nombre tiré au hasard. Ce jeu avait été mis dans kinit parce qu'a ce moment, il n'y avait pas encore d'application utilisateur. Nous vous proposons de mettre le jeu dans l'application user et de limiter le temps pendant lequel vous pouvez jouer. Nous allons vous quider pas-à-pas.356 357 Récuperez l'[htdocs:files/tp3.tgz archive du code du tp3], placez-là dans le répertoire `kO6` et décompressez-là. Les commandes ci-dessous suppose que vous avez mis l'archive dans le répertoire `k06`357 Dans le premier TME, vous avez réalisé un petit jeu dans lequel vous deviez deviner un nombre tiré au hasard. Ce jeu avait été mis dans `kinit` parce qu'à ce moment, il n'y avait pas encore d'application utilisateur. Nous vous proposons de mettre le jeu dans l'application user et de limiter le temps pendant lequel vous pouvez jouer. Nous allons vous guider pas-à-pas. 358 359 Récuperez l'[htdocs:files/tp3.tgz archive du code du tp3], placez-là dans le répertoire `kO6` et décompressez-là. Les commandes ci-dessous supposent que vous avez mis l'archive dans le répertoire `k06` 358 360 {{{#!bash 359 361 cd ~/k06 … … 397 399 1. Essayez le jeu (dans le répertoire `tp3/1_gameover`) : tapez `make exec`\\ 398 400 comme vous pouvez le constater, vous avez le temps de jouer. 399 1. Dans la version précédente du gestionnaire de syscall, nous avions masqué les IRQ en écrivant `0` dans le registre `c0_status`(registre $12 du coprocesseur 0). Cela avait pour conséquence de mettre tout à 0, entre autre le bit IE. Il faut modifier ça, parce que sinon, lorsque l'utilisateur demandera à lire le clavier avec l'appel système `fgets()`, l'IRQ venant du timer ne sera jamais prise en compte (`TODO1`), ensuite au retour de la fonction qui réalise l'appel système, il faut masquer les IRQ pour ne pas avoir d'interruption pendant la restauration des registres jusqu'au `eret` qui fait sortir du kernel.401 1. Dans la version précédente du gestionnaire de syscall, nous avions masqué les IRQ en écrivant `0` dans le registre `c0_status`(registre $12 du coprocesseur 0). Cela avait pour conséquence de mettre tout à 0, entre autre le bit `IE`. Il faut modifier ça, parce que sinon, lorsque l'utilisateur demandera à lire le clavier avec l'appel système `fgets()`, l'IRQ venant du timer ne sera jamais prise en compte (`TODO1`), ensuite au retour de la fonction qui réalise l'appel système, il faut masquer les IRQ pour ne pas avoir d'interruption pendant la restauration des registres jusqu'au `eret` qui fait sortir du kernel. 400 402 {{{#!c 401 403 addiu $29, $29, -8*4 // context for $31 + EPC + SR + syscall_code + 4 args … … 445 447 '' 446 448 }}} 447 1. Ouvrez le fichier `kernel/harch.c` et vous allez devoir remplir 3 fonctions pour configurer le timer: `arch_in ti()`, `timer_init()` et `timer_isr()` (pour trouver ces fonctions cherchez le mot `TODO`)449 1. Ouvrez le fichier `kernel/harch.c` et vous allez devoir remplir 3 fonctions pour configurer le timer: `arch_init()`, `timer_init()` et `timer_isr()` (pour trouver ces fonctions cherchez le mot `TODO`) 448 450 {{{#!c 449 451 void arch_init (int tick) 450 452 { 451 453 // TODO A remplir avec 4 lignes : 452 // 1) appel de la fonction timer_init (pour le timer 0 avec tick comme période454 // 1) appel de la fonction timer_init pour le timer 0 avec tick comme période 453 455 // 2) mise à 1 du bit 0 du registre ICU_MASK en utilisant la fonction icu_set_mask() 454 456 // 3) initialisation de la table irq_vector_isr[] vecteur d'interruption avec timer_isr() … … 459 461 // TODO A remplir avec 2 lignes : 460 462 // 1) initialiser le registre period du timer n°timer avec la période tick (reçus en argument) 461 // 2) initialiser le registre mode du timer n°timer avec 3 (démarre le timer avec IRQ demandée) 463 // 2) initialiser le registre mode du timer n°timer avec 3 (démarre le timer avec IRQ demandée) si la période est non nulle 462 464 } 463 465 static void timer_isr (int timer)