Initialisation de la pile pour les jeux SMS sur Megadrive

Le problème

J'ai fabriqué des adaptateurs permettant d'utiliser des jeux SMS sur une console Megadrive et jeux MarkIII/SMS-J sur une console Megadrive . Cela fonctionne bien, mais il y a une petite complication:

Lorsqu'un jeu est exécuté sur une console Megadrive, ce n'est pas après l'exécution d'un «bios» comme sur une console master system. En fait, le dès la mise sous tension, le jeu est exécuté. Cela en empêche certains de fonctionner car ils ont été codés en assumant que le «bios» se serait déjà chargé de certaines choses, notamment l'initialisation du pointeur de pile («stack pointer»).

Pour faire démarrer un jeu qui ne démarre pas à cause de cela, il suffit de d'abord d'allumer la console avec un jeu fonctionnel, l'éteindre et changer pour le jeu qui ne fonctionne pas. Mettre à nouveau la console sous tension et il devrait démarrer. C'est que le premier jeu a initialisé le pointeur, et malgré que l'alimentation ait été coupée momentanément, le registre de pointeur de pile contient encore la dernière valeur utilisée!

Bien que ce truc semble bien fonctionner, ce n'est pas idéal. Il faut répéter cette manipulation à chaque fois, et il faut aussi posséder un jeu qui fonctionne.


La solution de Sega dans le Power base converter

Un produit équivalent à mon adaptateur a été à l'époque vendu par Sega sous les noms Power base converter, Mega Adaptor(メガアダプタ), Master System Converter ou Adaptador Para os Jogos Master System selon la région du monde[1].

Il se trouve que ce produit officiel n'a pas le problème de démarrage de certains jeux exposé dans les paragraphes précédents. Une discussion dans le forum smspower nous apprends qu'une puce de logique programmable simple est utilisée pour faire exécuter quelques instructions au CPU qui servent à initialiser la pile avant que le jeu soit exécuté:
	21 01 E1 : LD HL, $E101
	25 -- -- : DEC H
	F9 -- -- : LD SP,HL
	C7 -- -- : RST $00
La même discussion nous présente également les équations de logique qui montrent que l'adresse sur le BUS est utilisée pour présenter les octets formant les instructions ci-dessus dans le bon ordre, et comment un conflit d'adresse avec la cartouche est évité en faisant passer les signaux "chip enable" via cette même puce. Voir la discussion pour une explication technique complète.

Fait intéressant: Comme la puce de logique n'avait pas assez de sorties pour piloter les 8 lignes de data du Bus, le bit 0 est tiré à un niveau logique 1 via une résistance externe. Les instructions ci-dessus ont donc tous le bit le moins significatif à 1!

[1] Source: http://segaretro.org/Power_Base_Converter.


Ma solution avec un AVR

Je voulais règler mon problème rapidement avec le matériel dont je disposais sans refaire le circuit imprimé de l'adaptateur à partir de zéro. J'ai donc décidé d'essayer mon petit circuit à usage multiple lequel est basé sur un micro-contrôleur AVR d'atmel.

Le micro-contrôleur surveille le signal de lecture (RD) et à chaque impulsion, présente les bits de l'instruction suivante sur le BUS (D0 à D7), jusqu'à ce que les 6 octets soient passés, suite à quoi les broches du micro-contrôleur sont toutes mises en mode entrée pour laisser le jeu s'exécuter sans rien perturber.

Le micro-contrôleur ne surveille pas le signal CE car il n'est pas assez rapide. Les signaux data du bus sont pilotés continuellement, alors que normalement ils devraient l'être seulement lorsque RD et CE sont bas. Ce n'est pas très propre, mais comme nous contrôlons les instructions et savons qu'elles n'impliquent aucune écriture, je ne crois pas qu'il y ait de problème.

Pour isoler le signal CE de la cartouche de jeu, j'ai installé une résistance de 1.5k entre la megadrive et la cartouche. Le micro-contrôleur est relié au signal du côté de la cartouche. Pour empêcher un conflit lorsque le micro-contrôleur présente les instructions d'initialisation sur le BUS, il suffit de mettre un niveau logique 1 sur la ligne. Bien que du côté console de la résistance ce signal soit à zéro, il n'y a pas de danger car la résistance limite le courant. Lorsque le micro-contrôleur a terminé son travail et qu'il est temps d'exécuter le jeu, la broche correspondant au signal CE est mise en mode entrée et le signal CE passe alors de la console vers la cartouche de jeu via la résistance. La valeur de la résistance est assez basse pour ne pas trop ralentir les transitions.

J'ai simplement imité ce que Sega a fait pour le bit D0, bien que j'avais encore un bit de libre (PORTB3). Je ne me souviens pas pourquoi (car j'ai attendu trois mois avant d'écrire cette page) mais c'était peut-être pour faciliter la programmation lors du développement (un des signaux passe par là). Quel que soit la raison, il y a donc présentement besoin d'avoir une résistance pull-up sur D0, mais il serait facile de modifier le code pour l'éliminer.

Voici quelques photos du circuit installé sur l'adaptateur de cartouche. Si vous avez fabriqué un adaptateur comme moi ou en possédez un non fabriqué par Sega qui n'a pas de circuit d'initialisation de la pile, ce circuit peut être installé pour rectifier la situation.

Contactez-moi si cela vous serait utile et j'ajouterai ce circuit dans mon magasin en ligne.



Le code source est disponible:
stackchip.tar.gz

Voici une version abrégée pour montrer l'essentiel:
En développement

En développement

#define WAIT_RD()   do { } while (PIND & 0x04)
#define WAIT_RD_HIGH()  do { } while (!(PIND & 0x04))
#define OUTVAL(a,b) do { PORTC = a; PORTB = b | 0x10; } while(0)
#define RD_SYNC()   do { WAIT_RD(); WAIT_RD_HIGH(); } while(0)

...

/* LD HL, $E101 */
OUTVAL(0x10, 0x00);
RD_SYNC();
OUTVAL(0x00, 0x00);
RD_SYNC();
OUTVAL(0x70, 0x20);
RD_SYNC();

/* DEC H */
OUTVAL(0x12, 0x00);
RD_SYNC();

/* LD SP,HL */
OUTVAL(0x7C, 0x20);
RD_SYNC();

/* RST $00 */
OUTVAL(0x63, 0x20);
RD_SYNC();

// hands-off the bus
while (1) {
	DDRC = 0;
	DDRB = 0;
	set_sleep_mode(SLEEP_MODE_PWR_DOWN);
	sleep_enable();
	sleep_cpu();
}



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.