Site logo

Triceraprog
La programmation depuis le Crétacé

  • 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 :


  • Forth sur 6502, épisode 11 ()

    ACCEPT, enfin !

    Cela aura pris un peu de temps, entre autres raisons car d'autres activités se sont invitées entre-temps, mais ACCEPT est enfin implémenté ! ACCEPT est un mot qui lit une ligne de texte entrée par l'utilisateur et la stocke dans une adresse mémoire fournie lors de l'appel. Généralement, cette adresse est le TIB (Terminal Input Buffer), qui sera ensuite fournie à l'interpréteur Forth.

    Comme indiqué lors du précédent article, se posait la question de savoir comment récupérer les données. J'ai tenté deux versions et je suis finalement partie sur celle que je pressentais : utiliser la mémoire PPU pour stocker les données en cours d'édition, puis les récupérer lorsque la touche RETURN est appuyée.

    Oui, mais... même si la mémoire représentant les caractères est linéaire, depuis le début de l'implémentation j'ai réservé des caractères sur les bords de l'écran pour ne rien y afficher, afin de respecter les marges nécessaires lors d'un affichage sur écran cathodique. Récupérer les données nécessite donc de prendre des morceaux de mémoire à différents endroits. Pas forcément très complexe, mais ça nécessite un peu plus de réflexion qu'un simple transfert en une fois.

    Et tant qu'à faire, puisque je dois définir une géométrie d'écran logique, pourquoi ne pas implémenter un mot WINDOW qui permettrait de définir les marges haut, bas, gauche et droite ? C'est ce que j'ai commencé par faire, en adaptant la gestion du curseur qui était codée en dur avec des marges fixes. Deux routines me permettent d'avancer et de reculer le curseur en respectant cette géométrie de fenêtre logique, et c'est bon. Les marges sont toujours là, initialisées au démarrage, mais à présent elles sont configurables.

    Retour sur ACCEPT. Au début, il s'agit uniquement de reprendre le code d'affichage de caractères que j'avais déjà. Le code me semble quand même voué à être un peu long, je lui dédie donc un fichier. Il me faut implémenter l'édition d'une ligne logique, avec gestion des touches curseur du clavier (au moins droite et gauche), ainsi que des touches INS (insertion), DEL (suppression) et RETURN (validation de la ligne). Ces touches ne sont pas encore branchées, je repasse donc sur la gestion du clavier.

    Gestion du clavier complet

    Tant qu'à faire, puisque je suis sur le clavier, j'en profite pour gérer les majuscules, minuscules et kanas. Pour cela, il me faut compléter la fonte. Celle que j'avais choisie n'a pas tous ces caractères. J'en cherche une et je tombe sur la fonte Misaki, qui, en plus des katakanas, contient des caractères graphiques. Parfait pour utiliser la touche GRPH du clavier.

    La fonte format bitmap 8x8 est fournie avec beaucoup de caractères. J'écris donc un petit script Python pour en prendre une sélection et générer ma fonte dans le format Famicom attendu. Puis je mappe tous les scancodes, un par un, vers leurs équivalents pour quatre tables différentes : majuscules, minuscules, kanas et graphiques. Je sélectionne quelques codes entre 0 et 32 pour les touches de contrôle, en respectant les codes classiques et en improvisant un peu pour les autres.

    Et me voilà avec un mapping complet. Je peux compléter ACCEPT pour gérer les touches SHIFT, KANA et GRAPH. Les touches de direction avant et arrière ne posent pas beaucoup de problèmes... à part le curseur.

    Tant que le curseur était en fin de ligne, c'était simple. Mais maintenant qu'il se déplace sur des caractères déjà présents, je veux le faire clignoter afin de laisser le caractère en dessous apparent. Et pour savoir quel est ce caractère, il faut aller le chercher... dans la mémoire de l'écran !

    Transferts PPU <-> RAM

    Je laisse donc le clavier de côté. Il est temps de s'occuper des transferts RAM/PPU. J'ai déjà, via le framework utilisé, un transfert de buffer de la RAM vers la mémoire PPU. Celui-ci fonctionne par recopie de données dans un buffer de commandes. C'est bien pour la sécurité des données : comme elles sont copiées, la source peut changer en RAM, elles sont au chaud dans la commande. Par contre, cela prend du temps de recopie et de la place en RAM.

    J'implémente donc une version qui permet de référencer une adresse mémoire et une longueur, qui servent directement lors du décodage des commandes pendant la synchronisation verticale. À la charge de l'appelant d'assurer que les données sont toujours là où elles doivent être. J'en profite pour afficher le message de bienvenue avec cette commande, afin de valider le fonctionnement.

    De là, il est assez facile d'en faire la commande symétrique : une commande qui référence une adresse mémoire et une longueur en RAM, et qui y copiera les résultats de requêtes PPU lors de la prochaine synchronisation verticale. En spécifiant comme adresse celle d'une variable contenant le caractère sous le curseur et comme longueur 1, je peux récupérer ce caractère courant.

    Pour être sûr des buffers, j'attends la synchronisation verticale après chaque déplacement de curseur. Pendant l'édition d'une ligne d'entrée logique, ce n'est pas très important.

    Retour à l'édition de ligne logique

    Bien. À présent, j'ai la possibilité de récupérer le caractère sous le curseur, mais aussi tous les caractères à l'écran. Avant d'implémenter RETURN, je fais un détour par INS et DEL, afin de pouvoir faire de l'édition et de ne pas partir du principe que l'utilisateur tape une ligne parfaite du premier coup. Mes multiples tests montrent que ce n'est pas le cas. J'ai besoin de ces touches !

    Un détour par le Family BASIC me montre que INS insère un espace à l'emplacement du curseur, ok, mais que DEL est en fait un BACKSPACE : il supprime le caractère avant le curseur et recule le curseur d'une position. Par cohérence, j'implémente le même comportement.

    Cependant, il n'est pas possible de déplacer des morceaux de mémoire PPU directement. Ou alors je n'ai pas trouvé (et les personnes à qui j'ai demandé ne savaient pas). Qu'à cela ne tienne, ACCEPT a à sa disposition un buffer de travail dans lequel il déposera les données finales. Je l'utilise comme buffer temporaire. Pour les deux opérations, je récupère les données de l'écran (en respectant la géométrie de la fenêtre logique), je fais la modification en RAM, puis je renvoie le tout à l'écran.

    Je ne m'embête pas à trouver la sous-partie qui va bouger, je récupère et je renvoie tout. J'attends même une synchronisation verticale pour chaque ligne physique transférée pour être certain de tenir dans le temps de synchronisation. Sur émulateur, ça ne bronche pas. On verra sur vrai matériel. Au pire, je pourrais grouper quelques transferts pour trouver le bon équilibre. Mais là encore, on est en pleine édition de ligne logique utilisateur, on peut se permettre des attentes sans affecter l'expérience utilisateur.

    ACCEPT !

    L'avantage avec l'implémentation de INS et DEL, c'est qu'il y a déjà tout ce qu'il faut pour implémenter RETURN. J'ai la récupération des données en RAM. Reste à pousser la longueur actuelle de la ligne logique sur la pile. Cette longueur est maintenue au fur et à mesure des opérations d'édition.

    Il reste des choses à faire pour une édition au clavier agréable et complète. Et une paire de petits bugs, dont la longueur de la ligne logique qui n'est pas mise à jour correctement dans certains cas. Je m'en occuperai plus tard. Il est grand temps d'avancer vers INTERPRET !

    Amélioration du framework de test

    Au passage, avec l'arrivée du clavier, j'ai ajouté comme prévu l'injection de caractères depuis le framework de tests. Cela m'a permis d'écrire un test pour INS et un autre pour DEL. Ces tests demandent la mise en place de contextes en plusieurs étapes, avec parfois des attentes de frames pour attendre les résultats. Les tests commençaient à être très verbeux et j'ai donc fait une passe pour factoriser tout ça dans des fonctions d'aide qui me permettent d'écrire le déroulement des opérations qui seront ensuite conduites de manière asynchrone.

    Interprète... interprète !

    Maintenant que j'ai une boucle d'entrée de texte, la prochaine étape est l'interprétation du résultat. Cela va nécessiter l'écriture de nombreux mots standards de Forth (au passage, j'ai implémenté DROP car actuellement je dois ignorer le retour de ACCEPT). Cependant, ces mots devraient être nettement plus simples que ACCEPT ou la gestion clavier.

    La « simple » implémentation d'ACCEPT a eu de nombreuses ramifications. J'en ai même profité pour faire quelques petites optimisations/simplifications simples au passage.

    J'aimerais pour la suite pouvoir écrire quelque chose comme HEX 7FF FF C!, qui écrit la valeur 0xFF à l'adresse 0x7FFF, ce que le framework de test peut détecter. Cela signifie le découpage par mots de la chaîne d'entrée, un traitement de base numérique, le parsing de nombres dans cette base et l'implémentation de C! (le plus facile de toute la liste).

    Partons là-dessus !

    Forth sur 6502 - écriture interactive à l'écran 2


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

Tous les tags

3d (15), 6502 (16), 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 (12), Forth (17), 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 (22), 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 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
Forth sur 6502, épisode 11

Atom Feed

Réseaux