Billet #006 - 7 juin 2026
Prise en main du 6522 "Versatile Interface Adapter"
Jâai un systĂšme basĂ© sur le 6502 que je peux programmer librement. Lâobjectif maintenant est dâajouter des LEDs et des boutons pour pouvoir Ă©crire des programmes interactifs.
Le rĂŽle du 6522
Le 6502 seul nâest pas en mesure de piloter directement des LEDs et des boutons, car les seules choses quâil peut faire directement câest lire et Ă©crire sur les bus dâadresse et de donnĂ©es. Pour piloter une LED ou lire un bouton il faut un systĂšme intermĂ©diaire qui sâinterface avec la LED ou le bouton dâun cĂŽtĂ©, et communique avec le CPU via le bus de lâautre cĂŽtĂ©.
Le 6522 est une puce dâinterfaçage conçue pour fonctionner avec le 6502. Son nom en anglais est Versatile Interface Adatper, je lâappelle donc âVIAâ pour faire court. Le VIA propose plusieurs fonctions complĂ©mentaires, notamment des timers, mais ce qui nous intĂ©resse ici ce sont les deux ports parallĂšles dâentrĂ©e-sortie. Il sâagit de 16 lignes qui peuvent ĂȘtre configurĂ©es individuellement en entrĂ©e ou en sortie, et quâon va pouvoir lire ou Ă©crire depuis le CPU.
Le VIA possĂšde 16 registres de contrĂŽle dans lesquel le CPU va lire ou Ă©crire via le bus de donnĂ©es pour rĂ©aliser les fonctions souhaitĂ©es. Pour sĂ©lectionner le registre dans lequel on veut lire ou Ă©crire, on utilise le bus dâadresse. Comme on a que 16 registres, 4 lignes dâadresse suffisent.
Chip Select et espace dâadressage
JusquâĂ maintenant on avait quâun seul composant connectĂ© aux bus dâadresse et de donnĂ©es : lâEEPROM. On va maintenant ajouter le VIA, et il faut donc sâassurer que le CPU puisse communiquer avec chaque composant sans perturber les autres ou ĂȘtre perturbĂ© par leur prĂ©sence sur le bus. Pour ça on utilise le Chip Select (aussi appelĂ© Chip Enabled). Câest un signal qui permet dâactiver le composant avec lequel le CPU cherche Ă communiquer Ă un instant donnĂ©. Chaque composant possĂšde une ou plusieurs entrĂ©e pour ce signal, et ne prennent le contrĂŽle du bus que lorsque le signal les y autorise. Le reste du temps les pins connectĂ©es au bus sont Ă©lectroniquement dĂ©connectĂ©es du bus (dans ce quâon appelle un Ă©tat de haute impĂ©dance).
Pour dĂ©terminer quel composant doit ĂȘtre actif on utilise le bus dâadresses. Avec 16 lignes dâadresse le CPU peut produire 65 536 adresses diffĂ©rentes. Ces 65 536 adresses constituent ce quâon appelle âlâespace dâadressageâ, et lâidĂ©e est de dĂ©couper cet espace dâadressage en plusieurs plages et dâattribuer une plage Ă chaque composant. Pour ça on utilise des lignes dâadresse judicieusement choisies pour gĂ©nĂ©rer le signal Chip Select pour chaque composant.
JusquâĂ maintenant jâavais forcĂ© le Chip Select (signal /CE) de lâEEPROM pour quâelle soit toujours active. LâintĂ©gralitĂ© de lâespace dâadressage lui Ă©tait par consĂ©quent attribuĂ©e. La ROM possĂšde seulement 15 lignes dâadresse (32k adressable), et on avait laissĂ© la 16e ligne dĂ©connectĂ©e. Par consĂ©quent quand le CPU utilise une adresse dans la plage 0x0000-0x7FFF, ça correspond directement Ă une adresse dans la ROM. Mais câest Ă©galement le cas pour les adresses 0x8000-0xFFFF car si on ne prend en compte que les 15 premiers bits de lâadresses, les adresses sont identiques. Du point de vue du CPU le contenu de la ROM apparait dupliquĂ©.
| Binaire | Hexadécimal |
|---|---|
0000 0000 0000 0000 |
0x0000 |
0111 1111 1111 1111 |
0x7FFF |
1000 0000 0000 0000 |
0x8000 |
1111 1111 1111 1111 |
0xFFFF |
La 16e ligne dâadresse (A15) Ă©tant inutilisĂ©e pour adresser les donnĂ©es dans la ROM, on peut lâutiliser pour le Chip Select. Si on la connecte directement sur lâentrĂ©e /CE de la ROM, Ă©tant donnĂ© que la puce est activĂ©e si le signal est Ă 0, celle-ci ne rĂ©pondra plus quâaux adresse dans la plage 0x0000-0x7FFF. On a ainsi allouĂ© la plage 0x0000-0x7FFF Ă lâEEPROM et libĂ©rĂ© le reste pour dâautres composants. Cependant, rappelons-nous quâau dĂ©marrage le CPU interroge les adresses 0xFFFC et 0xFFFD (vecteur reset), et dans cette configuration de la mĂ©moire ça ne fonctionnerait pas. On pourrait rajouter un composant dont la tĂąche est de rĂ©pondre spĂ©cifiquement Ă ces deux adresses, mais on devrait alors veiller Ă mettre Ă jour la valeur en fonction dâoĂč on place le dĂ©but du programme dans la ROM. Le plus simple est en fait dâallouer la plage 0x8000-0xFFFF Ă la ROM. On peut faire ça en inversant A15 (avec une porte logique NOT) avant de le connecter sur /CE. Ainsi lâadresse 0x7FFC dans la ROM correspondra Ă lâadresse 0xFFFC du point de vue du CPU. En revanche, lâadresse 0x0000 de la ROM se retrouve Ă lâadresse 0x8000 du point de vue du CPU. Il faudra donc ĂȘtre vigilant lors de lâĂ©criture du programme.
On peut maintenant rĂ©flĂ©chir Ă lâespace mĂ©moire Ă allouer au VIA. On sait dĂ©jĂ que cette plage doit ĂȘtre comprise dans la plage 0x0000-0x7FFF. On pourrait allouer toute la plage, et tant quâon ajoute pas dâautres composants sur le bus ça ne pose pas de problĂšme. Mais je prĂ©vois dâajouter au moins une puce de RAM par la suite, donc essayons de faire mieux que ça. Pour rappel le VIA nâa que 16 registres, la plage dâadresse nâa donc besoin de contenir au minimum que 16 adresses. Elle peut Ă©videmment ĂȘtre plus grande que ça.
Je commence Ă ĂȘtre Ă court de breadboards, et celles dĂ©jĂ utilisĂ©es sont dĂ©jĂ bien chargĂ©es, je voudrais donc une solution qui utilise un minimum de connexions et un minimum de composants. Le VIA possĂšde deux signaux Chip Select : CS1 et /CS2. La puce est activĂ©e lorsque CS1 est Ă 1 et /CS2 Ă 0. On sait dĂ©jĂ que le VIA doit ĂȘtre dĂ©sactivĂ© lorsque la 16e ligne dâadresse (A15) est Ă 1, puisque ça correspond Ă la plage allouĂ©e Ă la ROM. On peut donc connecter A15 sur /CS2. Si on sâarrĂȘte lĂ on a effectivement allouĂ© la plage 0x0000-0x7FFF au VIA. Imaginons maintenant quâon branche A14 sur CS1. Le VIA ne serait alors actif que lorsque la 16e ligne dâadresse (A15) est Ă 0 et la 15e (A14) est Ă 1, ce qui correspond Ă la plage dâadresses 0x4000-0x7FFF. Si on ajoutait A13 avec un ET on rĂ©duirait Ă la plage 0x6000-0x7FFF. Et si on ajoutait encore A12 ça donnerait 0x7000-0x7FFF. Plus on rĂ©duit la plage mĂ©moire allouĂ©e et plus on laisse de lâespace pour autre chose, mais plus ça demande de logique pour le Chip Select.
| Binaire | Hexadécimal |
|---|---|
0000 0000 0000 0000 |
0x0000 |
0100 0000 0000 0000 |
0x4000 |
0110 0000 0000 0000 |
0x6000 |
0111 0000 0000 0000 |
0x7000 |
0111 1111 1111 1111 |
0x7FFF |
1000 0000 0000 0000 |
0x8000 |
1111 1111 1111 1111 |
0xFFFF |
Je choisis de rester simple pour lâinstant et de mâarrĂȘter Ă A14. Ăa permet de connecter CS1 et /CS2 diretement sans introduire de logique supplĂ©mentaire, et le compromis en terme dâallocation de lâespace dâadresse est ok pour lâinstant.
Résumé des connexions à faire :
| Ligne dâadresse | Connexion |
|---|---|
A15 |
/CE de la ROM via une porte NOT |
A15 |
/CS2 du VIA |
A14 |
CS1 du VIA |
Montage de lâEEPROM avec Chip Select et test du programme
Je veux installer le VIA et la logique du Chip Select de maniĂšre semi permantente sur une grande breadboard que jâassemble avec celle du 6502, mais je nâai plus de grande breadboard. Jâen ai commandĂ© des nouvelles, mais en attendant de les recevoir je fais un montage temporaire sur une petite breadboard, en faisant les connexion avec des lignes Dupont. Ăa ne me laissera pas assez de Duponts pour monitorer les bus avec lâArduino, mais tant pis.
Pour faire simple jâutilise une puce 74LS04 qui contient 6 inverseurs et je la place sur la breadboard du 6502 aprĂšs lâespace rĂ©servĂ© Ă la ROM. Câest temporaire car je prĂ©voie de mettre la RAM Ă cet endroit par la suite. Jâalimente le 74LS04, jâamĂšne A15 sur lâentrĂ©e du premier inverseur, je retire le fil de connexion qui maintenait /CE de la ROM Ă la masse, et je branche la sortie de lâinverseur Ă la place.
Avant de passer Ă lâinstallation du VIA et immobiliser les fils de connexion, il faut reprogrammer la ROM. Pour Ă©viter de reprogrammer si jamais ça ne fonctionne pas comme prĂ©vu du premier coup (ce qui demande pour lâinstant de recĂąbler lâArduino Ă chaque fois, ce nâest pas trĂšs pratique), jâessaie de faire un programme dont les effets sont reconnaissables sans ambiguitĂ©. Jâimagine un programme qui allume 3 LED avec un motif alternatif 010-101. Il nâest pas nĂ©cessaire de faire appel Ă un compteur ou un timer, avec une horloge suffisamment lente on verra le motif clignoter sans soucis mĂȘme si les instructions se suivent directement sans dĂ©lai.
Câest le moment de se pencher plus en dĂ©tails sur le fonctionnement du VIA. Pour configurer les pins du port A en sortie il faut Ă©crire dans le registre 3. Un bit Ă 1 dans ce registre configure le pin correspondant en sortie. Ensuite pour dĂ©finir la valeur sur le pin il faut Ă©crire dans le registre 1. Vue le mapping mĂ©moire que nous avons fait prĂ©cĂ©demment, lâadresse Ă utiliser pour les registres 1 et 3 sont respectivement 0x4001 et 0x4003.
Basiquement notre programme ressemble donc à ça :
- écrire
1111 1111(0xFF) Ă lâadresse0x4003 - Ă©crire
0000 0010(0x02) Ă lâadresse0x4001 - Ă©crire
0000 0101(0x05) Ă lâadresse0x4001 - recommencer Ă 2.
En pseudo code machine ça donne ça :
LDA #$FFSTA $4003LDA #$02STA $4001LDA #$05STA $4001JMP $XXXX
Explications: Pour Ă©crire une valeur donnĂ©e dans un registre du VIA, on charge dâabord la valeur dans lâaccumulateur, puis on envoie la valeur de lâaccumulateur Ă lâadresse du registre. Lâinstruction JMP permet de dĂ©placer le pointeur dâexĂ©cution Ă lâadresse indiquĂ©e. Ici on veut revenir Ă lâinstruction LDA #$02 pour former une boucle infinie. Pour dĂ©finir lâadresse Ă donner Ă lâinstruction JMP il faut connaĂźtre Ă quelle adresse exacte se situe lâinstruction visĂ©e. Pour ça il faut :
- savoir à quelle adresse commence le programm dans la mémoire
- combien dâoctets occupent les instructions qui prĂ©cĂšdent
- prendre en compte lâallocation de lâespace dâadressage dĂ©fini prĂ©cĂ©demment
Pour faire simple on peut placer le programme Ă lâadresse 0x0000 dans la mĂ©moire, ce qui correspond Ă 0x8000 du point de vue du CPU. Il faudra donc penser Ă placer cette valeur dans le vecteur reset.
Nous avons dĂ©jĂ rencontrĂ© lâinstruction STA prĂ©cĂ©demment. Le code correspondant est 0x8D, et lâadresse est passĂ©e dans les deux octets suivants, les poids faibles en premier. Nous avons Ă©galement dĂ©jĂ rencontrĂ© lâinstruction LDA, mais nous avions utilisĂ© la version qui prend une adresse, alors quâici nous voulons lui passer la valeur directement. On aurait pu mettre la donnĂ©e en mĂ©moire et utiliser LDA avec lâadresse correspondante, mais pourquoi faire compliquĂ©. Dans la datasheet on trouve que le code pour LDA en mode dâadressage immĂ©diat est 0xA9, et la valeur est indiquĂ©e dans lâoctet qui suit. Regardons maintenant lâinstruction JMP. Elle existe aussi dans plusieurs mode dâadressage, ici nous voulons le mode âadressage absoluâ qui prend une adresse. Le code correspondant est 0x4C, et lâadresse est indiquĂ©e sur les deux octets suivants, poids faibles en premier comme dâhabitude.
Voici le programme final :
| Adresse CPU | Adresse ROM | Donnée |
|---|---|---|
0x8000 |
0x0000 |
A9 FF |
0x8002 |
0x0002 |
8D 03 40 |
0x8005 |
0x0005 |
A9 02 |
0x8007 |
0x0007 |
8D 01 40 |
0x800A |
0x000A |
A9 05 |
0x800C |
0x000C |
8D 01 40 |
0x800F |
0x000F |
4C 05 80 |
0xFFFC |
0x7FFC |
00 |
0xFFFD |
0x7FFD |
80 |
On voit que lâinstruction LDA #$02 si retrouve Ă lâadresse 0x8005, câest donc cette valeur quâon donne au JMP. Je programme la ROM avec le setup dĂ©fini prĂ©cĂ©demment, et je la remet en place sur le circuit.
Avant dâinstaller le VIA je vĂ©rifie que le Chip Select fonctionne comme prĂ©vu et que le programme est bon. Je branche lâArduino sur le bus et observe les donnĂ©es, toujours avec uniquement les 4 premiĂšres lignes dâadresse. Voici le rĂ©sultat :
| Adresse théorique | Adresse observée | R/W | Donnée |
|---|---|---|---|
0xFFFc |
0xc |
R |
0x00 |
0xFFFd |
0xd |
R |
0x80 |
0x8000 |
0x0 |
R |
0xa9 |
0x8001 |
0x1 |
R |
0xff |
0x8002 |
0x2 |
R |
0x8d |
0x8003 |
0x3 |
R |
0x03 |
0x8004 |
0x4 |
R |
0x40 |
0x4003 |
0x3 |
W |
0xff |
0x8005 |
0x5 |
R |
0xa9 |
0x8006 |
0x6 |
R |
0x02 |
0x8007 |
0x7 |
R |
0x8d |
0x8008 |
0x8 |
R |
0x01 |
0x8009 |
0x9 |
R |
0x40 |
0x4001 |
0x1 |
W |
0x02 |
0x800a |
0xa |
R |
0xa9 |
0x800b |
0xb |
R |
0x05 |
0x800c |
0xc |
R |
0x8d |
0x800d |
0xd |
R |
0x01 |
0x800e |
0xe |
R |
0x40 |
0x4001 |
0x1 |
W |
0x05 |
0x800f |
0xf |
R |
0x4c |
0x8010 |
0x0 |
R |
0x05 |
0x8011 |
0x1 |
R |
0x80 |
0x8005 |
0x5 |
R |
0xa9 |
0x8006 |
0x6 |
R |
0x02 |
0x8007 |
0x7 |
R |
0x8d |
0x8008 |
0x8 |
R |
0x01 |
0x8009 |
0x9 |
R |
0x40 |
0x4001 |
0x1 |
W |
0x02 |
0x800a |
0xa |
R |
0xa9 |
0x800b |
0xb |
R |
0x05 |
0x800c |
0xc |
R |
0x8d |
0x800d |
0xd |
R |
0x01 |
0x800e |
0xe |
R |
0x40 |
0x4001 |
0x1 |
W |
0x05 |
0x800f |
0xf |
R |
0x4c |
0x8010 |
0x0 |
R |
0x05 |
0x8011 |
0x1 |
R |
0x80 |
Tout est conforme.
Montage du VIA
Je peux maintenant enfin installer le VIA. Je place le 6522 sur une petite breadboard, et je connecte tout de suite VDD et VSS. Jâajoute 3 LEDs Ă cĂŽtĂ©s avec leur rĂ©sistance et je connecte les LEDs aux 3 premiĂšres sorties du port A. Je passe en revue le reste des pins. Il faut connecter :
- les 8 lignes de données (
D0ĂD7) - les 4 lignes adresses (
A0ĂA15) - le signal dâĂ©criture/lecture (
/RW) - la clock (
PHI2) - le reset (
/RES) CS1et/CS2
Nous nâutilisions pas le signal dâĂ©criture/lecture (/RW) jusquâĂ prĂ©sent puisque la ROM nâest utilisĂ©e quâen lecture. Mais le VIA peut-ĂȘtre utilisĂ© en lecture et Ă©criture, mĂȘme si notre programme de test ne fait pour lâinstant quâĂ©crire. Les signaux dâhorloge et de reset peuvent ĂȘtre repris directement sur ceux du 6502. Je branche donc tout ça, lâArduino fournit le signal dâhorloge comme dâhabitude.
Je lance, fait un reset, mais ça ne fonctionne pas, les diodes restent Ă©teintes. Ăa me laisse perplexe. Je teste dâabord les LEDs en amenant directement le 5V dessus et elles sâallument bien. Jâobserve ensuite les valeurs en sortie du VIA avec Arduino, et elles restent toutes Ă 0. De la mĂȘme maniĂšre je vĂ©rifie les signaux CS1, /CS2, la clock, et /RW, et tout semble correcte. /RW est Ă 1 la plupart du temps pour indiquer une lecture, et passe Ă 0 de temps en temps pendant exactement un cycle. Idem pour CS1 et /CS2 qui prennent bien les valeurs attendues.
Jâentreprends alors dâessayer de piloter le VIA directement avec lâArduino pour vĂ©rifier que jâarrive Ă le faire fonctionner en envoyant manuellement des commandes et confirmer que le programme de test envoie bien les bonnes commandes. Sur la breadboard je force /CS1 Ă 1, /CS2 Ă 0, et /RW Ă 0. Avec le code je fais un reset en mettant Ă /RES Ă 0 et en faisant quelques cycles dâhorloge, puis jâenvoie les octets pour configurer le port A, mais toujours rien de visible. Jâessaie avec le port B et toujours rien. Ă ce moment je commence Ă soupçonner mon VIA dâĂȘtre dĂ©fectueux.
Je tente de lire les entrĂ©es sur les ports. Jâajoute /RW dans le code pour pouvoir lire/Ă©crire, et je connecte directement le 5V sur une des pins dâentrĂ©es. LĂ je rĂ©alise que les LEDs sont toujours connectĂ©es au port A alors que je teste le port B. Je corrige ça et relance le test prĂ©cĂ©dent mais toujours rien. Je fais le teste de lecture et je lis 0. Ăa me laisse vraiment perplexe.
Le code Arduino est disponible sur GitHub.
La suite
Je nâarrive pas Ă faire fonctionner le 6522, mais en revoyant la vidĂ©o de Ben Eater consacrĂ©e Ă son installation jâai lâidĂ©e de construire un latch comme il lâa montrĂ© dans cette vidĂ©o, et dâessayer de lâinterfacer avec le CPU. Câest un exercice intĂ©ressant. Si ça fonctionne ça permettra dâavoir dĂ©jĂ une sortie pilotable par le 6502, et donc dâavoir enfin des rĂ©sultats observables directement et dâĂ©crire des programmes qui font quelque chose.
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.