+++

title = "Fabriquer un lecteur de carte mémoire Nintendo 64 (3)"
date = 2012-09-21
aliases = [ "post/2012/09/21/Fabriquer-un-lecteur-de-carte-mémoire-Nintendo-64-(3)"]
[taxonomies]
tags = [ "jouage", "rebours", "bricole-picole" ]
+++

> J'avais jamais vu autant de bits d'un coup…


*Oui, je sais, elle est facile.*

<!-- more -->

Ave lecteur,

Plongeons plus profondément dans les entrailles de la bestioles et profitons-en pour apporter quelques petites corrections par rapport à la dernier fois.

# Compagnie Républicaine de Connards

es périgrinations au royaume du bit sur port série m'ont appris quelques petites subtilités vis-à-vis de l'adressage des cartes mémoires Nintendo 64. Dans le principe, tout ce que j'ai donné précédemment est effectivement vrai : les adresses vont de 0x0000 à 0x7FFF et l'on ne peut taper que sur les multiples de 0x20 de sorte à toujours lire ou écrire 32 octets de données.

aintenant, il y a une petite subtilité dans l'adressage en lui-même : il n'y a pas seulement un CRC pour les données (ce qui paraît logique) mais aussi un CRC pour les adresses (!). Lorsque l'on veut lire ou écrire des données, il faut donc passer une moulinette pour transformer les adresses de lecture.

Heureusement pour moi (et surtout pour mes neurones), [le projet Cube64](http://svn.navi.cx/misc/trunk/wasabi/devices/cube64/notes/addr_encoder.py) a déjà un algorithme tout prêt (en Python) pour calculer ce CRC d'adresse. L'auteur a également fait une rétro-ingénierie du CRC de données (qui n'est pas le même et qui est beaucoup plus compliqué) mais je n'ai pas vraiment eu le temps de m'y intéresser jusqu'à présent. Et même si c'est cohérent pour un dumper/loader de cartes mémoire, c'est pour le moment trop complexe à implémenter dans Arduino.

Le CRC de données est codé sur 8 bits, sous forme d'un octet de retour systématiquement : quand on demande à lire 32 octets de mémoire, la manette en renvoit 33, le dernier étant le CRC de données ; quand on demande à écrire 32 octets en mémoire, la manette utilise l'octet de CRC en guise de réponse. Le CRC d'adresse lui est codé sur 5 bits. Comme les adresses sont systématiquement « arrondies » de 0x20 en 0x20, cela laisse exactement 5 bits de libre dans les bits de poids faible et c'est là qu'on glisse ce nouveau CRC.

Bref, comment que ça marche le bouzin ? Chaque fois que l'on souhaite lire la carte mémoire, on envoit donc l'instruction 0x02 suivie de l'adresse **codée via le CRC** à partir de l'adresse en clair. Balayer l'ensemble du contenue de la mémoire demande ainsi une opération supplémentaire, la traduction des adresses.

Ainsi, pour lire le secteur 0x0020 de la carte mémoire, on doit respecter l'ordre suivant, dans un timing très précis :
* envoyer 0x02 à la manette (ordre de lecture) ;
* calculer le CRC de l'adresse -> 0x0015 ;
* envoyer l'adresse et le CRC additionné : 0x0035 ;
* lire 32 octets de données, lire 1 octet de CRC.

Et évidemment, il faut exécuter tout ça dans un timing absolument impeccable.

# Présente n64cmd par Waffle

Heureusement pour moi (et pour mes neurones), [Waffle](http://arduino.cc/forum/index.php?action=profile;u=4537) a écrit une petite fonction tout en assembleur du meilleur goût pour effectuer des lectures et des écritures successives sur le bus de la manette N64, adapté pour Arduino, j'ai nommé : [n64cmd](http://pastebin.com/f286fdbc2) !

La fonction est assez simple : elle prend en entrée un pointeur vers une structure d'octet qui contiendra la réponse (préférentiellement des entiers non-signés sur 8 bits `uint8_t` ou plus classiquement des `unsigned char`), suivi de la taille que l'on souhaite lire, un pointeur vers une structure d'octet qui contient la question, suivi de sa taille. La fonction en elle-même renvoit le nombre d'octets lus au total (qui doit toujours être inférieur ou égal à la taille demandée de la réponse).

Waffle a donné un petit exemple d'utilisation sous la forme d'un programme Arduino qui renvoit sur le port série les boutons qui viennent d'être appuyés sur la manette, le tout en utilisant une structure faisant 4 octets pile poil. Cette version n'utilise donc que l'instruction 0x01.

Pour les branchements, il faut relier les ports GND et 3.3V sur les ports correspondants de la manette et mettre le port série de la manette sur le port 9. Il est également nécessaire de mettre une résistance de tirage de 1K entre le 3.3V et le port série (cela permet d'éviter les erreurs lors de la lecture).

Pour le lulz et en attendant la suite, ton serviteur te propose une version détournée du sketch de Waffle qui permet de déclencher et d'arrête à intervalles réguliers le kit vibration préalablement branché sur la manette N64. Une bonne soirée en perspective :).
