Adressage de la console



Présentation

La console est un dispositif de traitement de l'information, elle doit donc pouvoir la manipuler, ici sous une forme numérique. Comme évoqué dans son architecture matérielle, notre console disposera de plusieurs mémoires, qu'il s'agit de pouvoir exploiter. Pour cela, il faut a minima être à même de les désigner.

Les quatre mémoires des sous-systèmes

Prenons des adresses codées en 32 bits, qui sera très probablement la taille retenue. On peut adresser 2^32 = 4 294 967 296 cellules de mémoire distinctes, ce qui est largement suffisant pour une console, même en prenant des mots de 8 bits comme cellule élémentaire : cela ferait plus de 4 Go adressables. Un autre choix courant est de retenir des mots de 32 bits. Rappelons qu'espace d'adressage et taille du mot adressé sont complètement indépendants.

D'après l'architecture vue sous l'angle du chipset, il y a quatre plages logiques distinctes à adresser, les mémoires principales :

Comme le noyau devra probablement embarquer plus de données que ses comparses, sa plage comptera quadruple. Comme il serait intéressant de réserver une plage au système lui-même (qui pourrait par exemple être placé sur une ROM annexe), cela fera au total 4 plages simples et une quadruple. Il est alors commode de diviser l'espace d'adressage par 4 + 4 = 8 = 2^3.

Cela fait ainsi, pour chaque plage, une taille maximale de 2^29 = 536 870 812 cellules adressables, ce qui reste très confortable même avec des mots de 8 bits (512 Mo). Bien évidemment, cette valeur est une borne supérieure, et dans les faits seule une fraction de l'espace d'adressage correspondra à des cellules mémoires effectives.

Les plages d'adresse

En rentrant un peu plus dans les détails, voici les différentes tailles réelles, envisagées pour chacune des zones mémoire :

Répartition de l'espace d'adressage
Mémoire Type Taille réelle Taille maximale Adresse de début Adresse de fin réelle Adresse de fin maximale
Système
ROM
256 Mo
512 Mo
0x0000-0000
0x0FFF-FFFF
0x1FFF-FFFF
Principale
RAM
256 Mo
2 Go
(2 048 Mo)
0x2000-0000
0x2FFF-FFFF
0x9FFF-FFFF
Vidéo
RAM
128 Mo
512 Mo
0xA000-0000
0xA7FF-FFFF
0xBFFF-FFFF
Audio
RAM
64 Mo
512 Mo
0xC000-0000
0xC3FF-FFFF
0xDFFF-FFFF
Entrée-sortie
RAM
64 Mo
512 Mo
0xE000-0000
0xE3FF-FFFF
0xFFFF-FFFF

Les plages sont à considérer bornes incluses. Cela fait un total de 256 Mo de ROM et de 512 Mo de RAM.

Gestion des adresses

Un décodeur classique permet de déterminer quelle plage mémoire une adresse désigne.

Analyse

En reprenant des adresses codées sur 32 bits, en choisissant de prendre par convention les bits de poids forts à gauche, une adresse peut se représenter sous la forme de quatre octets :

a b c d

Quand, à partir d'une adresse, il s'agit de déterminer quel composant est référencé (c'est-à-dire ici quelle mémoire est visée), les plages du tableau précédent montrent que les octets de poids faibles c et d ne sont pas discriminants, que b l'est partiellement, et a complètement. Ainsi, pour vérifier que l'adresse 0xA142-FE81 désigne bien une adresse de la mémoire vidéo, il suffit de vérifier que

0xA000 < 0xA142 < 0xC000
pour trancher par l'affirmative. Remarquons que cette adresse se trouve être valide, c'est-à-dire qu'elle correspond à une case mémoire réelle.

Fonctions logiques

Il est alors possible d'écrire les fonctions logiques qui, en fonction des bits de a et de b, déterminent si une mémoire donnée est visée.

En gardant à l'esprit que les bits, de gauche à droite, vont du poids fort au poids faible, en prenant la convention que ? désigne une valeur quelconque, établissons sur un exemple simple une fonction booléenne de détection. Celle-ci déterminera si, pour une adresse donnée, la mémoire système est référencée.

Soit une adresse de la forme précédente

a b c d
explicitée :
a15-a14-a13-12-a11-[...]-a3-a2-a1-a0 b15-b14-[...]-b1-b0 c15-[...]-c0 d15-[...]-d0

Du point de vue du décodeur, qui n'a pas à dépendre de la quantité de mémoire réellement installée, mais de la quantité de mémoire potentielle (maximale), la mémoire système s'étend de l'adresse 0x0000-0000 à l'adresse 0x1FFF-FFFF. Donc une adresse référence la mémoire système si et seulement si elle est de la forme 0x0???-???? ou 0x1???-????, c'est-à-dire si et seulement si, en reprenant la convention, on a : { a15, a14, a13, a12 } = { 0, 0, 0, 0 } ou { 0, 0, 0, 1 }, pour former 0x0 ou 0x1.

Si . désigne le "et" logique, * le "ou" logique, et - le "non" logique, 1 la valeur vraie et 0 la valeur fausse, alors notre fonction déterminant si l'adresse désigne la mémoire système est :

MemSys = (-a15).(-a14).(-a13)

Elle se traduit littéralement par : MemSys est vrai (vaut 1) si et seulement si a15 et a14 et a13 sont faux (quel que soit a13, et les bits restants).

Sur des cas plus compliqués, la fonction serait au pire une conjonction (une suite de "et") de disjonctions (une suite de "ou") formant la table de vérité nécessaire (ex : (a15.(-a14)) * (a15.a14.a13.(-a12)) * () ...), elle ne serait donc pas fondamentalement différente.

Conception du circuit

Vient alors la dernière étape de conception du circuit logique, l'assemblage de portes élémentaires :

Circuit de sélection de la mémoire système

Il a été ici considéré que l'on disposait de portes "et" à deux entrées non-inverseuses, et d'inverseurs.

Conversion en adresse locale

Dernière opération à mener à ce niveau : la traduction d'une adresse globale en une adresse locale, c'est-à-dire relative à un composant de mémoire (une barrette). En effet notre exemple d'adresse, 0xA142-FE81 est censé désigner une cellule de la mémoire vidéo. Or cette mémoire commence à compter ses cellules à partie de l'adresse 0 (0x0000-0000), et non pas de l'adresse globale virtuelle qui lui a été assignée, 0xA000-0000.

Pour donc que ce composant ne voit que des adresses décrites dans son référentiel, il est nécessaire de les lui traduire, en l'occurrence en soustrayant de l'adresse globale l'adresse de début de la plage concernée, ce qui donne l'adresse locale 0x0142-FE81.

Cela pose un petit problème dans la mesure où la soustraction électronique est une opération chère et compliquée, que l'on préférerait replacer par de simples opérations booléennes ou des décalages. Comme il ne semble pas facile de s'y ramener, et sachant qu'il y aurait finalement peu de valeurs à convertir (8 pour notre plage d'adressage la plus grande, celle de la mémoire principale, c'est-à-dire autant que de blocs de 2^28=256 Mo), une seule table associative par plage serait probablement la solution la plus élégante.

Dans cet exemple relatif à la mémoire principale, seul les quatre bits de plus fort poids de l'adresse sont touchés.

Préfixe d'adressage global
(a15-a13-a12-a11)
Traduction en adressage local
(soustraction de 0x2000-0000)
0x0010
0x0000
0x0011
0x0001
0x0100
0x0010
0x0101
0x0011
0x0110
0x0100
0x0111
0x0101
0x1000
0x0110
0x1001
0x0111

On voit tout naturellement la table de vérité et le circuit logique qui en découlent : en appelant e3-e2-e1-e0 les quatre bits de poids forts que doit voir la barrette de la mémoire principale (les autres bits restant tels quels), on obtient les fonctions logiques suivantes.

On remarquera qu'une sortie ne dépend pas des entrées (e3 est toujours à l'état faux, comme c'était visible en première colonne de traduction). Le circuit logique s'en déduit immédiatement, une simplification gagnant à être appliquée dans le cas de e2.

En effet, de part et d'autres du "ou" central, les deux expressions sont constituées de variables logiques opposées, ce qui surchargerait le circuit d'inverseurs (plus cher, plus long à monter, plus lent à s'exécuter, moins fiable). En remarquant, par exemple pour la branche de droite, que

a15.(-a14).(-a13) = - ( (-a15) * a14 * a13 ))
on réécrit e2 sous la forme plus simple à traduire en circuit : e2 = ( (-a15).a14.a13 ) * - ( (-a15) * a14 * a13 ))

Cela donne, in fine :

Unité logique de traduction


Pour simplifier le schéma, des portes à trois entrées ont été utilisées pour le "et" et pour le "ou", quand nécessaire. Les multiples inverseurs en cascade (pour c1 et c0) ne sont pas, contrairement aux apparences, inutiles. En prenant pour hypothèse que le temps de passage d'une porte est uniforme d'un type de porte à l'autre, ces inverseurs servent à éviter les décalages temporels pouvant survenir quand un bit produit d'un calcul comportant peu de portes est dans le même mot qu'un autre bit faisant l'objet d'un calcul plus compliqué, comportant plus de portes, et donc plus de retards : cela favorise la synchronisation des signaux logiques, un problème épineux quand les fréquences sont élevées.

Les étapes suivantes

Quelques étapes restent encore avant que le système d'adressage soit fonctionnel : il faut sélectionner les composants effectifs réalisant les fonctions logiques élémentaires (ex : choisir telle référence de tel constructeur qui propose sur une seule puce tant inverseurs avec tel brochage pour tel prix etc.), les agencer dans un circuit, le simuler et le valider. Ensuite il faudra le graver ou le faire graver (multiples étapes) avant de souder les composants et en tester le résultat. C'est un long processus (si l'on ne se contente pas de simulation) !





N'hésitez pas à nous faire part de votre avis !

Si vous avez des remarques à formuler, ou si vous disposez d'informations plus détaillées ou plus récentes que celles présentées dans ce document, si vous avez remarqué des erreurs, oublis, ou points insuffisamment traités, ou si vous avez envie d'apporter une aide, aussi petite soit-elle, envoyez-nous un courriel !




[Retour en haut de page]

Dernière mise à jour : 19 Août 2004