Autres articles / Other articles

Programmer en assembleur XTENSA

publication: 11 novembre 2022 / mis à jour 21 octobre 2023

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

Pour ceux qui ne connaissent pas le langage assembleur, c'est la couche de plus bas niveau en programmation. En assembleur, on s'adresse directement au processeur.

C'est aussi un langage difficile, peu lisible. Mais en contrepartie, les performances sont exceptionnelles.

On programme en assembleur:

A titre d'exemple, voici le code du décodage de Huffman réalisé en assembleur XTENSA:

/* input in t0, value out in t1, length out in t2 */ 
    srl t1, t0, 6
    li t3, 3
    beq t3, t4, 2f
    li t2, 2
    andi t3, t0, 0x20
    beq t3, r0, 1f
    li t2, 3
    andi t3, t0, 0x10
    beq t3, r0, 1f
    li t2, 4
    andi t3, t0, 0x08
    beq t3, r0, 1f
    li t2, 5
    andi t3, t0, 0x04
    beq t3, r0, 1f
    li t2, 6
    andi t3, t0, 0x02
    beq t3, r0, 1f
    li t2, 7
    andi t3, t0, 0x01
    beq t3, r0, 1f
    li t2, 8
    b 2f
    li t1, 9
1: /* length = value */
    move t1, t2
2: /* done *

Depuis la version 7.0.7.4, ESP32forth intègre un assembleur XTENSA complet. Cet assembleur utilise une notation infixée:

\ in conventionnal assemler: 
\   andi t3, t0, 0x01 
         
\ in ESP32forth xtensa-assembler: 
    a3 a0 $01 ANDI, 

ESP32forth est le tout premier langage de programmation de haut niveau pour ESP32 qui intègre un assembleur XTENSA.

Cette particularité permet au programmeur de définir ses macros d'assemblage.

Tout mot écrit en langage assembleur XTENSA depuis ESP32forth est immédiatement utilisable dans n'importe quelle définition en langage FORTH.

Compiler l'assembleur XTENSA

Depuis la version 7.0.7.15, ESP32forth propose l'assembleur XTENSA comme option. Pour compiler cette option:

Si tout c'est bien passé, vous accéder à l'assembleur XTENSA en tapant une seule fois :

xtensa-assembler 

Pour vérifier la bonne disponibilité du jeu d'instructions XTENSA :

assembler xtensa vlist 

Programmer en assembleur

Afin de bien comprendre ce qui a été affirmé dans le précédent paragraphe, voici une définition proposée comme exemple par Brad NELSON:

\ example from Brad NELSON 
code my2*  
    a1 32 ENTRY,  
    a8 a2 0 L32I.N,  
    a8 a8 1 SLLI,  
    a8 a2 0 S32I.N,  
    RETW.N,  
end-code  

On vient de définir le mot my2* qui a exactement la même action que le mot 2*. L'assemblage du code est immédiat. On peut donc tester notre définition de my2* depuis le terminal:

--> 3 my2*
 ok
6 --> 21 my2*
 ok
6 42 -->

Cette possibilité de tester immédiatement un code assemblé permet de le tester in situ. Si on est amené à écrire un code un peu complexe, il sera aisé de le découper en fragments et tester chaque partie de ce code depuis l'interpréteur de ESP32forth.

Le code assembleur XTENSA est placé après le mot à définir. C'est la séquence code my2* qui crée le mot my2*.

Les lignes suivantes contiennent le code assembleur XTENSA. La définition en assembleur s'achève avec l'exécution de end-code.

Vidéo

2022-10-22 - Assembler / Disassembler for the ESP32 - Brad Nelson:
“The ESP32 uses the Xtensa LX6 instruction set, a 32-bit RISC architecture with a range of optional "modules", many of which are present on the ESP32. I'll present my project to add an Xtensa assembler / disassembler to ESP32forth.”

Jeu d'instructions

Voici le jeu d'instructions XTENSA classé par ordre alphabétique:

ABS,        ABS.S,      ADD,        ADD.N,      ADD.S,      ADDI,       ADDI.N,     ADDMI,  
ADDX2,      ADDX4,      ADDX8,      ALL4,       ALL8,       ALU.S       AND,        ANDB,  
ANDBC,      ANY4,       ANY8,       BALL,       BANY,       BBC,        BBCI,       BBS,  
BBSI,       BEQ,        BEQI,       BEQZ,       BEQZ.N,     BF,         BGE,        BGEI,  
BGEU,       BGEUI,      BGEZ,       BLT,        BLTI,       BLTU,       BLTUI,      BLTZ,  
BNALL,      BNE,        BNEI,       BNEZ,       BNEZ.N,     BNONE,      BREAK,      BREAK.N, 
BT,         CALL0,      CALL12,     CALL4,      CALL8,      CALLX0,     CALLX12,    CALLX4,  
CALLX8,     CEIL.S,     CLAMPS,     DHI,        DHU,        DHWB,       DHWBI,      DII,  
DIU,        DIWB,       DIWBI,      DPFL,       DPFR,       DPFRO,      DPFW,       DPFWO,  
DSYNC,      ENTRY,      ESYNC,      EXCW,       EXTUI,      EXTW,       FLOAT.S,    FLOOR.S,  
IDTLB,      IHI,        IHU,        III,        IITLB,      IIU,        ILL,        ILL.N,  
IPF,        IPFL,       ISYNC,      J,          JX,         L16SI,      L16UI,      L32AI,  
L32E,       L32I,       L32I.N,     L32R,       L8UI,       LDCT,       LDDEC,      LDINC,       
LICT,       LICW,       LOOP,       LOOPGTZ,    LOOPNEZ,    LSI,        LSIU,       LSX, LSXU,  
MADD.S,     MAX,        MAXU,       MEMW,       MIN,        MINU,       MOV,        MOV.N,  
MOV.S,      MOVEQZ,     MOVEQZ.S,   MOVF,       MOVF.S,     MOVGEZ,     MOVGEZ.S,   MOVI,  
MOVI.N,     MOVLTZ,     MOVLTZ.S,   MOVNEZ,     MOVNEZ.S,   MOVSP,      MOVT,       MOVT.S,  
MSUB.S,     MUL.AA.HH,  MUL.AA.HL,  MUL.AA.LH,  MUL.AA.LL,  MUL.AD.HH,  MUL.AD.HL,  MUL.AD.LH,  
MUL.AD.LL,  MUL.DA.HH,  MUL.DA.HL,  MUL.DA.LH,  MUL.DA.LL,  MUL.DD.HH,  MUL.DD.HL,  MUL.DD.LH,  
MUL.DD.LL,  MUL.S,      MUL16S,     MUL16U,     MULA.AA.HH, MULA.AA.HL, MULA.AA.LH, MULA.AA.LL,  
MULA.AD.HH, MULA.AD.HL, MULA.AD.LH, MULA.AD.LL, MULA.DA.HH, MULA.DA.HH.LDDEC,        
MULA.DA.HH.LDINC,       MULA.DA.HL, MULA.DA.HL.LDDEC,       MULA.DA.HL.LDINC,  
MULA.DA.LH, MULA.DA.LH.LDDEC,       MULA.DA.LH.LDINC,       MULA.DA.LL, MULA.DA.LL.LDDEC,  
MULA.DA.LL.LDINC,       MULA.DD.HH, MULA.DD.HH.LDDEC,       MULA.DD.HH.LDINC,       MULA.DD.HL,   
MULA.DD.HL.LDDEC,       MULA.DD.HL.LDINC,       MULA.DD.LH, MULA.DD.LH.LDDEC,  
MULA.DD.LH.LDINC,       MULA.DD.LL, MULA.DD.LL, MULA.DD.LL.LDDEC,       MULA.DD.LL.LDINC, 
MULL,       MULSH,      MULUH,      NEG,        NEG.S,      NOP,        NOP.N,      NSA,  
NSAU,       OEQ.S,      OLE.S,      OLT.S,      OR,         ORB,        ORBC,       PDTLB,  
PITLB,      QUOS,       QUOU,       RDTLB0,     RDTLB1,     REMS,       REMU,       RER,  
RET,        RET.N,      RETW,       RETW.N,     RFDD,       RFDE,       RFDO,       RFE,  
RFI,        RFME,       RFR,        RFUE,       RFWO,       RFWU,       RITLB0,     RITLB1,  
ROTW,       ROUND.S,    RSIL,       RSR,        RSYNC,      RUR,        S16I,       S32C1I,  
S32E,       S32I,       S32I.N,     S32RI,      S8I,        SDCT,       SEXT,       SICT,  
SICW,       SIMCALL,    SLL,        SLLI,       SRA,        SRAI,       SRC,        SRL,  
SRLI,       SSA8B,      SSA8L,      SSAI,       SSI,        SSIU,       SSL,        SSR,  
SSX,        SSXU,       SUB,        SUB.S,      SUBX2,      SUBX4,      SUBX8,      SYSCALL,  
TRUNC.S,    UEQ.S,      UFLOAT.S,   ULE.S,      ULT.S,      UN.S,       UTRUNC.S,   WAITI,  
WDTLB,      WER,        WFR,        WITLB,      WSR,        WUR,        XOR,        XORB,  
XSR,  

Résumé des instructions de base

Liste des instructions de base incluses dans toutes les versions de l'architecture Xtensa. Le reste de cette section donne un aperçu des instructions de base.

Load / chargement
L8UI, L16SI, L16UI, L32I, L32R, 
Store / stockage
S8I, S16I, S32I, 
Memory ordering / mise en ordre mémoire
MEMW, EXTW, 
Jump call / sauts
CALL0, CALLX0, RET, J, JX, 
Conditional branch / branchement conditionnel
BALL, BNALL, BANY, BNONE, BBC, BBCI, BBS, BBSI, BEQ, BEQI, BEQZ, BNE,  
BNEI, BNEZ,BGE, BGEI, BGEU, BGEUI, BGEZ, BLT, BLTI, BLTU, BLTUI, BLTZ, 
Move / déplacement
MOVI, MOVEQZ, MOVGEZ,  MOVLTZ, MOVNEZ, 
Arithmetic / arithmétique
ADDMI, ADD, ADDX2, ADDX4, ADDX8, SUB, SUBX2, SUBX4, SUBX8, NEG, ABS, 
Bitwise logical / logique binaire
AND, OR, XOR, 
Shift / décalage
EXTUI, SRLI, SRAI, SLLI, SRC, SLL, SRL, SRA, SSL, SSR, SSAI, SSA8B, SSA8L, 
Processor control / contrôle processeur
RSR, WSR, XSR, RUR, WUR, ISYNC, RSYNC, ESYNC, DSYNC, NOP, 

Un désassembleur en prime

Un assembleur, c'est très bien. Un code facile à intégrer aux définitions FORTH, c'est merveilleux. Mais disposer d'un désassembleur XTENSA, alors là, c'est royal!

Si on reprend la défintion de my2* que nous avons assemblé, il est facile d'en obtenir le désassemblage:

' my2* cell+ @ 20 disasm 
\ display:  
\ 1074338656  --  a1 32 ENTRY,            -- 004136 
\ 1074338659  --  a8 a2 0 L32I.N,                 -- 0288 
\ 1074338661  --  a8 a8 1 SLLI,           -- 1188F0 
\ 1074338664  --  a8 a2 0 S32I.N,                 -- 0289 
\ 1074338666  --  RETW.N,                 -- F01D 
\ 1074338668  -- ...... 

Le code de notre mot my2* n'est accessible que par indirection dont l'adresse est placée dans le champ des paramètres.

Chaque ligne affiche:

Le désassembleur peut aussi agir sur l'ensemble du code déjà compilé ou assemblé. Voyons le code du mot 2*:

' 2* @ 20 disasm 
\ display: 
\ 1074606252  --  a12 a3 0 L32I.N,                -- 03C8 
\ 1074606254  --  a5 a5 1 SLLI,           -- 1155F0 
\ 1074606257  --  a15 a12 0 L32I.N,               -- 0CF8 
\ 1074606259  --  a3 a3 4 ADDI.N,                 -- 334B 
\ 1074606261  --  1074597318 J,           -- F74346 

Le désassemblage indique que le code mène à un saut inconditionnel 1074597318 J,. Il est facile de poursuivre le désassemblage vers cette nouvelle adresse:

1074597318 20 disasm 
\ display:  
\ 1074597318  --  a15 JX,                 -- 000FA0 
\ 1074597321  --  a10 64672 L32R,                 -- FCA0A1 
\ 1074597324  --  a5 a7 1 S32I,           -- 016752 
\ 1074597327  --  1074633168 CALL8,               -- 08C025 
\ 1074597330  --  a12 a3 0 L32I,          -- 0023C2 
\ 1074597333  --  a2 a7 4 ADDI,           -- 04C722 
\ 1074597336  ...... 

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