Site logo

Triceraprog
La programmation depuis le Crétacé

  • Tuiles des plus très-curieuses ()

    Et voici la cinquième session de Retro Programmers United for Obscure Systems, organisée par Olipix qui se termine !

    Et j'y ai participé.

    La machine

    Tout d'abord, la machine. Le principe de cette game jam est de développer un jeu pour une machine qui n'a pas eu une grande ludothèque. Avec le Matra Alice, la question se posait. En effet, la première machine de la gamme, le Matra Alice 4k, est la même machine que le Tandy MC-10, qui a lui une ludothèque un peu plus fournie.

    L'idée était donc de se concentrer plutôt sur les deux autres machines de la gamme commerciale : le Matra Alice 32 et le Matra Alice 90. Ces machines, qui offrent une compatibilité au niveau BASIC avec la première, sont néanmoins différentes, en particulier à cause d'un processeur graphique différent. Dans ces deux machines, il s'agit de l'EF9345. Le même qui équipe le VG5000µ, avec la même taille de mémoire vidéo associée, 8k.

    Autant dire que niveau graphique, j'étais en terrain connu.

    Niveau processeur par contre, c'est une découverte. Le 6803 est un microcontrôleur 8 bits, de la famille des 6800. Mais je ne connaissais pas vraiment. En tout cas, je n'en avais aucune pratique. Il a de la RAM embarquée sur la page 0. Il a aussi un chronomètre (timer), normalement utilisée pour les communications (séries et cassette).

    Le développement

    Avant de parler du jeu, un mot sur le développement. Comme je venais de recevoir l'extension « Multiports » , je voulais que le jeu puisse être sur cartouche. Autre avantage, pas de temps de chargement si l'émulateur gère bien cette extension.

    Vous le savez si vous avez lu d'autres articles sur ce blog, j'aime bien avoir une chaîne de développement avec le maximum d'automatismes, pour me concentrer sur le développement du jeu et faire le moins d'opérations manuelles possibles.

    Mon choix habituel va vers MAME. Et MAME a un support pour l'Alice... mais pas pour l'extension. Mon premier développement a donc été d'ajouter à MAME le support de l'extension, en tout cas le support cartouche et l'ajout de RAM. Le changement a été accepté, mais j'ai quelques modifications qui m'ont été demandées et que je dois toujours terminer.

    Utilisant mes scripts d'automatisation habituels, j'avais en tout cas de quoi lancer l'émulateur automatiquement après une compilation.

    Cependant pour compiler... il faut un compilateur. Il n'y a pas beaucoup de choix pour le 6803 pour un compilateur C, et légèrement plus, mais pas trop, pour un assembleur. Dans un premier temps, j'ai fais quelques tests avec un premier assembleur... mais avec le jeu que je voulais faire, je me suis dit que j'y gagnerais en productivité avec un compilateur C.

    Après quelques recherches et essais, j'ai choisi CC6303. Le message « The assembler and linker should be reasonably reliable and complete. » m'a fait un peu peur, mais j'ai quand même tenté. J'ai fais des tests, et ça semblait générer du code correct.

    Sur toute la durée du développement, j'ai eu deux fois des problèmes de génération de code. Je ne les ai pas analysés plus que ça, car c'était (bien entendu) vers la fin.

    J'ai contribué à une paire de modifications au passage. Au moins, la game jam aura permis modestement d'améliorer les outils de développement pour cette machine.

    Le jeu

    Comme d'habitude, je suis parti sur une idée bien trop ambitieuse, et avec le premiers mois consacré à la découverte de la machine et aux modifications de MAME, j'ai dû revoir mes plans. En fait, même avec la totalité du temps, je n'aurais pas pu faire ce que je voulais...

    Je suis donc parti sur une idée de jeu que je voulais aussi faire : un Match-3. C'est un type de jeu auquel je joue beaucoup. C'est aussi un type de jeu qui a beaucoup de variations : est-ce que les tuiles tombent, est-ce qu'elles montent, est-ce qu'elles sont renouvelées, quel scoring, quels bonus, des challenges, etc.

    Pour démarrer, j'ai fait un prototype avec un terrain de 10 par 10, toujours rempli de tuiles. Lorsque 3 tuiles identiques ou plus sont alignées, elles disparaissent. Les tuiles du dessus tombent, et des nouvelles tuiles apparaissent en haut. Les tuiles étaient représentées par des chiffres. Le but pour moi était de 1/ trouver l'algorithme de recherche des tuiles alignées, 2/ vérifier que la machine était assez puissante pour ce type de jeu.

    Prototype du jeu

    Une fois le prototype fonctionnel, j'ai commencé à ajouter des graphismes. J'ai utilisé Pixelorama pour dessiner les tuiles, avec un thème « Alice au Pays des Merveilles ». Comme je l'ai fait auparavant, j'exporte manuellement les images en PNG (j'aimerais bien un export automatique, mais cela ne semble pas possible pour le moment, ou alors je n'ai pas trouvé). Ces imagines PNG sont ensuite converties en données dans un format que je peux inclure dans le code.

    De temps en temps, je lançais un test sur la machine réelle. C'est ainsi que je me suis aperçu que mon extension a un problème avec son extension RAM. Comme je n'avais pas le temps de m'en occupé, j'ai coupé la RAM supplémentaire (c'est une option de l'extension). Le jeu n'a pas besoin de beaucoup de mémoire, le code et les données graphiques étant présents dans la ROM.

    Les tuiles

    Une fois le jeu fonctionnel, je voulais ajouter un principe de challenges pour avoir une sorte de mode « histoire ». Je voulais aussi ajouter un mode « infini », mais je n'aurai pas assez de place pour ça. Je voulais aussi ajouter un petit personnage qui réagit aux actions du joueur.

    Dessiner un personnage avec les contraintes de couleur et mes (bas) talents de dessinateur a été un peu compliqué, mais je suis assez content du résultat.

    INSÉRER IMAGE AVEC LE PERSONNAGE Le personnage animé

    Problème : la place sur la cartouche. Une cartouche d'extension Multiports a une taille totale de 64k. En mode cartouche, cette taille est divisée en 8 banques de 8k. Cela signifie qu'à un moment donné, il n'y a que 8ko accessible. Le Multiports a un système simpliste de changement de banque : il suffit d'écrire sur une plage de donnée précise le numéro de la banque voulue. C'est suffisant, mais sans support du compilateur, c'est un peu acrobatique.

    Je n'avais pas le temps de pousser un système d'appels de code entre les banques, j'ai donc séparé le jeu en deux grandes parties. Dans la première partie, et donc la première banque, je mets tout ce qui est graphiques. C'est une astuce sur les jeux cassettes que je reprends ici : un premier programme se charge et redéfini les caractères. Ensuite, il lance le jeu.

    La première banque contient aussi l'écran de titre.

    Le cœur du jeu est dans la deuxième banque. Pour passer d'une banque à l'autre, j'ai un petit bout de code que je place en RAM pour faire le changement. Chaque programme est compilé comme un logiciel indépendant.

    Mais... et le titre ?

    Le titre est une référence à la traduction française de « Alice's Adventures in Wonderland » qui est trouvable sur le projet Gutenberg. Le chapitre deux commence par ce passage : « “De plus très-curieux en plus très-curieux!” s’écria Alice ».

    Dans mon jeu, Alice se retrouve dans un monde étrange avec des tuiles à aligner. On ne peut pas dire que ça va très loin d'un point de vue histoire et justification... mais ça suffira.

    Oh, et j'ai aussi dessiné une jaquette pour la cartouche et la manuel. À base de dessin sur tablette et de beaucoup de temps de retouche avec The Gimp, puis de composition avec Blender pour ajouter les tuiles.

    Quelques liens

    Conclusion

    Le jeu est disponible sur itch.io. J'ai rapidement ajouté une version cassette, car tout le monde n'a pas un Multiports (pas encore disponible sur la page, elle sera dans la version 1.1 que j'ajouterai bientôt).

    Tuiles des plus très-curieuses


  • Notes sur le Motorola 6809 ()

    Je place ici quelques notes sur le Motorola 6809, pour me remettre rapidement dans le bain lorsque je change de processeur.

    Registres

    • 2 accumulateurs 8 bits A et B, qui peuvent se joindre en un seul accumulateur 16 bits D
    • 1 registre d'index X 16 bits
    • 1 registre SP (Stack Pointer)
    • 1 registre PC (Program Counter)
    • 1 registre d'état : 11HINZVC
      • 5, H : half carry
      • 4, I : interrupt
      • 3, N : negative
      • 2, Z : zero
      • 1, V : overflow
      • 0, C : carry

    Interruptions

    • NMI (Non Maskable Interrupt)
    • IRQ1 (Interrupt Request) : pour les périphériques externes
    • IRQ2 (Interrupt Request) : pour le timer et l'interface série

    IRQ1 a la priorité sur IRQ2.

    Vecteurs d’interruptions :

    MSB LSB Interruption
    FFFE FFFF Reset
    FFFC FFFD NMI
    FFFA FFFB Software interrupt (SWI)
    FFF8 FFF9 IRQ1
    FFF6 FFF7 ICF (Input Capture)
    FFF4 FFF5 OCF (Output Compare)
    FFF2 FFF3 TOF (Timer Overflow)
    FFF0 FFF1 SCI (RDRF + ORFE + TDRE)

    Ensemble des Instructions

    Mode d'adressage

    • Implied/Inherent : aucune donnée n'est nécessaire
    • Immediate : la donnée est dans l'instruction (1 ou 2 octets)
    • Direct : la donnée est dans l'octet suivant (1 octet, le poids fort est fixé à $00)
    • Extended : la donnée est dans les deux octets suivants (adresse 16 bits)
    • Indexed : la donnée est dans la mémoire, à l'adresse donnée par le registre d'index (opérande de 8 bits ajoutée à X)
    • Relative : la donnée est dans l'octet suivant, signée (pour les branchements)

    Instructions

    Opérations à pointeur Mnemonic Imm Dir Ind Ext Inh Operation HINZVC
    Compare Index Reg CPX X X X X X - M : M + 1 ..!!!!
    Decrement Index Reg DEX X X - 1-> X ...!..
    Decrement SP DES X SP - 1-> SP ......
    Increment Index Reg INX X X + 1-> X ...!..
    Increment SP INS X SP + 1-> SP ......
    Load Index Reg LDX X X X X M -> Xh, M+1 -> Xl ..!!0.
    Load SP LDS X X X X M -> SPh, M+1 -> SPl ..!!0.
    Store Index Reg STX X X X Xh -> M, Xl -> M+1 ..!!0.
    Store SP STS X X X SPh -> M, SPl -> M+1 ..!!0.
    Index to Stack TXS X X - 1 -> SP ......
    Stack to Index TSX X SP + 1 -> X ......
    Add B with X ABX X B + X -> B ......
    Push X PSHX X Xl->(SP),SP-1>SP,Xh... ......
    Pull X PULX X (SP)+1->SP,Xh->Xh,... ......
    Operations Acc. & Mémoire Mnemonic Imm Dir Ind Ext Inh Operation HINZVC
    Add Accumulators ABA X A + B -> A !.!!!!
    Add B to X ABX X 00:B + X -> X ......
    Add A with Carry ADCA X X X X A + M + C -> A !.!!!!
    Add B with Carry ADCB X X X X B + M + C -> B !.!!!!
    Add with A ADDA X X X X A + M -> A !.!!!!
    Add with B ADDB X X X X B + M -> B !.!!!!
    Add Double ADDD X X X X D + M:M+1 -> D ..!!!!
    And with A ANDA X X X X A & M -> A ..!!0.
    And with B ANDB X X X X B & M -> B ..!!0.
    Shift Left Arithmetic M ASL X X B7 dans C, C dans B0 ..!!!!
    Shift Left Arithmetic A ASLA X B7 dans C, C dans B0 ..!!!!
    Shift Left Arithmetic B ASLB X B7 dans C, C dans B0 ..!!!!
    Shift Left Arithmetic D ASLD X B15 dans C, C dans B0 ? ..!!!!
    Shift Right Arithmetic M ASR X X B0 dans C, B7 dans B7 ..!!!!
    Shift Right Arithmetic A ASRA X B0 dans C, B7 dans B7 ..!!!!
    Shift Right Arithmetic B ASRB X B0 dans C, B7 dans B7 ..!!!!
    Bit Test A BITA X X X X A & M, A non modifié ..!!0.
    Bit Test B BITB X X X X B & M, B non modifié ..!!0.
    Compare A/B with M CBA X A & B, A/B non modifié ..!!!!
    Clear Memory CLR X X 00 -> M ..0100
    Clear A CLRA X 0 -> A ..0100
    Clear B CLRB X 0 -> B ..0100
    Compare with A CMPA X X X X A - M ..!!!!
    Compare with B CMPB X X X X B - M ..!!!!
    1's Complement M COM X X ~M -> M ..!!01
    1's Complement A COMA X ~A -> A ..!!01
    1's Complement B COMB X ~B -> B ..!!01
    Decimal Adj. A DAA X Ajustement BCD ..!!!!
    Decrement M DEC X X M - 1 -> M ..!!!.
    Decrement A DECA X A - 1 -> A ..!!!.
    Decrement B DECB X B - 1 -> B ..!!!.
    Exclusive OR with A EORA X X X X A ^ M -> A ..!!0.
    Exclusive OR with B EORB X X X X B ^ M -> B ..!!0.
    Increment M INC X X M + 1 -> M ..!!!.
    Increment A INCA X A + 1 -> A ..!!!.
    Increment B INCB X B + 1 -> B ..!!!.
    Load to A LDAA X X X X M -> A ..!!0.
    Load to B LDAB X X X X M -> B ..!!0.
    Load to D LDD X X X X M:M+1 -> D ..!!0.
    Logical Shift Left M LSL X X B7 dans C, 0 dans B0 ..!!!!
    Logical Shift Left A LSLA X B7 dans C, 0 dans B0 ..!!!!
    Logical Shift Left B LSLB X B7 dans C, 0 dans B0 ..!!!!
    Logical Shift Left D LSLD X B15 dans C, 0 dans B0 ? ..!!!!
    Shift Right Logical M LSR X X B0 dans C, 0 dans B7 ..0!!!
    Shift Right Logical A LSRA X B0 dans C, 0 dans B7 ..0!!!
    Shift Right Logical B LSRB X B0 dans C, 0 dans B7 ..0!!!
    Shift Right Logical D LSRD X B0 dans C, 0 dans B15 ? ..0!!!
    Multiply MUL X A * B -> D .....!
    2's Complement M NEG X X -M -> M ..!!!!
    2's Complement A NEGA X -A -> A ..!!!!
    2's Complement B NEGB X -B -> B ..!!!!
    No Operation NOP X ......
    Logical OR with A ORAA X X X X A M -> A
    Logical OR with B ORAB X X X X B M -> B
    Push A PSHA X A -> (SP), SP - 1 -> SP ......
    Push B PSHB X B -> (SP), SP - 1 -> SP ......
    Pull A PULA X SP + 1 -> SP, (SP) -> A ......
    Pull B PULB X SP + 1 -> SP, (SP) -> B ......
    Rotate Left M ROL X X C dans B0, B7 dans C ..!!!!
    Rotate Left A ROLA X C dans B0, B7 dans C ..!!!!
    Rotate Left B ROLB X C dans B0, B7 dans C ..!!!!
    Rotate Right M ROR X X C dans B7, B0 dans C ..!!!!
    Rotate Right A RORA X C dans B7, B0 dans C ..!!!!
    Rotate Right B RORB X C dans B7, B0 dans C ..!!!!
    Subtract A with B SBA X A - B -> A ..!!!!
    Subtract with Carry with A SBCA X X X X A - M - C -> A ..!!!!
    Subtract with Carry with B SBCB X X X X B - M - C -> B ..!!!!
    Store A STAA X X X A -> M ..!!0.
    Store B STAB X X X B -> M ..!!0.
    Store D STD X X X D -> M:M+1 ..!!0.
    Subtract from A SUBA X X X X A - M -> A ..!!!!
    Subtract from B SUBB X X X X B - M -> B ..!!!!
    Subtract Double SUBD X X X X D - M:M+1 -> D ..!!!!
    Transfer A to B TAB X A -> B ..!!0.
    Transfer B to A TBA X B -> A ..!!0.
    Test Zero or Minus M TST X X M, M non modifié ..!!00
    Test Zero or Minus A TSTA X A, A non modifié ..!!00
    Test Zero or Minus B TSTB X B, B non modifié ..!!00
    Sauts et Branches Mnemonic Dir Rel Ind Ext Inh Test HINZVC
    Branch Always BRA X ......
    Branch Never BRN X ......
    Branch on Carry Clear BCC X C = 0 ......
    Branch on Carry Set BCS X C = 1 ......
    Branch on Equal BEQ X Z = 1 ......
    Branch on Greater or Equal BGE X N ^ V = 0 ......
    Branch on Greater BGT X (N ^ V) Z = 0
    Branch on Higher BHI X C + Z = 0 ......
    Branch on Higher or Same BHS X C = 0 ......
    Branch on Less or Equal BLE X (N ^ V) Z = 1
    Branch on Less than 0 BLT X N ^ V = 1 ......
    Branch on Minus BMI X N = 1 ......
    Branch on Not Equal BNE X Z = 0 ......
    Branch on Overflow Clear BVC X V = 0 ......
    Branch on Overflow Set BVS X V = 1 ......
    Branch on Plus BPL X N = 0 ......
    Branch to Subroutine BSR X ......
    Jump JMP X X ......
    Jump to Subroutine JSR X X X ......
    Return from Interrupt RTI X !!!!!!
    Return from Subroutine RTS X ......
    Software Interrupt SWI X !1!!!!
    Wait for Interrupt WAI X ......
    Manipulation des drapeaux Mnemonic Inh Operation HINZVC
    Clear Carry CLC X 0 -> C .....0
    Clear Interrupt CLI X 0 -> I .0....
    Clear Overflow CLV X 0 -> V ....0.
    Set Carry SEC X 1 -> C .....1
    Set Interrupt SEI X 1 -> I .1....
    Set Overflow SEV X 1 -> V ....1.
    Accumulator to CCR TAP X A -> CCR !!!!!!
    CCR to Accumulator TPA X CCR -> A ......

    Ports

    Port 1

    P10-P17 : entrées/sorties, 8 bits. Toutes les lignes sont configurables en entrée ou en sortie indépendamment.

    Port 2

    P20-P24 : entrées/sorties, 5 bits.

    • P20 et P21 déterminent le mode de fonctionnement du processeur (lors du reset)
    • Si P21 est configuré en sortie, il est lié à la fonction de comparison du timer
    • Peut être utilisé comme port série
    • Les lignes sont configurables en entrée ou en sortie indépendamment.

    Port 3

    P30-P37 : entrées/sorties, 8 bits. Adresses et données multiplexées. A0 à A7 et D0 à D7.

    Port 4

    P40-P47 : adressage de la mémoire externe, A8 à A15.

    Mémoire interne

    • 128 octets de RAM interne

    Timer programmable

    • Compteur ($09:$0A) : lecture seule. Une écriture dans $09 reset le compteur à $FFF8, à éviter.
    • Comparateur ($0B:$0C) : 16 bits, lecture/écriture. Lorsqu'il est égal au compteur, OCF est mis à 1.
    • Capture d'entrée ($0D:$0E) : lecture seule. Enregistre la valeur du compteur lorsqu'une transition est détectée, tel que définie par IEG.
    • Contrôle du Timer ($08) : lecture, écriture sur bits 0-4. Les bits de poids fort représentent l'état.

  • Sous le capot de l'Alice 32/90, un EF9345 ()

    La machine de la nouvelle session du « Retro Programmers United for Obscure Systems » est connue. C'est le Matra Alice. Et plus exactement les version 32 et 90, afin de s'échapper de la trop grande proximité entre le Alice premier du nom et le Tandy MC-10 (une telle proximité que ce sont les mêmes machines).

    Les versions 32 et 90 étant très similaires niveau hardware, je les nommerais conjointement Alice 32/90.

    Pour cet article, ce qui va m'intéresser est que l'Alice 32/90 utilise un EF9345, comme le VG5000. Et l'EF9345 étant aussi utilisé dans le VG5000µ, c'est une puce que je connais bien. Cependant, l'Alice 32/90 l'utilise différemment. Je dirais même qu'il l'utilise mieux.

    L'autre axe de cet article est que je veux utiliser l'EF9345 depuis le BASIC. La machine tournant avec un 6803, les I/O sont mappées en mémoire. Et il est donc possible d'accéder aux registres de l'EF9345 depuis le BASIC avec des PEEKs et POKEs. Pas besoin de passer par l'assembleur. Par contre, pas de mystère, c'est lent !

    Le mode graphique en BASIC sur l'Alice

    Première chose amusante, l'Alice 32/90 démarre dans un mode 32 colonnes qui n'existe pas pour l'EF9345. Je pense que ce mode par défaut, qui utilise en fait le mode 40 colonnes de l'EF9345, est là pour être compatible avec le Alice 4k au niveau BASIC. Pour assurer cette compatibilité, des caractères utilisateurs sont chargés dans la RAM vidéo au démarrage pour représenter les différentes combinaison d'un bloc de 2x2 « gros pixels » pour chaque caractère.

    L'Alice 32/90 peut cependant utiliser l'EF9345 en vrai mode 40 colonnes, et même en mode 80 colonnes. Pour cela passer d'un mode à l'autre, il faut utiliser les commandes CLS32, CLS40 et CLS80. Je vais me concentrer sur le mode 40 colonnes.

    Celui-ci est initialisé dans le mode « 40 CHAR LONG ». C'est un mode qui prend trois pages de 1Ko en mémoire vidéo. La première page contient les caractères, la deuxième les attributs et la troisième les couleurs. Ça fait beaucoup sur les 8ko de RAM vidéo de la machine, et le VG5000µ avait fait le choix d'utilise le mode « 40 CHAR SHORT » qui ne prend que 2ko. Cependant, on y gagner en simplicité et flexibilité au niveau des attributs.

    Autre choix de l'Alice : le système ne conserve pas de miroir en RAM de l'affichage. Là encore, bon choix pour l'utilisation de la RAM principale. En contrepartie cela signifie que les opérations non prévues par le BASIC devront se faire en s'adressant directement à l'EF9345.

    Plus techniquement, le mode est initialisé avec les registres suivants :

    - TGS = 0x10 (binaire: 00010000) -> 312 lignes non entrelacées, synchro composite, pas de synchro entrante, service row = 0, 40 Char Long
    - MAT = 0x28 (binaire: 00101000) -> couleur de marge noire, curseur complet clignotant, curseur désactivé (!), simple hauteur
    - PAT = 0x67 (binaire: 01100111) -> service row visible, bulk haut et bas visible, conceal désactivé, flash activé
    - DOR = 0x13 (binaire: 00010011) -> page G'0 située en Z = 3, page G'10 située en Z = 2, page Q située en Z = 0
    - ROR = 0x08 (binaire: 00001000) -> première ligne bulk = 8, page d'origine Z = 0
    

    Les registres de l'EF9345

    Depuis le processeur, l'EF9345 est accessible via 8 registres. Ces registres sont accessibles en lecture et écriture, et sont tous des registres de 8 bits. Ils sont accessibles via les adresses suivantes :

    - R0 = $BF20 ; 48928 (commande)
    - R1 = $BF21 ; 48929 (paramètre principal)
    - R2 = $BF22 ; 48930 (paramètre)
    - R3 = $BF23 ; 48931 (paramètre)
    - R4 = $BF24 ; 48932 (pointeur auxiliaire haut)
    - R5 = $BF25 ; 48933 (pointeur auxiliaire bas)
    - R6 = $BF26 ; 48934 (pointeur principal haut)
    - R7 = $BF27 ; 48935 (pointeur principal bas)
    

    Une adresse supplémentaire est située en $BF28 (48936). Il s'agit en fait de R0 mais avec le flag d'exécution (bit 7 du numéro de registre) mis à 1. Cela permet de demander à l'EF9345 d'exécuter la commande indiquée dans R0.

    Techniquement, n'importe quel registre peut être utilisé pour exécuter une commande en mettant le bit 7 à 1. Cela permet d'ailleurs quelques optimisations. Je n'ai pas vérifié si les adresses au delà de $BF28 étaient mappées. Si ce n'est pas le cas, on n'utilisera pas, voire jamais, R0 directement en écriture directement, mais toujours via le « faux registre » R8.

    Note additionnel : le livre "les astuces d'Alice 32 et 90" indique qu'il est en effet possible d'utiliser tous les registres en mode « exécution ».

    Un premier affichage

    Voici un programme qui place tous les registres directs correctement pour afficher un « A » à l'écran sur la ligne 0 (ligne de service), colonne 10. Notez que cela fonctionnera parfaitement en mode CLS32. Vous pouvez vous amuser à écrire où vous voulez dans l'espace de 40 colonnes par 25 lignes pour constater que le mode 32 colonnes est en fait le mode 40.

    Attention, dans cette configuration de l'EF9345, la deuxième ligne affichée est la ligne... numéro 8.

    100 REM AFFICHE UN CARACTERE
    110 POKE 48928, 0   : REM R0 (COMMANDE) KRF / INUTILE
    120 POKE 48929, 65  : REM R1 (C)
    130 POKE 48930, 0   : REM R2 (B)
    140 POKE 48931, 20  : REM R3 (A)
    150 POKE 48932, 0   : REM R4 (NA pour KRF)
    160 POKE 48933, 0   : REM R5 (NA pour KRF)
    170 POKE 48934, 0   : REM R6 (MP / LIGNE)
    180 POKE 48935, 10  : REM R7 (MP / COL)
    190 POKE 48936, 1   : REM R0 + EXEC (KRF)
    

    Une démonstration plus complète

    Voici un programme de démonstration plus complet, mais pas entièrement, puisqu'il y a plein de choses à faire avec l'EF9345 qui ne sont pas démontrées ici.

    Attention : je n'ai pas du tout testé sur vrai matériel. L'EF9345 étant sensible aux synchronisations (on ne peut pas lui parler n'importe quand), je ne sais pas à quel point le BASIC est capable de gérer cela. Il est possible que ce programme ne fonctionne pas bien sur vrai matériel. Je suis preneur de retours (et j'essaierai moi même un de ces jours).

    Voici quelques commentaires :

    • En ligne 100, on initialise les registres nécessaires pour afficher une chaîne de caractère utilisant les mêmes attributs.
    • En ligne 200, on initialise les registres restants pour afficher un caractère et passer à la colonne suivante (attention, il n'y a pas de détection de fin de ligne).
    • En ligne 300, on initialise tous les registres pour afficher un caractère avec des attributs différents. Dans les commentaires KRF est le nom de la commande d'affichage d'un caractère en mode « 40 CHAR LONG ».
    • En ligne 400, une routine se charge de monter en mémoire vidéo les données pour un caractère utilisateur.
    • En ligne 10000, c'est le début du test et j'affichage "BONJOUR". C'est un PRINT en bien plus compliqué et bien plus lent...
    • En ligne 10100, j'affiche les 128 caractères alphanumériques en ROM de l'EF9345.
    • En ligne 10200, j'affiche une autre plage de 32 caractères, graphiques, en ROM de l'EF9345.
    • En ligne 10300, j'affiche les 128 caractères semi-graphiques en ROM de l'EF9345. Dans ces trois affichages, c'est la variable B qui indique le type de caractères à utiliser.
    • En ligne 10400, j'affiche un caractère graphique plein pour montrer les 16 teintes disponibles pour les caractères.
    • En ligne 11000, je tente de lire les registres indirects de l'EF9345. Cela ne fonctionne pas tout à fait bien. Possible que ce soit un problème de synchro (d'où la petite boucle, même si 1/ ce n'est pas comme cela qu'on synchronise l'EF9345 2/ la lenteur du BASIC me fait penser que quoique l'on fasse, il y a toujours un risque de tomber au mauvais moment).
    • En ligne 12300, je modifie le registre indirect ROR afin de faire un scrolling vertical. Comme la mémoire « sous » l'écran n'est pas préparée, cela affiche un peu n'importe quoi. C'est surtout une démonstration de l'utilisation de registre indirect en écriture.
    • En ligne 13000, je charge un caractère utilisateur (le bonhomme du manuel du VG5000µ) puis j'affichage un des « sets » de caractères redéfinis. Particularité : c'est un ensemble de 100 caractères allant de 0 à 3, puis de 32 à 127... L'adresse de destination A=192 est aussi assez compliquée à calculer (en tout cas, ça ne s'invente pas, et le datasheet demande une grande attention, je ferai peut-être un article séparé là-dessus). Dans les caractères affichés, vous verrez les blocs redéfinis pour la compatibilité avec l'Alice 4k.

    Pour la manière dont fonctionne la mémoire de l'EF9345, en attendant un article, vous pouvez tentez de comprendre avec le code du fichier ef9345_memory.py dans mon dépôt GitHub dédié aux outils d'étude pour le VG5000µ.

    10 CLS:GOTO 10000
    
    100 REM PREPARATION AFFICHAGE CARACTERE
    110 POKE 48930,B
    120 POKE 48931,A
    130 POKE 48934,Y
    140 POKE 48935,X
    150 RETURN
    
    200 REM AFFICHE UN CARACTERE AVEC INCREMENTATION
    210 POKE 48929,C
    220 POKE 48936,1:REM KRF + INCR
    230 RETURN
    
    300 REM AFFICHE UN SEUL CARACTERE COMPLET
    310 POKE 48929,C
    320 POKE 48930,B
    330 POKE 48931,A
    340 POKE 48934,Y
    350 POKE 48935,X
    360 POKE 48936,0:REM KRF
    370 RETURN
    
    400 REM CHARGEMENT D'UN CARACTERE REDÉFINI
    410 FOR I=1 TO 10
    420 READ C
    430 POKE 48932,INT(A/256)
    440 POKE 48933,A AND 255
    450 POKE 48929,C
    460 POKE 48936,48+4:REM OCT + AUX_PTR (EXEC)
    470 A=A+4
    480 NEXT I
    490 RETURN
    
    10000 REM PROGRAMME DE TEST
    10010 X=5:Y=0 : REM COORDONNEE
    10020 B=0:A=20 : REM ATTRIBUTS
    10030 A$="BONJOUR"
    10040 GOSUB 100
    10050 FOR I=1 TO LEN(A$)
    10060 C=ASC(MID$(A$,I,1))
    10070 GOSUB 200
    10080 NEXT I
    
    10100 REM AFFICHAGE DE CARACTERES
    10110 Y=8:X=0:B=0:A=112
    10120 FOR C=0 TO 127
    10130 IF X>39 THEN X=0:Y=Y+1
    10140 X=X+1
    10150 GOSUB 300
    10160 NEXT C
    
    10200 Y=12:X=0:B=48:A=112
    10210 FOR C=0 TO 31
    10220 GOSUB 300
    10230 X=X+1
    10240 NEXT C
    
    10300 Y=13:X=0:B=32:A=112
    10310 FOR C=0 TO 127
    10320 IF X>39 THEN X=0:Y=Y+1
    10330 GOSUB 300
    10340 X=X+1
    10350 NEXT C
    
    10400 REM COULEURS
    10410 Y=17:X=0:B=32:C=127
    10420 FOR A=16 TO 112 STEP 16
    10430 GOSUB 300
    10440 X=X+1
    10450 NEXT A
    10460 Y=18:X=0:B=33
    10470 FOR A=16 TO 112 STEP 16
    10480 GOSUB 300
    10490 X=X+1
    10500 NEXT A
    
    11000 REM LECTURE DES REGISTRES INDIRECTS
    11010 POKE 48936,128+8+1:REM IND + LECTURE + TGS (EXEC)
    11020 T=PEEK(48929):REM LECTURE R1
    11030 PRINT"TGS=";T:FOR I=0 TO 20:NEXT I
    11040 POKE 48936,128+8+2:REM IND + LECTURE + MAT (EXEC)
    11050 M=PEEK(48929):REM LECTURE R1
    11060 PRINT"MAT=";M:FOR I=0 TO 20:NEXT I
    11070 POKE 48936,128+8+3:REM IND + LECTURE + PAT (EXEC)
    11080 P=PEEK(48929):REM LECTURE R1
    11090 PRINT"PAT=";P:FOR I=0 TO 20:NEXT I
    11110 POKE 48936,128+8+5:REM IND + LECTURE + DOR (EXEC)
    11120 D=PEEK(48929):REM LECTURE R1
    11130 PRINT"DOR=";D:FOR I=0 TO 20:NEXT I
    11140 POKE 48936,128+8+7:REM IND + LECTURE + ROR (EXEC)
    11150 R=PEEK(48929):REM LECTURE R1
    11160 PRINT"ROR=";R
    
    12300 REM CHANGE ROR POUR SCROLLING
    12310 FOR I=8 TO 31
    12320 POKE 48929,I:REM ECRITURE R1
    12330 POKE 48936,128+0+7:REM IND + ECRITURE + ROR (EXEC)
    12340 FOR J=0 TO 20:NEXT J
    12350 NEXT I
    12360 POKE 48929,8:REM ECRITURE R1
    12370 POKE 48936,128+0+7:REM IND + ECRITURE + ROR (EXEC)
    
    13000 REM CARACTERES REDÉFINIS
    13010 DATA 28,58,28,8,127,93,93,28,54,99
    13020 A=192
    13030 GOSUB 400
    
    13100 Y=20:X=0:B=128+32+16:A=112:REM GP11
    13110 FOR C=0 TO 127
    13120 IF X>39 THEN X=0:Y=Y+1
    13125 IF C=4 THEN C=32
    13130 GOSUB 300
    13140 X=X+1
    13150 NEXT C
    
    14000 GOTO 14000
    

  • Dans la prison hantée sur AgonLight ()

    Comme présenté dans un article précédent, j'ai participé à la game jam Retro Programmers United for Obscure Systems, organisée par Olipix. Le principe est de développer un jeu pour une machine qui n'a pas eu une grande ludothèque (moins de 100 titres).

    Après avoir terminé ma contribution sur le Lynx, je me suis dit qu'un portage pour l'AgonLight serait intéressant et plutôt facile. Les capacités graphiques sont bien supérieures, et le processeur est un Z80, supporté par la même toolchain que j’avais utilisée pour le Lynx (z88dk).

    Un petit mois plus tard, c'est chose faite. Le jeu est disponible sur itch.io.

    J'en ai profité pour ajouter une version en anglais et une version en esperanto. Puisque tout est développé depuis les mêmes sources, ces versions sont aussi disponibles sur le Lynx.

    Au passage, la taille de l'exécutable a été un tout petit peu réduite. Pas assez pour entrer sur la version Lynx 48k malheureusement. Et en projetant le gain potentiel en travaillant la compression des données, j'ai assez peu d'espoir d'y arriver. Cela pourrait probablement être possible en reprogrammant le jeu en assembleur, mais j'ai déjà passé assez de temps sur ce projet et j'ai envie de passer à autre chose. De plus, je perdrai la possibilité d'un portage facile sur une machine avec un autre processeur.

    J'ai aussi publié les sources du jeu sur GitHub.

    À bientôt pour de nouvelles aventures !

    Dans la prison hantée sur AgonLight2


  • VG5000µ, Schémas de principe mis à jour en v1.5 ()

    Et voici une nouvelle mise à jour du schéma de principe.

    Il y a une seule modification par rapport à la version 1.4, qui est l'ajout du mode international lorsque la diode 6602 relie le signal NMI/ au Y3/ de 7807. Avec cette diode présente, le VG5000µ passe en anglais.

    Merci à Etno pour cette information.

    Ce qui donne, mis à jour.

    La platine principale

    Image cliquable pour une version en haute définition. (mise à jour 21 novembre 2023)

    Platine principale

    La platine K7/Son

    Image cliquable pour une version en haute définition. (mise à jour 9 sept. 2018)

    Platine K7/Son

    Rappel des versions précédentes


Page 1 / 21 (suivant) »