Programmer en assembleur XTENSA
publication: 11 novembre 2022 / mis à jour 21 octobre 2023
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:
- quand il n'y a plus d'autre solution pour accéder à certaines fonctionnalités d'un processeur;
- pour rendre certaines parties de programme plus rapides. Le code généré par un assembleur ets le plus rapide!
- pour le fun. La programmation en assembleur est un défi intellectuel;
- parce qu'aucun langage évolué ne sait tout faire. Parfois, on peut programmer en assembleur des fonctions trop complexes à écrire dans un autre langage.
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:
- ouvrir le dossier optional dans le dossier où vous avez décompressé le fichier ZIP de la version ESP32forth
- copier le fichier assemblers.h vers le dossier racine contenant le fichier ESP32forth.ino
- lancez ARDUINO IDE, compilez ESP32forth.ino et téléverser vers la carte ESP32
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:
- l'adresse du code assemblé
- le code désassemblé à cette adresse sur 2 ou 3 octets
- le code hexadécimal correspondant au code désassemblé
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