SPC

Un processeur
Cours de SPCInterruptions

Ce qui se passe sans qu'on le voit

Comme on l'a dit sur la page précédente, un traitant d'interruption ne se comporte pas totalement comme une fonction classique. Certaines choses sont différentes au niveau du compilateur et du matériel charger de gérer les interruptions.

En général, une fonction n'a que quelques registres à sauvegarder et restaurer, et c'est à la fonction appelante de sauvegarder le reste si elle en a besoin. Le souci avec les interruptions, c'est qu'on ne sait pas à quel moment elles peuvent arriver : le compilateur ne peut pas ajouter les instructions de sauvegarde des registres avant que le traitant se lance, puisqu'on ne sait pas quand le traitant va se lancer. Le traitant doit donc sauvegarder et restaurer tous les registres. La ligne __attribute__((interrupt)) sert à indiquer au compilateur de rajouter les instructions pour celà.

Quand on appelle un traitant, le processeur va aussi changer de mode : on doit toujours être en mode « noyau » (privilégié) quand on exécute un traitant, même si on était en train d'exécuter du code en mode « utilisateur » au moment où l'interruption est apparue.

En plus de ça, appeler un traitant demande de mofidier lr, sp et pc comme pour une fonction classique. Mais pour se simplifier la tâche et éviter de devoir sauvegarder et restaurer ces registres, ils sont en réalité dupliqués, et chaque mode a sa copie de ces registres. En plus de ça, on peut ainsi accéder aux anciennes valeurs de ces registres : imaginons que le processeur émette une interruption parce qu'une instruction qui n'existe pas vient d'être exécutée, c'est utile de savoir l'ancienne valeur de pc pour savoir à quel endroit du programme se trouve cette instruction invalide.

Une fois que le traitant a été exécuté, il faut restaurer les registres et reprendre l'éxécution normale du code. Pour la plupart des registres pas de souci, on reprend la valeur qu'on avait sauvegardé en mémoire. Mais pour pc et cpsr on a un problème : lequel restaurer en premier ? Si on restaure d'abord pc, on va sauter ailleurs dans le code, et l'instruction pour restaurer cpsr ne sera jamais exécutée. Si on change d'abord cpsr, le mode du processeur va changer, et lorsqu'on voudra faire mov pc, lr pour revenir là où on était avant, lr désignera la version originale du registre, pas celle valable dans le traitant, donc on ne sautera pas au bon endroit. En ARM, il y a donc une instruction dédiée pour faire cette opération : movS pc, lr.