49 | | Sur le schéma ci-dessu:s, 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 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). |
50 | | |
51 | | 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 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é. |
| 54 | 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 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). |
| 55 | |
| 56 | 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 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é. |
57 | | - À 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`.\\\\ |
58 | | - À 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**. Ici, il 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 a 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 d'autres termes, Il y a une fonction ISR unique 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 `0`, `1`, `2` et `3` qui correspondent bien au numéro d'instance des TTYs. |
| 62 | - À 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`.\\\\ |
| 63 | - À 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**. Ici, il 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 d'autres termes, il y a une fonction ISR unique 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 `0`, `1`, `2` et `3` qui correspondent bien au numéro d'instance des TTYs. |
189 | | * 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 device trouvé dans le tableau `IRQ_VECTOR_DEV[]` à la case du numéro de l'IRQ. |
190 | | '' |
191 | | }}} |
192 | | 1. À l'entrée dans le noyau, `kentry` analyse le champ `XCODE` du registre de `c0_cause` et si c'est `0` alors il saut au code donné ci-après (ce n'est pas exactement le code que vous pouvez voir dans les fichiers source pour que ce soit plus facile à comprendre). |
| 194 | * 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. |
| 195 | '' |
| 196 | }}} |
| 197 | 1. À l'entrée dans le noyau, `kentry` analyse le champ `XCODE` du registre de `c0_cause` et si c'est `0` alors il saut au code donné ci-après (ce n'est pas exactement le code que vous pouvez voir dans les fichiers sources pour que ce soit plus facile à comprendre). |