PAMPUK Forth
L'interpréteur
Lorsque l'on démarre Forth, on se trouve dans un mode interactif dans lequel on peut taper des mots sur une ligne et valider cette ligne avec la touche entrée.
Un mot est une suite de caractères séparés des autres par des espaces. Lors de la validation de la ligne, l'interpréteur Forth va prendre chaque mot et les exécuter. Si le mot trouvé est dans son dictionnaire courant (nous verrons plus tard ce qu'est un dictionnaire), il va exécuter le code associé. Si aucun mot ne correspond, il va essayer de convertir le mot en nombre et le mettre sur la pile.
Les piles
La pile des paramètres
Si on ne précise pas de quelle pile on parle, c'est généralement de la pile des paramètres qu'il s'agit. C'est une pile LIFO (Last In First Out), c'est-à-dire que le dernier élément mis sur la pile est le premier à en sortir. Cette pile est un concept central du Forth.
Beaucoup de mots vont prendre leurs paramètres dans cette pile, et y laisser leurs résultats.
En opération simple pour voir le fonctionnement de la pile est d'empiler trois nombres puis des les affiches avec le mot .
:
1 2 3 . . .
Le résultat affiché est :
3 2 1
Un autre exemple simple, qui est un peu le Hello World
du Forth, est de taper 1000 2000 + .
et de valider la ligne. Le résultat affiché est 3000
.
Le déroulement de l'interprétation est le suivant :
1000
n'est pas un mot reconnu et est mis sur la pile en tant que nombre,2000
n'est pas un mot reconnu et est mis sur la pile en tant que nombre,+
est un mot reconnu qui prend les deux premiers éléments de la pile, les additionne et met le résultat sur la pile,.
est un mot reconnu prend le premier élément de la pile et l'affiche.
La pile retour
Cette seconde pile est utilisée pour stocker les adresses de retour lors de l'exécution de mots. Lorsque Forth exécute un mot, il doit savoir où reprendre l'exécution après ce mot. Pour cela, Forth enregistre à chaque appel l'adresse de retour de l'appelant. Lorsque le mot est terminé, Forth peut lire dans cette pile de retour l'adresse à laquelle il doit reprendre l'exécution.
Certains micro processeurs, comme le 6809, ont l'avantage de gérer nativement au moins deux piles. Mais ce n'est pas le cas du Z80 utilisé par le Hector HRX. L'interpréteur Forth doit donc gérer lui-même cette pile retour, la pile gérée par le processeur (via le registre SP) étant réservée aux paramètres.
Cependant, il est fréquent d'utiliser la pile retour pour y stocker temporairement des valeurs afin de désencombrer la pile des paramètres.
Le mot >R
transfert le sommet de la pile de paramètres vers le sommet de la pile retour.
Le mot R>
transfert le sommet de la pile retour et le met sur la pile des paramètres.
Exemple d'utilisation. Nous partons d'une pile de 4 éléments n4 n3 n2 n1
et nous voulons les réorganiser pour obtenir n3 n4 n2 n1
, c'est-à-dire inverser les deux nombres en positions 3 et 4 de la pile.
: INVERSE-3-4
>R >R \ Transfère n1 et n2 dans la pile retour
SWAP \ Échange n3 et n4
R> R> \ Récupère n2 et n1 de la pile retour
;
4 3 2 1 INVERSE-3-4
. \ Affiche 1
. \ Affiche 2
. \ Affiche 4
. \ Affiche 3
Règle d'or : à l'intérieur d'un même mot, il faut exécuter autant de R>
qu'il y a de >R
avant de sortir du mot. En effet, l'interpréteur Forth devra retrouver l'adresse de retour là où il l'attends.
Les mots
Comme indiqué plus haut, un mot est une suite de caractères. Ces caractères peuvent être quelconques, même s'il est conseillé de donner aux noms un sens.
Lorsque Forth démarre, il a déjà connaissance d'un certain nombre de mots, qui forment un vocabulaire. À chaque mot est défini un code à exécuter. Ce code peut être lui-même composé d'autres mots en Forth, mais il peut être aussi écrit en assembleur.
Il est possible de créer de nouveaux mots. Et c'est d'ailleurs la manière de programmer en Forth.
Les commentaires
Dans PAMPUK Forth, les commentaires commencent par (
et se terminent par )
. Comme '(' est un mot, il est essentiel de mettre des espaces avant et après. Comme le mot ignore tout ce qui se trouve avant le prochain )
, cette parenthèse fermante n'est pas un mot, et l'espace avant n'est pas nécessaire. Cependant, par soucis d'équilibre esthétique, il est conseillé de le mettre.
Le mot de commentaire \
, qui ignore le texte jusqu'à la fin de la ligne, n'est pas disponible en standard sur ce Forth. Il est cependant utilisé dans les exemples donnés.
Les annotations
Les annotations sont des commentaires avec un format spécifique qui indique les opérations effectuées par un mot sur la pile des paramètres et si une chaîne de caractères est lue depuis le flot d'entrée.
Les annotations sont en commentaires et sont destiné à la lecture humaine, l'interpréteur/compilateur n'en fait pas usage.
Dans une annotation, ce qui doit se trouver sur la pile avant l'appel au mot se trouve avant un tiret -
, ce qui y est laissé par le mot se trouve après le tiret. Si le mot lit une chaîne de caractères, celle-ci est indiquée entre signes inférieurs <
et supérieurs >
après le tiret et, s'ils existent, après les annotations de paramètres laissés par le mot.
Que ce soit avant ou après le tiret, les éléments sont représenté du plus profond à gauche, au plus haut (le sommet de la pile) à droite.
Par exemple DUP ( n - n n )
indique que le mot DUP
prend un nombre sur la pile et en laisse deux.
Certaines conventions donnent plus de détails sur la nature de l'opération effectuée, ou bien sur la sémantique des paramètres. Dans ce manuel, seul le type des paramètres est indiqué.
Les abbréviations utilisées sont les suivantes :
Abbréviation | Signification |
---|---|
n | un entier 16 bits signé |
u | un entier 16 bits non signé |
d | un entier 32 bits signé |
ud | un entier 32 bits non signé |
b | un entier 16 bits représentant un booléen |
addr | une adresse mémoire sur 16 bits |
<nom> | une chaîne de caractères lu depuis le flot d'entrée |
Lorsque plusieurs paramètres sont de même type, ils sont distingués par un nombre en suffixe. Par exemple, n1 n2 n3
indique trois entiers 16 bits signés.
Si la même abbréviation, eventuellement avec le même suffixe, est présent des deux côtés du tiret, cela signifie que la valeur est identique avant et après l'appel du mot.
Les nombres
Par défaut, les nombres sont entrés en simple précision, c'est-à-dire sur 16 bits. Ils sont manipulés par défaut comme des nombres signés avec le bit 7 de l'octet de poids fort indiquant le signe. Il existe des nots pour traiter les nombres spécifiquements en nombres non signés (ceux-ci commence par U
).
Il est possible d'entrer des nombres double précision dans l'instruction en les faisant suivre par un .
. Plus exactement, le .
peut-être n'importe où dans le nombre.
Forth peut comprendre et afficher des nombres en n'importe quelle base. Pour cela, il suffit de préciser la base soit en utilisant les mots prédéfinis DECIMAL
et HEX
, soit en manipulant la variable BASE
.
PAMPUK Forth, comme beaucoup de Forth de base, ne connaît que les nombres entiers.
Les expressions
Du fait du fonctionnement du Forth avec une pile, les expressions sont écrites de manière postfixée. Cela signifie que l'opérateur suit les opérandes.
Par exemple, l'expression 4 + 3
en notation usuelle mathématique (infixée) devient 4 3 +
en notation postfixée.
Exemple plus complexe :
5 7 * 3 +
Cette expression est équivalente à 5 * 7 + 3
en notation usuelle et donne le résultat 38
.
Les constantes
Forth peut créer des mots dont l'exécution met une valeur sur la pile. Ces mots sont appelés des constantes. Pour créer une constante, on utilise le mot CONSTANT
. Ce mot est suivi du nom de la constante. La valeur associée est celle qui est sur la pile lors de la création de la constante.
Exemple :
5 CONSTANT CINQ
Ce code crée une constante CINQ
qui met la valeur 5
sur la pile. On peut utiliser cette constante de la manière suivante :
CINQ .
Le mot CINQ
met la valeur 5
sur la pile, puis le mot .
prend cette valeur et l'affiche.
Les variables
Forth peut créer des mots qui mettent sur la pile l'adresse d'une variable. Pour cela, on utilise le mot VARIABLE
. Ce mot est suivi du nom de la variable. Lors de l'exécution de ce mot, l'adresse de la variable est mise sur la pile.
Cela permet par la suite de stocker des valeurs à des adresses mémoires spécifiquement allouées et associé à un nom.
Exemple :
10 VARIABLE X
Ce code crée une variable X
initialisée à 10
. On peut utiliser cette variable de la manière suivante :
X @
Le mot X
met l'adresse de la valeur de la variable X
sur la pile, puis le mot @
prend cette adresse et met la valeur à cette adresse sur la pile. Cela permet de lire la valeur de la variable X
.
11 X !
Le mot 11
met la valeur 11
sur la pile, puis le mot X
met l'adresse de la variable X
sur la pile et enfin le mot !
prend la valeur et l'adresse sur la pile et met la valeur à cette adresse. Cela permet de changer la valeur de la variable X
.
Les chaînes de caractères
Le noyau du PAMPUK Forth ne possède pas de vocabulaire spécifique pour les chaînes de caractères, mais il est possible d'ajouter un vocabulaire spécialisé.
Ce manuel propose un vocabulaire de chaînes de caractères, dont le fonctionnement est expliqué dans ce chapitre.
Voici un aperçu des mots disponibles dans ce vocabulaire. Des exemples sont donnés avec l'explication des mots.
Création et manipulation de base
STRING
: crée une variable chaîne avec une taille maximale spécifiée.S"
: crée une chaîne littérale (stockée temporairement dansPAD
).S!
: stocke une chaîne dans une variable.LEN
etMLEN
: retournent respectivement la taille actuelle et maximale d'une chaîne.
Extraction et manipulation
LEFT$
: extrait une partie gauche d'une chaîne.RIGHT$
: extrait une partie droite d'une chaîne.MID$
: extrait une partie centrale d'une chaîne.SUB!
: remplace une partie d'une chaîne.S+
: concatène deux chaînes (avec troncature si nécessaire).
Comparaisons et recherche
Note importante : Les chaînes littérales utilisant le même buffer temporaire (PAD
), il faut éviter de comparer directement deux chaînes littérales entre elles.
Conversions
ASC
: donne le code ASCII du premier caractère.CHR$
: convertit un code ASCII en chaîne d'un caractère.STR$
: convertit un nombre double précision en chaîne.VAL
: convertit une chaîne en nombre double précision.
Tableaux
STRING-ARRAY
: crée un tableau de chaînes avec indexation.
La création de mots
La manière la plus standard de créer un mot en Forth est d'utiliser le mot :
. Ce mot est suivi du nom du mot à créer, séparé par un espace bien entendu. Suit le code qui sera associé à ce mot, c'est-à-dire le code qui sera exécuté lorsque le mot sera interprété. Enfin, le mot ;
est utilisé pour indiquer la fin du code et terminer la définition du mot.
En Forth, cette opérations est appelée la compilation. Le code est compilé dans le dictionnaire courant à la suite des autres mots.
Exemple :
: BONJOUR ." BONJOUR A TOUS" ;
Ce code crée un mot BONJOUR
qui affiche BONJOUR A TOUS
à l'écran.
: *2 DUP + ;
Ce code crée un mot *2
qui double la valeur sur la pile. En effet, DUP
duplique la valeur sur la pile, et +
ajoute les deux premières valeurs de la pile. Le résultat se retrouve sur la pile. On peut utiliser ce mot de la manière suivante :
5 *2 .
Qui affiche 10
.
Comme on peut le voir, les mots créés peuvent être nommés avec des caractères spéciaux. Forth ne connaît que les mots et ne cherche pas à les interpréter autrement que par leur nom. 5 *2
n'est pas une expression mathématique, mais deux mots à exécuter.
Il est aussi possible de créer des mots en langage machine. Pour cela, on utilise le mot CREATE
suivi du nom du mot et du langage machine à exécuter. Les valeurs du langage machines sont compilés directement grâce aux mots ,
et C,
. La création du mot se termine par le mot SMUDGE
qui indique que le mot est valide et prêt à être exécuté (en inversant le drapeau SMUDGE
du mot).
Par exemple, après avoir oublié la définition de *2
en utilisant le mot FORGET
, on peut créer un mot *2
en langage machine :
FORGET *2
HEX
CREATE *2 E1 C, 29 C, E5 C, E9DD , SMUDGE
Le code machine correspond à l'assembleur suivant :
E1 ; POP HL \ Retire la valeur de la pile et la place dans HL
29 ; ADD HL, HL \ Double la valeur dans HL
E5 ; PUSH HL \ Remet la valeur de HL sur la pile
DDE9 ; JP (IX) \ Saute à l'interpréteur Forth pour continuer l'exécution
Structure d'un mot
Comprendre comment est formé un mot en Forth est important pour comprendre comment fonctionne le langage en interne. Cela aide lorsque l'on veut comprendre comment un mot est exécuté, ou comment un mot est compilé. Et cela aide aussi à comprendre comment fonctionnent les mots de définition.
Nom | Signification | Taille | Contenu |
---|---|---|---|
NFA | Name Field Address | 1 octet | bit 7 : 1 |
bit 6 : PRECEDENCE | |||
bit 5 : SMUDGE | |||
bit 4-0 : longueur du nom | |||
n octets | nom du mot, le dernier octet a le bit 7 à 1 | ||
LFA | Link Field Address | 2 octets | adresse du mot précédent |
CFA | Code Field Address | 2 octets | adresse du code à exécuter |
PFA | Parameter Field Address | n octets | code à exécuter, adresses de mots, valeurs... |
NFA
Le Name Field Address commence un mot et décrire ses caractéristiques. Le bit 7 du premier octet est à 1. Les bits 4 à 0 de ce même premier octet indiquent la longueur du nom du mot. C'est pourquoi un mot Forth a une limite à 31 caractères.
PRECEDENCE
: si le bit 6 est à 1, cela signifie que le mot est de type IMMEDIATE
. Lors de la compilation d'un mot, un mot immédiat est exécuté sur le moment, plutôt que compiler. (?TODO? Cf. le fonctionnement de la compilation)
SMUDGE
: si le bit 5 est à 0, cela signifie que le mot est valide. S'il est à 1, il sera ignoré par la recherche de mots.
Lors de la définition d'un mot avec :
, SMUDGE
est placé à 1 par :
, puis c'est le mot ;
qui place ce bit à 0 lors de la fin de la compilation d'un mot.
Les octets qui suivent forment le nom du mot. Le dernier octet de ce nom a le bit 7 à 1.
LFA
Le Link Field Address pointe vers le mot précédent dans le dictionnaire. L'intégralité des mots du dictionnaire courant forment ainsi une liste chaînée. Le premier mot défini, LIT
dans cette implémentation, a un LFA à 0, indiquant la fin de la chaîne.
CFA
Le Code Field Address pointe vers le code à exécuter lors de l'exécution du mot. Lors de l'exécution d'un mot, Forth prend l'adresse du CFA et y saute pour exécuter le code.
Cette adresse peut-être tout simplement l'adresse du PFA. C'est le cas pour les mots écrits en assembleur directement. Ce code aura la charge de rappeler la routine qui passe au mot suivant. Sur cette implémentation, il suffit de faire un JP (IX)
.
L'adresse du CFA peut aussi pointer vers un code qui va lire successivement des adresses de mots présentes dans la PFA. C'est le cas pour les mots écrits à partir d'autres mots Forth.
Note : PAMPUK Forth est un Forth avec une implémentation ITC (Indirect Threaded Code), ce qui est un type d'implémentation usuel sur les machines 8 bits. Dans d'autres types d'implémentations (DTC/Direct Threaded Code, STC/Subroutine Threaded Code, TIC/Token Threaded Code,...), le contenu du CFA peut être différent. Cependant, sa sémanitque reste la même : c'est ce qui indique ce qui doit être exécuté.
PFA
Le Parameter Field Address est l'endroit où sont stockés les paramètres du mot. Cela peut être :
- du code assembleur lors que le CFA pointe directement vers le PFA,
- des adresses de mots Forth lorsque le mot a été défini par
:
, - des valeurs quelconques utilisées par d'autres types de mots (variables, constantes,...).
Exemples
Le mot EXECUTE
prend une adresse sur la pile et continue l'exécution à cette adresse. Le mot est situé à l'adresse 2026h
.
Champ | Valeurs en mémoire | Signification |
---|---|---|
NFA | 87h | Bit 7 à 1 et longueur du nom du mot : 7 |
45h 58h 45h 43h 55h 54h C5h | Les octets ASCII du nom du mot qui forment EXECUTE , le dernier octet a son bit 7 à 1. |
|
LFA | 15h 20h | Adresse du mot précédent : 2015h, l'adresse du NFA de LIT |
CFA | 32h 20h | Adresse du PFA de EXECUTE , qui suit juste après |
PFA | Le code machine qui prendre l'adresse sur la pile, la place dans le registre HL puis saute à cette adresse. |
Le code assembleur dans le PFA :
POP HL
LD E,(HL)
INC HL
LD D,(HL)
EX DE,HL
JP (HL)
Le mot ALLOT
qui réserve de la place dans le dictionnaire, est un mot écrit avec d'autres mots Forth. Il est situé à l'adresse 2774h
.
Champ | Valeurs en mémoire | Signification |
---|---|---|
NFA | 85h | Bit 7 à 1 et longueur du nom du mot : 5 |
41h 4Ch 4Ch 4Fh D4h | Les octets ASCII du nom du mot qui forment ALLOT , le dernier octet a son bit 7 à 1. |
|
LFA | 69h 27h | Adresse du mot précédent : 2769h, l'adresse du NFA de HERE |
CFA | 32h 20h | Adresse du code d'exécution des mots définis par : . |
PFA | Liste de CFA des mots qui composent ALLOT . |
Le code Forth dans le PFA :
DP \ met sur la pile la dernière adresse allouée
+! \ prend la valeur en seconde position sur la pile et l'ajoute à la valeur pointée par l'adresse en première position de la pile
; \ termine le mot et retourne à la boucle d'exécution Forth
Les mots de définition
Les mots de définition sont des mots qui créent d'autres mots. Le plus utilisé est :
, central au Forth. Mais on y trouve aussi CONSTANT
et VARIABLE
. À chaque fois que l'exécution d'un mot en ajoute un nouveau au dictionnaire, ce mot est un mot de définition.
Pour comprendre les mots de définition, il est nécessaire d'avoir compris la structure d'un mot en Forth. Un mot de définition a en effet en charge de remplir les champs du mot créé.
Ainsi, le mot CONSTANT
crée un NFA avec le nom qui suit, lie le nouveau mot au précédent du dictionnaire courant, met dans le CFA l'adresse d'un code qui mettra la valeur trouvée dans le PFA sur la pile, et enfin met dans le PFA la valeur trouvée sur la pile lors de l'exécution de CONSTANT
.
Le nouveau mot créé, lorsqu'il sera exécuté, aura donc pour CFA l'adresse du code qui mettra la valeur sur la pile, et pour PFA la valeur à mettre sur la pile.
On peut voir que le mot CONSTANT
est associé à deux codes exécutables : le code de CONSTANT
en soi, exécuté lors de son appel et qui en charge de construire l'autre mot ; mais aussi le code qui sera « donné » à chacun des mots créés. À chacune des constantes dans ce cas-ci.
Créer des mots de définition
Il est possible de créer ses propres mots de définitions, et pour cela, Forth offre deux mots pour aider à ces manipulations : <BUILDS
et DOES>
.
<BUILDS
se charge de créer un mot avec le nom qui suivra le mot de définition lors de son appel. Les mots qui suivent servent ensuite à opérer sur ce mot afin de le construire, de le mettre en forme.
Il est possible par exemple de stocker des informations dans le PFA du mot créé.
DOES>
se charge d'indiquer que les mots suivant seront exécutés lors de l'exécution du mot créé. Lors de l'exécution de cette partie, l'adresse PFA+2
du mot créé sera disponible sur la pile.
Par exemple, CONSTANT
qui est un mot de définition, pourrait être définit de la manière suivante :
: CONSTANT
<BUILDS ,
DOES> @
;
Lorsque le mot CONSTANT
est appelé, l'exécution de <BUILDS
crée un mot avec le nom qui suit l'appel de CONSTANT
. Le premier paramètre du PFA
est aussi réservé. Puis ,
est exécuté. Ce mot prend la valeur sur la pile et l'ajoute à la fin du dictionnaire, c'est-à-dire, à ce moment-là, au PFA+2 du mot en train d'être créé.
Ensuite, DOES>
est exécuté. Ce mot place (DOES)
(un mot non disponible à l'utilisation directe) dans le CFA du mot en train d'être créé. Dans le premier paramètre du PFA
, DOES>
place un pointeur vers la liste de mots qui le suivent.
Le code pointé est ici @
, qui prend l'adresse sur la pile et met la valeur à cette adresse sur la pile. L'adresse sur la pile est l'adresse du PFA+2
, qui est l'adresse où se trouve la valeur qui a été mise là lors de la création du mot par ,
. @
est suivi de ;S
, qui termine l'exécution du mot et retourne à l'appelant.
Pour aller plus loin, un exemple plus détaillé est disponible dans la section des exemples.
Créer des mots de définition en assembleur
Il existe une alternative à <BUILDS
DOES>
pour créer des mots de définition. Elle est à utiliser lorsque le code exécuté par le mot créé est en assembleur plutôt qu'en Forth.
Ce nouveau couple de mots est CREATE
et ;CODE
.
Dans cette version, CONSTANT
serait défini de la manière suivante :
: CONSTANT
CREATE , \ Cette partie est similaire à <BUILDS
[COMPILE] SMUDGE \ Cependant, avec CREATE, il est nécessaire d'utiliser SMUDGE
;CODE \ Équivalent à DOES>, mais la suite devra être en assembleur Z80
HEX
13 C, \ INC DE se place sur la valeur de la constante
EB C, \ EX DE,HL
5E C, \ LD E,(HL) / récupère
23 C, \ INC HL | la valeur
56 C, \ LD D,(HL) | de la
D5 C, \ PUSH DE \ constante
DD C, E9 C, \ JP (IX) Continue l'exécution de l'interpréteur Forth
;
Le code après ;CODE
est tout simplement le code en ROM du mot CONSTANT
de ce Forth.
Note : le mot ;CODE
termine effectivement le mot CONSTANT
. Cela agit comme un ;
, mais place aussi la suite de l'exécution, en code machine, à l'adresse qui suit. Pour y placer le code machine, on utilise le mot C,
qui place un octet à HERE
et incrémente cette variable.
Pour aller plus loin, un exemple plus détaillé est disponible dans la section des exemples.
Les mots immédiats
Les mots immédiats sont des mots qui sont exécutés immédiatement lors de la compilation, plutôt que compilés.
Normalement, lors de la compilation, les adresses des mots spécifiés sont ajouté au code du mot en cours. Cependant, lorsqu'un mot immédiat est rencontré, plutôt que compilé, il est exécuté. Cela permet d'agir sur la compilation en cours.
Exemple IF/ENDIF
Prenons pour exemple les mots IF
et ENDIF
. Ce sont deux mots immédiats dont les définitions sont les suivantes :
: IF COMPILE OBRANCH HERE 0 , 2 ; IMMEDIATE
: ENDIF ?COMP 2 ?PAIRS HERE OVER - SWAP ! ; IMMEDIATE
Le mot IMMEDIATE
après la définition indique que le mot est immédiat. Il est donc exécuté lors de la compilation, plutôt que compilé dans le mot en cours.
Ainsi, lorsque IF
est rencontré lors de la compilation, il exécute immédiatement le code suivant :
COMPILE OBRANCH \ Compile le CFA du mot 0BRANCH
HERE \ Met immédiatement dans la pile l'adresse courante de la RAM
0 , \ Place 0000 (sur 2 octets) à l'adresse courante de la RAM
2 \ Met la valeur 2 dans la pile
; \ Fin de la procédure IF
Ainsi, après l'exécution de IF
, la RAM ressemblera à ceci :
...
CFA de 0BRANCH \ 2 octets
00 00 \ 2 octets, la valeur 0000
...
Et sur la pile nous avons l'adresse où a été placé 0000
, ainsi que la valeur 2
.
Plus tard, lorsque ENDIF
est rencontré lors de la compilation, il exécute immédiatement le code suivant :
?COMP \ Vérifie si nous sommes en mode de compilation d'un mot, sinon affiche une erreur
2 ?PAIRS \ Vérifie si le sommet de la pile est égal à 2, sinon affiche une erreur
\ le 2 placé par IF est consommé, le sommet de la pile est donc l'adresse de 0000
HERE \ Met l'adresse courante de la RAM sur la pile
OVER \ Duplique l'adresse de 0000 et le place au sommet de la pile
- \ Soustrait l'adresse de 0000 de l'adresse courante, laissant la différence sur la pile
\ Ce résultat est la distance entre l'adresse courante et l'adresse de 0000 placée par IF
SWAP \ Échange les deux valeurs du sommet de la pile, laissant l'adresse de 0000 en haut
! \ Prend l'adresse de 0000 et la distance calculée, et place cette distance à l'adresse de 0000
\ Ceci va servir de paramètre au saut relatif effectué par 0BRANCH
; \ Fin de la procédure ENDIF
Après ENDIF
, la RAM ressemblera à ceci :
...
CFA de 0BRANCH \ 2 octets
nn nn \ saut relatif de 2 octets calculé par ENDIF
...
Lorsque 0BRANCH
est exécuté lors de l'exécution du mot qui a été compilé avec IF
et ENDIF
, il lit le sommet de la pile. Si ce sommet est égal à 0, il ajoute nnnn
(la valeur calculée par ENDIF
) à son IP (Instruction Pointer) pour effectuer le saut relatif jusqu'à l'adresse correspondant à ENDIF
. Sinon, il ajoute 2 à son IP pour poursuivre l'exécution du programme.
Les conditions
Le mot principal pour définir un branchement conditionnel en Forth est IF
. Ce mot prend la valeur sur la pile et si celle-ci est non nulle, continue l'exécution du code du mot en cours. Dans le cas contraire, l'exécution se poursuit après le mot ELSE
s'il
est présent, ou après le mot THEN
sinon.
D'un point de vue syntaxique, la lecture d'une condition en Forth est un peu étonnante lorsque l'on vient de langages plus usuels.
La condition se trouve en effet avant le mot IF
. Et THEN
est à comprendre comme un « puis ensuite », terminant la clause conditionnelle.
: IS<3 3 < IF ." INFERIEUR A 3" ELSE ." PAS INFERIEUR A 3" THEN ;
2 IS<3 \ Affiche "INFERIEUR A 3"
4 IS<3 \ Affiche "PAS INFERIEUR A 3"
IF
, ELSE
et THEN
étant des mots immédiats, leur utilisation n'est valide que pendant la compilation d'un mot.
ENDIF
est équivalent à THEN
, et est parfois préféré pour des raisons de clarté.
Les boucles
Il existe plusieurs manières d'effectuer des boucles en Forth.
DO/LOOP
La plus usuelle est la boucle utilisant DO
et LOOP
. Elle prend le format suivant :
<borne supérieure> <valeur de démarrage> DO ... LOOP
À l'intérieur de la boucle, entre les deux mots, le mot I
permet de lire la valeur de l'index de la boucle, dont les valeurs successives sont comprises entre la valeur de démarrage et la borne supérieure (exclue).
En détails :
-
DO
est un mot immédiat qui compile sa primitive(DO)
(attention aux parenthèses !) dans le mot en cours de définition.(DO)
se chargera à l'exécution de lire les valeurs de la borne supérieure et de la valeur initiale pour les enregistrer dans la pile de retour. La valeur initiale, en haut de la pile, devient alors la valeur de l'index courant. [DO
] utilise aussi le même mécanisme queIF
/ENDIF
pour préparer le saut relatif qui sera effectué parLOOP
(voir l'exemple du paragraphe sur les mots immédiats). -
DO
etLOOP
doivent obligatoirement se trouver à l'intérieur de la même définition, c'est-à-dire entre un:
et;
d'un même mot. -
LOOP
est un mot immédiat qui compile sa primitive(LOOP)
dans le mot en cours de définition. Le mot se charge également de calculer le saut relatif attendu parDO
. L'exécution de(LOOP)
augmente l'index de 1 (l'index est présent en haut de la pile retour) et vérifie si l'index a atteint ou dépassé la borne supérieure (en deuxième position dans la pile retour). Si c'est le cas, la boucle se termine, sinon le programme continue à exécuter le code entreDO
etLOOP
. -
Le mot
I
lit la valeur de l'index à l'intérieur de la boucle. Il est important de noter queI
ne peut être utilisé qu'à l'intérieur de la boucle, c'est-à-dire entreDO
etLOOP
, pour avoir le sens attendu.
Code exemple :
DECIMAL
: TEST 10 1 DO CR ." INDEX = " I . LOOP CR ;
TEST
Affiche
INDEX = 1
INDEX = 2
INDEX = 3
INDEX = 4
INDEX = 5
INDEX = 6
INDEX = 7
INDEX = 8
INDEX = 9
Il est possible de faire des boucles imbriquées, c'est-à-dire de mettre un DO
/LOOP
à l'intérieur d'un autre DO
/LOOP
. Dans ce cas, le mot J
permet de lire l'index de la boucle extérieure. I
continue de lire l'index de la boucle la plus intérieure.
Code exemple :
: TEST
2 1 DO
3 1 DO
CR
." INDEX EXTERIEUR = " J .
." INDEX INTERIEUR = " I .
LOOP
LOOP
CR ;
TEST
Affiche
INDEX EXTERIEUR = 1 INDEX INTERIEUR = 1
INDEX EXTERIEUR = 1 INDEX INTERIEUR = 2
INDEX EXTERIEUR = 1 INDEX INTERIEUR = 3
INDEX EXTERIEUR = 2 INDEX INTERIEUR = 1
INDEX EXTERIEUR = 2 INDEX INTERIEUR = 2
INDEX EXTERIEUR = 2 INDEX INTERIEUR = 3
DO/+LOOP
Variante de DO
/LOOP
, la boucle DO
/+LOOP
permet d'incrémenter l'index de la boucle d'une valeur différente de 1. Elle prend le format suivant :
<borne supérieure> <valeur de démarrage> DO ... <valeur d'incrémentation> +LOOP
Code exemple :
DECIMAL
: TEST 10 1 DO CR ." INDEX = " I . 2 +LOOP CR ;
TEST
Affiche
INDEX = 1
INDEX = 3
INDEX = 5
INDEX = 7
INDEX = 9
BEGIN/UNTIL
Une autre manière de faire des boucles est d'utiliser les mots BEGIN
et UNTIL
. Cette boucle continue tant qu'une condition n'est pas remplie. Cette condition est testée à chaque itération de la boucle en évaluant le sommet de la pile au moment du UNTIL
.
Code exemple :
: TEST
BEGIN \ marque le début de la boucle
CR ." KEY 5 ?" \ affiche "KEY 5 ?"
KEY \ lit une touche et met la valeur sur la pile
53 = \ teste si la touche est 5 (53 en ASCII) et met le résultat sur la pile
UNTIL \ tant que le sommet de la pile n'est pas 1, retourne au début de la boucle
CR \ affiche un retour à la ligne
." OK 5" CR \ affiche "OK 5"
; \ termine le mot TEST
BEGIN/WHILE/REPEAT
Une variante de la boucle BEGIN
/UNTIL
est la boucle BEGIN
/WHILE
/[REPEAT
]. Elle continue tant qu'une condition est remplie. Cette condition est testée au début de chaque itération de la boucle en évaluant le sommet de la pile au moment du WHILE
.
Code exemple :
: TEST
BEGIN \ marque le début de la boucle
CR ." KEY 9 ?" \ affiche "KEY 9 ?"
KEY \ lit une touche et met la valeur sur la pile
57 < \ teste si la touche est inférieure à 9 (57 en ASCII) et met le résultat sur la pile
WHILE \ si le sommet de la pile est 0 (faux), alors la boucle se termine.
." < 9" \ sinon affiche "< 9"
REPEAT \ puis retourne au début de la boucle
CR \ affiche un retour à la ligne
." OK 9" CR \ affiche "OK 9"
; \ termine le mot TEST
BEGIN/AGAIN
La boucle BEGIN
/AGAIN
est une boucle infinie. On ne peut en sortir qu'explicitement, par exemple en utilisant le mot ABORT
ou en réinitialisant la machine.
Code exemple :
: TEST
BEGIN \ marque le début de la boucle
CR ." PRISONNIER !" \ affiche "PRISONNIER !"
KEY \ lit une touche et met la valeur sur la pile
53 = \ teste si la touche est 5 (53 en ASCII) et met le résultat sur la pile
IF \ si le sommet de la pile est 1
ABORT \ alors on réinitialise l'interpréteur Forth
ENDIF
AGAIN \ retourne au début de la boucle
; \ termine le mot TEST
La mémoire
La mémoire de la machine est entièrement accessible. Il est bien entendu important de connaître sa structure pour savoir où lire, où écrire et aussi surtout où ne pas écrire n'importe quoi.
Il y a des espaces mémoire importants et nommés en Forth. Par exemple, HERE
pointe vers la prochaine adresse libre dans le dictionnaire, TIB
pointe vers le buffer de texte, PAD
pointe vers un espace mémoire temporaire.
Les mots principaux pour la mémoire sont @
et !
. Le premier permet de lire une valeur à une adresse, le second d'écrire une valeur à une adresse.
Pour manipuler des octets, on utilise les mots C@
et C!
. Pour manipuler des valeurs de 32 bits, on utilise les mots 2@
et 2!
.
Il est aussi possible d'accéder à la mémoire vidéo avec les mots V@
et V!
.
Les adresses importantes s'obtiennent à partir de mots spécifiques. Par exemple, un mot construit par VARIABLE
donne l'adresse de la variable ainsi créée.
Il est aussi possible de réserver de la mémoire avec le mot ALLOT
.
Plan de la mémoire du HRX
Mémoire principale
---- --------------------------- -----
0000 ROM
Système d'exploitation et
routines graphiques
1FFF
---- --------------------------- -----
2000 ROM FORTH
3FFF
---- --------------------------- -----
4000 Pile images (empile vers
les addresses hautes)
Pile des paramètres
(empile vers les addresses
5E00 basses)
---- --------------------------- -----
5FF0 Début de la pile des S0 @
paramètres
---- --------------------------- -----
6000 Dictionnaire (empile vers
les addresses hautes)
DDBC 10 buffers d'édition FIRST
...
... LIMIT
FE00 TIB TIB @
Pile des appels (empile
vers les addresses basses)
FF42 Variables FORTH R0
FF8E Mot FORTH en RAM
FFA0 Adresse de départ
FFF0 Autres variables et pile
système (?TODO?)
Variables FORTH
Adresse | Contenu |
---|---|
FF42 | NFA du dernier mot du vocabulaire éditeur |
FF44 | Nombre de lignes par « screen » (21) |
FF46 | Adresse d'exécution de BLOCK |
FF48 | Adresse d'exécution de R/W |
FF4A | Adresse du CFA de R/W |
FF4C | Variable USE (prochain buffer) |
FF4E | Variable PREV (buffer courant) |
FF50 | Variable OFFSET |
FF52 | Nombre de caractères pour le nom des « screens » |
FF54 | Nombre de caractères par ligne pour l'éditeur |
FF56 | Variable FIRST (DDBCh) |
FF58 | Variable LIMIT (FE00h) |
FF5A | Nombre d'octets par buffer |
FF5C | Variable R0 |
FF5E | Variable TIB |
FF60 | Variable WIDTH |
FF62 | Variable FENCE |
FF64 | Variable DP |
FF66 | Variable VOC-LINK |
FF68 | Variable BLK |
FF6A | Variable IN |
FF6C | Variable SCR |
FF6E | Variable CONTEXT |
FF70 | Variable CURRENT |
FF72 | Variable STATE |
FF74 | Variable BASE |
FF76 | Variable DPL |
FF78 | Variable CSP |
FF7A | Variable R |
FF7C | Variable HLD |
FF7E | Variable ASSADR qui contient le CFA du vocabulaire d'assembleur (?TODO?). Pointe sur QUIT s'il n'y a pas de vocabulaire d'assembleur. |
FF80 | Adresse de NUMBER |
FF82 | Adresse de ERROR |
FF84 | Adresse de (chaînage d'un autre langage ?TODO?) |
FF86 | Adresse de FWADR , adresse du premier mot Forth exécuté. Pointe sur ABORT . |
FF88 | Graine pour RND et RANDOM |
FF8A | Pointeur vers le dernier MESSAGE |
FF8C | Pointeur vers la pile des appels |
FF8E | Le mot FORTH compilé |
FF9C | Variable LATEST |
FFA1 | Variable S0 |
Mémoire vidéo
---- --------------------------- -----
C000 Écran vidéo
---- --------------------------- -----
F900 Alphabet spécial
---- --------------------------- -----
FD00 Alphabet standard
---- --------------------------- -----
FE61 Variables graphiques
---- --------------------------- -----
FFF0 Autres variables et pile
système (?TODO?)
---- --------------------------- -----
Adresse | Contenu |
---|---|
FE8A | calibrage 50ième de seconde (horloge) |
FE8B | calibrage secondes (horloge) |
FE8C | calibrage minutes (horloge) |
FE8D | calibrage heures (horloge) |
FE8E | 50ième de seconde (horloge) |
FE8F | secondes (horloge) |
FE90 | minutes (horloge) |
FE91 | heures (horloge) |
Les mots de vocabulaire
Il existe pour Forth deux vocabulaires actifs : le vocabulaire courant et le vocabulaire de contexte. Le vocabulaire courant est celui dans lequel les mots compilés sont ajoutés. Le vocabulaire de contexte est celui dans lequel les mots sont cherchés lors de l'interprétation et de la compilation.
Les vocabulaires sont chaînés, c'est-à-dire qu'un vocabulaire nouvellement défini pointe vers le vocabulaire courant. Ainsi, les mots de ce vocabulaire « parent » sont disponibles pour le nouveau vocabulaire.
Lors de l'utilisation du mot :
celui-ci commence par changer le vocabulaire de contexte pour le vocabulaire courant. Ainsi, après une définition, le contexte est revenu au vocabulaire courant.
Exemple :
VOCABULARY MONVOC \ Crée un nouveau vocabulaire MONVOC
: BONJOUR ." BONJOUR" ; \ Crée un mot BONJOUR dans le vocabulaire FORTH et non MONVOC
MONVOC DEFINITIONS \ Change le vocabulaire courant et de contexte pour MONVOC
: AUREVOIR ." AUREVOIR" ; \ Crée un mot AUREVOIR dans le vocabulaire MONVOC
BONJOUR \ Affiche BONJOUR
AUREVOIR \ Affiche AUREVOIR
FORTH \ Change le vocabulaire de contexte pour FORTH
BONJOUR \ Affiche BONJOUR
AUREVOIR \ Erreur, le mot AUREVOIR n'est pas dans
\ le vocabulaire de contexte
\ ??? Et pourtant ça fonctionne. AUREVOIR est trouvé. Pourquoi ?
: BYE ." BYE" ; \ Le mot BYE est ajouté au vocabulaire MONVOC, qui est
\ toujours le vocabulaire courant. Au passage, le vocabulaire
\ de contexte est changé pour MONVOC
BYE \ Affiche BYE
AUREVOIR \ Affiche AUREVOIR
Le mini-éditeur
PAMPUK Forth est livré en ROM avec un éditeur de texte rudimentaire. Celui-ci permet de manipuler et de mettre au point des mots puis de les compiler, les sauvegarder, les charger.
L'éditeur manipule des SCREEN
de 38 colonnes par 21 lignes, ce qui fait 798 octets. Ces screens
sont stockés dans des buffers de 826 octets dont la structure est détaillée plus bas. Il y a de la place réservée pour 10 screens
simultanés dans la mémoire de l'ordinateur. Lorsque cette mémoire est pleine et qu'un nouveau screen
est demandé, un plus ancien sera retiré de la mémoire, après sauvegarde si nécessaire.
Un buffer peut contenir du code source afin de le compiler, mais il peut tout aussi bien contenir des données brutes afin de les sauver et charger depuis une mémoire de masse.
Attention, du au fonctionnement du Forth, il est important d'oublier (FORGET
) les versions précédentes d'un mot avant d'en compiler une nouvelle version. Si le compilateur PAMPUK Forth affiche un message lorsqu'un mot est redéfini, ce n'est qu'un avertissement, le mot est effectivement redéfini.
Manipulations dans le mini-editeur
Pour pouvoir changer le contenu d'un écran il faut utiliser le vocabulaire de contexte EDITOR
.
Format interne des screens et buffers
Un buffer est composé de 826 octets.
Offset Contenu
------ -------
0-1 Numéro du buffer, le bit de poids fort est à 1 si le buffer a été modifié.
2-25 Nom du buffer. Initialisé avec des zéros.
Lorsque le nom est modifié, il est complété avec des espaces.
26-823 798 octets de données.
824-825 Deux octets à 0 ?
Les buffers se situent entre les adresses FIRST
et LIMIT
.
Note : lors de la première utilisation de OPEN
, le buffer ouvert est le suivant par rapport à PREV
. Ce qui fait que le premier buffer n'a l'air utilisé qu'après avoir rempli tous les autres.
Il y a deux variables qui indiquent quel est le buffer courant : l'une est PREV
, qui sert pour les manipulations de buffers par le système et indique une adresse. L'autre est SCR
, qui est utilisée pour les manipulations par l'utilisateur et indique un numéro.
L'éditeur pleine page
Il existe aussi un éditeur pleine page, disponible sur cassette (et disquette pour le Hector HRX/MX uniquement ?TODO?).
Il se loge en adresse 4000h
, ce qui permet de laisser libre l'espace mémoire usuel de compilation de mots, au détriment de la place pour manipuler les images
.
Se lance avec EDIT (n - )
ou E
(pour le screen
courant).
Ajoute les mots GLUPS ( - n1 n2)
(pour les erreurs de compilation), WHERE
(pour afficher le screen
au niveau de l'erreur), LLIST
pour un listing sur imprimante, COPY ( n1 n2 - )
pour copier le contenu d'un buffer
vers un autre, :MOT
qui permet d'ajouter des raccourcis clavier d'édition et KILL_EDITOR
qui supprime l'éditeur pleine page de la mémoire.
Des commandes d'édition sont ajoutées aux commandes usuelles (?TODO? les lister ici ?).
On quitte l'éditeur avec CTRL + RETURN
.
Fonctionnement avec une cassette
Lors d'un FLUSH
avec une cassette, le système va proposer des opérations pour chacun des buffers modifiés.
Par exemple :
ECRAN NO 1
SUR K7 ?
Les commandes possibles à ce moment sont :
R
pour rembobiner la cassetteP
pour passer un bloc (nom pour la représentation d'un buffer sauvegardé) de la cassette. Son numéro est affiché mais il n'est pas chargé en mémoire.O
oui, sauve le buffer sur cassetteN
non, ne sauve pas le buffer sur cassette
Lors d'un LIST
ou un LOAD
, si le buffer n'a pas été ouvert, le système va automatiquement charger depuis la cassette le premier bloc trouvé et l'insérer dans le buffer avec le numéro indiqué.
Fonctionnement avec une disquette
Afin de pouvoir utiliser une disquette, il est nécessaire de charger les mots supplémentaires depuis la disquette PAMPUK Forth. Celle-ci doit être insérée dans le lecteur A puis l'entrée « disquette » doit-être sélectionnée dans le menu de démarrage.
Une fois les mots chargés, le Forth est initialisé et se trouve avec le vocabulaire DISK
actif. Les nouveaux mots sont donc disponibles.
Le mot R/W
est aussi redirigé pour fonctionner avec la disquette.
(?TODO?) ajouter ce paragraphe
Affichage graphique
La surface d'affichage de l'Hextor HRX fait 243 x 228 pixels adressables individuellement, chaque pixel pouvant prendre une couleur dans une palette de 4 couleurs. Ces couleurs sont choisis parmi 18couleurs en deux luminosités.
L'origine de l'écran est en bas à gauche.
La mémoire vidéo se situe entre les adresses C000h
et FFFFh
. Ces adresses sont partagés avec les adresses de la RAM, il est donc nécessaire de choisir le mapping de la mémoire pour accéder à la mémoire vidéo.
La partie affichée de la mémoire vidéo se situe entre les adresses C000h
et F8FFh
incluses. Chaque pixel est représenté par 2 bits, ce qui permet les 4 index de couleurs simultanés possibles. Cela signifie aussi qu'un octet encode 4 pixels consécutifs. Les 2 bits de poids fort de l'octet représentent le pixel le plus à droite de l'écran, et inversement, les 2 bits de poids faible représentent le pixel le plus à gauche.
La mémoire d'affichage est linéaire, partant du coin haut gauche de l'écran et décrivant l'affichage ligne par ligne. Chaque ligne utilise 64 octets. Cela donne une largeur en pixels théorique de 256. Cependant, seuls les 243 premiers sont affichés.
Couleurs
Code | Pleine luminosité | Demi-luminosité |
---|---|---|
0 | Noir | Noir |
1 | Rouge | Rubis |
2 | Vert | Olive |
3 | Jaune | Marron |
4 | Bleu | Marine |
5 | Magenta | Violet |
6 | Cyan | Turquoise |
7 | Blanc | Gris |
La palette se change avec le mot COLOR
.
Modes d'affichage graphique
Il y a deux modes d'affichages, le mode BIG
et le mode LITTLE
. Dans le mode BIG
, les opérations sur la surface graphiques sont effectués par groupe d'octets, ce qui permet un accès rapide. Dans le mode LITTLE
, les opérations sont effectuées pixel par pixel, ce qui permet plus de précision, au détriment de la vitesse.
Système d'images
Il est possible de définir des images avec le mot IMAGE
. Ce mot est un mot de définition, qui va en créer un autre. Celui-ci aura la capacité de s'afficher à l'écran.
Exemple :
4 BASE ! \ passe en base 4
1111 1111 \ défini la forme de l'image
1000 0001
1222 2221
1111 1111
DECIMAL \ passe en décimal
2 4 IMAGE CARRE \ défini le mot CARRE de 2 octets par 4 lignes
3 INK 25 25 75 75 BOX \ affiche un rectangle
50 50 0 CARRE \ affiche l'image entièrement
Il est possible de créer un masque associé à une image. La définition de MASK
est similaire à celle de IMAGE
et doit suivre sa définition afin d'y être associé.
Exemple :
4 BASE ! \ passe en base 4
0111 1110 \ défini la forme de l'image
1000 0001
1000 0001
0111 1110
DECIMAL \ passe en décimal
2 4 IMAGE ROND \ défini le mot ROND de 2 octets par 4 lignes
4 BASE ! \ passe en base 4
3000 0003 \ défini la forme du masque
0000 0000
0000 0000
3000 0003
DECIMAL
2 4 MASK \ défini le masque de l'image précédente
3 INK 25 25 75 75 BOX \ affiche un rectangle
50 50 1 ROND \ affiche l'image avec son masque
30 30 2 ROND \ affiche l'image en mode « dessus »
30 50 3 ROND \ affiche l'image en mode « dessous » (et donc n'apparait pas, car dans le rectangle)
100 100 3 ROND \ affiche l'image en mode « dessous » (et ici, en dehors du rectangle, apparait)
Les modes 4 à 7 permettent de copier le morceau d'image cible (là où l'image s'affiche) dans une pile d'images. Il est ensuite possible de rappeler ces images, ce qui permet une gestion de l'affichage en plusieurs couches, ou de faire des sprites de manière aidée.
Exemple
50 50 0 CARRE \ affiche CARRE
50 50 4 ROND \ affiche ROND au même endroit avec copie de l'image cible
BPOP \ le dessin de CARRE est restauré
Mode | Effet |
---|---|
0 | Affichage de l'image telle quelle, y compris la couleur d'index 0. |
1 | Affichage de l'image associée à son masque. Les couleurs d'index 3 du masque laissent voir le fond. |
2 | Mode « dessus ». Affiche tous les points dont l'index est différente de celle de PAPER . |
3 | Mode « dessous ». Affiche tous les points si le pixel de dessin est d'index de couleur égale à PAPER . |
4 | Comme le mode 0, plus copie dans la pile image |
5 | Comme le mode 1, plus copie dans la pile image |
6 | Comme le mode 2, plus copie dans la pile image |
7 | Comme le mode 3, plus copie dans la pile image |
Modes texte
L'alphabet SPECIAL
affiche les caractères s'affichent toujours en mode plein
et en mode BIG
. Les caractères ne peuvent être placés que sur des multiples de 4 pixels. Il y a 28 colonnes dans ce mode et l'affichage du texte est rapide.
L'alphabet spécial a des représentations pour les caractères ASCII de 32 à 95.
L'alphabet STANDARD
affiche les caractères en mode calque
par défaut et en mode LITTLE
. Les caractères peuvent être placés au pixel près. Il y a 38 colonnes dans ce mode et l'affichage du texte est plus lent.
Les modes d'affichage texte et les modes d'affichages graphiques sont indépendants. On peut être en STANDARD
et en BIG
par exemple, ou bien en SPECIAL
et LITTLE
.
Caractères de contrôles
Les caractères de contrôles s'utilisent avec EMIT
. Par exemple 11 EMIT
est l'équivalent de CLS
.
Code | Effet |
---|---|
1 | HOME |
7 | Émet un bip |
8 | Recule le curseur du mode texte |
9 | Avance le curseur du mode texte |
11 | CLS |
12 | PAGE |
13 | CR |
14 | Place le curseur en haut à gauche de l'écran sans l'effacer |
15 | CLS HOME |
23 | Mode vidéo inverse , valable en SPECIAL et STANDARD , en mode papier |
24 | Mode normal , valable en SPECIAL et STANDARD (annule 23) |
25 | Mode papier , valable en STANDARD |
26 | Mode calque , valable en STANDARD |
27 | AT (0 0 25 EMIT met le curseur en haut à gauche de l'écran) |
28 | SCALE |
29 | WINDOW |
30 | PEN |
31 | PAPER |