Changes between Version 34 and Version 35 of Archi-1-TP11


Ignore:
Timestamp:
Dec 11, 2021, 8:12:12 PM (3 years ago)
Author:
heydeman
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Archi-1-TP11

    v34 v35  
    4343Les 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.
    4444
    45 Sur le schéma de la plateforme des TP, on peut voir que ce sont seulement les composants TTY et TIMER qui 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.
     45Sur 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.
    4646
    4747[[Image(htdocs:img/Archi_TP11.png,nolink,height=250)]]
     
    5151[[Image(htdocs:img/IRQ_routage.png,nolink,height=200)]]
    5252
    53 Sur le schéma ci-dessus, on voit que l'IRQ du TTY0 entre 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 le bit `EXL` EXception Level).
     53Sur 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).
    5454
    5555Quand 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é.
     
    6060
    6161- À 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
     64Enfin, 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.
    6565
    6666[[Image(htdocs:img/C0_registers.png,nolink,height=300)]]
    6767
    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, interruptions masquées.
     68Les 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.
    6969
    7070
     
    7777
    7878
    79 1. A quelles adresses dans l'espaces 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 ?
     791. À 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 ?
    8080{{{#!protected ------------------------------------------------------------------------------------
    8181''
     
    9595{{{#!protected ------------------------------------------------------------------------------------
    9696''
    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 dite 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).
    9898''
    9999}}}
     
    101101{{{#!protected ------------------------------------------------------------------------------------
    102102''
    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}}}
     1061. Les IRQ relient des composants sources et des composants destinataires, quels sont ces composants ? Donnez un exemple.
    107107{{{#!protected ------------------------------------------------------------------------------------
    108108''
     
    137137{{{#!protected ------------------------------------------------------------------------------------
    138138''
    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 mettre 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.
     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}}}
     1421. 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.
    143143{{{#!protected ------------------------------------------------------------------------------------
    144144''
     
    152152''
    153153}}}
    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 les 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` ?
     1541. 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` ?
    155155{{{#!protected ------------------------------------------------------------------------------------
    156156''
    157157 * 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.00010100` = `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`\\
    160160   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).
    161161''
     
    213213{{{#!protected ------------------------------------------------------------------------------------
    214214''
    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}}}
     2191. 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}}}
     2251. 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.
    228229''
    229230}}}
     
    240241    sw      $1,     1*4($29)            // save all temporary registers including HI and LO
    241242    sw      $2,     2*4($29)           
    242     [etc. pour les autres sw de registres temporaires]                             
     243    [etc. pour les autres sauvegardes des registres temporaires]                             
    243244
    244245    jal     irq_handler                 // call the irq handler fontion écrite en C
     
    246247    lw      $1,     1*4($29)            // restore all temporary registers including HI and LO
    247248    lw      $2,     2*4($29)
    248     [etc. pour les autres lw de registres temporaires]   
     249    [etc. pour les autres restaurations des registres temporaires]   
    249250    lw      $26,    20*4($29)           // get old SR
    250251    lw      $27,    21*4($29)           // get return address of syscall
     
    261262''
    262263}}}
    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.
     2641. 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.
    264265{{{#!c
    265266struct icu_s {
     
    287288
    288289}}}
    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 cette variable `__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` ?\\
    291292 Que font les fonctions `icu_get_highest()`, `icu_set_mask()` et `irq_handler()`?\\
    292293 Comment s'appelle le couple de tableaux `irq_vector_isr[irq]` et `irq_vector_dev[irq]` ?\\
     
    294295{{{#!protected ------------------------------------------------------------------------------------
    295296''
    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`
    297298  * `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`.
    299300  * `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[]`.
    300301  * Les deux tableaux constituent le vecteur d'interruption et ils ont autant de cases que l'ICU prend d'IRQ, c.-à-d. 32.
     
    304305{{{#!protected ------------------------------------------------------------------------------------
    305306''
    306   * 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  * 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.
    307308''
    308309}}}
     
    310311{{{#!protected ------------------------------------------------------------------------------------
    311312''
    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).
    313314''
    314315}}}
     
    323324extern volatile struct timer_s __timer_regs_map[NCPUS];
    324325}}}
    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.
    326327{{{#!protected ------------------------------------------------------------------------------------
    327328''
     
    334335}}}
    335336}}}
    336 1. La configuration des périphériques et des interruptions est faites 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`.
     3371. 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`.
    337338{{{#!protected ------------------------------------------------------------------------------------
    338339''
    339340 * Il faut une séquence de 4 instructions :
    340341{{{#!c
     342int tick = 1000000;
    341343timer_init (0, tick);           // sets period of timer n'0 (thus for CPU n'0) and starts it
    342344icu_set_mask (0, 0);            // [CPU n'0].IRQ <-- ICU.PIN[0] <- Interrupt signal timer n'0
     
    353355
    354356
    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`
     357Dans 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
     359Ré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`
    358360{{{#!bash
    359361cd ~/k06
     
    3973991. Essayez le jeu (dans le répertoire `tp3/1_gameover`) : tapez `make exec`\\
    398400   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.
     4011. 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.
    400402{{{#!c
    401403    addiu   $29,    $29,    -8*4        // context for $31 + EPC + SR + syscall_code + 4 args
     
    445447''
    446448}}}
    447 1. Ouvrez le fichier `kernel/harch.c` et vous allez devoir remplir 3 fonctions pour configurer le timer: `arch_inti()`, `timer_init()` et `timer_isr()` (pour trouver ces fonctions cherchez le mot `TODO`)
     4491. 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`)
    448450{{{#!c
    449451void arch_init (int tick)
    450452{
    451453// TODO A remplir avec 4 lignes :
    452 // 1) appel de la fonction timer_init(pour le timer 0 avec tick comme période
     454// 1) appel de la fonction timer_init pour le timer 0 avec tick comme période
    453455// 2) mise à 1 du bit 0 du registre ICU_MASK en utilisant la fonction icu_set_mask()
    454456// 3) initialisation de la table irq_vector_isr[] vecteur d'interruption avec timer_isr()
     
    459461// TODO A remplir avec 2 lignes :
    460462// 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
    462464}
    463465static void timer_isr (int timer)