py/emitinlinextensa: Add the rest of LX3 opcodes to the assembler.

This commit expands the Xtensa inline assembler to support most if not
all opcodes available on the ESP8266 and LX3 Xtensa cores.

This is meant as a stepping stone to add inline assembler support for
the ESP32 and its LX6 core, along to windowed-specific opcodes and
additional opcodes that are present only on the LX7 core (ESP32-S3 and
later).

New opcodes being added are covered by tests, and the provided tests
were expanded to also include opcodes available in the existing
implementation.  Given that the ESP8266 space requirements are tighter
than ESP32's, certain opcodes that won't be commonly used have been put
behind a define to save some space in the general use case.

Signed-off-by: Alessandro Gatti <a.gatti@frob.it>
This commit is contained in:
Alessandro Gatti
2025-01-25 09:33:41 +01:00
committed by Damien George
parent 555f1cf488
commit 1006ed69f0
18 changed files with 1145 additions and 14 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}
}
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;

View File

@@ -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)

View File

@@ -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))

View File

@@ -0,0 +1,5 @@
1
2
3
6
10

View File

@@ -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)))

View File

@@ -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

View File

@@ -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))

View File

@@ -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

View File

@@ -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())

View File

@@ -0,0 +1,2 @@
2
2

View File

@@ -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))

View File

@@ -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

View File

@@ -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))

View File

@@ -0,0 +1,3 @@
True
True
2

View File

@@ -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))

View File

@@ -0,0 +1,17 @@
0x246
0x800000
0x91
0x10000
0x91
-0x1
0x246
0x91
0x91
0x800000
0x1234
0x12340000
0x60000000
0x12
31
31
32