Le dispositif de jeu (la console DreamCast) est toujours le seul à pouvoir émettre des requêtes ou des ordres à destination des autres dispositifs présents sur le Maple Bus, ce qui implique que le tout premier des challenges devra être la réception et le décodage des trames descendantes émises par la console.
Chaque trame étant précédée d'un fanion, le premier job va donc consister à le reconnaître.
Comme il en existe trois différents («Start», «SDCKB Occupy authorization» et «Reset»), autant prévoir une routine de reconnaissance la plus flexible possible.
Ces fanions sont caractérisés par un palier bas sur le fil SDCKA encadrant un nombre pair de fronts descendants d'horloge sur le fil SDCKB. Ils débutent avec le front descendant sur le fil SDCKA et se terminent avec le front montant sur ce même fil.
L'idée de départ est d'utiliser les interruptions que peuvent générer les changements d'état sur les broches du port B du micro-contrôleur, broches préalablement déclarées comme entrées.
L'exemple de routine d'interruption donné §6.4.7, page 159 du "SX User's Manual", va servir de base de départ.
La concrétisation de cet exemple se réalisera dans la pratique par raccordement du fil SDCKA sur RB0 (broche 10 du SX 28) et du fil SDCKB sur RB1 (broche 11), ainsi un changement d'état sur le Maple Bus pourra interrompre le SX28 si ce changement a été préalablement autorisé à pouvoir le faire.
L'interruption interne produite par le débordement du compteur RTCC pourra servir à abandonner une attente par "time-out" comme par exemple celle inhérente à la réception complète d'une trame.
La routine d'interruption ci-dessus se doit d'être intégrée à l'intérieur du source d'un programme.
Un programme source comporte en premier lieu des directives, ne serait ce que pour définir :
- Le vecteur de reset pointant sur la séquence d'initialisation.
- Les bits de configuration qui seront programmés en même temps que le code machine dans le micro-contrôleur SX28.
Il doit aussi comporter une séquence d'initialisation permettant de pré-positionner les entrées/sorties, la source des interruptions, les variables en mémoire, et cætera.
LIST | Q = 37, F = INHX16 | | ; Inhibit warning 37, Intel Hex output |
DEVICE | SX28AC | | ; Sets Device type inside «DEVICE» configuration register |
DEVICE | TURBO, SYNC, OSCHS3 | | ; Bits inside «FUSE» configuration register |
DEVICE | OPTIONX | | ; Bit inside «FUSEX» configuration register |
FREQ | 80_000_000 | | ; Sets up PLL on SX-Key module |
RESET | Init | | ; Sets reset vector |
| | | |
| org | $100 | ; Initialization code must reside inside page 0 |
Init | equ | $ | ; Initialization starts here |
La séquence d'initialisation devra principalement pré-positionner le port B et accessoirement quelques variables en mémoire, elle sera inspirée de l'exemple donné §4.4.1, page 137 du "SX User's Manual".
Comme seulement RB0 / SDCKA et RB1 / SDCKB seront utilisés, la séquence ci-dessus devra être modifiée pour n'initialiser que ces deux entrées.
Reprenons le source de l'exemple après avoir ajouté une quatrième ligne dans l'unique table de redirection pour traiter le cas exceptionnel où des changements d'états sur SDCA et SDCKB se produiraient en même temps.
| org | 0 | ; Interrupt routine starts at address 000H |
| mov | M, #9 | ; Set up MODE register to read WKPND_B |
| clr | W | ; Clear W to zero |
| mov | !RB, W | ; Exchange contents of W and WKPND_B |
| and | W, #00000011B | ; Mask out unused bits from WKPND_B |
| | | ; W now indicates cause of interrupt: |
| | | ; 00H = RTCC, 01H = RB0, or 02H = RB1 |
| add | PC, W | ; Add W to program counter for indirect jump |
| | | |
Pos0 | jmp | RTCCisr | ; W = 0, jump to RTCC interrupt service routine |
| jmp | Isr0A | ; W = 1, jump to SDCKA / RB0 ISR |
| jmp | Isr0B | ; W = 2, jump to SDCKB / RB1 ISR |
| reti | | ; W = 3, unexpected event |
| | | |
RTCCisr | nop | | ; RTCC ISR here |
| reti | | |
| | | |
Isr0A | nop | | ; SDCKA / RB0 ISR here |
| reti | | |
Isr0B | nop | | ; SDCKB / RB1 ISR here |
| reti | | |
L'émission d'un fanion par le dispositif de jeu (la console) produit tout d'abord un état bas sur SDCKA, donc une transition négative et par conséquent une interruption par changement d'état sur RB0.
Le logiciel du SX28 doit alors évoluer d'une position d'attente à une position de réception du fanion.
La seconde idée est celle de caractériser chaque position que sera amené à prendre le logiciel par une table de redirection spécifique. Ainsi les interruptions générées par une même source pourront être redirigées en fonction de la position logicielle courante vers la routine de traitement adéquate.
Ainsi l'unique table de redirection de l'exemple deviendra la toute première et figurera la position de repos.
La section commune dans la routine de traitement des interruptions devra être à même d'indexer la table de redirection correspondant à la position logicielle courante. Comme cette position est virtuelle et n'est concrétisée que par la table associée, une variable sera nécessaire pour stocker l'adresse de cette table :
- En fait il est plus pratique de stocker l'offset par rapport à la première table.
- Cet offset devra être positionné à zéro par la séquence d'initialisation générale suite à un reset du SX28.
| org | 8 | ; First address of user RAM |
Offset | ds | 1 | ; Offset of the table figuring current position |
Acount | ds | 1 | ; Used to count falling edges on SDCKA line |
Bcount | ds | 1 | ; Used to count falling edges on SDCKB line |
| | | |
| org | 0 | ; Interrupt routine starts at address 000H |
| mov | M, #9 | ; Set up MODE register to read WKPND_B |
| clr | W | ; Clear W to zero |
| mov | !RB, W | ; Exchange contents of W and WKPND_B |
| and | W, #00000011B | ; Mask out unused bits from WKPND_B |
| | | ; W now indicates cause of interrupt: |
| | | ; 00H = RTCC, 01H = RB0, or 02H = RB1 |
| add | W, Offset | ; Select table according to current position |
| add | PC, W | ; Add W to program counter for indirect jump |
Pos0 | | | ; First position : Standby |
| jmp | RTCCisr | ; W = 0, jump to RTCC interrupt service routine |
| jmp | Isr0A | ; W = 1, jump to SDCKA / RB0 ISR 0 |
| jmp | Isr0B | ; W = 2, jump to SDCKB / RB1 ISR 0 |
| reti | | ; W = 3, unexpected event |
Pos1 | | | ; Second position : Pattern being received |
| jmp | RTCCisr | ; W = 0, jump to RTCC ISR |
| jmp | Isr1A | ; W = 1, jump to SDCKA / RB0 ISR 1 |
| jmp | Isr1B | ; W = 2, jump to SDCKB / RB1 ISR 1 |
| reti | | ; W = 3, unexpected event |
| | | |
RTCCisr | nop | | ; RTCC ISR here |
| reti | | |
| | | |
Isr0A | | | ; SDCKA / RB0 ISR 0 starts here |
| mode | 10 | ; Select WKED_B |
| mov | !RB, #11111110B | ; Pattern ends with rising edge on RB0 / SDCKA |
| clr | Bcount | ; Reset SDCKB falling edges counter |
| mov | Offset, #(Pos1 - Pos0) | ; Compute and save offset for next position |
| reti | | |
Isr0B | nop | | ; SDCKB / RB1 ISR 0 starts here |
| reti | | |
| | | |
Isr1A | nop | | ; SDCKA / RB0 ISR 1 here |
| reti | | |
Isr1B | nop | | ; SDCKB / RB1 ISR 1 here |
| reti | | |
En rouge le traitement effectué par la routine d'interruption suite à la détection d'un début de fanion :
- Inversion de la sensibilité sur RB0 pour que la prochaine interruption se produise en fin de fanion avec la transition positive sur SDCKA.
- Le compteur de transitions négatives sur RB1 / SDCKB est réinitialisé à zéro.
- La position logicielle est modifiée, elle évolue de "Attente / Stanby" à "Réception de fanion en cours / Pattern being received".
La présence d'un fanion ayant été détectée, il va alors être nécessaire :
- De compter les transitions négatives sur SDCKB / PB1 afin de pouvoir déterminer par la suite le type de fanion reçu.
C'est la routine d'interruption Isr1B qui effectue ce job. - De traiter le fanion une fois complet, c'est le front montant sur SDCKA / PB0 qui en délimite la fin.
La position logicielle devra à nouveau évoluer vers celle spécifique au type de fanion reçu, c'est la routine Isr1A qui va effectuer cette tâche.
Isr0A | | | ; SDCKA / RB0 ISR 0 starts here |
| mode | 10 | ; Select WKED_B |
| mov | !RB, #11111110B | ; Pattern ends with rising edge on RB0 / SDCKA |
| clr | Bcount | ; Reset SDCKB falling edges counter |
| mov | Offset, #(Pos1 - Pos0) | ; Compute and save offset for next position |
| reti | | |
Isr0B | nop | | ; SDCKB / RB1 ISR 0 starts here |
| reti | | |
| | | |
Isr1A | | | ; SDCKA / RB0 ISR 1 starts here |
| mov | W, #11110001B | ; Mask for hiding bits 1 to 3 |
| and | W, Bcount | ; Check Bcount |
| sz | | ; Keep only even count less than 16 |
| jmp | Count0 | ; Others discarded |
| mov | W, Bcount | ; Get the even count in W |
| add | PC, W | ; Add W to PC for indirect jump |
| | | |
Count0 | | | ; Table of jumps, 8 × 2 instructions |
| clr | Offset | ; Spurious pulse on SDCKA line if count zero else unused patterns |
| jmp | PattEnd | ; Return to standby |
| clr | Offset | ; Count 2 : Unused pattern, return to stanby |
| jmp | PattEnd | |
| mov | w, #(Pos2 - Pos0) | ; Count 4 : «Start» pattern |
| jmp | Count4 | |
| clr | Offset | ; Count 6 : Unused pattern, return to standby |
| jmp | PattEnd | |
| mov | w, #(Pos3 - Pos0) | ; Count 8 : «SDCKB occupancy permission» pattern |
| jmp | Count8 | |
| clr | Offset | ; Count 10 : Unused pattern, return to standby |
| jmp | PattEnd | |
| clr | Offset | ; Count 12 : Unused pattern, return to standby |
| jmp | PattEnd | |
| page | $07FE | ; Count 14 : «Reset» pattern |
| jmp | $07FE | ; Jump immediatly to SX28 reset vector |
| | | |
Isr1B | | | ; SDCKB / RB1 ISR 1 starts here |
| inc | Bcount | ; Count falling edges on SDCKB / RB1 wire |
| reti | | |
La routine Isr1A (
en rouge) est appelée par la transition positive sur PB0 / SDCKA. Cette transition détermine la fin du fanion.
- Le compteur Bcount qui a permis de comptabiliser les transitions sur PB1 / SDCKB est testé. Un nombre de transitions impair ou «supérieur ou égal à 16» est rejeté. Le fanion reçu est alors ignoré et le logiciel retourne en position standby.
- Le nombre de transitions étant reconnu pair et plus petit que 16, sert à indexer une table de 8 lignes, chaque ligne comportant deux instructions. Ces deux instructions permettent d'accepter le fanion ou bien de le rejeter et de retourner à la position standby.
- En cas d'acceptation, exception faite du fanion «Reset», l'offset associé à la nouvelle position logicielle est calculé et la routine d'interruption se poursuit avec un traitement différent pour chaque type de fanion. («Start» ou «SDCKB Occupy authorization»).
La routine Isr1B (
en bleu) appelée par une transition négative sur PB1 / SDCKB comptabilise ces transitions.
Le traitement de fin de la routine est pratiquement la même quelque soit le type de fanion reçu. Seul le fanion «Start» prépare la réception des données qui le suivent en réinitialisant le compteur de bits et le compteur d'octets avant de rejoindre le tronc commun.
Count4 | | | ; Ends ISR for the «Start» pattern |
| clr | BitCnt | ; Reset bit counter |
| clr | ByteCnt | ; Reset byte counter |
| | | |
Count8 | | | ; Ends ISR for the «SDCKB occupancy permission» pattern |
| mov | Offset, W | ; Save offset for new position |
| | | |
PattEnd | | | ; Ends ISR for all patterns, even those rejected |
| mode | 10 | ; Select WKED_B |
| mov | !RB, #11111111B | ; Falling edge on RB.1 and RB.0 |
| reti | | |
La réception du fanion «Reset» est le cas à part puisqu'elle entraîne immédiatement la réinitialisation du SX28 par appel à son vecteur de reset localisé à l'adresse $07FF (c'est l'adresse de la dernière ligne de la mémoire programme). En fait il s'agit d'une instruction de saut court localisée en $07FF que le SX28 va rechercher à cette adresse immédiatement après un reset.
Le problème est que le vrai reset réinitialise préalablement les registres internes, dont les bits de pagination, avant d'exécuter l'instruction de saut du vecteur alors qu'un appel par programme ne le fait pas. C'est pour cette raison que l'appel du vecteur se fera plutôt sur l'adresse qui le précède, en $07FE, où l'on aura pris soin d'insérer une instruction de positionnement de page.
RESET | Init | | ; Reset Vector @ $07FF |
| ... | ... | |
| org | $07FE | |
| page | 0 | ; Reset page number before using reset vector. |
La directive assembleur "RESET" est, en principe, placée au début du programme source.
Maintenant que cet algorithme de décodage est établi et son déroulement simulé avec le programme SXSim cité dans le précédent message, il ne reste plus qu'à le tester en grandeur réelle avec différents fanions qui seront générés dans un premier temps grâce à la fonction générateur de l'analyseur Scanalogic 2.
A suivre...