Cassette Nintendo reprogrammable

L'idée

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

readnes:

./readnes rom.nes [nb repetitions prg] [nb repetitions chr]

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.

Mise-à-jour! (Octobre 2011) : Kevin Selwyn a créé un port de readnes en PHP: http://www.kevinselwyn.com/ReadNES/

nesgg

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'.

Voici un exemple:
$ ./nesgg PAUKEZLA TAUKEZLA PAUKEZLE
PAUKEZLA: Value: $01  Compare Value: $03  Address: $9470
TAUKEZLA: Value: $06  Compare Value: $03  Address: $9470
PAUKEZLE: Value: $09  Compare Value: $03  Address: $9470
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

cablage 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.:
cablage



Références

Un excellent site d'info sur le NES: http://nesdev.parodius.com/
Infos sur le pinout des roms Nintendo: NES_ROM_Pinouts.txt
Infos sur le pinout du connecteur de la cartouche et des mappers: rom.txt
Infos sur le MMC1: mmc1.txt
Infos sur l'encodage des codes de game genie: nesgg.txt
Datasheet des flash AT49F002: doc1017.pdf



Avertissement

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.