Skip to content

Commit 9dcad25

Browse files
agattidpgeorge
authored andcommitted
py/emitinlinextensa: Add inline assembler support for windowed cores.
This commit introduces support for writing inline assembler code snippets when targeting Xtensa cores that use register windows (eg. the whole ESP32 family). Opcodes support is still limited to what the ESP8266 supports (as in, LX3 cores opcodes), however each LX core version is guaranteed to support all previous versions' opcodes as well. The ESP32 does not have the inline assembler enabled by default, following the existing expectations when it comes to firmware footprint. Since now emitted functions may have one of two possible exit sequences, the L32I test had to be fixed. It would return the word containing the L32I opcode itself, but the upper 8 bits of the word came from the following opcode - which can change depending on the exit code sequence. Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
1 parent dc91fa6 commit 9dcad25

5 files changed

Lines changed: 37 additions & 12 deletions

File tree

py/asmxtensa.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,10 +115,12 @@ void asm_xtensa_exit(asm_xtensa_t *as) {
115115
}
116116

117117
void asm_xtensa_entry_win(asm_xtensa_t *as, int num_locals) {
118-
// jump over the constants
119-
asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4);
120-
mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte
121-
as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);
118+
if (as->num_const > 0) {
119+
// jump over the constants
120+
asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4);
121+
mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte
122+
as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4);
123+
}
122124

123125
as->stack_adjust = 32 + ((((ASM_XTENSA_NUM_REGS_SAVED_WIN + num_locals) * WORD_SIZE) + 15) & ~15);
124126
asm_xtensa_op_entry(as, ASM_XTENSA_REG_A1, as->stack_adjust);

py/compile.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ static const emit_inline_asm_method_table_t *emit_asm_table[] = {
147147
&emit_inline_thumb_method_table,
148148
&emit_inline_thumb_method_table,
149149
&emit_inline_xtensa_method_table,
150-
NULL,
150+
&emit_inline_xtensa_method_table,
151151
&emit_inline_rv32_method_table,
152152
};
153153

@@ -3551,7 +3551,7 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool
35513551
// TODO this can be improved by calculating it during SCOPE pass
35523552
// but that requires some other structural changes to the asm emitters
35533553
#if MICROPY_DYNAMIC_COMPILER
3554-
if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSA)
3554+
if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSA || mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSAWIN)
35553555
#endif
35563556
{
35573557
compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE);

py/emitinlinextensa.c

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@
3535

3636
#if MICROPY_EMIT_INLINE_XTENSA
3737

38+
#include "py/persistentcode.h"
39+
40+
static inline bool emit_windowed_code() {
41+
#if MICROPY_DYNAMIC_COMPILER
42+
return mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_XTENSAWIN;
43+
#elif MICROPY_EMIT_XTENSAWIN
44+
return true;
45+
#else
46+
return false;
47+
#endif
48+
}
49+
3850
struct _emit_inline_asm_t {
3951
asm_xtensa_t as;
4052
uint16_t pass;
@@ -73,11 +85,19 @@ static void emit_inline_xtensa_start_pass(emit_inline_asm_t *emit, pass_kind_t p
7385
memset(emit->label_lookup, 0, emit->max_num_labels * sizeof(qstr));
7486
}
7587
mp_asm_base_start_pass(&emit->as.base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE);
76-
asm_xtensa_entry(&emit->as, 0);
88+
if (emit_windowed_code()) {
89+
asm_xtensa_entry_win(&emit->as, 0);
90+
} else {
91+
asm_xtensa_entry(&emit->as, 0);
92+
}
7793
}
7894

7995
static void emit_inline_xtensa_end_pass(emit_inline_asm_t *emit, mp_uint_t type_sig) {
80-
asm_xtensa_exit(&emit->as);
96+
if (emit_windowed_code()) {
97+
asm_xtensa_exit_win(&emit->as);
98+
} else {
99+
asm_xtensa_exit(&emit->as);
100+
}
81101
asm_xtensa_end_pass(&emit->as);
82102
}
83103

tests/inlineasm/xtensa/asmloadstore.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import array
22

3-
# On the 8266 the generated code gets put into the IRAM segment, which is only
4-
# word-addressable. Therefore, to test byte and halfword load/store opcodes
5-
# some memory must be reserved in the DRAM segment.
3+
# On the ESP8266 the generated code gets put into the IRAM segment, which is
4+
# only word-addressable. Therefore, to test byte and halfword load/store
5+
# opcodes some memory must be reserved in the DRAM segment. This also happens
6+
# to work on the ESP32 too.
67

78
BYTE_DATA = array.array("B", (0x11, 0x22, 0x33, 0x44))
89
WORD_DATA = array.array("h", (100, 200, -100, -200))
@@ -29,8 +30,10 @@ def tl32r() -> int:
2930
@micropython.asm_xtensa
3031
def tl32i() -> uint:
3132
call0(ENTRY)
33+
align(4)
3234
label(ENTRY)
3335
l32i(a2, a0, 0)
36+
nop()
3437

3538

3639
print(hex(tl32i()))

tests/inlineasm/xtensa/asmloadstore.py.exp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
0x4030201
2-
0xf8002022
2+
0xf0002022
33
0x22
44
200
55
-200

0 commit comments

Comments
 (0)