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.
La pile
Si on ne précise pas de quelle pile on parle, c'est généralement de la pile de 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.
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 eux-même composés 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 de 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.
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 quel 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
(?TODO?) absence de S" et comment ajouter ce mot.
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.
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 à 1, cela signifie que le mot est valide. C'est le mot ;
qui place ce bit à 1 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 : PAMPUNK 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, lier le nouveau mot au précédent du dictionnaire courant, mettre dans le CFA l'adresse d'un code qui mettra la valeur trouvée dans le PFA sur la pile, et enfin mettre 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.
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 de modifier le CFA du mot créé pour exécuter le code qui suit DOES>
. Le code qui suit DOES>
est donc exécuté lors de l'appel du mot créé. À noter que le système met sur le pile l'adresse du PFA+2 lors de cette exécution.
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
. Puis ,
est exécuté. Ce mot prend la valeur sur la pile est l'ajoute à la fin du dictionnaire, c'est-à-dire, à ce moment-là, au PFA+2 du mot en train d'être créé.
Note : la première adresse de PFA est utilisée par le fonctionnement interne de la définition. (?TODO? détailler).
Ensuite, DOES>
est exécuté. Ce mot modifie le CFA du mot créé pour exécuter le code qui suit DOES>
. Ce code 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 ,
.
(?TODO? Que se passe-t-il avec la pile lors de l'exécution de DOES>
? Est-ce qu'il est obligatoire de consommer le PFA+2 ?)
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.
(?TODO?) Donner un exemple
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.
Les boucles
(?TODO?) ajouter ce paragraphe
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 |