Mémoires, périphériques et interruptions
CentraleSupélec
2026-10-07
Cours
TP
Caractéristiques
Les mémoires mortes : non volatiles, en lecture seule (\(\approx\))
Les mémoires vives: accès aléatoire, volatiles, en lecture/écriture
Les mémoires en lecture/écriture : non-Volatiles
Transistors pour \(n\) bits \(\approx 30 n\) Capacité \(\approx\) 32-64 bits
Temps d’accès \(\approx\) 1 ps (\(10^{-12}s\))
Volatile
Capacité : 10 Ko - 10 Mo
Temps d’accès \(\approx\) 1ns
Volatile Usage: Caches L1-L2-L3
Capacité : 10 Go
Temps d’accès : 80 ns (réécriture toutes les ms)
Volatile Usage : “Les barrettes de RAM”
Capacité : 1 To (plusieurs pistes découpées en secteurs de \(512\) octets) Temps d’accès : 10 ms (révolution à \(7400\) tr/min) Non volatile
Compromis ?
| Type | Capacité | Latence | Coût (au Gi-octet) |
|---|---|---|---|
| Registre | 100 bits | 20 ps | très cher |
| SRAM | 10 Ko - 10 Mo | 1-10 ns | ≈ 1000 € |
| DRAM | 10 Go | 80 ns | ≈ 10 € |
| Flash | 100 Go | 100 μs | ≈ 1 € |
| Disque dur Magnétique | 1 To | 10 ms | ≈ 0.1 € |
Une mémoire rapide et de grosse capacité ??
Idée: combiner une petite mémoire rapide avec une grosse mémoire lente
Problème de doublons ? Politique de remplacement ? Dépends de la réalisation…
Principe
A partir d’une petite information (clé), on retrouve le reste (valeur).
Analogie : annuaire téléphone
En pratique
L’adresse demandée est divisée en plusieurs parties dont une sert de clé.
Tableau associatif : Cache[clé] = {adr, valeur, ..}
Mémoire à \(2^{16}\) mots, Cache à \(2^{4}\) mots.
1 mot mémoire ne peut aller que dans une ligne de cache.
1 ligne de cache peut possiblement recevoir \(n\) mots mémoires.
RAM[Adr] → Cache[Adr₃Adr₂Adr₁Adr₀]
pourquoi les bits de poids faibles comme index ? 2 adresses proches ne doivent pas viser la même ligne de cache
Un bloc : \(2^{|offset|}\) mots; L’offset sert de bits de sélection d’un multiplexeur par ligne.
On charge directement un bloc de mots consécutifs.
Prenons le contre-pieds : Une donnée peut occuper n’importe quelle ligne de cache.
Lourd matériellement. Politique de remplaçement ? e.g. Least Recently Used
Compromis entre le cache direct et le cache associatif : le cache associatif à \(n\) voies
Problème
Une donnée d’une même adresse peut être à la fois en cache, mémoire centrale, voir même sur le disque (e.g. swap)
Politiques d’écriture
Les périphériques d’entrée/sortie
Au périphérique est associé un contrôleur (e.g. contrôleur disque) qui possède :
Le périphérique est couplé aux bus d’adresses, données, contrôle.
Exemple d’un contrôleur clavier (e.g. Intel 8042)
Les bus
| Bus | Largeur (bits) | Clk (MHz) | Débit (Mo/s) | Année |
|---|---|---|---|---|
| ISA 16 | 16 | 8.33 | 15.9 | 1984 |
| PCI 32 | 32 | 33 | 125 | 1993 |
| AGP | 32 | 66 | 250 | 1997 |
| PCI-E 3 (x16) | 16 | 8000 | 16000 | 2011 |
Bus parallèles (échange de mots, large mais court) / Bus série (bit à bit, e.g. USB)
Il faut pouvoir contacter les registres du contrôleur du périphérique.
Autre solution : pas de bus d’adresse; placer dans le message un identifiant du destinataire.
Les données doivent être disponibles au prochain front montant d’horloge.
\(\Rightarrow\) Fréquence d’horloge : ajustée au périphérique le plus lent
Un signal permet d’indiquer la présence de la donnée \(\Rightarrow\) le processeur peut vaquer à d’autres occupations.
Pas d’horloge mais des signaux d’état : handshaking
Plus réactif mais plus compliqué à mettre en oeuvre.
On sait :
mais on a :
Nécessité d’arbitrer, e.g. le premier dans un certain ordre.
Et comment la demande d’échange avec le périphérique est prise en charge ?
Déroutements (trap, exception): événements synchrones avec l’exécution d’un programme, liés à une erreur : division par zéro, overflow, accès invalide à la mémoire : e.g. stack overflow
Ex : Overflow
Comment prendre en charge des débordements lors d’opérations arithmétiques ?
Au regard d’un programme, on peut prévoir quand un déroutement peut avoir lieu.
Evènements asynchrones; e.g. appui sur un bouton, une touche de clavier, bourrage papier, lecture mémoire terminée, …
Prise en charge par scrutation
On interroge régulièrement le périphérique
Prise en charge par interruption
Ecoute passive du périphérique : exécute un programme particulier que lorsque le périphérique lève une demande d’interruption
→ sollicite moins le processeur (e.g. lecture sur disque : données prêtes)
On ajoute :
Avant le fetch/decode, en \(0x00\), on teste si une demande d’interruption est levée :
| CodeMCount | Z | INTR & IF | \(S_1S_0\) | Sémantique |
|---|---|---|---|---|
| 000 | - | - | 00 | MicroPC := MicroPC+1 |
| 001 | - | - | 01 | MicroPC := @Adr |
| 010 | - | - | 10 | MicroPC := Instruction |
| 011 | 0 | - | 00 | MicroPC := MicroPC+1 si \(S≠0\) |
| 011 | 1 | - | 01 | MicroPC := @Adr si \(S=0\) |
| 100 | - | 0 | 01 | MicroPC := @Adr si \(\overline{INTR \& IF}\) |
| 100 | - | 1 | 00 | MicroPC := MicroPC+1 si \(INTR \& IF\) |
Principe
L’interruption doit être gérée de manière transparente pour le programme interrompu
⇒ sauvegarde du contexte d’exécution (sur la pile)
Nouvelles instructions
Vecteur d’interruption : programme à exécuter en cas d’interruption
On stocke une table des vecteurs d’interruption en mémoire. L’adresse \(0x02\) est placée sur le bus pour adresser la bonne routine lorsque INTA est signalé.
Pour le moment, avec une seule interruption, l’adresse de la routine d’interruption est codée en dur, dans le registre INTAdr
Attention
La gestion de l’interruption implique la pile !! Phase d’initialisation (JMP init) minimale :
# par défaut IF = 0
LDSPI ...
STI
On s’est limité pour le moment à un seul périphérique.
Problème
Comment exécuter plusieurs programmes “en même temps” :

Produced with quarto
Comment exploiter les principes de localité ?
Solution 1) A la charge du programmeur
→ Pas très pratique…
Solution 2) Hierarchie de mémoires
Performances du cache
Temps moyen d’accès mémoire \(T_m \approx HR. t_{cache} + MR. t_{mem}\)
Pour \(HR = 90\%\) : \(T_m = 17 ns\).