summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--py/asmxtensa.c45
-rw-r--r--py/asmxtensa.h8
-rw-r--r--py/emitinlinextensa.c211
-rw-r--r--py/mpconfig.h5
-rw-r--r--tests/inlineasm/xtensa/asmargs.py44
-rw-r--r--tests/inlineasm/xtensa/asmargs.py.exp5
-rw-r--r--tests/inlineasm/xtensa/asmarith.py119
-rw-r--r--tests/inlineasm/xtensa/asmarith.py.exp40
-rw-r--r--tests/inlineasm/xtensa/asmbranch.py299
-rw-r--r--tests/inlineasm/xtensa/asmbranch.py.exp66
-rw-r--r--tests/inlineasm/xtensa/asmjump.py26
-rw-r--r--tests/inlineasm/xtensa/asmjump.py.exp2
-rw-r--r--tests/inlineasm/xtensa/asmloadstore.py98
-rw-r--r--tests/inlineasm/xtensa/asmloadstore.py.exp9
-rw-r--r--tests/inlineasm/xtensa/asmmisc.py25
-rw-r--r--tests/inlineasm/xtensa/asmmisc.py.exp3
-rw-r--r--tests/inlineasm/xtensa/asmshift.py137
-rw-r--r--tests/inlineasm/xtensa/asmshift.py.exp17
18 files changed, 1145 insertions, 14 deletions
diff --git a/py/asmxtensa.c b/py/asmxtensa.c
index 11b61ad94..0e612bfa7 100644
--- a/py/asmxtensa.c
+++ b/py/asmxtensa.c
@@ -37,8 +37,10 @@
#define WORD_SIZE (4)
#define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80))
#define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800))
+#define SIGNED_FIT18(x) ((((x) & 0xfffe0000) == 0) || (((x) & 0xfffe0000) == 0xfffe0000))
#define ET_OUT_OF_RANGE MP_ERROR_TEXT("ERROR: xtensa %q out of range")
+#define ET_NOT_ALIGNED MP_ERROR_TEXT("ERROR: %q %q not word-aligned")
void asm_xtensa_end_pass(asm_xtensa_t *as) {
as->num_const = as->cur_const;
@@ -266,4 +268,47 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx) {
asm_xtensa_op_callx8(as, ASM_XTENSA_REG_A8);
}
+void asm_xtensa_bit_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t bit, mp_uint_t label, mp_uint_t condition) {
+ uint32_t dest = get_label_dest(as, label);
+ int32_t rel = dest - as->base.code_offset - 4;
+ if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT8(rel)) {
+ mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_bit_branch);
+ }
+ asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(7, condition | ((bit >> 4) & 0x01), reg, bit & 0x0F, rel & 0xFF));
+}
+
+void asm_xtensa_call0(asm_xtensa_t *as, mp_uint_t label) {
+ uint32_t dest = get_label_dest(as, label);
+ int32_t rel = dest - as->base.code_offset - 3;
+ if (as->base.pass == MP_ASM_PASS_EMIT) {
+ if ((dest & 0x03) != 0) {
+ mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_call0, MP_QSTR_target);
+ }
+ if ((rel & 0x03) != 0) {
+ mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_call0, MP_QSTR_location);
+ }
+ if (!SIGNED_FIT18(rel)) {
+ mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_call0);
+ }
+ }
+ asm_xtensa_op_call0(as, rel);
+}
+
+void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label) {
+ uint32_t dest = get_label_dest(as, label);
+ int32_t rel = dest - as->base.code_offset;
+ if (as->base.pass == MP_ASM_PASS_EMIT) {
+ if ((dest & 0x03) != 0) {
+ mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_l32r, MP_QSTR_target);
+ }
+ if ((rel & 0x03) != 0) {
+ mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_l32r, MP_QSTR_location);
+ }
+ if (!SIGNED_FIT18(rel) || (rel >= 0)) {
+ mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_l32r);
+ }
+ }
+ asm_xtensa_op_l32r(as, reg, as->base.code_offset, dest);
+}
+
#endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN
diff --git a/py/asmxtensa.h b/py/asmxtensa.h
index 6451c75aa..d0fd2dcc1 100644
--- a/py/asmxtensa.h
+++ b/py/asmxtensa.h
@@ -64,9 +64,11 @@
#define ASM_XTENSA_REG_A14 (14)
#define ASM_XTENSA_REG_A15 (15)
-// for bccz
+// for bccz and bcci
#define ASM_XTENSA_CCZ_EQ (0)
#define ASM_XTENSA_CCZ_NE (1)
+#define ASM_XTENSA_CCZ_LT (2)
+#define ASM_XTENSA_CCZ_GE (3)
// for bcc and setcc
#define ASM_XTENSA_CC_NONE (0)
@@ -295,6 +297,10 @@ void asm_xtensa_l32i_optimised(asm_xtensa_t *as, uint reg_dest, uint reg_base, u
void asm_xtensa_s32i_optimised(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset);
void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx);
void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx);
+void asm_xtensa_bit_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t bit, mp_uint_t label, mp_uint_t condition);
+void asm_xtensa_immediate_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t immediate, mp_uint_t label, mp_uint_t cond);
+void asm_xtensa_call0(asm_xtensa_t *as, mp_uint_t label);
+void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label);
// Holds a pointer to mp_fun_table
#define ASM_XTENSA_REG_FUN_TABLE ASM_XTENSA_REG_A15
diff --git a/py/emitinlinextensa.c b/py/emitinlinextensa.c
index fed259cfc..d0eb3d566 100644
--- a/py/emitinlinextensa.c
+++ b/py/emitinlinextensa.c
@@ -173,7 +173,7 @@ static int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_
#define RRI8_B (2)
typedef struct _opcode_table_3arg_t {
- uint16_t name; // actually a qstr, which should fit in 16 bits
+ qstr_short_t name;
uint8_t type;
uint8_t a0 : 4;
uint8_t a1 : 4;
@@ -187,6 +187,13 @@ static const opcode_table_3arg_t opcode_table_3arg[] = {
{MP_QSTR_add, RRR, 0, 8},
{MP_QSTR_sub, RRR, 0, 12},
{MP_QSTR_mull, RRR, 2, 8},
+ {MP_QSTR_addx2, RRR, 0, 9},
+ {MP_QSTR_addx4, RRR, 0, 10},
+ {MP_QSTR_addx8, RRR, 0, 11},
+ {MP_QSTR_subx2, RRR, 0, 13},
+ {MP_QSTR_subx4, RRR, 0, 14},
+ {MP_QSTR_subx8, RRR, 0, 15},
+ {MP_QSTR_src, RRR, 1, 8},
// load/store/addi opcodes: reg, reg, imm
// upper nibble of type encodes the range of the immediate arg
@@ -208,21 +215,62 @@ static const opcode_table_3arg_t opcode_table_3arg[] = {
{MP_QSTR_bge, RRI8_B, ASM_XTENSA_CC_GE, 0},
{MP_QSTR_bgeu, RRI8_B, ASM_XTENSA_CC_GEU, 0},
{MP_QSTR_blt, RRI8_B, ASM_XTENSA_CC_LT, 0},
+ {MP_QSTR_bltu, RRI8_B, ASM_XTENSA_CC_LTU, 0},
{MP_QSTR_bnall, RRI8_B, ASM_XTENSA_CC_NALL, 0},
{MP_QSTR_bne, RRI8_B, ASM_XTENSA_CC_NE, 0},
{MP_QSTR_bnone, RRI8_B, ASM_XTENSA_CC_NONE, 0},
};
+// The index of the first four qstrs matches the CCZ condition value to be
+// embedded into the opcode.
+static const qstr_short_t BCCZ_OPCODES[] = {
+ MP_QSTR_beqz, MP_QSTR_bnez, MP_QSTR_bltz, MP_QSTR_bgez,
+ MP_QSTR_beqz_n, MP_QSTR_bnez_n
+};
+
+#if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
+typedef struct _single_opcode_t {
+ qstr_short_t name;
+ uint16_t value;
+} single_opcode_t;
+
+static const single_opcode_t NOARGS_OPCODES[] = {
+ {MP_QSTR_dsync, 0x2030},
+ {MP_QSTR_esync, 0x2020},
+ {MP_QSTR_extw, 0x20D0},
+ {MP_QSTR_ill, 0x0000},
+ {MP_QSTR_isync, 0x2000},
+ {MP_QSTR_memw, 0x20C0},
+ {MP_QSTR_rsync, 0x2010},
+};
+#endif
+
static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) {
size_t op_len;
const char *op_str = (const char *)qstr_data(op, &op_len);
if (n_args == 0) {
- if (op == MP_QSTR_ret_n) {
+ if (op == MP_QSTR_ret_n || op == MP_QSTR_ret) {
asm_xtensa_op_ret_n(&emit->as);
- } else {
- goto unknown_op;
+ return;
+ } else if (op == MP_QSTR_nop) {
+ asm_xtensa_op24(&emit->as, 0x20F0);
+ return;
+ } else if (op == MP_QSTR_nop_n) {
+ asm_xtensa_op16(&emit->as, 0xF03D);
+ return;
}
+ #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
+ for (size_t index = 0; index < MP_ARRAY_SIZE(NOARGS_OPCODES); index++) {
+ const single_opcode_t *opcode = &NOARGS_OPCODES[index];
+ if (op == opcode->name) {
+ asm_xtensa_op24(&emit->as, opcode->value);
+ return;
+ }
+ }
+ #endif
+
+ goto unknown_op;
} else if (n_args == 1) {
if (op == MP_QSTR_callx0) {
@@ -234,19 +282,45 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
} else if (op == MP_QSTR_jx) {
uint r0 = get_arg_reg(emit, op_str, pn_args[0]);
asm_xtensa_op_jx(&emit->as, r0);
+ } else if (op == MP_QSTR_ssl) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ asm_xtensa_op_ssl(&emit->as, r0);
+ } else if (op == MP_QSTR_ssr) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ asm_xtensa_op_ssr(&emit->as, r0);
+ } else if (op == MP_QSTR_ssai) {
+ mp_uint_t sa = get_arg_i(emit, op_str, pn_args[0], 0, 31);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 4, sa & 0x0F, (sa >> 4) & 0x01));
+ } else if (op == MP_QSTR_ssa8b) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 3, r0, 0));
+ } else if (op == MP_QSTR_ssa8l) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 2, r0, 0));
+ } else if (op == MP_QSTR_call0) {
+ mp_uint_t label = get_arg_label(emit, op_str, pn_args[0]);
+ asm_xtensa_call0(&emit->as, label);
+ #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
+ } else if (op == MP_QSTR_fsync) {
+ mp_uint_t imm3 = get_arg_i(emit, op_str, pn_args[0], 0, 7);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 0, 2, 8 | imm3, 0));
+ } else if (op == MP_QSTR_ill_n) {
+ asm_xtensa_op16(&emit->as, 0xF06D);
+ #endif
} else {
goto unknown_op;
}
} else if (n_args == 2) {
uint r0 = get_arg_reg(emit, op_str, pn_args[0]);
- if (op == MP_QSTR_beqz) {
- int label = get_arg_label(emit, op_str, pn_args[1]);
- asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_EQ, r0, label);
- } else if (op == MP_QSTR_bnez) {
- int label = get_arg_label(emit, op_str, pn_args[1]);
- asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_NE, r0, label);
- } else if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) {
+ for (size_t index = 0; index < MP_ARRAY_SIZE(BCCZ_OPCODES); index++) {
+ if (op == BCCZ_OPCODES[index]) {
+ mp_uint_t label = get_arg_label(emit, op_str, pn_args[1]);
+ asm_xtensa_bccz_reg_label(&emit->as, index & 0x03, r0, label);
+ return;
+ }
+ }
+ if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) {
// we emit mov.n for both "mov" and "mov_n" opcodes
uint r1 = get_arg_reg(emit, op_str, pn_args[1]);
asm_xtensa_op_mov_n(&emit->as, r0, r1);
@@ -254,7 +328,53 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
// for convenience we emit l32r if the integer doesn't fit in movi
uint32_t imm = get_arg_i(emit, op_str, pn_args[1], 0, 0);
asm_xtensa_mov_reg_i32(&emit->as, r0, imm);
- } else {
+ } else if (op == MP_QSTR_abs_) {
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 6, r0, 1, r1));
+ } else if (op == MP_QSTR_neg) {
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 6, r0, 0, r1));
+ } else if (op == MP_QSTR_sll) {
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 10, r0, r1, 0));
+ } else if (op == MP_QSTR_sra) {
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 11, r0, 0, r1));
+ } else if (op == MP_QSTR_srl) {
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 9, r0, 0, r1));
+ } else if (op == MP_QSTR_nsa) {
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 14, r1, r0));
+ } else if (op == MP_QSTR_nsau) {
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 15, r1, r0));
+ } else if (op == MP_QSTR_l32r) {
+ mp_uint_t label = get_arg_label(emit, op_str, pn_args[1]);
+ asm_xtensa_l32r(&emit->as, r0, label);
+ } else if (op == MP_QSTR_movi_n) {
+ mp_int_t imm = get_arg_i(emit, op_str, pn_args[1], -32, 95);
+ asm_xtensa_op_movi_n(&emit->as, r0, imm);
+ } else
+ #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
+ if (op == MP_QSTR_rsr) {
+ mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 3, 0, sr, r0));
+ } else if (op == MP_QSTR_rur) {
+ mp_uint_t imm8 = get_arg_i(emit, op_str, pn_args[1], 0, 255);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 3, 14, r0, (imm8 >> 4) & 0x0F, imm8 & 0x0F));
+ } else if (op == MP_QSTR_wsr) {
+ mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 3, 1, sr, r0));
+ } else if (op == MP_QSTR_wur) {
+ mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 3, 15, sr, r0));
+ } else if (op == MP_QSTR_xsr) {
+ mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 1, 6, sr, r0));
+ } else
+ #endif
+ {
goto unknown_op;
}
@@ -288,7 +408,72 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_
return;
}
}
- goto unknown_op;
+
+ if (op == MP_QSTR_add_n) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ mp_uint_t r2 = get_arg_reg(emit, op_str, pn_args[2]);
+ asm_xtensa_op16(&emit->as, ASM_XTENSA_ENCODE_RRRN(10, r0, r1, r2));
+ } else if (op == MP_QSTR_addi_n) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ mp_int_t imm4 = get_arg_i(emit, op_str, pn_args[2], -1, 15);
+ asm_xtensa_op16(&emit->as, ASM_XTENSA_ENCODE_RRRN(11, r0, r1, (imm4 != 0 ? imm4 : -1)));
+ } else if (op == MP_QSTR_addmi) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ mp_int_t imm8 = get_arg_i(emit, op_str, pn_args[2], -128 * 256, 127 * 256);
+ if ((imm8 & 0xFF) != 0) {
+ emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("%d is not a multiple of %d"), imm8, 256));
+ } else {
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(2, 13, r1, r0, imm8 >> 8));
+ }
+ } else if (op == MP_QSTR_bbci) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t bit = get_arg_i(emit, op_str, pn_args[1], 0, 31);
+ mp_int_t label = get_arg_label(emit, op_str, pn_args[2]);
+ asm_xtensa_bit_branch(&emit->as, r0, bit, label, 6);
+ } else if (op == MP_QSTR_bbsi) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t bit = get_arg_i(emit, op_str, pn_args[1], 0, 31);
+ mp_uint_t label = get_arg_label(emit, op_str, pn_args[2]);
+ asm_xtensa_bit_branch(&emit->as, r0, bit, label, 14);
+ } else if (op == MP_QSTR_slli) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ mp_uint_t bits = 32 - get_arg_i(emit, op_str, pn_args[2], 1, 31);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 0 | ((bits >> 4) & 0x01), r0, r1, bits & 0x0F));
+ } else if (op == MP_QSTR_srai) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ mp_uint_t bits = get_arg_i(emit, op_str, pn_args[2], 0, 31);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 2 | ((bits >> 4) & 0x01), r0, bits & 0x0F, r1));
+ } else if (op == MP_QSTR_srli) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ mp_uint_t bits = get_arg_i(emit, op_str, pn_args[2], 0, 15);
+ asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 4, r0, bits, r1));
+ } else if (op == MP_QSTR_l32i_n) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ mp_uint_t imm = get_arg_i(emit, op_str, pn_args[2], 0, 60);
+ if ((imm & 0x03) != 0) {
+ emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("%d is not a multiple of %d"), imm, 4));
+ } else {
+ asm_xtensa_op_l32i_n(&emit->as, r0, r1, imm >> 2);
+ }
+ } else if (op == MP_QSTR_s32i_n) {
+ mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]);
+ mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]);
+ mp_uint_t imm = get_arg_i(emit, op_str, pn_args[2], 0, 60);
+ if ((imm & 0x03) != 0) {
+ emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("%d is not a multiple of %d"), imm, 4));
+ } else {
+ asm_xtensa_op_s32i_n(&emit->as, r0, r1, imm >> 2);
+ }
+ } else {
+ goto unknown_op;
+ }
} else {
goto unknown_op;
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 49a9fa35c..01712bd5b 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -406,6 +406,11 @@
#define MICROPY_EMIT_INLINE_XTENSA (0)
#endif
+// Whether to support uncommon Xtensa inline assembler opcodes
+#ifndef MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES
+#define MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES (0)
+#endif
+
// Whether to emit Xtensa-Windowed native code
#ifndef MICROPY_EMIT_XTENSAWIN
#define MICROPY_EMIT_XTENSAWIN (0)
diff --git a/tests/inlineasm/xtensa/asmargs.py b/tests/inlineasm/xtensa/asmargs.py
new file mode 100644
index 000000000..2bfccfcc6
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmargs.py
@@ -0,0 +1,44 @@
+# test passing arguments
+
+
+@micropython.asm_xtensa
+def arg0():
+ movi(a2, 1)
+
+
+print(arg0())
+
+
+@micropython.asm_xtensa
+def arg1(a2):
+ addi(a2, a2, 1)
+
+
+print(arg1(1))
+
+
+@micropython.asm_xtensa
+def arg2(a2, a3):
+ add(a2, a2, a3)
+
+
+print(arg2(1, 2))
+
+
+@micropython.asm_xtensa
+def arg3(a2, a3, a4):
+ add(a2, a2, a3)
+ add(a2, a2, a4)
+
+
+print(arg3(1, 2, 3))
+
+
+@micropython.asm_xtensa
+def arg4(a2, a3, a4, a5):
+ add(a2, a2, a3)
+ add(a2, a2, a4)
+ add(a2, a2, a5)
+
+
+print(arg4(1, 2, 3, 4))
diff --git a/tests/inlineasm/xtensa/asmargs.py.exp b/tests/inlineasm/xtensa/asmargs.py.exp
new file mode 100644
index 000000000..e33a6964f
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmargs.py.exp
@@ -0,0 +1,5 @@
+1
+2
+3
+6
+10
diff --git a/tests/inlineasm/xtensa/asmarith.py b/tests/inlineasm/xtensa/asmarith.py
new file mode 100644
index 000000000..1c0934eb7
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmarith.py
@@ -0,0 +1,119 @@
+@micropython.asm_xtensa
+def f1(a2):
+ abs_(a2, a2)
+
+
+for value in (10, -10, 0):
+ print(f1(value))
+
+
+ADDMI_TEMPLATE = """
+@micropython.asm_xtensa
+def f1(a2) -> int:
+ addmi(a2, a2, {})
+print(f1(0))
+"""
+
+for value in (-32768, -32767, 32512, 32513, 0):
+ try:
+ exec(ADDMI_TEMPLATE.format(value))
+ except SyntaxError as error:
+ print(error)
+
+
+@micropython.asm_xtensa
+def a2(a2, a3) -> int:
+ addx2(a2, a2, a3)
+
+
+@micropython.asm_xtensa
+def a4(a2, a3) -> int:
+ addx4(a2, a2, a3)
+
+
+@micropython.asm_xtensa
+def a8(a2, a3) -> int:
+ addx8(a2, a2, a3)
+
+
+@micropython.asm_xtensa
+def s2(a2, a3) -> int:
+ subx2(a2, a2, a3)
+
+
+@micropython.asm_xtensa
+def s4(a2, a3) -> int:
+ subx4(a2, a2, a3)
+
+
+@micropython.asm_xtensa
+def s8(a2, a3) -> int:
+ subx8(a2, a2, a3)
+
+
+for first, second in ((100, 100), (-100, 100), (-100, -100), (100, -100)):
+ print("a2", a2(first, second))
+ print("a4", a4(first, second))
+ print("a8", a8(first, second))
+ print("s2", s2(first, second))
+ print("s4", s4(first, second))
+ print("s8", s8(first, second))
+
+
+@micropython.asm_xtensa
+def f5(a2) -> int:
+ neg(a2, a2)
+
+
+for value in (0, -100, 100):
+ print(f5(value))
+
+
+@micropython.asm_xtensa
+def f6():
+ movi(a2, 0x100)
+ movi(a3, 1)
+ add(a2, a2, a3)
+ addi(a2, a2, 1)
+ addi(a2, a2, -2)
+ sub(a2, a2, a3)
+
+
+print(hex(f6()))
+
+
+@micropython.asm_xtensa
+def f7():
+ movi(a2, 0x10FF)
+ movi(a3, 1)
+ and_(a4, a2, a3)
+ or_(a4, a4, a3)
+ movi(a3, 0x200)
+ xor(a2, a4, a3)
+
+
+print(hex(f7()))
+
+
+@micropython.asm_xtensa
+def f8(a2, a3):
+ add_n(a2, a2, a3)
+
+
+print(f8(100, 200))
+
+
+@micropython.asm_xtensa
+def f9(a2):
+ addi_n(a2, a2, 1)
+
+
+print(f9(100))
+
+
+@micropython.asm_xtensa
+def f10(a2, a3) -> uint:
+ mull(a2, a2, a3)
+
+
+print(hex(f10(0xC0000000, 2)))
diff --git a/tests/inlineasm/xtensa/asmarith.py.exp b/tests/inlineasm/xtensa/asmarith.py.exp
new file mode 100644
index 000000000..7aba46a27
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmarith.py.exp
@@ -0,0 +1,40 @@
+10
+10
+0
+-32768
+-32767 is not a multiple of 256
+32512
+'addmi' integer 32513 isn't within range -32768..32512
+0
+a2 300
+a4 500
+a8 900
+s2 100
+s4 300
+s8 700
+a2 -100
+a4 -300
+a8 -700
+s2 -300
+s4 -500
+s8 -900
+a2 -300
+a4 -500
+a8 -900
+s2 -100
+s4 -300
+s8 -700
+a2 100
+a4 300
+a8 700
+s2 300
+s4 500
+s8 900
+0
+100
+-100
+0xff
+0x201
+300
+101
+0x80000000
diff --git a/tests/inlineasm/xtensa/asmbranch.py b/tests/inlineasm/xtensa/asmbranch.py
new file mode 100644
index 000000000..22bcd5a7c
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmbranch.py
@@ -0,0 +1,299 @@
+# test branch instructions
+
+
+@micropython.asm_xtensa
+def tball(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ ball(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tball(0xFFFFFFFF, 0xFFFFFFFF))
+print(tball(0xFFFEFFFF, 0xFFFFFFFF))
+print(tball(0x00000000, 0xFFFFFFFF))
+print(tball(0xFFFFFFFF, 0x01010101))
+
+
+@micropython.asm_xtensa
+def tbany(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ bany(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbany(0xFFFFFFFF, 0xFFFFFFFF))
+print(tbany(0xFFFEFFFF, 0xFFFFFFFF))
+print(tbany(0x00000000, 0xFFFFFFFF))
+print(tbany(0xFFFFFFFF, 0x01010101))
+
+
+@micropython.asm_xtensa
+def tbbc(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ bbc(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbbc(0xFFFFFFFF, 4))
+print(tbbc(0xFFFEFFFF, 16))
+print(tbbc(0x00000000, 1))
+
+
+BBCI_TEMPLATE = """
+@micropython.asm_xtensa
+def tbbci(a2) -> int:
+ mov(a3, a2)
+ movi(a2, 0)
+ bbci(a3, {}, end)
+ movi(a2, -1)
+ label(end)
+
+print(tbbci({}))
+"""
+
+
+for value, bit in ((0xFFFFFFFF, 4), (0xFFFEFFFF, 16), (0x00000000, 1)):
+ try:
+ exec(BBCI_TEMPLATE.format(bit, value))
+ except SyntaxError as error:
+ print(error)
+
+
+@micropython.asm_xtensa
+def tbbs(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ bbs(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbbs(0x00000000, 4))
+print(tbbs(0x00010000, 16))
+print(tbbs(0xFFFFFFFF, 1))
+
+
+BBSI_TEMPLATE = """
+@micropython.asm_xtensa
+def tbbsi(a2) -> int:
+ mov(a3, a2)
+ movi(a2, 0)
+ bbsi(a3, {}, end)
+ movi(a2, -1)
+ label(end)
+
+print(tbbsi({}))
+"""
+
+
+for value, bit in ((0x00000000, 4), (0x00010000, 16), (0xFFFFFFFF, 1)):
+ try:
+ exec(BBSI_TEMPLATE.format(bit, value))
+ except SyntaxError as error:
+ print(error)
+
+
+@micropython.asm_xtensa
+def tbeq(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ beq(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbeq(0x00000000, 0x00000000))
+print(tbeq(0x00010000, 0x00000000))
+print(tbeq(0xFFFFFFFF, 0xFFFFFFFF))
+
+
+@micropython.asm_xtensa
+def tbeqz(a2) -> int:
+ mov(a3, a2)
+ movi(a2, 0)
+ beqz(a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbeqz(0))
+print(tbeqz(0x12345678))
+print(tbeqz(-1))
+
+
+@micropython.asm_xtensa
+def tbge(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ bge(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbge(0x00000000, 0x00000000))
+print(tbge(0x00010000, 0x00000000))
+print(tbge(0xF0000000, 0xFFFFFFFF))
+
+
+@micropython.asm_xtensa
+def tbgeu(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ bgeu(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbgeu(0x00000000, 0x00000000))
+print(tbgeu(0x00010000, 0x00000000))
+print(tbgeu(0xF0000000, 0xFFFFFFFF))
+print(tbgeu(0xFFFFFFFF, 0xF0000000))
+
+
+@micropython.asm_xtensa
+def tbgez(a2) -> int:
+ mov(a3, a2)
+ movi(a2, 0)
+ bgez(a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbgez(0))
+print(tbgez(0x12345678))
+print(tbgez(-1))
+
+
+@micropython.asm_xtensa
+def tblt(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ blt(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tblt(0x00000000, 0x00000000))
+print(tblt(0x00010000, 0x00000000))
+print(tblt(0xF0000000, 0xFFFFFFFF))
+
+
+@micropython.asm_xtensa
+def tbltu(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ bltu(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbltu(0x00000000, 0x00000000))
+print(tbltu(0x00010000, 0x00000000))
+print(tbltu(0xF0000000, 0xFFFFFFFF))
+print(tbltu(0xFFFFFFFF, 0xF0000000))
+
+
+@micropython.asm_xtensa
+def tbltz(a2) -> int:
+ mov(a3, a2)
+ movi(a2, 0)
+ bltz(a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbltz(0))
+print(tbltz(0x12345678))
+print(tbltz(-1))
+
+
+@micropython.asm_xtensa
+def tbnall(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ bnall(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbnall(0xFFFFFFFF, 0xFFFFFFFF))
+print(tbnall(0xFFFEFFFF, 0xFFFFFFFF))
+print(tbnall(0x00000000, 0xFFFFFFFF))
+print(tbnall(0xFFFFFFFF, 0x01010101))
+
+
+@micropython.asm_xtensa
+def tbne(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ bne(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbne(0x00000000, 0x00000000))
+print(tbne(0x00010000, 0x00000000))
+print(tbne(0xFFFFFFFF, 0xFFFFFFFF))
+
+
+@micropython.asm_xtensa
+def tbnez(a2) -> int:
+ mov(a3, a2)
+ movi(a2, 0)
+ bnez(a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbnez(0))
+print(tbnez(0x12345678))
+print(tbnez(-1))
+
+
+@micropython.asm_xtensa
+def tbnone(a2, a3) -> int:
+ mov(a4, a2)
+ movi(a2, 0)
+ bnone(a4, a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbnone(0xFFFFFFFF, 0xFFFFFFFF))
+print(tbnone(0xFFFEFFFF, 0xFFFFFFFF))
+print(tbnone(0x00000000, 0xFFFFFFFF))
+print(tbnone(0x10101010, 0x01010101))
+
+
+@micropython.asm_xtensa
+def tbeqz_n(a2) -> int:
+ mov(a3, a2)
+ movi(a2, 0)
+ beqz_n(a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbeqz_n(0))
+print(tbeqz_n(0x12345678))
+print(tbeqz_n(-1))
+
+
+@micropython.asm_xtensa
+def tbnez_n(a2) -> int:
+ mov(a3, a2)
+ movi(a2, 0)
+ bnez(a3, end)
+ movi(a2, -1)
+ label(end)
+
+
+print(tbnez_n(0))
+print(tbnez_n(0x12345678))
+print(tbnez_n(-1))
diff --git a/tests/inlineasm/xtensa/asmbranch.py.exp b/tests/inlineasm/xtensa/asmbranch.py.exp
new file mode 100644
index 000000000..319a4b435
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmbranch.py.exp
@@ -0,0 +1,66 @@
+0
+-1
+-1
+0
+0
+0
+-1
+0
+-1
+0
+0
+-1
+0
+0
+-1
+0
+0
+-1
+0
+0
+0
+-1
+0
+0
+-1
+-1
+0
+0
+-1
+0
+0
+-1
+0
+0
+0
+-1
+-1
+-1
+0
+-1
+-1
+0
+-1
+-1
+-1
+0
+-1
+0
+0
+-1
+-1
+0
+-1
+-1
+0
+0
+-1
+-1
+0
+0
+0
+-1
+-1
+-1
+0
+0
diff --git a/tests/inlineasm/xtensa/asmjump.py b/tests/inlineasm/xtensa/asmjump.py
new file mode 100644
index 000000000..f41c94823
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmjump.py
@@ -0,0 +1,26 @@
+@micropython.asm_xtensa
+def jump() -> int:
+ movi(a2, 0)
+ j(NEXT)
+ addi(a2, a2, 1)
+ j(DONE)
+ label(NEXT)
+ addi(a2, a2, 2)
+ label(DONE)
+
+
+print(jump())
+
+
+@micropython.asm_xtensa
+def jumpx() -> int:
+ call0(ENTRY)
+ label(ENTRY)
+ movi(a2, 0)
+ addi(a3, a0, 12)
+ jx(a3)
+ movi(a2, 1)
+ movi(a2, 2)
+
+
+print(jumpx())
diff --git a/tests/inlineasm/xtensa/asmjump.py.exp b/tests/inlineasm/xtensa/asmjump.py.exp
new file mode 100644
index 000000000..51993f072
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmjump.py.exp
@@ -0,0 +1,2 @@
+2
+2
diff --git a/tests/inlineasm/xtensa/asmloadstore.py b/tests/inlineasm/xtensa/asmloadstore.py
new file mode 100644
index 000000000..b185e3052
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmloadstore.py
@@ -0,0 +1,98 @@
+import array
+
+# On the 8266 the generated code gets put into the IRAM segment, which is only
+# word-addressable. Therefore, to test byte and halfword load/store opcodes
+# some memory must be reserved in the DRAM segment.
+
+BYTE_DATA = array.array("B", (0x11, 0x22, 0x33, 0x44))
+WORD_DATA = array.array("h", (100, 200, -100, -200))
+DWORD_DATA = array.array("i", (100_000, -200_000, 300_000, -400_000))
+
+
+@micropython.asm_xtensa
+def tl32r() -> int:
+ nop()
+ j(CODE)
+ align(4)
+ label(DATA)
+ data(1, 1, 2, 3, 4, 5, 6, 7)
+ align(4)
+ label(CODE)
+ nop_n()
+ nop_n()
+ l32r(a2, DATA)
+
+
+print(hex(tl32r()))
+
+
+@micropython.asm_xtensa
+def tl32i() -> uint:
+ call0(ENTRY)
+ label(ENTRY)
+ l32i(a2, a0, 0)
+
+
+print(hex(tl32i()))
+
+
+@micropython.asm_xtensa
+def tl8ui(a2) -> uint:
+ mov(a3, a2)
+ l8ui(a2, a3, 1)
+
+
+print(hex(tl8ui(BYTE_DATA)))
+
+
+@micropython.asm_xtensa
+def tl16ui(a2) -> uint:
+ mov(a3, a2)
+ l16ui(a2, a3, 2)
+
+
+print(tl16ui(WORD_DATA))
+
+
+@micropython.asm_xtensa
+def tl16si(a2) -> int:
+ mov(a3, a2)
+ l16si(a2, a3, 6)
+
+
+print(tl16si(WORD_DATA))
+
+
+@micropython.asm_xtensa
+def ts8i(a2, a3):
+ s8i(a3, a2, 1)
+
+
+ts8i(BYTE_DATA, 0xFF)
+print(BYTE_DATA)
+
+
+@micropython.asm_xtensa
+def ts16i(a2, a3):
+ s16i(a3, a2, 2)
+
+
+ts16i(WORD_DATA, -123)
+print(WORD_DATA)
+
+
+@micropython.asm_xtensa
+def ts32i(a2, a3) -> uint:
+ s32i(a3, a2, 4)
+
+
+ts32i(DWORD_DATA, -123456)
+print(DWORD_DATA)
+
+
+@micropython.asm_xtensa
+def tl32i_n(a2) -> uint:
+ l32i_n(a2, a2, 8)
+
+
+print(tl32i_n(DWORD_DATA))
diff --git a/tests/inlineasm/xtensa/asmloadstore.py.exp b/tests/inlineasm/xtensa/asmloadstore.py.exp
new file mode 100644
index 000000000..e6672df6f
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmloadstore.py.exp
@@ -0,0 +1,9 @@
+0x4030201
+0xf8002022
+0x22
+200
+-200
+array('B', [17, 255, 51, 68])
+array('h', [100, -123, -100, -200])
+array('i', [100000, -123456, 300000, -400000])
+300000
diff --git a/tests/inlineasm/xtensa/asmmisc.py b/tests/inlineasm/xtensa/asmmisc.py
new file mode 100644
index 000000000..271ab8366
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmmisc.py
@@ -0,0 +1,25 @@
+@micropython.asm_xtensa
+def tnop(a2, a3, a4, a5):
+ nop()
+
+
+out2 = tnop(0x100, 0x200, 0x300, 0x400)
+print(out2 == 0x100)
+
+
+@micropython.asm_xtensa
+def tnop_n(a2, a3, a4, a5):
+ nop_n()
+
+
+out2 = tnop_n(0x100, 0x200, 0x300, 0x400)
+print(out2 == 0x100)
+
+
+@micropython.asm_xtensa
+def tmov_n(a2, a3):
+ mov_n(a4, a3)
+ add(a2, a4, a3)
+
+
+print(tmov_n(0, 1))
diff --git a/tests/inlineasm/xtensa/asmmisc.py.exp b/tests/inlineasm/xtensa/asmmisc.py.exp
new file mode 100644
index 000000000..eefaa35da
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmmisc.py.exp
@@ -0,0 +1,3 @@
+True
+True
+2
diff --git a/tests/inlineasm/xtensa/asmshift.py b/tests/inlineasm/xtensa/asmshift.py
new file mode 100644
index 000000000..271ca1ccd
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmshift.py
@@ -0,0 +1,137 @@
+@micropython.asm_xtensa
+def lsl1(a2):
+ slli(a2, a2, 1)
+
+
+print(hex(lsl1(0x123)))
+
+
+@micropython.asm_xtensa
+def lsl23(a2):
+ slli(a2, a2, 23)
+
+
+print(hex(lsl23(1)))
+
+
+@micropython.asm_xtensa
+def lsr1(a2):
+ srli(a2, a2, 1)
+
+
+print(hex(lsr1(0x123)))
+
+
+@micropython.asm_xtensa
+def lsr15(a2):
+ srli(a2, a2, 15)
+
+
+print(hex(lsr15(0x80000000)))
+
+
+@micropython.asm_xtensa
+def asr1(a2):
+ srai(a2, a2, 1)
+
+
+print(hex(asr1(0x123)))
+
+
+@micropython.asm_xtensa
+def asr31(a2):
+ srai(a2, a2, 31)
+
+
+print(hex(asr31(0x80000000)))
+
+
+@micropython.asm_xtensa
+def lsl1r(a2):
+ movi(a3, 1)
+ ssl(a3)
+ sll(a2, a2)
+
+
+print(hex(lsl1r(0x123)))
+
+
+@micropython.asm_xtensa
+def lsr1r(a2):
+ movi(a3, 1)
+ ssr(a3)
+ srl(a2, a2)
+
+
+print(hex(lsr1r(0x123)))
+
+
+@micropython.asm_xtensa
+def asr1r(a2):
+ movi(a3, 1)
+ ssr(a3)
+ sra(a2, a2)
+
+
+print(hex(asr1r(0x123)))
+
+
+@micropython.asm_xtensa
+def sll9(a2):
+ ssai(9)
+ sll(a2, a2)
+
+
+print(hex(sll9(1)))
+
+
+@micropython.asm_xtensa
+def srlr(a2, a3):
+ ssa8l(a3)
+ srl(a2, a2)
+
+
+print(hex(srlr(0x12340000, 2)))
+
+
+@micropython.asm_xtensa
+def sllr(a2, a3):
+ ssa8b(a3)
+ sll(a2, a2)
+
+
+print(hex(sllr(0x1234, 2)))
+
+
+@micropython.asm_xtensa
+def srcr(a2, a3, a4):
+ ssr(a4)
+ src(a2, a2, a3)
+
+
+print(hex(srcr(0x00000001, 0x80000000, 2)))
+
+
+@micropython.asm_xtensa
+def srai24(a2):
+ srai(a2, a2, 24)
+
+
+print(hex(srai24(0x12345678)))
+
+
+@micropython.asm_xtensa
+def nsar(a2, a3):
+ nsa(a2, a3)
+
+
+print(nsar(0x12345678, 0))
+print(nsar(0x12345678, -1))
+
+
+@micropython.asm_xtensa
+def nsaur(a2, a3):
+ nsau(a2, a3)
+
+
+print(nsaur(0x12345678, 0))
diff --git a/tests/inlineasm/xtensa/asmshift.py.exp b/tests/inlineasm/xtensa/asmshift.py.exp
new file mode 100644
index 000000000..3e2bb3b4a
--- /dev/null
+++ b/tests/inlineasm/xtensa/asmshift.py.exp
@@ -0,0 +1,17 @@
+0x246
+0x800000
+0x91
+0x10000
+0x91
+-0x1
+0x246
+0x91
+0x91
+0x800000
+0x1234
+0x12340000
+0x60000000
+0x12
+31
+31
+32