Je possède une console NES (Nintendo Entertainment System) encore en
très bon état. Malheureusement, je n'ai pas beaucoup de
jeux et certains sont très difficile à trouver (Bubble
Bubble par exemple).
J'ai décidé de modifier une cassette Nintendo de façon à
la rendre reprogrammable afin de pouvoir jouer à d'autres jeux,
essayer des démos, essayer des jeux faits maisons et peut-être
un jour, essayer mes propres programmes sur un vrai Nintendo.
J'ai utilisé deux Flash AT49F002 (256K). Je les programmes avec un programmeur
universel. La hauteur du socket et de la puce de flash est trop haute pour qu'il soit
possible de fermer le boitier. J'ai donc découpé un trou. C'est pratique
pour les reprogrammer car je n'ai pas besoin de démonter la cassette.
Fonctionnement
Une cassette Nintendo contient habituellement 2 Roms. (Mémoire morte)
Un pour le programme, accédé par le CPU et un pour les dessins,
accédé par le PPU (Picture Processing Unit.). Ces deux mémoires
sont sur des Bus séparés.
Le CPU du NES peut seulement addresse 16 bits, ce qui limite la mémoire (Morte ou vive) pouvant
être utilisée par le CPU à 65536 caractères. De ces 65536 caractères,
32768 sont utilisés pour la mémoire vive et l'entrée sortie. Il reste donc
seulement 32768 caractères pour le programme dans la cartouche.
Le PPU a aussi des limitations semblables au CPU.
Pour permettre au NES d'utiliser plus de mémoire, des puces supplémentaires sont utilisés
dans les cassettes. On les nomme les 'Mappers'. L'utilisation de ces puces permet la pagination de la
mémoire. Par exemple, la zone d'addresse du NES $C000-$FFFF qui normalement accède aux
addresses $4000-$7FFF du rom pourra, lorsque décidé, accéder en fait aux addresses
$8000-$C000 du rom, de manière transparente
du point de vue du CPU.
Il existe plusieurs mappers, certains très compliqués. Celui qui est présent dans ma cassette
est un MMC1 de Nindendo. Voici un document expliquant son fonctionnement: mmc1.txt
Étant donné que je souhaitais jouer à Bubble Bubble et que ce jeu utilise le Mapper MMC1
de Nintendo, j'ai récupéré la cassette de Motor City Patrol qui utilisait le même mapper.
Il y a aussi une puce de protection (CIC). La puce CIC de la cassette communique avec la puce CIC de la console. Si
tout est valide, la puce de la console arrête de resetter le NES a tout les secondes et le jeu fonctionne. J'ai
tout simplement laissé cette puce ou elle était.
J'ai choisi d'utiliser des flashs AT49F002 (256K) car j'en avait déja en stock. Le pinout de ces flash ne
correspond pas au pinout des ROMs utilisés par Nintendo. J'ai du couper des traces sur le PCB et installer
des fils. Heureusement il n'y avait pas trop de différences. Voici le document duquel j'ai tiré l'information
sur les ROMs de Nintendo dont j'avais besoin: NES_ROM_Pinouts.txt. Voici un autre document
très utile pour connaitre le pinout du connecteur de la cassette et du MMC1: rom.txt
Code
Les roms de NES en format .nes renferment le contenu des 2 roms (PRG et CHR) de la cassette en plus d'une en-tête
précisant certaines caractéristiques tels que le mapper utilisée, le type de mirroring
et la taille. Il me fallait un outil pour séparer ces informations fonctionnant sous linux alors j'en
ai codé un. (Je n'ai pas cherché très longtemps).
J'ai codé trois petits utilitaires: readnes, nesgg et patchnes.
Code source en C: nesutils-1.0.tar.gz
Code source en C + Executables DOS: nesutils-1.0.rar
Il suffit de preciser un fichier d'entré .NES, et on obtient ensuite deux fichiers, un .PRG pour le
contenu du rom contenant le code exécutable, et un .CHR pour le contenu du rom de graphiques.
Optionellement, ce programme peut répéter le contenu plusieurs fois. J'ai fait cela car
j'ai voulu mettre un jeu de 128k dans ma flash de 256k. Le signal d'addresse A17 ne restait pas toujours a zero a
cause de la maniere dont le jeu utilisait le MMC1, alors le CPU accédait parfois à des valeurs
non-programmés (alors rien ne fonctionnait).
J'aurais pu simplement modifier le circuit un peu plus et mettre 0 volts sur A17, mais j'aurais perdu la
possibilité d'utiliser des jeux nécéssitant 256k. En répétant deux fois
le contenu du rom, peut importe l'état d'A17 c'est la même valeur. (mêmes valeurs de
0 a 127K et de 128K - 255K).
Voici un exemple d'utilisation:
$ ./readnes BUBBLE.NES 2 1
File length :262288 Bytes
NES PRG: 08 CHR: 10 MAPPER: 11 44
Nintendo MMC1
Flags: 01
V
PRG 8 pages of 16kb (131072 bytes)
CHR 16 pages of 8kb (131072 bytes)
End at 262160
Remaining bytes: 128
BUBBLE BOBBLE From MINDRAPE and EFX
Writing BUBBLE.prg
.
Writing BUBBLE.chr
..
Ensuite, il reste tout simplement a programmer les flash.
L'utilitaire nesgg decode les codes pour 'Game genie' de 6 ou 8 lettres pour NES, est affiche la signification
du code clairement: Addresse, valeur de remplacement et valeur a comparer.
Un game genie s'installe normalement entre le CPU et le ROM. Lorsque le CPU accède a l'addresse encodée
dans le code, le game genie place sur le BUS de donnés une valeur différente (provenant du code) de
celle du ROM. S'il s'agit d'un code de 8 lettres, la valeur est remplacée seulement uniquement si la
valeur dans le ROM est la bonne (valeur provenant du code). Ceci empéche le game genie de remplacer
des valeurs qui ne devrait pas l'étre lorsque la cassette utilise du 'Bank switching'.
Ces trois codes sont pour Bubble Bubble. Ils changent le nombre de vies qu'on
a au départ, soit 1, 6 ou 9 respectivements. On comprends que l'octet
à l'addresse $9470 (lorsque sa valeur d'origine est de 3) représente
le nombre de vie au départ.
Voici un document expliquant l'encodage des codes de game genie: nesgg.txt
patchnes
patchnes applique un code de game genie sur un rom.
Appliquer un code de game genie sur un rom sans mapper est très facile.
Par contre, lorsqu'il y a un mapper, il faut tenter d'appliquer le code sur chacune
des pages pouvant être rendue accessible à cette addresse. Il y a
alors un risque qu'on remplace une valeur qu'il ne fallait pas remplacer car
peut-être que la page en question n'aurait jamais été placée
a cet endroit.
J'ai utilisé cet outil seulement sur Bubble Bubble (MMC1)et je n'ai pas eu de problèmes.
$ ./patchnes BUBBLE.NES PAUKEZLE
Working on rom BUBBLE.NES
Applying 8 letters code 'PAUKEZLE'
Not replacing $11 by 09 at address $9470 because it is not $03
Not replacing $02 by 09 at address $D470 because it is not $03
Not replacing $C4 by 09 at address $11470 because it is not $03
Not replacing $F1 by 09 at address $15470 because it is not $03
Not replacing $A9 by 09 at address $19470 because it is not $03
Not replacing $4C by 09 at address $1D470 because it is not $03
Replaced $03 by $09 at address $21470
Not replacing $FC by 09 at address $25470 because it is not $03
Programmation
Pour programmer les flash, j'utilise un vieux programmeur universel de
xeltek. Vous pouvez acheter un
programmeur universel sur ebay pour environ 50$ US ou construire
votre propre programmeur car les datasheet expliquent comment
programmer les flash.
Images
La carte SL-ROM-6, provenant du jeu Motor City Patrol. J'ai remplacé les roms d'origine par deux socket de
32 pins. J'ai modifié le pinout des roms pour pouvoir utiliser des flash AT49F002.
Ce n'est pas facile à voir dans la photo, mais les puce sont vraiment installés dans des 'sockets'.
Voici des images du tout en action: Note: Malheureusement, je n'ai pas installé une sortie VGA sur ce NES. J'utilise une
carte de capture vidéo.
Améliorations
Quelques jours plus tard, j'ai réalisé que je pourrais mettre 2 jeux de
128K à la fois en les programmants un à la suite de l'autre
dans les flash de 256k. La sélection du jeu peu alors se faire en controlant le bit
le plus significatif d'addresse (Interrupteur de droite). Pour un jeu de 256k, Il suffit de laisse
passer le signal du Mapper vers ce bit directement (Interrupteur de gauche).
Il a fallu couper quelques traces de plus pour rediriger les signaux. Voici une image du cablage.:
Je ne saurais être tenu responsable pour les dommages
que l'utilisation des informations ou la mise en œuvre des instructions présentées
sur cette page pourrait causer à votre équipement,
à vous-même ou à autrui. Aussi, je ne donne aucune garantie quant
à l'exactitude des informations et à leur fonctionnement.