Avec le chapitre précédent, on sait que les RAM et ROM contiennent des cellules mémoires, qui mémorisent chacune un bit. On pourrait croire que cela suffit à créer une mémoire, mais il n'en est rien. Il faut aussi des circuits pour gérer l'adressage, le sens de transfert (lecture ou écriture), et bien d'autres choses. Schématiquement, on peut subdiviser toute mémoire en plusieurs circuits principaux.
Nous allons étudier le plan mémoire dans ce chapitre, le contrôleur mémoire et l'interface avec le bus seront vu dans les deux chapitres suivants. Cela peut paraitre bizarre de dédier un chapitre complet au plan mémoire, mais il y a de quoi. Celui-ci n'est pas qu'un simple amoncellement de cellules mémoire et de connexions vaguement organisées. On y trouve aussi des circuits électroniques aux noms barbares : amplificateur de tension, égaliseur de ligne de bit, circuits de pré-charge, etc. L'organisation des fils dans le plan mémoire est aussi intéressante à étudier, celle-ci étant bien plus complexe qu'on peut le croire.
Les fils et signaux reliés aux cellules.
Le plan mémoire est surtout composé de fils, sur lesquels on connecte des cellules mémoires. Rappelons que les cellules mémoires se présentent avec une interface simple, qui contient des broches pour le transfert des données et d'autres broches pour les commandes de lecture/écriture. Reste à voir comment toutes ses broches sont reliées aux différents bus et au contrôleur mémoire. Ce qui va nous amener à parler des lignes de bit et des signaux de sélection de ligne. Il faut préciser que la distinction entre broches de commande et de données est ici très importante : les broches de données sont connectées indirectement au bus, alors que les broches de commande sont reliées au contrôleur mémoire. Aussi, nous allons devoir parler des deux types de broches dans des sections séparées.
La connexion des broches de données : les lignes de bit.
Afin de simplifier l'exposé, nous allons étudier une mémoire série dont le byte est de 1 bit. Une telle mémoire est dite bit-adressable, c’est-à-dire que chaque bit de la mémoire a sa propre adresse. Nous étudierons le cas d'une mémoire quelconque plus loin, et ce pour une raison : on peut construire une mémoire quelconque en améliorant le plan mémoire d'une mémoire bit-adressable, d'une manière assez simple qui plus est. Parler de ces dernières est donc un bon marche-pied pour aboutir au cas général.
Le cas d'une mémoire bit-adressable.
Une mémoire bit-adressable est de loin celle qui a le plan mémoire le plus rudimentaire. Quand on sélectionne un bit, avec son adresse, son contenu va se retrouver sur le bus de données. Dit autrement, la cellule mémoire va se connecter sur ce fils pour y placer son contenu. On devine donc comment est organisé le plan mémoire : il est composé d'un fil directement relié au bus de donnée, sur lequel les cellules mémoire se connectent si besoin. Le plan mémoire se résume donc à un ensemble de cellules mémoires dont l'entrée/sortie est connectée à un unique fil. Ce fil s'appelle la ligne de bit ("bitline" en anglais).
En réalité, peu de mémoires suivent actuellement le principe précédent. Les mémoires assez évoluées utilisent deux lignes de bit par colonne ! La première transmet le bit lu et l'autre son inverse, ce qui se marie bien avec le fait que certaines bascules fournissent le bit et son inverse sur deux broches distinctes. La mémoire utilise la différence de tension entre ces deux fils pour représenter le bit lu ou à écrire. Un tel codage est appelé un codage différentiel. L'utilité d'un tel codage assez difficile à expliquer sans faire intervenir des connaissances en électricité, mais tout est une histoire de fiabilité et de résistance aux parasites électriques.
Certaines mémoires ont amélioré les lignes de bit différentielles en interchangeant leur place à chaque cellule mémoire. La ligne de bit change donc de côté à chaque passage d'une cellule mémoire. Cette organisation porte le nom de lignes de bit croisées.
Les lignes de bit différentielles se marient assez mal avec les cellules mémoire de DRAM, qui n'ont pas de seconde sortie pour lire l'inverse du bit stocké. Malgré tout, l'usage de lignes de bit différentielle est possible, bien que compliqué, grâce à des techniques comme l'usage de cellules factices (nous en reparlerons plus bas). Cependant, il est possible d'utiliser une organisation intermédiaire entre des lignes de bit simple et des lignes différentielles, qui connecte des cellules consécutives comme illustré ci-dessous. On voit qu'il y a deux lignes de bit : la moitié des cellules est connectée à la première ligne, l'autre moitié à la seconde, avec une alternance entre cellules consécutives. Cela permet d'avoir moins de cellules mémoires connectées sur le même fil, ce qui améliore certains paramètres électriques des lignes de bit. Cette organisation porte le nom de ligne de bit repliée.
Le cas d'une mémoire quelconque (avec byte > 1).
Après avoir vu le cas des mémoires bit-adressables, il est temps d'étudier les mémoires quelconques, celles où un byte contient plus que 1 bit. Surprenamment, ces mémoires peuvent être conçues en utilisant plusieurs mémoires bit-adressables. Par exemple, prenons une mémoire dont le byte fait deux bits (ce qui est rare, convenons-en). On peut l'émuler à partir de deux mémoires de 1 bit : la première stocke le bit de poids faible de chaque byte, alors que l'autre stock le bit de poids fort. Et on peut élargir le raisonnement pour des bytes de 3, 4, 8, 16 bits, et autres. Par exemple, pour une mémoire dont le byte fait 64 bits, il suffit de mettre en parallèle 64 mémoires de 1 bit.
Mais cette technique n'est pas appliquée à la lettre, car il y a moyen d'optimiser le tout. En effet, on ne va pas mettre effectivement plusieurs mémoires bit-adressables en parallèle, car seuls les plans mémoires doivent être dupliqués. Si on utilisait effectivement plusieurs mémoires, chacune aurait son propre plan mémoire, mais aussi son propre contrôleur mémoire, ses propres circuits de communication avec le bus, etc. Or, ces circuits sont en fait redondants dans le cas qui nous intéresse.
Prenons le cas du contrôleur mémoire, qui reçoit l'adresse à lire/écrire et qui envoie les signaux de commande au plan mémoire. Avec N mémoires en parallèle, N contrôleurs mémoire recevront l'adresse et généreront les N mêmes signaux, qui seront envoyés à N plans mémoire distincts. Au lieu de cela, il est préférable d'utiliser un seul contrôleur mémoire, mais de dupliquer les signaux de commande en autant N exemplaires (autant qu'il y a de plan mémoire). Et c'est ainsi que sont conçues les mémoires quelconques : pour un byte de N bits, il faut prendre N plans mémoires de 1 bit. Cela demande donc d'utiliser N lignes de bits, reliée convenablement aux cellules mémoires. Le résultat est un rectangle de cellules mémoires, où chaque colonne est traversée par une ligne de bit. Chaque ligne du tableau/rectangle, correspond à un byte, c'est-à-dire une case mémoire.
Là encore, chaque colonne peut utiliser des lignes de bits différentielles ou croisées.
La connexion des broches de commande : le transistor et le signal de sélection.
Évidemment, les cellules mémoires ne doivent pas envoyer leur contenu sur la ligne de bit en permanence. En réalité, chaque cellule est connectée sur la ligne de bit selon les besoins. Les cellules correspondant au mot adressé se connectent sur la ligne de bit, alors que les autres ne doivent pas le faire. La connexion des cellules mémoire à la ligne de bit est réalisée par un interrupteur commandable, c’est-à-dire par un transistor appelé transistor de sélection. Quand la cellule mémoire est sélectionnée, le transistor se ferme, ce qui connecte la cellule mémoire à la ligne de bit. À l'inverse, quand une cellule mémoire n'est pas sélectionnée, le transistor de sélection se comporte comme un interrupteur ouvert : la cellule mémoire est déconnectée du bus.
La commande du transistor de sélection est effectuée par le contrôleur mémoire. Pour chaque ligne de bit, le contrôleur mémoire n'ouvre qu'un seul transistor à la fois (celui qui correspond à l'adresse voulue) et ferme tous les autres. La correspondance entre un transistor de sélection et l'adresse est réalisée dans le contrôleur mémoire, par des moyens que nous étudierons dans les prochains chapitres. Toujours est-il que le contrôleur mémoire génère, pour chaque octet, un bit qui dit si celui-ci est adressé ou non. Ce bit est appelé le signal de sélection. Le signal de sélection est envoyé à toutes les cellules mémoire qui correspondent au byte adressé. Vu que tous les bits d'un byte sont lus ou écrits en même temps, toutes les cellules correspondantes doivent être connectées à la ligne de bit en même temps, et donc tous les transistors de sélection associés doivent se fermer en même temps. En clair, le signal de sélection est partagé par toutes les cellules d'un même mot mémoire.
Le cas des lignes de bit simples et repliées.
Voyons comment les bitlines simples sont reliées aux cellules mémoires. Les mémoires 1T-DRAM n'ont qu'une seule broche entrée/sortie, sur laquelle on effectue à la fois les lectures et les écritures. Cela se marie très bien avec des bitlines simples, mais ça les rend incompatibles avec des bitlines différentielles. Le cas des DRAM à bitlines simples, avec une seule sortie, un seul transistor de sélection, est illustré ci-dessous. On peut noter que les cellules de SRAM peuvent malgré tout s’accommoder de bitlines simples : il suffit de connecter la sortie Q sur la bitline simple et ne pas connecter la sortie formula_1 à quoi que ce soit. On peut même en profiter pour supprimer le transistor de sélection de cette sortie, ce qui réduit le nombre de transistors à seulement 5.
La connexion des transistors de sélection pour des lignes de bit repliée n’est pas très différente de celle des lignes de bit simple. Elle est illustrée ci-dessous.
Le cas des lignes de bit différentielles.
Le cas des mémoires SRAM est de loin le plus simple à comprendre. Celles-ci utilisent toutes (ou presque) des bitlines différentielles, chose qui se marie très bien avec l'interface des cellules SRAM. Rappelons que celle-ci possèdent deux broches pour les données : une broche Q sur laquelle on peut lire ou écrire un bit, et une broche complémentaire sur laquelle on récupère l'inverse du bit lu. À chaque broche correspond un transistor de sélection différents. Dans ce cas, la sortie Q est connectée sur une bitline, alors que l'autre sortie complémentaire formula_1 l'est sur l'autre bitline.
Précisons que les DRAM se marient assez mal avec l'usage de lignes de bit différentielle, vu qu'elles n'ont pas de sortie complémentaire formula_1, mais n'ont qu'une seule sortie Q. Mais quelques astuces permettent d'utiliser des lignes de bit différentielles sur ces mémoires. La plus connue est de loin l'utilisation de cellules factices ("dummy cells"), des cellules mémoires vides placées aux bouts des lignes de bit. Lors d'une lecture, ces cellules vides se remplissent avec l'inverse du bit à lire. La ligne de bit inverse (celle qui contient l'inverse du bit) est alors remplie avec le contenu de la cellule factice, ce qui donne bien un signal différentiel. Le bit inversé est fournit par une porte logique qui inverse la tension fournie par la cellule mémoire. Cette tension remplis alors la cellule factice, avec l'inverse du bit lu.
Le cas des cellules mémoires double port.
Après avoir vu les cellules mémoire "normales" plus haut, il est temps de passer aux cellules mémoire de type double port. Pour simplifier, les cellules double port possèdent une sortie pour les lectures et une entrée pour les écritures, toutes deux d'un bit. On peut les utiliser pour concevoir des mémoires double port, mais aussi des mémoires simple port.
Cette particularité est exploitée pour créer des mémoires double-port bit-adressables, qui ont une broche pour les lectures et une autre pour les écritures. Le plan mémoire contient alors deux lignes de bit, une pour la broche de lecture et une autre pour la broche d'écriture. Le transistor de lecture est connecté à la ligne de bit de lecture, alors que celui pour l'écriture est relié à la ligne de bit d'écriture.
Pour les mémoires simple port, c'est-à-dire avec une seule broche qui sert à la fois pour les lectures et écritures, les deux transistors sont reliés à la même ligne de bit. Ils vont s'ouvrir ou se fermer selon les besoins, sous commande du contrôleur mémoire.
Dans les deux cas, le contrôleur mémoire est relié directement aux transistors de sélection. Il doit générer à la fois les signaux d'autorisation de lecture que ceux pour l'écriture. Ces deux signaux peuvent être déduit du bit de sélection et du bit R/W, comme vu dans le chapitre précédent. 
L'amplificateur de tension.
Quand on connecte une cellule mémoire à une ligne de bit, c'est à la cellule mémoire de fournir le courant pour mettre la ligne à 0 ou à 1. Mais dans certains cas, la cellule mémoire ne peut pas fournir assez courant pour cela. Cela arrive surtout sur les mémoires DRAM, basées sur un condensateur. Ces condensateurs ont une faible capacité et ne peuvent pas conserver beaucoup d'électrons, surtout sur les mémoires modernes. Du fait de la miniaturisation, les condensateurs des DRAM actuelles ne peuvent stocker que quelques centaines d'électrons, parfois beaucoup moins. Autant dire que la vidange du condensateur dans la ligne de bit ne suffit pas à la mettre à 1, même si la cellule mémorisait bien un 1. La lecture crée à peine une tension de quelques millivolts dans la ligne de bit, pas plus. Mais il y a une solution : amplifier la tension de quelques millivolts induite par la vidange du condensateur sur le bus. Pour cela, il faut donc placer un dispositif capable d'amplifier cette tension, bien nommé amplificateur de lecture.
L’amplificateur utilisé n'est pas le même avec des lignes de bit simples et des lignes de bit différentielles. Dans le cas différentiel, l'amplificateur doit faire la différence entre les tensions sur les deux lignes de bit et traduire cela en un niveau logique. C'est l'amplificateur lui-même qui fait la conversion entre codage différentiel (sur deux lignes de bit) et codage binaire. Pour le distinguer des autres amplificateurs, il porte le nom d'amplificateur différentiel. L'amplificateur différentiel possède deux entrées, une pour chaque ligne de bit, et une sortie. Dans ce qui va suivre, les entrées seront notées formula_4 et formula_5, la sortie sera notée formula_6. L’amplificateur différentiel fait la différence entre ces deux entrées et amplifie celle-ci. En clair :
Il faut noter qu'un amplificateur différentiel peut fonctionner aussi bien avec des lignes de bit différentielles qu'avec des lignes de bit simples. Avec des lignes de bit simples, il suffit de placer l'autre entrée à la masse, au 0 Volts, et de n'utiliser qu'une seule sortie.
Il existe de nombreuses manières de concevoir un amplificateur différentiel, mais nous n'allons aborder que les circuits les plus simples. Dans les grandes lignes, il existe deux types d'amplificateurs de lecture : ceux basés sur des bascules et ceux basés sur une paire différentielle. Bizarrement, vous verrez que les deux ont une certaine ressemblance avec les cellules de SRAM ! Il faut dire qu'une porte NON, fabriquée avec des transistors, est en réalité un petit amplificateur spécialisé, chose qui tient au fonctionnement de son circuit.
L'amplificateur de lecture à paire différentielle.
Le premier type d'amplificateur que nous allons voir est fabriqué à partir de transistors bipolaires. Pour rappel, un transistor bipolaire contient deux entrées, la base et l'émetteur, et une sortie appelée le collecteur. Il prend en entrée un courant sur sa base et fournit un courant amplifié sur l'émetteur. Pour cela, il faut fournir une source de courant sur le collecteur, obtenue en faisant une tension aux bornes d'une résistance.
La paire différentielle est composée de deux amplificateurs de ce type, reliés à un générateur de courant. La résistance est placée entre la tension d'alimentation et le transistor, alors que le générateur de courant est placé entre le transistor et la tension basse (la masse, ou l'opposé de la tension d'alimentation, selon le montage). Le circuit ci-contre illustre le circuit de la paire différentielle.
Précisons que la résistance mentionnée précédemment peut être remplacée par n'importe quel autre circuit, l'essentiel étant qu'il fournisse un courant pour alimenter l'émetteur. Il en est de même que le générateur de courant. Dans le cas le plus simple, une simple résistance suffit pour les deux. Mais ce n'est pas cette solution qui est utilisée dans les mémoires actuelles. En effet, intégrer des résistances est compliqué dans les circuits à semi-conducteurs modernes, et les mémoires RAM en sont. Aussi, les résistances sont généralement remplacées par des circuits équivalents, qui ont le même rôle ou qui peuvent remplacer une résistance dans le montage voulu.
Les deux résistances du haut sont remplacées chacunes par un "miroir de courant", à savoir un circuit qui crée un courant constant sur une sortie et le recopie sur une seconde sortie. Il existe plusieurs manières de créer un tel miroir de courant avec des transistors MOS/CMOS, la plus simple étant illustrée ci-dessous (le miroir de courant est dans l'encadré bleu). On pourrait aborder le fonctionnement d'un tel circuit, pourquoi il fonctionne, mais nous n'en parlerons pas ici. Cela relèverait plus d'un cours d'électronique analogique, et demanderait de connaître en détail le fonctionnement d'un transistor, les équations associées, etc. L'avantage est que le miroir de courant fournit le même courant aux deux "bitlines", il égalise les courants dans les deux bitlines.
L'amplificateur de lecture à verrou.
Le second type d'amplificateur de lecture est l'amplificateur à verrou. Il amplifie une différence de tension entre les deux lignes de bit d'une colonne différentielle. Les deux colonnes doivent être préchargées à Vdd/2, à savoir la moitié de la tension d'alimentation. La raison à cela deviendra évidente dans les explications qui vont suivre. Toujours est-il que ce circuit a besoin qu'un circuit dit de précharge s'occupe de placer la tension adéquate sur les lignes de bit, avant toute lecture ou écriture. Nous reparlerons de ce circuit de précharge dans les sections suivantes, vers la fin de ce chapitre. Cela peu paraître peu pédagogique, mais à notre décharge, sachez que le circuit de précharge et l'amplificateur de lecture sont intimement liés. Il est difficile de parler de l'un sans parler de l'autre et réciproquement. Pour le moment, tout ce que vous avez à retenir est qu'avant toute lecture, les lignes de bit sont chargées à Vdd/2, ce qui permet à l'amplificateur à verrou de fonctionner correctement.
Le circuit de l'amplificateur de lecture à verrou.
L'amplificateur à verrou est composé de deux portes NON reliées tête-bêche, comme dans une cellule de SRAM. Chaque ligne de bit est reliée à l'autre à travers une porte NON. Sauf que cette fois-ci, il n'y a pas toujours de transistors de sélection, ou alors ceux-ci sont placés autrement.
Le circuit complet est illustré ci-dessous, de même qu'une version plus détaillée avec des transistors CMOS. Du fait de son câblage, l'amplificateur à verrou a pour particularité d'avoir des broches d'entrées qui se confondent avec celles de sortie : l'entrée et la sortie pour une ligne de bit sont fusionnées en une seule broche. L'utilisation d'inverseurs explique intuitivement pourquoi il faut précharger les lignes de bit à Vdd/2 : cela place la tension dans la zone de sécurité des deux inverseurs, là où la tension ne correspond ni à un 0, ni à un 1. Le fonctionnement du circuit dépend donc du fonctionnement des transistors, qui servent alors d'amplificateurs.
On peut noter que cet amplificateur est parfois fabriqué avec des transistors bipolaires, qui consomment beaucoup de courant. Mais même avec des transistors MOS, il est préférable de réduire la consommation électrique du circuit, quand bien même ceux-ci consomment peu. Pour cela, on peut désactiver l’amplificateur quand on ne l'utilise pas. Pour cela, on entoure l'amplificateur avec des transistors qui le débranchent, le déconnectent si besoin.
Le fonctionnement de l'amplificateur à verrou.
Expliquer en détail le fonctionnement de l'amplificateur à verrou demanderait de faire de l'électronique assez poussée. Il nous faudrait détailler le fonctionnement d'un transistor quand il est utilisé en tant qu'amplificateur, donner des équations, et bien d'autres joyeusetés. À la place, je vais donner une explication très simplifiée, que certains pourraient considérer comme fausse (ce qui est vrai, dans une certaine mesure).
Avant toute chose, précisons que les seuils pour coder un 0 ou un 1 ne sont pas les mêmes entre l’entrée d'une porte NON et sa sortie. Ils sont beaucoup plus resserrés sur l'entrée, la marge de sécurité entre 1 et 0 étant plus faible. Un signal qui ne correspondrait pas à un 0 ou un 1 en sortie peut l'être en entrée.
Le fonctionnement du circuit ne peut s'expliquer correctement qu'à partir du rapport entre tension à l'entrée et tension de sortie d'une porte NON. Le schéma ci-dessous illustre cette relation. On voit que la porte logique amplifie le signal d'entrée en plus de l'inverser. Pour caricaturer, on peut décomposer cette caractéristique en trois parties : deux zones dites de saturation et une zone d'amplification. Dans la zone de saturation, la tension est approximativement égale à la tension maximale ou minimale, ce qui fait qu'elle code pour un 0 ou un 1. Entre ces deux zones extrêmes, la tension de sortie dépend linéairement de la tension d'entrée (si on omet l'inversion).
Quand on place deux portes NON l'une à la suite de l'autre, le résultat est un circuit amplificateur, dont la caractéristique est illustrée dans le second schéma. On voit que l'amplificateur amplifie la différence de tension entre VDD/2 et la tension d'entrée (sur la ligne de bit).
Si on regarde le circuit complet, on s’aperçoit que chaque ligne de bit est bouclée sur elle-même, à travers cet amplificateur. Cela fait boucler la sortie de l'amplificateur sur son entrée : la tension de base est alors amplifiée une fois, puis encore amplifiée, et ainsi de suite. Au final, les seuls points stables du montage sont la tension maximale ou la tension minimale, soit un 0 ou un 1, ou la tension VDD/2.
Ceci étant dit, on peut enfin comprendre le fonctionnement complet du circuit d'amplification. Commençons l'explication par la situation initiale : la ligne de bit est préchargée à VDD/2, et la cellule mémoire est déconnectée des lignes de bit. La ligne de bit est préchargée à VDD/2, l'amplificateur a sa sortie comme son entrée égales à VDD/2 et le circuit est parfaitement stable. Ensuite, la cellule mémoire à lire est connectée à la ligne de bit et la tension va passer au-dessous ou au-dessus de VDD/2. Nous allons supposer que celle-ci contenait un 1, ce qui fait que sa connexion entraîne une montée de la tension de la ligne de bit. La tension ne va cependant pas monter de beaucoup, mais seulement de quelques millivolts. Cette différence de tension va être amplifiée par les deux portes logiques, ce qui amplifie la différence de tension. Et rebelote : cette différence amplifiée est ré-amplifiée par le montage, et ainsi de suite jusqu’à ce que le circuit se stabilise soit à 0 soit à 1.
L'optimisation du temps de charge/décharge des lignes de bit.
Si les lignes de bit sont de simples fils conducteurs passifs, cela ne veut pas dire qu'ils n'ont pas d'influence sur les lectures et écritures. En réalité, ils jouent un grand rôle dans la rapidité des accès mémoire, pour des raisons techniques. Selon leur longueur, la tension va prendre plus ou moins de temps pour s'établir dans la ligne de bit, ce qui impacte directement les performances de la mémoire. Diverses techniques ont étés inventées pour résoudre ce problème, la plus importante étant l'utilisation d'un circuit dit de pré-charge, que nous allons étudier maintenant.
Les lignes de bit ne sont pas des fils parfaits : non seulement ils ont une résistance électrique, mais ils se comportent aussi comme des condensateurs (dans une certaine mesure). Nous n'expliquerons pas dans la physique de ce phénomène, mais allons simplement admettre qu'un fil électrique se modélise bien en mettant une résistance R en série avec un condensateur C : le circuit obtenu est un circuit RC. Le condensateur, appelée capacité parasite, n’apparaît que lorsque la tension de la ligne de bit change en passant de 0 à 1 ou inversement. Ce qui n'arrive que lors d'une lecture ou écriture, cela va de soit. Lorsque l'on change la tension en entrée d'un tel montage, la tension de sortie met un certain temps avant d'atteindre la valeur d'entrée. Ce qui est illustré dans les deux schémas ci-dessous, pour la charge (passage de 0 à 1) et la décharge (passage de 1 à 0). La variation est d'ailleurs exponentielle. On estime qu'il faut un temps égal formula_8, avec R la valeur de la résistance et C celle du condensateur. En clair : la ligne de bit met un certain temps avant que la tension atteigne celle qui correspond au bit lu ou à écrire.
L'organisation du plan mémoire.
Une première idée pour optimiser le temps RC est de diminuer la résistance de la ligne. Il se trouve que celle-ci est proportionnelle à la longueur de la ligne de bit : plus la ligne de bit est longue, plus la résistance R sera élevée. On voit donc une première solution pour réduire la résistance, et donc le temps RC : réduire la taille des lignes de bit. Les petites mémoires, avec peu de cellules sur une colonne, ont des lignes de bit plus petites et sont donc plus rapides. Cela explique en partie pourquoi les temps d'accès des mémoires varient selon la capacité, chose que nous avons abordé il y a quelques chapitres. De même, à capacité égale, il vaut mieux utiliser des bytes large, pour réduire la taille des colonnes.
L'agencement en colonne de donnée ouvertes.
Mais d'autres optimisations du plan mémoire permettent d'obtenir des lignes de bit plus petites, à capacité et largeur de byte inchangée. Par exemple, on peut placer l'amplificateur de lecture au milieu du plan mémoire, et non au bout. En faisant ainsi, on doit couper la ligne de bit en deux, chaque moitié étant placée d'un côté ou de l'autre de l’amplificateur. La colonne contient ainsi deux lignes de bits séparées, chacune ayant une longueur réduite de moitié. Cette organisation est dite en colonne de donnée ouvertes. Mais cette organisation a un défaut : il est difficile d'implémenter l'amplificateur au milieu de la mémoire. Le nombre de fils qui doivent passer par le milieu de la RAM est important, rendant le câblage compliqué. De plus, les perturbations électromagnétiques ne touchent pas de la même manière chaque côté de la mémoire et l'amplificateur peut donner des résultats problématiques à cause d'elles.
Il est aussi possible de répartir les amplificateurs de tension autrement. On peut mélanger les organisations en colonne de données ouvertes et "normales", en mettant les amplificateurs à la fois au milieu de la RAM et sur les bords. Une moitié des amplificateurs est placée au milieu du plan mémoire, l'autre moitié est placée sur les bords. On alterne les lignes de bits connectée entre amplificateurs selon qu’ils sont sur les bords ou au milieu. L'organisation est illustrée ci-dessous.
La pré-charge des lignes de bit.
Une autre solution, beaucoup plus ingénieuse, ne demande pas de modifier la longueur des lignes de bit. À la place, on rend leur charge plus rapide en les pré-chargeant. Sans pré-charge, la ligne de bit est à 0 Volts avant la lecture et la lecture altère cette tension, que ce soit pour la laisser à 0 (lecture d'un 0), ou pour la faire monter à la tension maximale Vdd (lecture d'un 1). Le temps de réaction de la ligne de bit dépend alors du temps qu'il faut pour la faire monter à Vdd. Avec la pré-charge, la ligne de bit est chargée avant la lecture, de manière à la mettre à la moitié de Vdd. La lecture du bit fera descendre celle-ci à 0 (lecture d'un 0) ou la faire grimper à Vdd (lecture d'un 1). Le temps de charge ou de décharge est alors beaucoup plus faible, vu qu'on part du milieu.
On peut penser qu'il faudra deux fois moins de temps, mais la réalité est plus complexe (regardez les graphes de charge/décharge situés plus haut). De plus, il faut ajouter le temps mis pour précharger la ligne de bit, qui est à ajouter au temps de lecture proprement dit. Sur la plupart des mémoires, la pré-charge n'est pas problématique. Il faut dire qu'il est rare que la mémoire soit accédé en permanence et il y a toujours quelques temps morts pour pré-charger la ligne de bit. On verra que c'est notamment le cas sur les mémoires DRAM synchrones modernes, comme les SDRAM et les mémoires DDR. Mais passons...
Les circuits de précharge.
La pré-charge d'une ligne de bit se fait assez facilement : il suffit de connecter la ligne de bit à une source de tension qui a la valeur adéquate. Par exemple, une mémoire qui se pré-charge à Vdd a juste à relier la ligne de bit à la tension d'alimentation. Mais attention : cette connexion doit disparaître quand on lit ou écrit un bit dans les cellules mémoire. Sans cela, le bit envoyé sur la ligne de bit sera perturbé par la tension ajoutée. Il faut donc déconnecter la ligne de bit de la source d'alimentation lors d'une lecture écriture. On devine rapidement que le circuit de pré-charge est composé d'un simple interrupteur commandable, placé entre la tension d'alimentation (Vdd ou Vdd/2) et la ligne de bit. Le contrôleur mémoire commande cet interrupteur pour précharger la ligne de bit ou stopper la pré-charge lors d'un accès mémoire. Si un seul transistor suffit pour les lignes de bit simples, deux sont nécessaires pour les lignes de bit différentielles ou croisées. Ils doivent être ouvert et fermés en même temps, ce qui fait qu'ils sont commandés par un même signal.
L'égaliseur de tension.
Pour les lignes de bit différentielles et croisées, il se peut que les deux lignes de bit complémentaires n'aient pas tout à fait la même tension suite à la pré-charge. Pour éviter cela, il est préférable d'ajouter un circuit d'égalisation qui égalise la tension sur les deux lignes. Celui-ci est assez simple : c'est un interrupteur commandable qui connecte les deux lignes de bit lors de la pré-charge. Là encore, un simple transistor suffit. L'égalisation et la pré-charge ayant lieu en même temps, ce transistor est commandé par le même signal que celui qui active le circuit de précharge. Le circuit complet, qui fait à la fois pré-charge et égalisation des tensions, est représenté ci-dessous.
Annexe : l'attaque "rowhammer".
Vous connaissez maintenant comment fonctionnent les cellules mémoires et le plan mémoire, ce qui fait que vous avez les armes nécessaires pour aborder des sujets assez originaux. Profitons-en pour aborder une faille de sécurité présente dans la plupart des mémoires DRAM actuelles : l'attaque "row hammer". Vous avez bien entendu : il s'agit d'une faille de sécurité matérielle, qui implique les mémoires RAM, qui plus est. Voilà qui est bien étrange. D'ordinaire, quand on parle de sécurité informatique, on parle surtout de failles logicielles ou de problèmes d'interface chaise-clavier. La plupart des attaques informatiques sont des attaques d’ingénierie sociale où on profite de failles humaines pour obtenir un mot de passe ou toute autre information confidentielle, suivies par les failles logicielles, les virus, malwares et autres méthodes purement logicielles. Mais certaines failles de sécurités sont purement matérielles et profitent de bugs présents dans le matériel pour fonctionner. Car oui, les processeurs, mémoires, bus et périphériques peuvent avoir des bugs matériels qui sont généralement bénins, mais que des virus, logiciels ou autres malware peuvent exploiter pour commettre leur méfaits.
L'attaque "row hammer", aussi appelée attaque par martèlement de mémoire, utilise un bug de conception des mémoires DRAM. Le bug en question tient dans le fait que les cellules mémoires ne sont pas parfaites et que leur charge électrique tend à fuir. Ces fuites de courant se dispersent autour de la cellule mémoire et tendent à affecter les cellules mémoires voisines. En temps normal, cela ne pose aucun problème : les fuites sont petites et l'interaction électrique est limitée. Cependant, des hackers ont réussit à exploiter ce comportement pour modifier le contenu d'une cellule mémoire sans y accèder. En accédant d'une manière bien précise à une ligne de la mémoire, on peut garantir que les fuites de courant deviennent signifiantes, suffisamment pour recopier le contenu d'une ligne mémoire dans les lignes mémoires voisines. Pour cela, il faut accéder un très grand nombre de fois à la cellule mémoire en question, ce qui explique pourquoi cette attaque s'appelle le "martèlement" de mémoire. Une autre méthode, plus fiable, est d’accéder à deux lignes de mémoires, qui prennent en sandwich la ligne mémoire à altérer. On accède successivement à la première, puis la seconde, avant de reprendre au début, et cela un très grand nombre de fois par secondes.
Modifier plusieurs bytes sans y accéder, mais en accédant à leurs voisins est une faille exploitable par les pirates informatiques. L'intérêt est de contourner les protections mémoires liées au système d'exploitation. Sur les systèmes d'exploitation modernes, chaque programme se voit attribuer certaines portions de la mémoire, auxquelles il est le seul à pouvoir accéder. Des mécanismes de protection mémoire intégré dans le processeur permettent d'isoler la mémoire de chaque programme, comme nous le verrons dans le chapitre sur la mémoire virtuelle. Mais avec "row hammer", les accès à un byte attribué à un programme peuvent déborder sur les bytes d'un autre programme, avec des conséquences assez variables. Par exemple, un virus présent en mémoire pourrait interagir avec le byte qui mémorise un mot de passe ou une clé de sécurité RSA, ou toute donnée confidentielle. Il pourrait récupérer cette information, ou alors la modifier pour la remplacer par une valeur connue et l'attaquant.
La faille "row hammer" est d'autant plus simple que la physique des cellules mémoire est médiocre. Les progrès de la miniaturisation rendent cette attaque de plus en plus facilement exploitable, les fuites étant d'autant plus importantes que les cellules mémoires sont petites. Mais exploiter cette attaque est compliqué, car il faut savoir à quelle adresse se situe a donnée à altérer, sans compter qu'il faut avoir des informations sur l'adresse des cellules voisines. Rappelons que la répartition physique des adresses/bytes dépend de comment la mémoire est organisée en interne, avec des banques, rangées et autres. Deux adresses consécutives ne sont pas forcément voisines sur la barrette de mémoire et l relation entre deux adresses de cellules mémoires voisines n'est pas connue avec certitude tant elle varie d'un système mémoire à l'autre.
Les solutions pour mitiger l'attaque "row hammer" sont assez limitées. Une première solution est d'utiliser les techniques de correction et de détection d'erreur comme l'ECC, mais là l'effet est limité. Une autre solution est de rafraichir la mémoire plus fréquemment, mais cela a un effet assez limité, sans compter que cela a un impact sur les performance et la consommation d'énergie de la RAM. Les concepteurs de matériel ont dû inventer des techniques spécialisées, comme le " pseudo target row refresh" d'Intel ou le "target row refresh" des mémoires LPDDR4. Ces techniques consistent, pour simplifier, à détecter quand une ligne mémoire est accédée très souvent, à rafraichir les lignes de mémoire voisines assez régulièrement. L'effet sur les performances est limité, mais cela demande d'intégrer cette technique dans le contrôleur mémoire externe/interne.