Cette page a au moins 16 ans ! This page is at least 16 years old !
Le Fat-Ass project de la fin d'année, avec peut être un
second pour suivre.
Je tente de faire une interface MIDI / Master System qui tient dans une
cartouche.
14 Novembre:
Pour l'accès aux données à partir
de la cartouche, j'ai choisi d'utiliser les ports d'I/O du Z80, puisque
les registres en mémoire demanderaient pas mal d'hardware en plus.
Un ATMega8 se chargerait de la conversion MIDI vers parallèle et
de la mémoire tampon pour que Midisms (le programme en cartouche)
puisse aller les chercher à chaque VBL.
En regardant le schéma officiel de la Master System, on voit que
seules les lignes d'adresse A0, A6 et A7 servent pour les I/O normales.
Exemples:
Une lecture sur le port $DC (pad joueur 1):
Bit 76543210 760
DC= 11011100 110
Adresse le 315-5218 (controleur propriétaire d'I/O
pour les ports DB9). C'est lui qui va répondre sur le bus de données.
Sur smspower.org il est écrit que certains jeux
utilisent le port $C0 au lieu du port $DC, effectivement, ça ne
change rien du tout car les bits 7,6,5 et 0 sont les mêmes.
Bit 76543210 760
C0= 11000000 110
Tous les ports ont alors 15 mirroirs (2^4 bits inutilisés
- le port indiqué par Sega), sur la Master System en tout cas.
On peut très bien lire le port $C0, $C2, $C4, $C6... au lieu de
$DC.
J'ai pu tester ça avec plusieurs ports, y compris $BF et $BE, ça
a toujours fonctionné. Et de toutes façons, aucun composant
censé réagir à IORQ/ n'est relié à
A1, A2, A3 et A4.
Autre exemple, une écriture sur le port $BF (adressage
VDP):
Bit 76543210 760
BF= 10111111 101
Le port $7F qui sert à commander le PSG (OUT) et
à lire le numéro de ligne TV (IN):
Bit 76543210 760
7F= 01111111 010
Normalement les deux réponses devraient être
faites par le VDP (le PSG est dedans), A6 est à 1 car le port $3F
sert à autre chose. Il en va de même pour $7E et $3E.
Une bonne partie du logiciel de debug est écrite, il tourne en
émulateur et sur la vraie machine.
Premiers essais de Midisms sur la vraie machine. Les essais du PSG fonctionnent,
et le compteur de VBL permet de voir rapidement si quelque chose a foiré.
J'ai enfin mes routines propres pour afficher de l'hexa, du binaire et
des petites "progressbars" ! Le seul sprite dans tout ça,
c'est la petite note à gauche qui permet de choisir quelle ligne
on veut modifier.
La valeur lue sur le port $14 n'était pas vraiment attendue...
Chaque IN sur un port "non routé" sur la console retourne
justement le numéro de port. Emukon retourne $FF.
IN A,($14) met $14 dans A.
$14 ne devrait avoir aucune raison de se mettre dans A car il n'est écrit
que sur le bus d'adresse. Soit j'ai raté un composant, soit j'ai
rien compris.
15 Novembre:
Breadboard et câblage terminés, tout fonctionne
comme prévu à l'exception de la valeur retournée
par IN toujours. Y'a un véritable souci mais au moins je sais d'où
il vient maintenant.
Hier je me demandais pourquoi IN A,(xx) mettait xx dans A alors que le
bus de données ne changeait pas.
En fait, (et là je découvre !) juste avant d'éxecuter
le IN a,(xx), le Z80 devait aller lire les opcodes dans la mémoire
de la cartouche. L'opcode de IN A,(xx) est la suivante: DB xx.
Ce qui veut dire que le Z80 a lu "$DB", puis "XX",
et a exécuté l'instruction. Mais après avoir lu ce
"XX", le bus de données ne change pas (la RAM dans ma
cartouche maintient le bus a sa dernière valeur),
la lecture que fait IN A,(XX) retourne forcément "XX",
puisqu'il traînait encore sur le bus ! C'est simplement le dernier
bout d'opcode qui restait coincé dessus, c'est logique après
tout. Il n'y a aucune raison
que le bus de données change de valeur entre temps...
Le souci maintenant c'est que le Mega8 réagit parfaitement bien
à l'adressage sur A1A2A3A4 avec le décodeur NAND/NOR, mais
il ne peut répondre qu'en "demi-tristate" pour rester
dans les temps. Ce "demi-tristate" met la broche en vrai tristate
si elle doit sortir un "0", et fournit du courant si elle doit
sortir un "1". C'est comme ça lorsqu'on met DDRx à
$00 en ayant PUD de SFIOR à 0 (Tristate enable, Pull up enable).
Concretement, ceci permet de fixer des lignes du bus de données
à 1, mais pas de les descendre à 0. Il reste alors le 00010100
du $14 en masque.
Par exemple, si je fais sortir 10101010 sur le Mega8, le IN A,($14) donnera
10111110. Les bits sont coincés à 1.
Tout le problème réside dans le fait que
pour pouvoir fixer des bits à 0, il faut que les broches du Mega8
soient toutes en "vraie" I/O, pas de tristate nul part. Alors
que quand rien ne lui est demandé, il
faut impérativement que toutes ses broches soient en tristate,
sinon il fixerait tout le temps le bus de données. C'est testé
et approuvé: tout plante.
Rien que le fait de changer DDRx met le Mega8 en dehors des temps, et
le fait répondre après que le Z80 lise le bus. La lecture
avec IN A,($14) donne des valeurs instables et fait parfois planter la
console.
J'imagine que le Mega8 répond lorsque le Z80 passe à la
requête de l'instruction suivante, et lui pourrit les premiers bits.
Le matériel encore raisonablement organisé, avec l'ancien
décodeur NAND/NOR, la cartouche RAM, le Mega8 et le bus de données
cablé sur le port cartouche.
La LED rouge changeait d'état à chaque fois que Midisms
réclamait quelque chose sur le port $14.
Schéma sans décodeur (vite corrigé, toutes les entrées
d'adresses ont été mises sur des portes logiques, et leur
sortie finale reliée à PD2.)
Croire que le Mega8 était assez rapide pour décoder l'adresse
au niveau logiciel et répondre dans les temps, c'était se
fourrer le doigt dans le cul jusqu'à l'oeil.
16 Novembre:
Pour faire ça proprement j'ai décider d'utiliser
un latch. La valeur derrière sera prévue par le Mega8, et
il pourra la donner sur le bus de données exactement dans les temps.
J'utiliserais un 74LS373, octuple latch-D inverseur. OE/ passant à
l'état bas posera les données sur le bus, pile quand le
port sera adressé. OE/ passant à l'état haut remettera
les sorties du 74LS373 en tristate.
Ca fait un gros circuit intégré en plus, mais on gagne en
fiabilité et de toutes façons, on perd le 4011 puisque je
ne vérifie plus qu'une seule ligne d'adresse (A2, qui ne devrait
jamais être à 0 pendant une
opération d'I/O). Je pourrais de cette manière lire l'octet
sur le latch en lisant le port $1A (00011010) ou ses mirroirs ($00 $02
$08 $0A $10 $12 $18). Encore faut-il que ni le VDP, ni le 315-5218, ne
réagisse à
A7A6A5A0=0000... A vérifier.
Il faut aussi que je finisse par tester l'entrée
midi et la mémoire tampon sur le Mega8; ça devrait pas être
trop dur. Ca sera ça de fait.
Le 373 va être beau à câbler sur si peu de place...
Je vois mal la cartouche finale tenir sur de la plaque en bandes, va falloir
demander aux chinois.
20 Novembre:
Finalement le latch a bien été utile, tout
fonctionne comme prévu et la console répond maintenant à
deux canaux midi. Ca a bien avancé.
Cette fois-ci, le décodeur NOR (A2) est directement relié
à OE/ du 74LS737: plus aucun délai. Le Mega8 est informé
de l'accès car il y est lui aussi relié. Entre deux VBL
il a donc largement le temps de préparer le prochain octet. Après
un peu de discution sur le forum d'smspower.org,
j'ai eu confirmation des mirroirs des ports.
Aussi, en lisant de plus près la documentation du Z80, je me suis
aperçu qu'il y avait une broche prévue pour lui indiquer
quand les données étaient prêtes (WAIT/). Mais l'espoir
fut bref, car l'état de cette ligne est samplée pendant
un cycle, juste après la descente de IORQ/: le Mega8 aurait jamais
le temps de la faire descendre également. A moins que ça
devienne un boulot supplémentaire pour les portes NOR... A voir.
Il n'y a pas encore de vraie polyphonie. C'est à
dire qu'il y a bien plusieurs notes qui peuvent être jouées,
mais chaqu'une sur un canal midi différent. Cela pourra être
implémenté sans trop d'éfforts avec une petit liste
de "disponibilité" de chaque voix du PSG. Il n'y a pas
non plus de vrai buffer MIDI encore, j'ai pu tester la communication jusqu'à
40 notes par seconde et tout c'est bien passé, logique puisque
le Mega8 se fait interroger 50 ou 60 fois par seconde (PAL/NTSC). Les
doubles-notes ne fonctionnent pas, mais c'est une conséquence de
ne pas avoir de buffer. Puisque les deux messages Note-On se suivent,
le dernier écrase le premier. Le plus étrange c'est que
mon Electribe-A n'a pas l'air d'envoyer ces messages dans l'ordre des
numéros de canaux... J'ai alternativement la note du canal 1 ou
du canal 2, sans jamais trop savoir. Autre souci que devrait règler
le buffer, c'est l'utilisation des potards/pitch mod, qui impliquent de
balancer un gros paquet de messages midi pour avoir une réaction
rapide.
Il faudra peut être que Midisms aille réclamer les données
en dehors du VBL pour obtenir des vitesses plus acceptables (ou lire plus
de fois).
Schéma avec simple décodeur (attend que RD/, IORQ/ et A2
soient tous à 0), et latch parallèle.
MCUCR
= 0b00000010; // INT0 sur front descendant
GICR = 0b01000000; // INT0 ON
B:8
C:Valeur
Showbinary:
PUSH AF
PUSH BC
LD A,C
AND $80
JR Z,Zero
LD A,$11 ;Tile du "1"
OUT ($BE),A
JP One
Zero:
LD A,$10 ;Tile du "0"
OUT ($BE),A
One:
XOR A
OUT ($BE),A
SLA C
DJNZ Showbinary
POP BC
POP AF
RET
Routine d'affichage hexa:
C:Valeur
Showhex:
PUSH AF
LD A,C
AND $F0
SRL A
SRL A
SRL A
SRL A
CALL Checkalpha
ADD A,$10 ;Tile du "0"
OUT ($BE),A
XOR A
OUT ($BE),A
LD A,C
AND $0F
CALL Checkalpha
ADD A,$10
OUT ($BE),A
XOR A
OUT ($BE),A
POP AF
RET
Checkalpha:
CP $0A
RET M
ADD A,$07 ;Tile du "A" par rapport au tile du "0"
RET
Génerateur de tiles pour la "barre de progression":
Créé
9 tiles (couleur 15), utilise CD BC et AF
LD C,$09
LD D,$00
Ldbars:
LD B,$20 ;4 bitplanes * 8 lignes
Ldbar:
LD A,D
OUT ($be),A
DJNZ Ldbar
SCF
RR D
DEC C
LD A,C
OR A
JR NZ,Ldbars
Routine d'affichage de "barre de progression":
B:Largeur
max en tiles C:Valeur Nécéssite 9 tiles consécutifs, un vide,
puis avec une ligne verticale, deux lignes, trois...
Showbar:
PUSH AF
PUSH BC
Showbarlp:
LD A,C
CP $09
JP C,Infer
LD A,$69 ;Tile rempli (neuvième)
OUT ($BE),A
XOR A
OUT ($BE),A
DEC B
LD A,C
SUB $08
LD C,A
CP $00
JR Z,fill
JP Showbarlp
Infer:
LD A,$61 ;Tile vide (premier)
ADD A,C
OUT ($BE),A
XOR A
OUT ($BE),A
Fill:
LD A,$61 ;Tile vide (premier)
OUT ($BE),A
XOR A
OUT ($BE),A
DJNZ fill
POP BC
POP AF
RET