![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() Version LibreOffice modifiable Je veux le traduire! Il s'agit d'un Éditeur, Interpréteur et Compilateur FORTH pour ATARI sous TOS.
|
Version 0.5.4 (28/01/2023):
|
Un langage interactif: Le langage permet une utilisation en mode direct, à la manière d'une calculatrice, mais dans lequel on peut créer de nouveaux mots afin d'enrichir les possibilités. Ci-contre, imaginons qu'on veuille réduire une série de prix de 20%, on en calcule à chaque fois 80%. Le premier exemple donne le nouveau prix pour un article de 59€: c'est 47€. Vous remarquez qu'on empile d'abord les valeurs avant d'opérer dessus, le "." sert à afficher le sommet de la pile. Pour éviter de retaper les calculs, on crée le mot reduc avec la paire : ; et on l'utilise sur un prix de 70€ réduit à 56€. On peut également taper un petit programme avec ici la stucture list..dolist..lloop qui crée une boucle à partir d'une liste hétéroclite de valeurs. Dans la boucle on affiche l'indice i (prix de départ) puis un espace puis le prix réduit. system permet de quitter l'interpréteur. |
![]() Utilisation en mode direct |
![]() Codage d'un message avec une seule variable! |
Un programme de codage de message Écrivons pas à pas un programme sous GEM avec menu pour coder ou décoder un message. Allons d'abord au coeur du sujet... Nous allons coder un mot qui permet de réaliser un décalage quelconque dans l'alphabet sur un message en majuscules. Pour cela, une seule variable: p qui pointera sur les caractères successifs de la chaîne passée sur la pile.
|
Utilisons notre mot Pour cela, on va passer par la chaine prédéfinie pad qui sert au forth pour certains résultats d'opérations de chaines.
Pour décoder un message sans la clé, on peut lui faire subir les 25 décalages possibles: c'est ce que fait la boucle 25 ndo..nloop suivante.
|
![]() |
![]() Version utilisable dans un programme. |
Codage avec prompt Nous allons enrober le mot code afin qu'il demande clairement les informations à l'utilisateur et affiche le résultat. C'est ce que fait le mot code-decode.
|
La recherche brute De même, implémentons la recherche brute des 25 décalages si un message est fourni sans sa clé, c'est le mot multi-decode.
|
![]() |
![]() |
Créons le menu !![]()
|
Un dernier effort Un petit mot pour réagir à l'entrée Infos... du menu. Ce sera une simple boîte d'alerte. |
![]() |
![]() |
La boucle principale! Voici une boucle classique de gestion d'événements AES.
|
Lancement automatique ou non Je veux que sous l'interpréteur, la compilation du source ne lance pas l'exécution du programme afin de garder la main en mode interactif et de tester chaque partie indépendemment. Par contre, lorsque j'utilise le compilateur externe pour générer un programme indépendant et débuggé, il faut que la procédure se lance. On utilise à nouveau une compilation conditionnelle avec le flag 13 qui est vrai sous l'interpréteur et faux sous le compilateur. Note: par défaut, le programme compilé efface la souris, donc on a ajouté v_show_c pour qu'elle revienne. |
![]() |
![]() Codage d'un message puis décodage brut |
Notre programme en action ! Le programme se lance, affiche son menu et sa fenêtre. Il ne vous reste plus qu'à utiliser les différentes entrées pour le tester. |
![]() Vue partielle du décodage brut, on retrouve notre message |
![]() Versions 68030 et 68000, exécutables et sources. ![]() avec l'aimable autorisation de Pierre-Louis Lamballais et d'Eric Da Cunha. ![]() |
![]() |
Autres exemples de programmes en FORTH Lien avec la HP-41 et son interface série Menu, communication série Utilisation des instructions pour piloter le Supercharger comme un coprocesseur. Inclusion assembleur PC, instructions Supercharger Sauvegarde et restauration des données de la BOSS-DR5 via MIDI. Menu, fichiers, communication MIDI Gestion de l'horloge RTC de l'Apollo Vampire V4. Inclusion assembleur, création dialogue, dialogue en fenêtre |
![]() |
![]() |
Inclure de l'assembleur On peut vouloir remplacer le mot code par une routine assembleur. Ceci est très simple:
|
Encore mieux: tout dans un seul source! Le texte en assembleur ainsi que la génération du PRG à inclure peuvent être pilotés directement depuis le FORTH. Voici comment:
Lors de la compilation, vous verrez l'activité de votre assembleur: ![]() Note: vous remarquez un argument 0 pour ces directives, il peut être utilisé en liaison avec un Flag afin d'exécuter ou d'ignorer ces ordres. Par exemple, si vous ne travaillez que sur la partie Forth, il est inutile de resauver et générer le PRG de la partie assembleur à chaque compilation. |
![]() |
Définition des variables | |||
---|---|---|---|
variable p \ le module RIM variable t \ le TRM variable fichier \ adresse du fichier variable total \ taille totale fichier 256 string filename \ chemin+nom du fichier 1536 allot constant PALs \ palette source 1536 allot constant PALd \ palette destination variable fhd |
Chaque module sera pointé par une variable. Les palettes sont à leur taille maximale pour recevoir 256 couleurs au format VDI: 256 couleurs × 3 composantes × un mot de 2 octets (0 à 1000) = 1536. |
||
Chargement des modules | |||
: main " d:\parx.sys\" 1 modset 0 t ! " parx252.trm" graphic_card negate t modload drop 0 p ! " rim\gif00.rim" -1 p modload drop |
|
||
Lecture et décompression du GIF | |||
" F:\FORTH\GIPHY.GIF" filename $! filename 0 fopensize dup fhd ! 0> if total ! fhd @ total @ dup allot dup fichier ! fread drop fichier @ total @ filename fhd @ PALs 1 p dorim drop |
|
||
Tramage écran | |||
mfdbs mfdbd fillmfdb work_out 2- w@ mfdbd 12 + w! %b1100110 1 PALs PALd 3 t dotrm drop |
|
||
Copie vers l'écran | |||
mfdbd mfdbs fillmfdb PALs savevdipal PALd setvdipal 0 mfdbd ! 0 0 0 0 mfdbs 4 + w@ mfdbs 6 + w@ 3 vro_cpyfm key drop fhd @ fclose drop PALs setvdipal then p modunload t modunload ; |
|
||
Pour un programme compilé | |||
>comp -13 >ifflag fastopen drop main >endf |
|
Définition des variables | |||
---|---|---|---|
variable t \ le TRM variable fichier \ adresse du fichier variable total \ taille totale fichier 256 string filename 256 string chemin 32 string nom 1536 allot constant PALs 1536 allot constant PALd 20 allot constant MFDB variable fhd 100 array MODS variable nMODS |
|
||
Choix de l'image | |||
: main cls " \*.*" chemin $! " " nom $! chemin nom fsel_input chemin nom path filename $! cls |
|
||
Chargement des modules | |||
" d:\parx.sys\" 1 modset ." Charment des modules..." cr 0 t ! ( " parx252.trm" graphic_card negate t ) modload drop 0 0 MODS ! ( " rim\*.rim" -1 0 MODS ) modmload .. nMODS ! ." modules chargés" cr |
|
||
Chargement de l'image | |||
." Chargement du fichier..." cr filename 0 fopensize dup fhd ! 0> if total ! ( fhd @ total @ dup allot dup fichier ! ) fread drop |
Même système qu'avant, charge l'image en entier en mémoire. | ||
Recherche du bon WIM | |||
nMODS @ 0 do -1 mfdbs fillmfdb ( fichier @ total @ filename fhd @ PALs 1 i MODS ) dorim 0< ifloop |
|
||
Résultat de la recherche | |||
dup nMODS @ = if drop ." Image non reconnue" cr else MODS modlname type cr key drop |
|
||
Décodage et affichage | |||
mfdbs mfdbd fillmfdb work_out 2- w@ mfdbd 12 + w! ( %b1100110 1 PALs PALd 3 t ) dotrm drop mfdbd mfdbs fillmfdb PALs savevdipal PALd setvdipal ( 0 mfdbd ! 0 0 0 0 mfdbs 4 + w@ mfdbs 6 + w@ 3 ) vro_cpyfm key drop PALs setvdipal then fhd @ fclose drop then 0 MODS nMODS @ modmunload t modunload ; >comp -13 >ifflag fastopen drop main >endf |
|
Définition des variables | |||
---|---|---|---|
variable p \ le module WIM variable t \ le TRM 1536 allot constant PALs \ la palette source (si besoin) 1536 allot constant PALd \ la palette destination (inutilisée en 16 bits) |
Définition classique des variable, comme dans les deux précédents programmes.
Chaque module est pointé par une variable, les palettes sont réservées au maximum de leurs capacités. |
||
Chargement des modules | |||
: main absolute " d:\parx.sys\" 1 modset ." Chargement des modules..." cr 0 t ! " parx252.trm" graphic_card negate t modload if exit else ." TRM Ok" cr then 0 p ! " wim\tga_tc16.wim" 1 p modload if exit else ." WIM Ok" cr then remember |
|
||
Copie d'un bloc écran | |||
." Bloc 320x200 avec palette" cr 0 mfdbs ! 0 320 200 work_out 2- w@ 0 mfdbd fillmfdb mfdbd imagesize allot mfdbd ! 0 0 0 0 320 200 3 vro_cpyfm PALs savevdipal mfdbd mfdbs fillmfdb |
|
||
En cas de carte graphique | |||
( graphic_card work_out 2- w@ 4 8 <seg> ) and if ." Passage en mode VDI..." cr 1 mfdbd 10 + w! mfdbd imagesize allot mfdbd ! vr_trnfm mfdbd mfdbs fillmfdb then |
Si on se trouve sur une carte graphique dans un mode 4 ou 8 plans, il faut ramener notre bloc
vers le format indépendant VDI, le TRM n'a pas les routines pour.
Dans les modes TC (15, 16, 24 et 32 bits) il gère parfaitement l'encodage.
|
||
Passage du bloc en 16 bits | |||
." Transformation en 16 bits..." cr 16 mfdbd 12 + w! %b0100011 1 PALs PALd 3 t dotrm if exit else ." Dotrm Ok" cr then mfdbd mfdbs fillmfdb |
|
||
Sauvegarde de l'image en 16 bits | |||
." Sauvegarde en TGA 16 bits..." cr " I:\AAA.TGA" PALd 1 p dowim if exit else ." Dowim Ok" cr then |
|
||
Nettoyage de la mémoire | |||
restore t modunload p modunload relative ; |
|
![]() |
Définition des variables: n qui contiendra la limite à atteindre et les trois piles de travail pour chaque tâche. 10 entiers chacune est largement suffisant. |
![]() |
Calcul d'une somme: C'est ce même mot qu'appellent les trois tâches pour leur calcul. do ouvre la boucle de thid (l'identifiant 1,2 ou 3) à n+1 3 +loop permet d'aller de 3 en 3 après chaque addition, le thread passe la main au suivant avec thnext |
![]() |
Code exécuté par les threads 1 et 2: Voici le programme exécuté par les deux premiers threads, les esclaves. Tant que la valeur n est non nulle, ils calculent leur somme puis se mettent en attente de synchronisation sur le canal zéro avec 0 thsync pour transmettre leur résultat avant de recommencer. |
![]() |
Code exécuté par le threads 3: Voici le programme exécuté par le dernier thread, le maître.
|
![]() |
Le programme principal: Chaque thread est défini, ils partagent tous la page0 (seul l'un d'eux écrit), ont chacun leur pile. On leur donne un ID qui nous arrange bien ainsi que le nom du mot qui les lance. Le dernier thread défini est celui qui se lance en premier avec thrun. Ainsi, nous sommes certains que le thread maître sera le premier à prendre la main pour piloter la synchronisation avec les deux autres. |
![]() |
Exécution du programme: Main lance l'exécution des trois threads. On demande la somme de 1 à 100 qui vaut 5050 puis la somme de 1 à 2022 qui vaut 2.045.253. Pour finir, donner zéro est le critère de fin et les trois threads sont stoppés et effacés de la liste. |
![]() |
La fenêtre FORTH sera partagée en 3 colonnes. La première réservée au mode direct, les deux suivantes aux threads. L'un affiche des lignes en couleur
avec un mode REPLACE, l'autre affiche des lignes en noir avec un mode XOR.
Voyez sur le mode direct qu'on a lancé le programme avec main, puis forcé un arrêt du multitâche avec Ctrl+Alt+Shift et affiché la liste des processus en cours avec thstat. On peut relancer les tâches avec thrun là où elles s'étaient arrêtées. |
![]() |
Définition des variables: Voici comment FORTH s'en sort avec les variables locales, par exemple : 3 4 thvariable X1 crée un tableau interne de 3 valeurs sur 4 octets qui sera automatiquement indexé par l'identifiant du thread. En mode direct, ID=0, donc c'est X1(0) qui est utilisé, dans le thread 1, c'est X1(1) qui sera utilisé, et ainsi de suite. Vous avez le choix dans l'identifiant, mais lors de l'utilisation de variables locales, des valeurs consécutives commençant à 1 sont conseillées! |
![]() |
Les piles et les pages:
|
![]() |
Procédures communes aux deux threads
Initialisation d'un dessin: Pour démarrer, il nous faut deux points X1,Y1 et X2,Y2 ainsi qu'un décalage dX1,dY1 et dX2,dY2 pour aller vers la ligne suivante. Les points sont choisis entre 0 et Xmax/Ymax (taille de la page du thread) et les mouvements de 1 à 8 pixels. Le rebond: au cas où un point sorte de la page, c'est la routine bounce qui permet d'en calculer le rebond et de changer le signe du déplacement. |
![]() |
Avancer d'un pas: Ce mot permet de déplacer X1,Y1 et X2,Y2 et vérifie à chaque fois qu'il n'y a pas dépassement. Il est à noter qu'en FORTH, les coordonnées sont par défaut relatives à la page en cours. De ce fait, aucun décalage n'est à gérer par l'utilisateur, le coin supérieur gauche de la page est toujours 0,0 pour le programmeur. Notez que la structure case permet d'autres tests que l'égalité : 0 <of permet de tester si la valeur est négative et Xmax @ >of permet de tester si on dépasse Xmax. L'appel à v_pline dessine la ligne. |
![]() |
Le code du thread #2: C'est celui qui dessine les lignes en noir.
|
![]() |
Le code du thread #1: C'est celui qui trace les lignes en couleur.
|
![]() |
Le programme principal: Chaque thread est défini en utilisant non pas thread mais vthread. Cette variante demande l'ouverture d'une station VDI spécifique pour ce thread afin qu'il fixe ses propres réglages indépendamment des autres. thrun lance le travail multitâche et les dessins s'enchaînent dans les deux autres colonnes. |
Dialogue avec M_PLAYER/MP_STE (et ANIPLAY)
Création d'une animation vd_create passe en mode parallèle avec l'accessoire. C'est M_PLAYER qui fabrique une animation et, pour chaque image, il lance un mot FORTH qui génère les pixels. Cette fonction n'est pas implantée dans ANIPLAY. Voici l'exemple d'une création toute simple. L'animation sera en 120×96 et en 16 bits. Au départ l'image est noire (remplie de pixels nuls) et à chaque demande d'une nouvelle image, le mot FORTH remplit 4 lignes de pixels blancs par le haut (480 pixels égaux à FFFF). Au bout de 24 images, 4×24=96 lignes seront remplies, l'image sera entièrement blanche.
Une série de fonctions graphiques est venue enrichir le FORTH. Voici quelques exemples de tracé. Les fonctions principales sont:
![]()
Des fonctions de calcul sont également disponibles:
|