aboutsummaryrefslogtreecommitdiff
path: root/py/emitinlinethumb.c
diff options
context:
space:
mode:
authorChristian Zietz <czietz@gmx.net>2022-04-03 13:12:43 +0200
committerDamien George <damien@micropython.org>2022-04-11 15:35:39 +1000
commitb0bcb3862b95d54b0457d61d779826641e5784fd (patch)
treeee2c280c3ab0ad0f0a323230a3f528c961cb1513 /py/emitinlinethumb.c
parent1daeeb2430c4a4e436ef59d881e5d877d140048a (diff)
py/emitinlinethumb: Use 16 bit encodings for PUSH LR and POP PC.
The Thumb instruction set has special 16 bit encodings for PUSH involving LR and POP involving PC, which are commonly used in nested functions. Using this encoding is particularly important for ARMv6-M, where the more general 32 bit encoding of PUSH and POP is unavailable.
Diffstat (limited to 'py/emitinlinethumb.c')
-rw-r--r--py/emitinlinethumb.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c
index 1a35e25ad..1a9c06a2a 100644
--- a/py/emitinlinethumb.c
+++ b/py/emitinlinethumb.c
@@ -621,8 +621,13 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
asm_thumb_op16(&emit->as, ASM_THUMB_OP_CPSIE_I);
} else if (op == MP_QSTR_push) {
mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);
- if ((reglist & 0xff00) == 0) {
- asm_thumb_op16(&emit->as, 0xb400 | reglist);
+ if ((reglist & 0xbf00) == 0) {
+ if ((reglist & (1 << 14)) == 0) {
+ asm_thumb_op16(&emit->as, 0xb400 | reglist);
+ } else {
+ // 16-bit encoding for pushing low registers and LR
+ asm_thumb_op16(&emit->as, 0xb500 | (reglist & 0xff));
+ }
} else {
if (!ARMV7M) {
goto unknown_op;
@@ -631,8 +636,13 @@ STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_a
}
} else if (op == MP_QSTR_pop) {
mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);
- if ((reglist & 0xff00) == 0) {
- asm_thumb_op16(&emit->as, 0xbc00 | reglist);
+ if ((reglist & 0x7f00) == 0) {
+ if ((reglist & (1 << 15)) == 0) {
+ asm_thumb_op16(&emit->as, 0xbc00 | reglist);
+ } else {
+ // 16-bit encoding for popping low registers and PC, i.e., returning
+ asm_thumb_op16(&emit->as, 0xbd00 | (reglist & 0xff));
+ }
} else {
if (!ARMV7M) {
goto unknown_op;