Forth n'est pas seulement un langage, c'est aussi (et avant tout ?) un environnement interactif de développement. Il est possible dans une session de compiler des mots additionnels au dictionnaire. Le mot principal pour opérer est :.
Par exemple :
:AJOUTE_22+
Cela définit un mot qui ajoute 2 à la valeur au sommet de la pile.
100AJOUTE_2.
... affiche donc 102 à l'écran (le mot . affiche le contenu du sommet de la pile en tant que nombre).
Structure d'un mot
Il avait déjà été question de la structure d'un mot dans un Forth 8 bits classique lors de la partie 6 de ces articles. Ça remonte un peu. On peut aussi trouver des éléments dans la documentation de Pampuk Forth que j'avais écrite il y a un moment.
Rapidement, un mot est composé d'un NFA (longueur du nom et drapeaux, ainsi que le nom), d'un LFA (lien vers le …
Dans la partie 12 de cette série d'articles, j'annonçais m'attaquer à l'interprétation d'une ligne de Forth. Dans la partie 15... j'en vois le bout !
Forcément, avec la boucle QUIT, le mot INTERPRET forme le moteur de la partie interactive de Forth. Dans l'article précédent, j'avais énuméré tous les mots nécessaires à l'implémentation de NUMBER, élément manquant pour INTERPRET en mode d'interprétation (sans compilation). Et je terminais par si tout s'aligne parfaitement...
... quelques heures plus tard, en mettant au point NUMBER, je m'aperçois que je me suis trompé dans l'implémentation de DIGIT. Je n'avais pas écrit la signature en commentaire, codant de mémoire... et oubliant donc que la BASE qu'utilise DIGIT est un paramètre sur la pile, et non la variable directement. Ce fut vite corrigé.
J'ai aussi découvert que la chaîne du dictionnaire était cassée et que CFA était laissé de côté. Ce n'est pas la première fois …
À sa création, Forth ne manipule que les nombres entiers. C'est suffisant pour son usage. Et un nombre se stocke dans une cellule de données, généralement (et dans le choix d'implémentation de ce Forth sur 6502) une cellule de 16 bits pour un Forth sur processeur 8 bits.
Par la suite, les nombres « double » seront ajoutés, des nombres stockés sur deux cellules donc. Mais là où la plupart des langages de haut niveau utilisent les mêmes symboles arithmétiques quel que soit le type de donnée numérique, voire même font de la coercition (adapte les types de données pour pouvoir les manipuler ensemble), Forth n'a rien de tout cela : une addition de deux nombres « double » n'utilise pas le même symbole que l'addition de deux nombres simples.
Par exemple
46+.\ fait la somme de deux nombres simples (et l'affiche)4.6.D+D.\ fait la somme …
À partir de ce qui a été établi dans l'article précédent, il est à présent temps d'implémenter les mots nécessaires directement ou indirectement pour INTERPRET.
HERE
HERE est un mot qui indique quelle est la prochaine adresse libre dans l'espace de travail de l'interpréteur Forth. Il met en fait sur la pile le contenu d'une variable nommée DP qui pointe vers cette adresse. Cet emplacement se situe après le dictionnaire, et donc va se déplacer au fur et à mesure de l'ajout des mots.
L'implémentation est simple, cependant, cela signifie aussi de s'intéresser à l'emplacement de travail. Actuellement, on travaille sur la zone de 2ko de RAM disponible sur la Famicom. C'est probablement suffisant pour quelques tests. Le linker permet de savoir quel est le premier octet libre après la zone BSS (variables non initialisées). C'est vers là que je fais pointer DP lors de …
L'écriture de cet article a commencé le 3 mars 2026... et je le reprends le 9 juillet de la même année. Heureusement que j'avais déjà laissé pas mal de notes car la reprise est difficile !
Interpréter une ligne
Depuis l'article précédent, la boucle principale du système Forth est capable de récupérer une ligne de texte entrée par l'utilisateur. L'étape suivante est bien entendu d'en faire quelque chose : de l'interpréter.
INTERPRET est le mot Forth qui s'occupe de cela. Et ce que fait ce mot est assez simple : prendre le prochain morceau de texte entouré d'espace disponible dans la ligne, essayer de le trouver dans le dictionnaire, et si c'est le cas, l'exécuter. Si le mot n'est pas trouvé, la boucle tente de l'interpréter comme un nombre, et si c'est un nombre valide, elle le pousse sur la pile. Et si ce n'est pas un nombre, alors c'est une …
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 …
En attendant le prochain article de la série sur le développement d'un Forth sur Famicom, qui prend un peu de temps, je voulais faire une petite aparté pour présenter les deux livres qui m'accompagnent, en plus de différentes ressources en ligne.
En effet, un livre que l'on peut feuilleter, où on peut retrouver un passage rapidement, c'est pratique.
Making Games for the NES
Le premier livre est en anglais et aborde le développement de jeux pour la NES, et donc pour la Famicom. Très progressif, il amène chaque aspect de la machine avec clarté. Pas forcément dans les plus obscurs des détails et c'est aussi ce qui est intéressant : c'est une bonne première approche.
Le livre date un peu. Ça n'est pas très important pour la console elle-même, qui n'a pas bougé, mais quelques outils évoqués ne sont plus forcément les meilleurs choix.
Le clavier est pour le moment implémenté avec deux mots. L'un qui sera gardé, KBDSCAN et l'autre qui est là en attendant de pouvoir écrire la même chose en Forth, KBDPROCESS. L'objectif premier est de transformer KBDPROCESS en son équivalent Forth que je placerai dans ma boucle principale (pas encore QUIT, qui n'est pas encore prêt).
Mais avant toute chose, j'ai quelque chose à corriger avec le curseur. Pour le moment, j'affiche le curseur avec EMIT, ce qui fait avancer la prochaine position d'affichage de caractère. Ce que je veux, c'est afficher le caractère reçu du clavier avec EMITpuis afficher le caractère du curseur sans faire avancer la position d'affichage. Ainsi, le caractère du curseur sera toujours une position après le dernier caractère affiché.
Pour cela, j'ai un peu remanié le code afin de séparer l'envoi du caractère à afficher et la mise …
C'est triste un démarrage de Forth... COLD, ABORT, QUIT. On aurait pu imaginer des mots comme WARMUP, READY, LOOP. Mais je n'ai pas prévu de renommer les mots standards de Forth. Et comme indiqué dans l'article précédent, il est temps de déplacer le code de démarrage vers les mots officiels.
Et à vrai dire, comme prévu, il n'y avait pas grand chose à faire.
Tout d'abord, le code de démarrage devient juste initialiser l'interpréteur avec le mot COLD :
boot_forth:; Set the Work Register to the first word to execute:lda#<COLD_word_cfastaREG_Wlda#>COLD_word_cfastaREG_W+1; And use itjmpdocol
Et pour faire simple, ABORT et QUIT appellent juste des mots cachés qui contiennent le code assembleur que j'avais déjà. Cela donne :
; COLDDEFINE_FORTH_WORDCOLD,0,0.wordRESET_ENV_word_cfa.wordABORT_word_cfa; ABORT never returns, no need for DO_SEMI; ABORTDEFINE_FORTH_WORDABORT,COLD,0.word …
Lors du précédent article, l'ajout de variables et de la pile des paramètres nous a approché de l'objectif actuel : afficher des caractères à l'écran. Ou plus exactement, remplacer l'affichage de la chaîne de caractères depuis l'assembleur au démarrage du programme vers la partie Forth.
Pour commencer et s'assurer que j'ai du code qui peut transformer des coordonnées en adresse PPU et afficher un caractère, je crée un mot TEST_EMIT qui va prendre ces coordonnées et afficher un unique caractère comme curseur. Comme je n'ai que 26 lettres majuscules actuellement dans mes données graphiques, il est temps d'aller modifier les données. J'ajoute en caractères 255 un carré plein. Cela fera un bon curseur.
Il me faut aussi deux variables pour stocker les coordonnées du curseur : CURSOR_X et CURSOR_Y que j'initialise à l'emplacement où je veux afficher le curseur au démarrage (en effet, je n'ai pas encore de moyen …
L'étape d'aujourd'hui va permettre de se diriger vers l'affichage d'un texte à l'écran depuis la boucle Forth. Pour cela, il faut revenir un peu sur le fonctionnement de la Famicom.
Le processeur qui s'occupe de l'affichage est le PPU (Picture Processing Unit). Ce processeur a son espace d'adressage mémoire propre de 16 ko dont le routage est configuré par la cartouche insérée. Dans la console, 2 ko de RAM sont dédiés au PPU, assez pour stocker les informations de deux écrans (index de caractères et attributs). La cartouche doit apporter a minima les informations de caractères (en ROM généralement, mais peut aussi offrir un espace RAM pour les construire) ; elle peut aussi étendre le nombre d'écrans (jusqu'à 4) ou ajouter un système de banking de pages.
De manière générale, tout le mapping de la mémoire du PPU est contrôlé par …
Avant de passer à la lecture de l'article 2 de la série Moving Forth, je veux mettre en place un projet « minimal ». Plus exactement, c'est initialement ce que je voulais faire, avec un petit code source pour Famicom qui affiche un texte, un Makefile et bien entendu, un framework de tests.
Mais les notes que j'avais prises sur la Famicom remontaient à un petit moment, et il y a quelques trucs à initialiser avant d'afficher un caractère à l'écran. J'ai donc cherché un squelette de projet déjà fait. Sur une machine populaire, ça doit bien
exister.
Mon choix s'est porté sur Nes Template de Mike Moffitt. Le squelette n'est
pas minimaliste, mais a une bonne base, avec un système de configuration flexible pour la ROM destination, et assez de quoi
écrire un message à l'écran, ainsi que manipuler des banques de mémoire. C'est bien écrit, bien …
L'hiver dernier, j'ai découvert le Family Basic, ou Famibe, un BASIC pour la Famicom (le petit nom de la Family Computer de Nintendo, dont la version occidentale donnera la Nintendo Entertainment System, ou NES).
Le Family Basic, qui vient dans une boite bien visible sur une étagère, comprend une cartouche, un clavier et un manuel. Le clavier est un vrai clavier et est assez agréable à utiliser. Il se branche sur le port d'extension en façade de la console, là où se branchent les périphériques d'entrées supplémentaires, les deux manettes étant connectées à la console « en dur ».
La cartouche est plus haute que les cartouches Famicom classiques, presque la taille d'une cartouche NES. Dedans, il y a de la rom PRG (le programme), de la rom CHR (les données graphiques) et de la RAM (la mémoire vive) supplémentaire. Cette RAM peut d'ailleurs être alimentée par piles lorsque la console est …