From 9e4e474cd18d5c178e363688c350c99d15bcdcb0 Mon Sep 17 00:00:00 2001 From: Hinault David Date: Tue, 25 Aug 2026 15:10:30 +0200 Subject: [PATCH] xtensa: register FP opcodes for ESP32 and ESP32-S3 Both cores advertise a single-precision FPU -- XCHAL_HAVE_FP is 1 in their core-isa.h, along with FP_DIV, FP_SQRT, FP_RECIP and FP_RSQRT -- but their XtensaConfig had no .opcode_translators list. As a result no floating point opcode table was attached, config->opcode_ops[opc] stayed NULL, and every FP instruction ended up in the 'unimplemented opcode' path of xtensa_tr_init_dc() (translate.c:886). Reproducing is straightforward: run any ESP-IDF application that uses floats on cpuType "esp32s3". The firmware I hit this with contains ~700 FP instructions (180 lsx, 148 lsi, 100 add.s, 56 float.s) and aborts on the first one: unimplemented opcode 'lsi' in slot 0 (pc = 4200bdad) xtensa_fpu_opcodes is the correct table rather than xtensa_fpu2000_opcodes, for two reasons: the lsip/ssip forms the compiler emits only exist in the former, and FPU2000 provides neither divide nor square root, which both cores advertise. ESP32-S2 is deliberately left alone: XCHAL_HAVE_FP is 0 there, so it correctly has no FP table. Verified by building the xtensa target and running an ESP-IDF firmware that previously failed on the first FP instruction; it now executes them. --- arch/xtensa/core-esp32.c | 24 ++++++++++++++++++++++-- arch/xtensa/core-esp32s3.c | 24 ++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/arch/xtensa/core-esp32.c b/arch/xtensa/core-esp32.c index 2fdaad539..261e78e39 100644 --- a/arch/xtensa/core-esp32.c +++ b/arch/xtensa/core-esp32.c @@ -34,5 +34,25 @@ #define xtensa_modules xtensa_modules_esp32 #include "core-esp32/xtensa-modules.c.inc" -XtensaConfig esp32 - __attribute__((unused)) = { .name = "esp32", .isa_internal = &xtensa_modules, .clock_freq_khz = 140000, DEFAULT_SECTIONS }; +/* + * ESP32 has a single-precision FPU (XCHAL_HAVE_FP is 1 in + * core-esp32/core-isa.h, together with FP_DIV, FP_SQRT, FP_RECIP and + * FP_RSQRT). Without an .opcode_translators list, no floating point opcode + * table is attached to this configuration: opcode_ops[opc] stays NULL and + * every FP instruction fails with "unimplemented opcode 'lsi'". + * + * xtensa_fpu_opcodes is the right table rather than xtensa_fpu2000_opcodes: + * the lsip/ssip forms emitted by the compiler only exist in the former, and + * FPU2000 has neither divide nor square root, which this core advertises. + */ +XtensaConfig esp32 __attribute__((unused)) = { + .name = "esp32", + .isa_internal = &xtensa_modules, + .clock_freq_khz = 140000, + .opcode_translators = + (const XtensaOpcodeTranslators *[]) { + &xtensa_core_opcodes, + &xtensa_fpu_opcodes, + NULL, }, + DEFAULT_SECTIONS +}; diff --git a/arch/xtensa/core-esp32s3.c b/arch/xtensa/core-esp32s3.c index 9159e50c1..9cff18492 100644 --- a/arch/xtensa/core-esp32s3.c +++ b/arch/xtensa/core-esp32s3.c @@ -36,5 +36,25 @@ // use the common implementation of ESP32 #include "core-esp32/xtensa-modules.c.inc" -XtensaConfig esp32s3 - __attribute__((unused)) = { .name = "esp32s3", .isa_internal = &xtensa_modules, .clock_freq_khz = 140000, DEFAULT_SECTIONS }; +/* + * ESP32S3 has a single-precision FPU (XCHAL_HAVE_FP is 1 in + * core-esp32s3/core-isa.h, together with FP_DIV, FP_SQRT, FP_RECIP and + * FP_RSQRT). Without an .opcode_translators list, no floating point opcode + * table is attached to this configuration: opcode_ops[opc] stays NULL and + * every FP instruction fails with "unimplemented opcode 'lsi'". + * + * xtensa_fpu_opcodes is the right table rather than xtensa_fpu2000_opcodes: + * the lsip/ssip forms emitted by the compiler only exist in the former, and + * FPU2000 has neither divide nor square root, which this core advertises. + */ +XtensaConfig esp32s3 __attribute__((unused)) = { + .name = "esp32s3", + .isa_internal = &xtensa_modules, + .clock_freq_khz = 140000, + .opcode_translators = + (const XtensaOpcodeTranslators *[]) { + &xtensa_core_opcodes, + &xtensa_fpu_opcodes, + NULL, }, + DEFAULT_SECTIONS +};