Site logo

Triceraprog
La programmation depuis le Crétacé

  • TextooM, un jeu pour CP/M ()

    Une fois Micreversi terminé, et avant de revenir sur Family Forth, j'ai eu envie de faire un petit détour par une idée qui me trottait dans la tête depuis un bon moment. Depuis le moment du live de la restauration Micral N où on avait affiché « DOOM » en BASIC pour affirmer : Doom tourne sur Micral N. C'était une blague bien entendu, mais pourquoi pas continuer la blague.

    L'idée était donc de faire un Doom façon aventure textuelle, initialement pour Micral N. Mais après réflexion, comme ce n'est pas une machine très courante et puisque mon émulateur n'est pas très pratique à utiliser, je me suis dit qu'une version CP/M serait plus accessible. Et aussi plus facile à produire.

    Et voici ainsi TextooM, un jeu d'aventure textuelle pour CP/M qui s'inspire du premier niveau de Doom, E1M1. C'est plus un jouet qu'un vrai jeu, il ne faut pas en attendre beaucoup. Mais il y a des secrets à trouver, avec un pourcentage à la fin, et il est possible de rusher, ou de tenter le nettoyage complet du niveau (qui n'est pas si simple).

    De quoi amuser 15 minutes...

    TextooM n'est pas le premier jeu de ce type. Au début du développement, j'ai cherché si cela avait été déjà fait et, oui, cela a été fait. En 1996 même ! Ce jeu est Foom et utilise le moteur de fiction interactive TADS. N'ayant pas envie d'entreprendre un portage de TADS, et Foom ayant beaucoup de texte, peut-être beaucoup trop pour une machine CP/M, j'ai décidé de faire mon propre moteur, plus simple, et de faire un jeu plus court. Ah, et en français.

    Le code source du projet est disponible sur GitLab. Et je vous fournis ici l'exécutable pour CP/M.

    Écran de jeu de TextooM


  • Micreversi, un micro-jeu pour Canon X07 ()

    La session Canon X07 de la Game Jam « Retro Programmers United for Obscure Systems » se termine (officiellement, elle est terminée, mais cette game jam est flexible sur les délais), il est temps de revenir sur ma contribution, un Reversi (ou Othello, mais c'est une marque déposée).

    Le Reversi

    Tout d'abord, qu'est-ce que le Reversi ? C'est un jeu de plateau pour deux joueurs, joué sur une grille de 8x8 cases avec des pions réversibles, généralement noirs d'un côté et blancs de l'autre. Le but du jeu est d'avoir le plus de pions à sa couleur à la fin de la partie.

    Pour retourner des pions adverses, il faut les entourer de ses propres pions. Lors de la pose d'un pion, tous les pions adverses qui sont sur une ligne droite (horizontale, verticale ou diagonale) entre le pion posé et un autre pion de la même couleur sont retournés.

    C'est simple à comprendre, mais pas forcément si simple à jouer. Être trop gourmand au début risque de se retourner contre soi.

    Le Canon X07

    Le Canon X07 est un micro-ordinateur sous forme d'une grosse calculatrice, la version « imposante » des calculatrices programmables des années 80. Il est équipé d'un processeur compatible Z80, mais le gros du boulot graphique et sonore est assuré par un coprocesseur dédié. Il a pas mal de fonctionnalités et de périphériques. C'est une machine que j'aime bien, mais que je n'avais jamais eu l'occasion de programmer.

    Comme toujours avec ces machines, l'état des émulateurs n'est pas glorieux. Quelques participants, dont je fais partie, ont envoyés quelques patchs à MAME, mais il reste encore beaucoup de boulot pour avoir quelque chose d'à peu près fiable. Utiliser la vraie machine était quasi indispensable. Mais en contrepartie, mon programme final ne tourne avec MAME qu'avec une version très récente.

    Merci d'ailleurs à pR-0000 pour son câble série et son chargeur qui a permis des transferts très pratiques vers la machine.

    La source du jeu

    J'ai pas mal tourné en rond avant de trouver une idée qui me plaise et soit adapté à la machine. Je me dirigeais vers un jeu de pions, ce qui a l'avantage de ne pas nécessiter de grosses capacités graphiques, et je me suis souvenu quand dans ma pile de notes, j'avais référencé un programme de Reversi en BASIC publié dans le premier numéro du magazine l’Ordinateur Individuel en Octobre 1978 (pages 50 à 52, signé Jean-Marie Donat).

    Ce programme est assez court, plutôt bien expliqué avec un but pédagogique : apprendre à programmer en BASIC.

    L'idée a donc été d'en faire un portage pour le Canon X07, en ajoutant une interface graphique pour la sélection des pions avec un curseur, puisque le Canon X07 a 4 flèches directionnelles bien visibles. Le programme BASIC d'origine, lui, demande des coordonnées et fait un affichage en mode texte, en affichant à chaque tour la grille de jeu.

    Le BASIC, c'est lent !

    En tout cas, un BASIC Microsoft interprété sur une console construire autour de l'économie d'énergie... La première version complète du jeu, entièrement en BASIC, était injouable. La réflexion de l'ordinateur plusieurs secondes, mais à la rigueur, ce n'était pas le plus gênant. Le déplacement du curseur, prenant plus d'une seconde à chaque mouvement, était lui vraiment injouable.

    J'ai donc décidé de transcrire le tout en assembleur.

    L'assembleur, c'est plus rapide !

    Nettement, nettement plus rapide. Ça a pris un peu de temps à convertir, le temps de retrouver la bonne manière de s'adresser au coprocesseur pour la plupart des opérations. Là-dessus, les actifs du Discord ont été d'une grande aide, merci à eux !

    Partant d'un programme entièrement fonctionnel en BASIC, le reste de la transcription a été relativement automatique. Relativement.

    C'est fun ?

    Selon moi, le jeu se tient à peu près. Il est jouable, j'ai fait quelques parties. Le niveau de l'ordinateur est très basique. Il pourra battre un débutant, mais on peu rapidement prendre le dessus. Sans être un bon joueur de Reversi, je gagne à présent toutes les parties.

    C'était d'ailleurs une proposition de l'article dans le magazine : améliorer le programme. Je l'ai amélioré d'un point de vue utilisation et graphiquement, mais pas du tout d'un point de vue intelligence artificielle. C'est à la base pour cela que je l'avais pris en note. Pour un article potentiel sur ce site. L'idée est toujours là.

    Autre Reversi

    Contrairement à d'autres machines utilisées dans les « Retro Programmers United for Obscure Systems », le Canon X07 a eu droit a beaucoup de listings de jeux en BASIC. Il rentre donc dans la liste des machines avec peu de jeux officiellement exploité durant sa durée de vie, tout en ayant une ludothèque pas si maigre.

    Entre autre, il y a un jeu de Reversi publié page 138 du livre « Applications en assembleur dans l'univers du Canon X-07 ». J'ai tenté de le recopier, malheureusement, le scan auquel j'ai accès est très abîmé sur certaines parties, et le programme est listé comme un code machine en hexadécimal. Cependant, ce que j'ai pu récupérer à l'air de promettre un jeu graphique avec une IA plus développée que celle de l'article de l'Ordinateur Individuel, le tout en 3073 octets (mon programme fait 2460 octets).

    J'espère pouvoir le voir tourner un jour.

    Page du jeu

    Le jeu est disponible sur la page itch.io dédiée.

    J'ai aussi publié le code source de la version assembleur.

    Écran de jeu de Micreversi


  • Comparaisons 8 bits en Z80 ()

    Il y a bien quelque chose avec le Z80 qui me ralenti à chaque fois, ce sont les comparaisons. L'égalité, c'est facile. Mais dès qu'il s'agit de comparer deux octets pour savoir si l'un est plus grand que l'autre, strictement ou pas, et encore pire, si ce sont des octets signés, j'y passe du temps... pour souvent me tromper.

    Et donc, voici un petit tableau récapitulatif pour m'aider à m'y retrouver, et peut-être que ça pourra aussi vous aider.

    Table des matières

    Comparaisons non signées (8 bits)

    Un octet non signé est positif et dans l'intervalle [0, 255]. Après cp b (qui calcule A−B sans stocker le résultat), on a : Z = 1 si A = B et C = 1 si A < B.

    A = B

        cp b
        jr z,egal
        ; cas 1 : A ≠ B
        jr next
    egal:
        ; cas 2 : A = B
    next:
    

    A ≠ B

    Le même code que pour A = B, mais en privilégiant le cas A ≠ B.

        cp b
        jr nz,inegal
        ; cas 1 : A = B
        jr next
    inegal:
        ; cas 2 : A ≠ B
    next:
    

    A < B et A ≥ B

    Les deux cas sont identiques, c'est juste une question de sémantique.

        cp b
        jr c,inf_strict
        ; cas 1 : A < B (ou A ≥ B)
        jr next
    inf_strict:
        ; cas 2 : A ≥ B (ou A < B)
    next:
    

    A ≤ B et A > B

    Les deux cas sont identiques, c'est juste une question de sémantique.

        cp b
        jr z,inf_ou_egal
        jr c,inf_ou_egal
        ; cas 1 : A > B (ou A ≤ B)
        jr next
    inf_ou_egal:
        ; cas 2 : A ≤ B (ou A > B)
    next:
    

    Comparaisons signées (8 bits)

    En signé, les deux octets sont dans l'intervalle [−128, +127]. La condition A < B est plus complexe à évaluer, car il faut aussi prendre en compte le flag de débordement (overflow) qui peut se produire lors de la soustraction A−B.

    Si on est assuré qu'aucun overflow ne se produit (si A et B sont tous deux dans un intervalle [−64, +63]), voir la section suivante.

    En signé ou pas, l'égalité est identique à celle des non signés, elle n'est pas reproduite ici.

    Note : jr ne supporte pas les conditions sur S et V, il faut donc utiliser jp pour ces cas.

    A > B ou A ≤ B (signé)

        cp b
        jr z,inf_ou_egal    ; A et B égaux
        jp pe,ov_gt         ; Overflow, il faut inverser la condition
        jp p,sup_strict     ; S=0 et pas d'overflow, donc A > B (strict)
        jp inf_ou_egal      ; S=1 et pas d'overflow, donc A ≤ B
    ov_gt:                  ; Cas de l'overflow
        jp m,sup_strict     ; S=1 et overflow, donc A > B
        jp inf_ou_egal      ; S=0 et overflow, donc A ≤ B
    sup_strict:
        ; cas 1 : A > B (signé)
        jp next
    inf_ou_egal:
        ; cas 2 : A ≤ B (signé)
    next:
    

    A < B ou A ≥ B (signé)

        cp b
        jp pe,ov_lt         ; Overflow, il faut inverser la condition
        jp m,inf_strict     ; S=1 et pas d'overflow, donc A < B
        jp sup_ou_egal      ; S=0 et pas d'overflow, donc A ≥ B
    ov_lt:                  ; Cas de l'overflow
        jp p,inf_strict     ; S=0 et overflow, donc A < B
        jp sup_ou_egal      ; S=1 et overflow, donc A ≥ B
    inf_strict:
        ; cas 1 : A < B (signé)
        jp next
    sup_ou_egal:
        ; cas 2 : A ≥ B (signé)
    next:
    

    Comparaisons signées simplifiées (8 bits)

    Lorsque A et B sont dans un intervalle tel qu'aucun overflow ne se produit lors de A−B (tous deux dans [−64, +63] ou toute opération garantie sans débordement) le code est simplifié en retirant les vérifications d'overflow.

    A > B ou A ≤ B (signé, pas d'overflow)

        cp b
        jr z,inf_ou_egal    ; A = B
        jp p,sup_strict     ; S=0, donc A > B
        jp inf_ou_egal      ; S=1, donc A ≤ B
    sup_strict:
        ; cas 1 : A > B (signé)
        jp next
    inf_ou_egal:
        ; cas 2 : A ≤ B (signé)
    next:
    

    A < B ou A ≥ B (signé, pas d'overflow)

        cp b
        jp m,inf_strict     ; S=1, donc A < B
        jp sup_ou_egal      ; S=0, donc A ≥ B
    inf_strict:
        ; cas 1 : A < B (signé)
        jp next
    sup_ou_egal:
        ; cas 2 : A ≥ B (signé)
    next:
    

    Les drapeaux

    L'état des drapeaux après cp b.

    Flag Signification
    Z 1 si A = B (A - B = 0)
    C 1 si A < B (non signé) (emprunt lors de A−B)
    S Bit 7 de A−B (signe du résultat 8 bits)
    P/V 1 si overflow signé (voir conditions ci-dessous)

    À propos de l'overflow signé : il se produit lorsque A et B ont des signes opposés et que le résultat de A−B a un signe différent de celui de A.

    Entre autre, il n'y a pas d'overflow possible si A et B sont de même signe.

    À propos de S et V :

    S V Interprétation
    0 0 A − B ≥ 0, pas de débordement, donc A ≥ B
    1 0 A − B < 0, pas de débordement, donc A < B
    0 1 Résultat positif mais a débordé, donc A < B
    1 1 Résultat négatif mais a débordé, donc A > B

    Instructions et drapeaux

    La syntax des sauts ne fait pas toujours référence directe au nom des drapeaux, ce qui est confusant.

    Instruction Description
    jr z/nz Saut relatif sur Z
    jr c/nc Saut relatif sur C
    jp m/p Saut absolu sur S
    jp pe/po Saut absolu sur P/V

  • z80dezasm, désassembler et commenter le Z80 ()

    L'origine

    C'est à l'été 2017 qu'après avoir commencé à étudier en profondeur le VG5000µ, je me mets en tête de commenter l'intégralité de sa ROM. Il y a bien quelques morceaux de ROM désassemblée qui existent, mais c'est incomplet et surtout, à cause des astuces d'instructions partielles du Z80, pas ré-assemblable à l'identique.

    Or, en plus de l'étude, j'aimerais pouvoir modifier la ROM pour faire des essais, voire ajouter des commandes. Je cherche alors un désassembleur Z80 qui puisse aussi ajouter des commentaires et produire un code ré-assemblable. Je n'en trouve pas. Et puis, il y a cette page qui me fait dire que ça ne serait pas si compliqué que ça à faire.

    C'est ainsi que je commence à développer un désassembleur Z80, que je nomme alors z80tools, car il n'est alors qu'une partie d'un répertoire d'outils variés permettant d'analyser la ROM. Une partie de ces outils seront extraits au fur et à mesure pour donner ce repo. Il m'en reste une paire d'autres à extraire et puis, surtout, il reste ce plus gros morceau : le désassembleur/commenteur lui-même.

    Seulement, c'est un gros morceau de scripts écrits itérativement au fur et à mesure de mes besoins, sans vraiment une idée de produit publiable. Je le garde donc dans un coin et je me contente de publier le résultat du commentaire de la ROM du VG5000µ, avec la spécification du format que j'utilise.

    Mars 2026

    Cet outil me servira dans d'autres projets, principalement lors des sessions de la RPUfOS, pour analyser les ROMs des machines cibles lorsque celles-ci utilisent un Z80. Jamais rien de complet ceci dit.

    Et puis vient à nouveau une session, avec pour machine cette fois le Canon X-07. C'est une machine qui a de la documentation, mais pas toujours très précise, et de l'émulation, mais pas vraiment fiable (en cause, le coprocesseur T6834, pas documenté assez précisément). Je relance l'outil pour aller vérifier certaines hypothèses et je me dis qu'il serait peut-être temps que je publie ce projet !

    Et c'est donc chose faite. J'ai donné un nom au projet : z80dezasm, packagé l'application avec uv, fait un peu de ménage à coup de linter (même si c'est encore vraiment le bazar dans le code), nettoyé les trucs hardcodé qui ne fonctionnent que sur ma machine ou sur le VG5000µ et écrit un README pour expliquer comment utiliser l'outil, en récupérant le bout de spécification que j'avais écrit pour le dépôt des commentaires. Ouf.

    z80dezasm

    L'outil z80dezasm est ici !.

    Gardez en tête que ça reste un outil personnel trituré depuis 2017 et dont j'ai été le seul utilisateur pendant presque 9 ans. Ce n'est peut-être pas l'outil le plus facile à utiliser, ni le plus robuste, ni (certainement pas) le plus rapide. Mais s'il vous convient comme il me convient, c'est tant mieux.

    Entre temps, une ou deux années après avoir commencé, j'avais trouvé un autre désassembleur/commenteur assez similaire (dont j'ai perdu la trace, désolé), mais bon, j'avais l'habitude du mien. Il existe aussi le maintenant bien connu ghidra, mais pareil... j'ai mes habitudes et ma façon de faire.


  • Adressage 6502, un récapitulatif ()

    Si vous aussi vous jetez régulièrement un œil sur les adressages possibles et valides pour le 6502, voici un tableau récapitulatif qui pourra vous servir. En tout cas, il me servira.

    Tableau Récapitulatif

    Mode Syntaxe Exemple Taille Cycles Notes
    Implicite OP RTS 1 2-6 -
    Accumulateur OP A LSR A 1 2 -
    Immédiat OP #nn LDA #$42 2 2 Constante
    Page Zéro OP $nn LDA $80 2 3-5 Rapide
    Page Zéro,X OP $nn,X LDA $80,X 2 4-6 Wrapping en page 0
    Page Zéro,Y OP $nn,Y LDX $10,Y 2 4 LDX/STX uniquement
    Absolu OP $nnnn LDA $1234 3 4-6 -
    Absolu,X OP $nnnn,X LDA $2000,X 3 4-7 +1 si page crossed
    Absolu,Y OP $nnnn,Y LDA $3000,Y 3 4-7 +1 si page crossed
    Relatif OP label BEQ Loop 2 2-4 Branches uniquement
    Indirect JMP ($nnnn) JMP ($FFFC) 3 5 JMP uniquement
    Indexed Indirect OP ($nn,X) LDA ($40,X) 2 6 X ajouté d'abord
    Indirect Indexed OP ($nn),Y LDA ($40),Y 2 5-6 Y ajouté après

    ($nn,X) vs ($nn),Y

    Indexed Indirect vs. Indirect Indexed, ma source de confusion préférée.

    Écriture ($nn,X) ($nn),Y
    Évaluation X ajouté avant lecture Y ajouté après lecture
    Calcul addr = read16(($nn+X)&$FF) addr = read16($nn)+Y
    Wrapping X wrappe en page 0 Y sur 16-bit complet
    Usage typique Tables de pointeurs, dispatch Tableaux, structures

    Références

    Les deux pages sur lesquelles je vais régulièrement :


« (précédent) Page 2 / 28 (suivant) »

Tous les tags

3d (15), 6502 (17), 6809 (1), 8bits (1), Affichage (24), AgonLight (2), Altaïr (1), Amstrad CPC (1), Apple (1), Aquarius (2), ASM (33), Atari (1), Atari 800 (1), Atari ST (2), Automatisation (4), BASIC (31), BASIC-80 (4), C (3), Calculs (1), Canon X07 (1), CDC (1), Clion (1), cmake (1), Commodore (1), Commodore PET (1), Compression (5), CP/M (1), CPU (1), Debug (5), Dithering (2), Divers (1), EF9345 (1), Émulation (7), Famicom (13), Forth (18), Game Jam (1), Hector (3), Histoire (1), Hooks (4), Huffman (2), i8008 (1), Image (17), Jeu (17), Jeu Vidéo (4), Livre (1), Logo (2), LZ (2), LZ77 (2), Machine virtuelle (2), Magazine (1), MAME (1), Matra Alice (3), MDLC (7), Micral (2), Motorola (1), MSX (1), Musée (2), Nintendo Switch (1), Nombres (3), Optimisation (1), Outil (1), Outils (3), Pascaline (1), Peertube (1), PHC-25 (2), Photo (2), Programmation (23), Python (1), RLE (2), ROM (15), RPUfOS (7), Salon (1), SC-3000 (1), Schéma (5), Synthèse (15), Tortue (1), Triceraprog (1), VG5000 (62), VIC-20 (1), vidéo (4), Z80 (23), z88dk (1), ZX0 (1)

Les derniers articles

Forth sur 6502, épisode 15
Forth sur 6502, épisode 14
Forth sur 6502, épisode 13
Forth sur 6502, épisode 12
Compression de données, la vidéo
TextooM, un jeu pour CP/M
Micreversi, un micro-jeu pour Canon X07
Comparaisons 8 bits en Z80
z80dezasm, désassembler et commenter le Z80
Adressage 6502, un récapitulatif

Atom Feed

Réseaux