Billet #002 - 2 juin 2026
Exécution du premier programme et découverte de l'EEPROM
Le 6502 est installé sur une breadboard et j’ai validé son bon fonctionnement. Pour l’instant la valeur 0xEA est câblée en dure le bus. L’objectif d’aujourd’hui et de fournir au CPU des données dynamiques en fonction de l’adresse qu’il demande, de sorte à former un programme qui ait du sens. Classiquement c’est le rôle d’une puce mémoire. Mais dans un premier temps j’expérimente avec Arduino.
Données dynamiques
En plus des 4 lignes d’adresses utilisées jusque là, j’ajoute les 8 lignes du bus de données. Je connecte également le signal read/write pour détecter quand le CPU cherche à lire sur le bus.
Avant d’aller plus loin je retravaille le programme pour afficher les nouvelles données, et je fais également en sorte que ce soit l’Arduino qui génère le signal d’horloge. Ça permet de mieux coordonner les actions sur le bus en fonction de l’horloge, et au passage de pouvoir régler librement la vitesse. Le module à base de 555 que j’utilise, bien que réglable, ne va pas aussi bas que je voudrais.
Ces modifications en place, j’écris un code qui envoie 0xEA sur le bus lorsque le CPU est en lecture.
Maintenant que je suis capable d’envoyer des données dynamiques au CPU, je peux essayer de lui faire exécuter une petit programme. Très petit en l’occurrence puisque comme je travaille avec seulement 4 bits d’adresse on ne peut fournir que 16 octets au total, dans lesquels il faut compter les deux bits d’adresse du vecteur reset situés aux adresses 0xC et 0xD. Techniquement j’aurais pu ajouter un fil ou deux ce qui pourrait respectivement doubler ou quadrupler l’espace disponible, mais je trouvais que c’était un bon challenge.
Pour que ce soit intéressant, je choisi des instructions qui provoquent des accès à la mémoire en lecture et en écriture. L’instruction LDA (Load Accumulator) charge dans l’accumulateur la valeur stockée à l’adresse indiquée. ADC (Add with Carry) additionne à l’accumulateur la valeur lue à l’adresse spécifiée. STA (Store Accumulator) écrit le contenu de l’accumulateur en mémoire. Chacun de ces trois instructions prennent en paramètre l’adresse mémoire à utiliser sur deux octets, les poids faibles en premier. Avec 3 instructions on a déjà rempli 9 octets. Immédiatement après je place les deux octets de données qui seront additionnés par le CPU. Il reste juste un octet libre avant le vecteur de reset.
Voici le programme final (données en hexadécimal):
| Addr | Instruction | Données |
|---|---|---|
0x0 |
LDA $0009 |
AD 09 00 |
0x3 |
ADC $000A |
6D 0A 00 |
0x6 |
STA $000B |
8D 0B 00 |
0x9 |
28 |
|
0xA |
02 |
|
0xB |
||
0xC |
00 |
|
0xD |
00 |
|
0xE |
||
0xF |
Explications :
LDA$0009: Charger la valeur à l’adresse0x09dans l’accumulateurADC$000A: Ajouter la valeur à l’adresse0x0Aà la valeur présente dans l’accumulateurSTA$000B: Écrire la valeur présente dans l’accumulateur à l’adresse0x0B
On devrait donc voir passer sur le bus les événements suivants :
| Addr | R/W | Data | Événement |
|---|---|---|---|
| 0xC | R | 00 | Lecture du vecteur reset |
| 0xD | R | 00 | |
| 0x0 | R | AD | Lecture de la première instruction |
| 0x1 | R | 09 | |
| 0x2 | R | 00 | |
| 0x9 | R | 28 | Lecture de la donnée |
| 0x3 | R | 6D | Lecture de la deuxième instruction |
| 0x4 | R | 09 | |
| 0x5 | R | 00 | |
| 0xA | R | 02 | Lecture de la donnée |
| 0x6 | R | 8D | Lecture de la troisième instruction |
| 0x7 | R | 0B | |
| 0x8 | R | 00 | |
| 0xB | W | 2A | Ecriture de la donnée |
Le résultat correspond bien à ce qui est attendu :
Le code Arduino est disponible sur GitHub.
Découverte de l’EEPROM
L’Arduino est bien sympatique, mais dans le système final les données sont stockées dans une puce mémoire. J’utilise ici une puce EEPROM AT28C256. C’est une mémoire de 32ko destinée à être utilisée en lecture seule, mais qu’on peut effacer et programmer éléctroniquement.
Je veux commencer par la base, en faisant des lectures et écritures en manipulant directement les signaux de contrôle. Sur une breadboard je connecte huit LEDs au bus de données de la ROM et je force toutes les lignes d’adresse à zéro à l’aide de cavaliers, sauf les quatre bits de poids faible que je connecte avec des fils de connexion repositionnables facilement.
Il y a 3 signaux de contrôle sur la ROM :
| Signal | Signification | Usage |
|---|---|---|
/CE |
Chip Enabled | Active la puce |
/OE |
Output Enabled | Active la sortie de données |
/WE |
Write Enabled | Déclenche l’écriture |
Sur la breadboard je connecte CE à 0, et je gère manuellement OE et WE.
Je commence par tester la lecture. Je mets /OE à 0 pour activer la sortie et /WE à 1 pour être en mode lecture, et je fais défiler les adresses en repositionnant les 4 fils prévus à cet effet. Les LEDs affichent le contenu stocké dans la mémoire à chaque adresse.
Voici mon relevé :
| Adresse | Donnée |
|---|---|
0x0000 |
00 |
0x0001 |
FF |
0x0002 |
00 |
0x0003 |
FF |
0x0004 |
00 |
0x0005 |
FF |
0x0006 |
00 |
0x0007 |
FF |
0x0008 |
FF |
0x0009 |
FF |
0x000A |
FF |
0x000B |
FF |
0x000C |
FF |
0x000D |
FF |
0x000E |
FF |
0x000F |
FF |
Je teste maintenant une écriture. Le fonctionnement est le suivant : En temps normal (mode lecture) /WE est à 1. Lorsque /WE passe à 0, la puce capture la valeur présente sur le bus d’adresse. Quand /WE repasse à 1 elle capture la donnée et procède à l’écriture dans la mémoire.
Je commence par désactiver la sortie en plaçant /OE à 1. Je configure l’adresse 0, puis je forme la valeur 0xEA sur le bus de données à l’aide de cavaliers, et je vérifie la valeur sur les LEDs. Enfin je fais passer /WE à 0 puis de nouveau à 1.
Je repasse en mode lecture en enlevant les cavalier sur les lignes de données, je remet /OE à 0, et je vois bien la valeur 0xEA apparaître sur les LEDs. Je regarde les autres adresses et constate que je retrouve bien les valeurs relevées précédemment à l’éxception de l’adresse 0 qui affiche désormais 0xEA. Première écriture manuelle réussie !
Je connecte maintenant l’adresse et les données ainsi que les signaux de contrôle à l’Arduino et code un programme pour automatiser les lectures et écritures.
Dans un premier temps le programme parcours séquentiellement les 16 adresses et affiche la données correspondante à chacune. Ça fonctionne bien et je retrouve bien le relevé initial avec la valeur 0xEA à l’adresse 0. Je code ensuite l’écriture, en commençant par une fonction qui écrit un seul octet. Il faut reproduire la séquence des signaux de contrôle que j’ai effectuée à la main juste avant. Ensuite j’ajoute la possibilité d’écrire une séquence de valeurs une à une.
Le code Arduino est disponible sur GitHub.
Connexion de l’EEPROM au 6502
L’objectif maintenant est de connecter la ROM au CPU pour que celui-ci lise et exécute le programme. En laissant la ROM sur sa breadboard, je relie désormais les 4 lignes d’adresse et le bus de données sur les broches correspondantes du 6502. Ce faisant je remarque que j’avais du aller un peu vite quand j’ai choisi les quatre lignes d’adresse à manipuler sur la ROM car ce n’était pas du tout les quatre bits de poids faible, bien que c’était mon intention. Il s’agissait en fait des lignes 13, 8, 9 et 11. En réalité ce n’est pas gênant, du moment que je connecte au CPU les mêmes lignes de la même manière, il retrouvera les données aux adresses attendues.
Pour analyser le résulat je choisis de me baser sur les LEDs connectés au bus de données de la ROM. Ce n’est pas forcément le plus pratique, et je pourrais connecter l’Arduino comme précédemment mais je n’ai pas envie d’ajouter encore davantage de fils volants à un montage déjà très chargé. Mais surtout j’aime utiliser toutes les opportunités qui se présentent pour confronter mes prédictions à la réalité. Parfois ça met en valeur des lacunes dans ma compréhension.
Avant de lancer le test je modifie le programme de sorte que le bus reste en mode lecture. Je retire l’instruction STA et restructure un peu l’ordre. Voici le nouveau programme :
| Addr | Instruction | Données |
|---|---|---|
0x0 |
LDA $0009 |
AD 09 00 |
0x3 |
LDA $000A |
AD 0A 00 |
0x6 |
ADC $000B |
6D 0B 00 |
0x9 |
28 |
|
0xA |
02 |
|
0xB |
0A |
|
0xC |
00 |
|
0xD |
00 |
|
0xE |
||
0xF |
Si tout se passe bien on est sensé observer les données suivantes sur le bus :
| Hexa | Binaire | Explication |
|---|---|---|
| 00 | 0000 0000 | Vecteur Reset |
| 00 | 0000 0000 | |
| AD | 1010 1101 | Première instruction |
| 09 | 0000 1001 | |
| 00 | 0000 0000 | |
| 28 | 0010 1000 | Donnée |
| AD | 1010 1101 | Deuxième instruction |
| 0A | 0000 1010 | |
| 00 | 0000 0000 | |
| 02 | 0000 0010 | Donnée |
| 6D | 0110 1101 | Troisième instruction |
| 0B | 0000 1011 | |
| 00 | 0000 0000 | |
| 0A | 0000 1010 | Donnée |
Les premières observations m’ont laissé perplexe. Les résultats n’avaient pas l’air de correspondre à ce qui est attendu, et j’ai commencé à me demander ce qui n’allait pas. J’avais l’impression de reconnaitre le 02 (0000 0010) mais à l’envers, mais je ne voyais pas comment les données auraient pu être inversées. Et puis j’ai réalisé que je lisais les LEDs dans le mauvais sens ! Je m’attendais à voir la même chose que ce que j’avais affiché à l’écran pour référence, mais sur les LEDs les bits de poids faible étaient à gauche et non à droite. J’ai retourné la plaque et là tout semblait correspondre. J’ai filmé la séquence pour analyser les résultat plus rigourseuement, et je confirme que tout correspond parfaitement.
La suite
Je veux maintenant connecter la ROM au 6502 de manière un peu plus permanente sur la même breadboard, câbler toutes les lignes d’adresse et de données, ainsi que la logique d’activation de la puce. Pour ça il sera utile de pouvoir programmer l’intrégralité de la mémoire disponible, et j’ai quelques idées à ce sujet. Après ça je pourrais commencer à installer la puce d’entrées-sorties qui permettra d’avoir enfin des résultats observables.
J'utilise des outils à base d'IA générative pour rédiger et/ou traduire le contenu de ce site. J'utilise l'IA comme un outil de productivité et d'inspiration, je m'assure toujours que les textes finaux reflètent fidèlement ma voix.