Autres articles / Other articles

Premiers pas en assembleur XTENSA

publication: 17 novembre 2022 / mis à jour 18 novembre 2022

Read this page in english

 

Appel à collaboration

Vous développez des montages, simples ou complexes avec ESP32 et ESP32forth.

Partagez-les ici sur ce site.

ESP32forth ne pourra se développer qu'avec la collaboration active de toutes les bonnes volontés.

Vos montages peuvent aider d'autres développeurs.

Les montages des autres développeurs peuvent vous aider.

Pour proposer un article ou un montage, cliquez ici


Préambule

Pourquoi programmer en assembleur?

Le code assembleur n'est pas portable dans un autre environnement, ou alors au prix d'énormes efforts de comprehension et d'adaptation du code assemblé.

Une version FORTH n'est pas complète si elle n'a pas d'assembleur.

La programmation en assembleur n'est pas une obligation. Mais dans certains cas, créer une définition en assembleur peut s'avérer bien plus aisé qu'une version en langage C ou en langage FORTH pur.

Mais surtout, une définition écrite en assembleur aura une rapidité d'exécution inégalable.

Nous allons voir, à partir d'exemples très simples et très courts comment maitriser la programmation de définitions FORTH écrites en assembleur Xtensa.

Invocation de l'assembleur Xtensa

Au démarrage de ESP32forth, impossible de définir des mots en assembleur Xtensa sans invoquer le mot xtensa-assembler. Ce mot va charger le contenu du vocabulaire xtensa. Ce mot ne doit être invoqué qu'une seule fois au démarrage de ESP32forth et avant toute définition d'un mot en code xtensa:

forth 
DEFINED? code invert [IF] xtensa-assembler [THEN] 

Maintenant, si on tape order, ESP32forth affiche:

    xtensa >> asm >> FORTH

C'est cet ordre de vocabulaires qu'il faudra respecter quand on veut définir un nouveau mot en assembleur Xtensa à l'aide des mots de définition code et end-code.

Xtensa et la pile FORTH

Le processeur Xtensa dispose de 16 registres, a0 à a15. En réalité, il y a 64 registres, mais on ne peut accéder qu'à une fenêtre de 16 registres parmis ces 64 registres, accessibles dans l'intervalle 00..15.

Le registre a2 contient le pointeur de pile FORTH.

A chaque empilement de valeur, le pointeur de pile est incrémenté de quatre unités:

SP@ .   \ display 1073632236 
1 
SP@ .   \ display 1073632240 
2 
SP@ .   \ display 1073632244 
drop drop 
SP@ .   \ 1073632236 

Voici comment on pourrait réécrire ce mot SP@ en assembleur Xtensa:

\ get Stack Pointer SP - equivalent for SP@ 
code mySP@ 
    a1 32       ENTRY, 
    a8 a2       MOV.N,  \ copy content of a2 in a8 
    a2 a2 4     ADDI,   \ increment a2 
    a8 a2 0     S32I.N, \ copy a8 in address pointed by a2+0 
                RETW.N, 
end-code 

Testons ce nouveau mot mySP@:

mySP@ . 
\ display 1073632240 
SP@ . 
\ display 1073632240 

Ecriture d'une macro instruction Xtensa

Dans notre définition du mot mySP@, la séquence a2 a2 4 ADDI, incrémente de quatre unités le pointeur de pile. Sans cette incrémentation, impossible de renvoyer une valeur au sommet de la pile FORTH. Avec FORTH, nous allons écrire une macro qui automatise cette opération.

Pour commencer, nous allons étendre le vocabulaire asm:

asm definitions 
 
: macro: 
    : 
  ; 

Notre définition macro: est redondante avec : mais à l'avantage de rendre ensuite le code FORTH un peu plus lisible quand on définit une macro-instruction qui étendra le vocabulaire xtensa:

xtensa definitions 
 
macro: sp++, 
    a2 a2 4    ADDI, 
  ; 

Avec cette nouvelle macro-instruction sp++,, nous pouvons réécrire la définition de mySP@:

forth definitions 
asm xtensa 
 
   \ get Stack Pointer SP - equivalent for SP@ 
code mySP@ 
    a1 32       ENTRY, 
    a8 a2       MOV.N,  \ copy content of a2 in a8 
        sp++, 
    a8 a2 0     S32I.N, \ copy a8 in address pointed by a2+0 
                RETW.N, 
end-code 

Il est parfaitement possible d'intégrer une macro dans une autre. Dans le code de mySP@, la ligne de code a8 a2 0 S32I.N, copie le contenu du registre a8 à l'adresse pointée par a2. Voici cette nouvelle macro instruction:

xtensa definitions 
 
\ increment Stack Pointer and store content of ar in addr pointed by Stack Pointer 
macro: arPUSH, { ar -- } 
    sp++, 
    ar a2 0 S32I.N, 
  ; 

Cette macro instruction utilise une variable locale ar. On aurait pu s'en passer, mais l'intérêt de cette variable est que le code de la macro est plus lisible.

Voici le code de mySP@ avec cette macro-instruction.

forth definitions 
asm xtensa 
 
\ get Stack Pointer SP - equivalent to SP@ 
code mySP@3 
    a1 32       ENTRY,  
    a8 a2       MOV.N, 
    a8  arPUSH, 
                RETW.N,  
end-code 

Complétons notre liste de macro instructions:

xtensa definitions 
 
\ decrement Stack Pointer 
macro: sp--,    ( -- ) 
    a2 a2 -4    ADDI, 
  ; 
 
\ Store content of addr pointed by Stack Pointer in ar and decrement Stack Pointer 
macro: arPOP,   { ar -- } 
    ar a2 0     L32I.N, 
    sp--, 
  ; 

Avec ces nouvelles macros, réécrivons swap:

forth definitions 
asm xtensa 
         
code mySWAP 
    a1 32       ENTRY,  
    a9  arPOP, 
    a8  arPOP, 
    a9  arPUSH, 
    a8  arPUSH, 
                RETW.N,  
end-code 
 
17 24 mySWAP 

Voici la fin de ces premiers pas avec l'assembleur xtensa. Nous n'avons abordé que la toute première page d'un énorme livre.


Legal: site web personnel sans commerce / personal site without seling