Pourquoi programmer en langage FORTH sur ESP32?
publication: 25 février 2023 / mis à jour 25 février 2023
Préambule
Bonjour,
Je programme en langage FORTH depuis 1983. J'ai cessé de programmer en FORTH en 1996. Mais je n'ai jamais cessé de surveiller l'évolution de ce langage. J'ai repris la programmation en 2019 sur ARDUINO avec FlashForth puis ESP32forth.
Je suis co-auteur de plusieurs livres concernant le langage FORTH:
- Introduction au ZX-FORTH (ed Eyrolles - 1984 - ASIN:B0014IGOXO)
- Tours de FORTH (ed Eyrolles - 1985 - ISBN-13: 978-2212082258)
- FORTH pour CP/M et MSDOS (ed Loisitech - 1986)
- TURBO-Forth, manuel d'apprentissage (ed Rem CORP - 1990)
- TURBO-Forth, guide de référence (ed Rem CORP - 1991)
La programmation en langage FORTH a toujours été un loisir jusqu'en 1992 où le responsable d'une société travaillant en sous-traitance pour l'industrie automobile me contacte. Ils avaient un souci de développement logiciel en langage C. Il leur fallait commander un automate industriel.
Les deux concepteurs logiciels de cette société programmaient en langage C: TURBO-C de Borland pour être précis. Et leur code n'arrivait pas à être suffisamment compact et rapide pour tenir dans les 64 Kilo-octets de mémoire RAM. On était en 1992 et les extensions de type mémoire flash n'existaient pas. Dans ces 64 Ko de mémoire vive, ll fallait faire tenir MS-DOS 3.0 et l'application!
Celà faisait un mois que les développeurs en langage C tournaient le problème dans tous les sens, jusqu'à réaliser du reverse engineering avec SOURCER (un désassembleur) pour éliminer les parties de code exécutable non indispensables.
J'ai analysé le problème qui m'a été exposé. En partant de zéro, j'ai réalisé, seul, en une semaine, un prototype parfaitement opérationnel qui tenait le cahier des charges. Le principe de cette application est expliqué dans cet article:
Un automate industriel avec matrice fractale
Pendant trois années, de 1992 à 1995, j'ai réalisé de nombreuses versions de cette application qui a été utilisée sur les chaines de montage de plusieurs constructeurs automobiles.
Limites entre langage et application
Tous les langages de programmation sont partagés ainsi:
- un interpréteur et le code source exécutable: BASIC, PHP, MySQL, JavaScript, etc... L'application est contenue dans un ou plusieurs fichiers qui sera interprété chaque fois que c'est nécessaire. Le système doit héberger de manière permanente l'interpréteur exécutant le code source;
- un compilateur et/ou assembleur: C, Java, etc... Certains compilateurs génèrent un code natif, c'est à dire exécutable spécifiquement sur un système. D'autres, comme Java, compilent un code exécutable sur une machine Java virtuelle.
Le langage FORTH fait exception. Il intègre:
- un interpréteur capable d'exécuter n'importe quel mot du langage FORTH
- un compilateur capable d'étendre le dictionnaire des mots FORTH
C'est quoi un mot FORTH?
Un mot FORTH désigne toute expression du dictionnaire composée de caractères ASCII
et utilisable en interprétation et/ou en compilation: words
permet
de lister tous les mots du dictionnaire FORTH.
Certains mots FORTH ne sont utilisables qu'en compilation: if else then
par exemple.
Avec le langage FORTH, le principe essentiel est qu'on ne crée pas une application. En FORTH, on étend le dictionnaire! Chaque mot nouveau que vous définissez fera autant partie du dictionnaire FORTH que tous les mots pré-définis au démarrage de FORTH. Exemple:
: typeToLoRa ( -- ) 0 echo ! \ disable display echo from terminal ['] serial2-type is type ; : typeToTerm ( -- ) ['] default-type is type -1 echo ! \ enable display echo from terminal ;
On crée deux nouveaux mots: typeToLoRa
et typeToTerm
qui vont compléter le dictionnaire des mots pré-définis.
Un mot c'est une fonction?
Oui et non. En fait, un mot peut être une constante, une variable, une fonction... Ici, dans notre exemple, la séquence suivante:
: typeToLoRa ...code... ;
aurait son équivalent en langage C:
void typeToLoRa() { ...code... }
En langage FORTH, il n'y a pas de limite entre le langage et l'application.
En FORTH, comme en langage C, on peut utiliser n'importe quel mot déjà défini dans la définition d'un nouveau mot.
Oui, mais alors pourquoi FORTH plutôt que C?
Je m'attendais à cette question.
En langage C, on ne peut accéder à une fonction qu'au travers de la principale fonction main()
.
Si cette fonction intègre plusieurs fonctions annexes, il devient difficile de retrouver une erreur de paramètre
en cas de mauvais fonctionnement du programme.
Au contraire, avec FORTH, il est possible d'exécuter - via l'interpréteur - n'importe quel mot pré-défini ou défini par vous, sans avoir à passer par le mot principal du programme.
L'interpréteur FORTH est immédiatement accessible sur la carte ESP32 via un programme de type terminal et une liaison USB entre la carte ESP32 et le PC.
La compilation des programmes écrits en langage FORTH s'effectue dans la carte ESP32 et non pas sur le PC. Il n'y a pas de téléversement. Exemple:
: >gray ( n -- n' ) dup 2/ xor \ n' = n xor ( 1 time right shift logic ) ;
Cette définition est transmise par copié/collé dans le terminal. L'interpréteur/compilateur
FORTH va analyser le flux et compiler le nouveau mot >gray
.
Dans la définition de >gray
, on voit la séquence dup 2/ xor
.
Pour tester cette séquence, il suffit de la taper dans le terminal. Pour exécuter
>gray
, il suffit de taper ce mot dans le terminal, précédé du nombre à transformer.
Le langage FORTH comparé au langage C
C'est la partie que j'aime le moins. Je n'aime pas comparer le langage FORTH par rapport au langage C. Mais comme quasiment tous les développeurs utilisent le langage C, je vais tenter l'exercice.
Voici un test avec if()
en langage C:
if(j > 13){ // If all bits are received rc5_ok = 1; // Decoding process is OK detachInterrupt(0); // Disable external interrupt (INT0) return; }
Test avec if
en langage FORTH (extrait de code):
j @ 13 > \ If all bits are received if 1 rc5_ok ! \ Decoding process is OK di \ Disable external interrupt (INT0) exit then
Voici l'initialisation de registres en langage C:
void setup() { // Timer1 module configuration TCCR1A = 0; TCCR1B = 0; // Disable Timer1 module TCNT1 = 0; // Set Timer1 preload value to 0 (reset) TIMSK1 = 1; // enable Timer1 overflow interrupt }
La même définition en langage FORTH:
: setup { \ Timer1 module configuration 0 TCCR1A ! 0 TCCR1B ! \ Disable Timer1 module 0 TCNT1 ! \ Set Timer1 preload value to 0 (reset) 1 TIMSK1 ! \ enable Timer1 overflow interrupt }
Ce que FORTH permet de faire par rapport au langage C
On l'a compris, FORTH donne immédiatement accès à l'ensemble des mots du dictionnaire, mais pas seulement. Via l'interpréteur, on aussi accès à toute la mémoire de la carte ESP32. Connectez-vous à la carte ARDUINO sur laquelle est installé FlashForth, puis tapez simplement:
hex here 100 dump
Vous devez retrouver ceci sur l'écran du terminal:
3FFEE964 DF DF 29 27 6F 59 2B 42 FA CF 9B 84 3FFEE970 39 4E 35 F7 78 FB D2 2C A0 AD 5A AF 7C 14 E3 52 3FFEE980 77 0C 67 CE 53 DE E9 9F 9A 49 AB F7 BC 64 AE E6 3FFEE990 3A DF 1C BB FE B7 C2 73 18 A6 A5 3F A4 68 B5 69 3FFEE9A0 F9 54 68 D9 4D 7C 96 4D 66 9A 02 BF 33 46 46 45 3FFEE9B0 45 39 33 33 2F 0D 08 18 BF 95 AF 87 AC D0 C7 5D 3FFEE9C0 F2 99 B6 43 DF 19 C9 74 10 BD 8C AE 5A 7F 13 F1 3FFEE9D0 9E 00 3D 6F 7F 74 2A 2B 52 2D F4 01 2D 7D B5 1C 3FFEE9E0 4A 88 88 B5 2D BE B1 38 57 79 B2 66 11 2D A1 76 3FFEE9F0 F6 68 1F 71 37 9E C1 82 43 A6 A4 9A 57 5D AC 9A 3FFEEA00 4C AD 03 F1 F8 AF 2E 1A B4 67 9C 71 25 98 E1 A0 3FFEEA10 E6 29 EE 2D EF 6F C7 06 10 E0 33 4A E1 57 58 60 3FFEEA20 08 74 C6 70 BD 70 FE 01 5D 9D 00 9E F7 B7 E0 CA 3FFEEA30 72 6E 49 16 0E 7C 3F 23 11 8D 66 55 EC F6 18 01 3FFEEA40 20 E7 48 63 D1 FB 56 77 3E 9A 53 7D B6 A7 A5 AB 3FFEEA50 EA 65 F8 21 3D BA 54 10 06 16 E6 9E 23 CA 87 25 3FFEEA60 E7 D7 C4 45
Ceci correspond au contenu de la mémoire flash.
Et ça, le langage C ne saurait pas le faire?
Si. mais pas de façon aussi simple et interactive qu'en langage FORTH.
Voyons un autre cas mettant en avant l'extraordinaire compacité du langage FORTH...
Mais pourqoi une pile plutôt que des variables?
La pile est un mécanisme implanté sur quasiment tous les microcontrôleurs et microprocesseurs. Même le langage C exploite une pile, mais vous n'y avez pas accès.
Seul le langage FORTH donne un accès complet à la pile de données. Par exemple,
pour faire une addition, on empile deux valeurs, on exécute l'addition, on affiche
le résultat: 2 5 + .
affiche 7.
C'est un peu déstabilisant, mais quand on a compris le mécanisme de la pile de données, on apprécie grandement sa redoutable efficacité.
La pile de données permet un passage de données entre mots FORTH bien plus rapidement que par le traitement de variables comme en langage C ou dans n'importe quel autre langage exploitant des variables.
Etes-vous convaincus?
Personnellement, je doute qu'un seul article vous convertisse irrémédiablement à la programmation en langage FORTH. En cherchant à maitriser les cartes ESP32, vous avez deux possibilités:
- programmer en langage C et exploiter les nombreuses librairies disponibles. Mais vous resterez enfermés dans les capacités de ces librairies. L'adaptation des codes en langage C requiert une réelle connaissance en programmation en langage C et maitriser l'architecture des cartes ESP32. La mise au point de programmes complexes sera toujours un souci.
- tenter l'aventure FORTH et explorer un monde nouveau et passionnant. Certes, ce ne sera pas facile. Il faudra comprendre l'architecture des cartes ESP32, les registres, les flags de registres de manière poussée. En contrepartie, vous aurez accès à une programmation parfaitement adaptée à vos projets.
Mais existe-t-il des applications professionnelles écrites en FORTH?
Oh oui! A commencer par le télescope spatial HUBBLE dont certains composants ont été écrits en langage FORTH.
Le TGV allemand ICE (Intercity Express) utilise des processeurs RTX2000 pour la commande des moteurs via des semi-conducteurs de puissance. Le langage machine du processeur RTX2000 est le langage FORTH.
Ce même processeur RTX2000 a été utilisé pour la sonde Philae qui a tenté d'atterrir sur une comète.
Le choix du langage FORTH pour des applications professionnelles s'avère intéressant si on considère chaque mot comme une boîte noire. Chaque mot doit être simple, donc avoir une définition assez courte et dépendre de peu de paramètres.
Lors de la phase de mise au point, il devient facile de tester toutes les valeurs possibles traitées par ce mot. Une fois parfaitement fiabilisé, ce mot devient une boîte noire, c'est à dire une fonction dont on fait une confiance sans imite à son bon fonctionnement. De mot en mot, on fiabilise plus facilement un programme complexe en FORTH que dans n'importe quel autre langage de programmation.
Mais si on manque de rigueur, si on construit des usines à gaz, il est aussi très facile d'obtenir une application qui fonctionne mal, voire de planter carrément FORTH!
Pour finir, il est possible, en langage FORTH, d'écrire les mots que vous définissez
dans n'importe quelle langue humaine. Cependant, les caractères utilisables sont limités au
jeu de caractères ASCII compris entre 33 et 127. Voic comment on pourrait réécrire
de manière symbolique les mots high
et low
:
\ Turn a port pin on, dont change the others. : __/ ( pinmask portadr -- ) mset ; \ Turn a port pin off, dont change the others. : \__ ( pinmask portadr -- ) mclr ;
A partir de ce moment, pour allumer la LED, on peut taper:
_O_ __/ \ turn LED on
Oui! La séquence _O_ __/
est en langage FORTH!
Avec ESP32forth, voici tous les caractères à votre disposition pouvant composer un mot FORTH:
~}|{zyxwvutsrqponmlkjihgfedcba`_ ^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@? >=<;:9876543210/.-,+*)('&%$#"!
.....
Bonne programmation.
Legal: site web personnel sans commerce / personal site without seling