• Aucun résultat trouvé

Chapitre 5 Conclusions et perspectives

B.7 Les interruptions

Nous abordons ici un point plus délicat de l’architecture des ordinateurs, moins fondamental car moins courant, mais qui peut s’avérer fondamental dans certains cas. Il s’agit d’appeler un

sous programme par une interruption hardware. Nous distinguerons les interruptions hardware (Interrupt ReQuest : IRQ) des interruptions logicielles qui ne sont que des routines (mais qui s’apparentent aux IRQ par le fait qu’elles interrompent l’exécution d’un programme pour entrer dans un sous programme avant de poursuivre l’exécution du programme principal).

L’objectif d’une interruption hardware est de temporairement interrompre l’exécution d’un programme, d’aller exécuter le contenu d’un sous programme lié à cette interruption, puis de poursuivre l’exécution du programme principale. L’interruption hardware est appelée par la mise au niveau bas d’une broche du bus : IRQx pour appeler l’interruption hardware x.

L’utilité des interruptions apparaît dans plusieurs cas. Citons par exemple l’appel périodique d’une fonction : un chronomètre active périodiquement la broche IRQx et appel de ce fait le sous programme qui lui est associé. L’avantage de l’utilisation d’une interruption est que le programme ne doit pas perdre son temps à tester l’état d’une broche mais est prévenu, au cours de son exécution, de l’activation de cette broche.

Nous allons approfondir l’exemple précédent en proposant un montage pratique. Mais il

numéro IRQ

08 IRQ0 (timer : 18.2 fois/s) 09 IRQ1 (clavier) 0A IRQ2 (cascade 8259) 0B IRQ3 (port série 2) 0C IRQ4 (port série 1) 0D IRQ5 (disque dur) 0E IRQ6 (disquette) 0F IRQ7 (imprimante) 70 IRQ8 (horloge temps réel) 71-74 IRQ9-12 (libres)

75 IRQ13 (80287 NMI) 76 IRQ14 (disque dur) 77 IRQ15 (libre) Exemple de gestion d’IRQ

faut avant tout comprendre ce qui se passe lorsqu’une interruption est activée. Une table contient en mé- moire, à un emplacement défini qu’il n’est pas né- cessaire de préciser ici, les adresses des sous pro- grammes liés aux diverses interruptions. La première opération qu’il nous faudra effectuer est de faire poin- ter la case mémoire liée à notre interruption vers l’adresse de notre fonction que nous voulons lui as- socier. Cette opération se fait généralement par une instruction du type setvect(). Pour pouvoir res- tituer en fin d’exécution du programme la fonction d’origine à son interruption, il faut auparavant sauver l’adresse de la routine associée à l’interruption que nous utiliserons ;getvect(). Enfin il faut activer cette interruption (qui par défaut est inac- tive si elle n’est pas déjà utilisée) :

/* Uses interrupt service routine to note interrupt from printer port. The interrupt is caused by a negative on /ACK input on Printer Port. Note that on my machine the printer port is located at 0x0378 - 0x037a and is associated with IRQ 7.

Name Address in Table

IRQ2=0x0a IRQ4=0x0c IRQ5=0x0d IRQ7=0x0f based on P.H. Anderson, MSU, 12 May 91; 26 July 95 */ #include <stdio.h>;

#include <bios.h>; #include <dos.h>; #define DATA 0x0378

#define STATUS DATA+1 #define CONTROL DATA+2 #define TRUE 1 #define FALSE 0 void open_intserv(void); void close_intserv(void); void int_processed(void); void interrupt far intserv(void);

int intlev=0x0f; /* interrupt level associated with IRQ7 */ void interrupt far (*oldfunc)();

B.7. Les interruptions

int main(void) {open_intserv();

outportb(CONTROL, inportb(CONTROL) | 0x10); /* set bit 4 on control port to logic one */

while(1) {if (int_occurred) {printf("Interrupt Occurred\n"); int_occurred=FALSE;}}

close_intserv();return(0); }

void interrupt far intserv(void)

/* This is written by the user. Note that the source of the interrupt must be cleared and then the PC 8259 cleared (int_processed). must be included in this function. */

{disable();int_processed();int_occurred=TRUE; /* do whatever u want here */ enable();

}

void open_intserv(void)

/* enables IRQ7 interrupt. On interrupt (low on /ACK) jumps to intserv. ** all interrupts disabled during this function; enabled on exit. */

{int int_mask;

disable(); /* disable all ints */

oldfunc=getvect(intlev); /* save any old vector */ setvect (intlev, intserv); /* set up for new int serv */ int_mask=inportb(0x21); /* 1101 1111 */

outportb(0x21, int_mask & ~0x80); /* set bit 7 to zero */

enable(); /* -leave others alone */

}

void close_intserv(void) /* disables IRQ7 interrupt */ {int int_mask;

disable();setvect(intlev, oldfunc);

int_mask=inportb (0x21) | 0x80; /* bit 7 to one */ outportb(0x21, int_mask);enable();

}

void int_processed(void)

/* signals 8259 that interrupt has been processed */ {outportb(0x20,0x20);}

L’exemple précédent montre comment utiliser l’interruption 7 qui se déclenche en appli- quant un pulse descendant sur la broche 10 du port parallèle. Nous voyons comment sauver le vecteur d’interruption courant (getvect(), comment faire pointer le vecteur d’interruption vers notre propre fonction (setvect(), les opérations à réaliser pour activer l’interruption si ce n’est dejà fait (écriture au port d’adresse 0x21 – cette opération n’est par exemple pas néces- saire pour l’interruption 8 qui correspond à l’horloge temps réel du PC qui est toujours active) et pour déclarer qu’une interruption a bien été traitée (écriture au port d’adresse 0x20).

Maintenant que nous savons comment gérer l’interruption au niveau logiciel, il ne reste plus qu’à voir au niveau électronique comment la déclencher. Les lignes d’interruptions étant rarement partagées nous pouvons nous permettre de rester continuellement dans un état bas pour n’envoyer un pulse vers le niveau haut que lorsque nous voulons déclencher l’interruption. La bascule reste alors au niveau bas jusqu’à ce que nous appliquions un signal sur la broche de reset pour ramener la sortie de la bascule à son niveau de repos. Le montage à base de bascule, proposé dans [Gaonkar 93] p.328, répond à un front du signal d’horloge et maintient le niveau de sortie sur la broche d’interruption jusqu’à ce que le programme de gestion de l’interruption envoie un pulse vers le niveau bas sur la broche de reset et ainsi arrête l’appel à l’interruption tout en permettant à une nouvelle interruption de rappeler la routine de gestion de cette IRQ.

Nous proposons là un schéma d’oscillateur qui appellera périodiquement une interruption

555 R1 C R2 3 4 8 7 6 2 1 C=0.1 uF R1=10k R2=10k +5 +5 reset R CK D S 7474 Q IRQ

Exemple de gestion d’IRQ

hardware. A noter que ce montage n’a qu’un intérêt pédago- gique puisque une excellente horloge est déjà disponible sur l’interruption IRQ8 (vecteur d’interruption 0x1C) du PC. L’os- cillateur 555 active le niveau bas d’une bascule qui est dans le cas le plus courant dans un état bas. L’activation de la bascule par le signal d’horloge fait passer la sortie de la bascule à la va- leur de D, i.e. +5V. L’appel au sous-programme de gestion de l’IRQ est appelé, et le programmeur est chargé à la fin de ce

sous-programme d’envoyer un pulse vers le niveau bas sur la broche de reset pour réactiver la bascule.

Ce circuit peut être utilisé pour tester le programme de gestion des interruptions matérielles vu plus haut.