36 #if MICROPY_EMIT_INLINE_THUMB 40 #define DEF_RULE(rule, comp, kind, ...) PN_##rule, 41 #define DEF_RULE_NC(rule, kind, ...) 47 #define DEF_RULE(rule, comp, kind, ...) 48 #define DEF_RULE_NC(rule, kind, ...) PN_##rule, 54 struct _emit_inline_asm_t {
67 *emit->error_slot = exc;
72 memset(&emit->as, 0,
sizeof(emit->as));
74 emit->max_num_labels = max_num_labels;
75 emit->label_lookup =
m_new(
qstr, max_num_labels);
80 m_del(
qstr, emit->label_lookup, emit->max_num_labels);
87 emit->error_slot = error_slot;
89 memset(emit->label_lookup, 0, emit->max_num_labels *
sizeof(
qstr));
102 emit_inline_thumb_error_msg(emit,
"can only have up to 4 parameters to Thumb assembly");
105 for (
mp_uint_t i = 0; i < n_params; i++) {
107 emit_inline_thumb_error_msg(emit,
"parameters must be registers in sequence r0 to r3");
111 if (!(
strlen(p) == 2 && p[0] ==
'r' && p[1] ==
'0' + i)) {
112 emit_inline_thumb_error_msg(emit,
"parameters must be registers in sequence r0 to r3");
120 assert(label_num < emit->max_num_labels);
123 for (
uint i = 0; i < emit->max_num_labels; i++) {
124 if (emit->label_lookup[i] == label_id) {
129 emit->label_lookup[label_num] = label_id;
134 typedef struct _reg_name_t {
byte reg;
byte name[3]; } reg_name_t;
135 STATIC const reg_name_t reg_name_table[] = {
159 #define MAX_SPECIAL_REGISTER_NAME_LENGTH 7 160 typedef struct _special_reg_name_t {
byte reg;
char name[MAX_SPECIAL_REGISTER_NAME_LENGTH + 1]; } special_reg_name_t;
161 STATIC const special_reg_name_t special_reg_name_table[] = {
178 const char *reg_str = get_arg_str(pn);
180 const reg_name_t *r = ®_name_table[i];
181 if (reg_str[0] == r->name[0]
182 && reg_str[1] == r->name[1]
183 && reg_str[2] == r->name[2]
184 && (reg_str[2] ==
'\0' || reg_str[3] ==
'\0')) {
185 if (r->reg > max_reg) {
186 emit_inline_thumb_error_exc(emit,
188 "'%s' expects at most r%d", op, max_reg));
195 emit_inline_thumb_error_exc(emit,
197 "'%s' expects a register", op));
202 const char *reg_str = get_arg_str(pn);
204 const special_reg_name_t *r = &special_reg_name_table[i];
205 if (
strcmp(r->name, reg_str) == 0) {
209 emit_inline_thumb_error_exc(emit,
211 "'%s' expects a special register", op));
215 #if MICROPY_EMIT_INLINE_THUMB_FLOAT 217 const char *reg_str = get_arg_str(pn);
218 if (reg_str[0] ==
's' && reg_str[1] !=
'\0') {
220 for (++reg_str; *reg_str; ++reg_str) {
222 if (!(
'0' <= v && v <=
'9')) {
225 regno = 10 * regno + v -
'0';
228 emit_inline_thumb_error_exc(emit,
230 "'%s' expects at most r%d", op, 31));
237 emit_inline_thumb_error_exc(emit,
239 "'%s' expects an FPU register", op));
259 reglist |= 1 << get_arg_reg(emit, op, pn, 15);
269 reglist |= 1 << get_arg_reg(emit, op, pns->
nodes[0], 15);
276 for (
int i = 0; i < n; i++) {
277 reglist |= 1 << get_arg_reg(emit, op, nodes[i], 15);
303 if ((i & (~fit_mask)) != 0) {
323 *pn_base = pns->
nodes[0];
324 *pn_offset = pns->
nodes[1];
338 for (
uint i = 0; i < emit->max_num_labels; i++) {
339 if (emit->label_lookup[i] == label_qstr) {
350 typedef struct _cc_name_t {
byte cc;
byte name[2]; } cc_name_t;
351 STATIC const cc_name_t cc_name_table[] = {
368 typedef struct _format_4_op_t {
byte op;
char name[3]; } format_4_op_t;
369 #define X(x) (((x) >> 4) & 0xff) // only need 1 byte to distinguish these ops 370 STATIC const format_4_op_t format_4_op_table[] = {
390 typedef struct _format_9_10_op_t {
uint16_t op;
uint16_t name; } format_9_10_op_t;
392 STATIC const format_9_10_op_t format_9_10_op_table[] = {
402 #if MICROPY_EMIT_INLINE_THUMB_FLOAT 404 typedef struct _format_vfp_op_t {
byte op;
char name[3]; } format_vfp_op_t;
405 STATIC const format_vfp_op_t format_vfp_op_table[] = {
414 #define ARMV7M MICROPY_EMIT_INLINE_THUMB_ARMV7M 428 const char *op_str = (
const char*)
qstr_data(op, &op_len);
430 #if MICROPY_EMIT_INLINE_THUMB_FLOAT 431 if (op_str[0] ==
'v') {
435 if (op == MP_QSTR_vcmp) {
438 mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]);
439 mp_uint_t vm = get_arg_vfpreg(emit, op_str, pn_args[1]);
441 op_code_hi | ((vd & 1) << 6),
442 op_code | ((vd & 0x1e) << 11) | ((vm & 1) << 5) | (vm & 0x1e) >> 1);
443 }
else if (op == MP_QSTR_vsqrt) {
446 }
else if (op == MP_QSTR_vneg) {
450 }
else if (op == MP_QSTR_vcvt_f32_s32) {
453 }
else if (op == MP_QSTR_vcvt_s32_f32) {
456 }
else if (op == MP_QSTR_vmrs) {
458 const char *reg_str0 = get_arg_str(pn_args[0]);
459 if (
strcmp(reg_str0,
"APSR_nzcv") == 0) {
462 reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
464 const char *reg_str1 = get_arg_str(pn_args[1]);
465 if (
strcmp(reg_str1,
"FPSCR") == 0) {
471 }
else if (op == MP_QSTR_vmov) {
474 const char *reg_str = get_arg_str(pn_args[0]);
475 if (reg_str[0] ==
'r') {
476 r_arm = get_arg_reg(emit, op_str, pn_args[0], 15);
477 vm = get_arg_vfpreg(emit, op_str, pn_args[1]);
480 vm = get_arg_vfpreg(emit, op_str, pn_args[0]);
481 r_arm = get_arg_reg(emit, op_str, pn_args[1], 15);
484 op_code_hi | ((vm & 0x1e) >> 1),
485 0x0a10 | (r_arm << 12) | ((vm & 1) << 7));
486 }
else if (op == MP_QSTR_vldr) {
489 mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]);
491 if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) {
492 mp_uint_t rlo_base = get_arg_reg(emit, op_str, pn_base, 7);
494 i8 = get_arg_i(emit, op_str, pn_offset, 0x3fc) >> 2;
496 op_code_hi | rlo_base | ((vd & 1) << 6),
497 0x0a00 | ((vd & 0x1e) << 11) | i8);
499 }
else if (op == MP_QSTR_vstr) {
505 }
else if (n_args == 3) {
508 if (strncmp(op_str + 1, format_vfp_op_table[i].name, 3) == 0 && op_str[4] ==
'\0') {
509 mp_uint_t op_code_hi = 0xee00 | (format_vfp_op_table[i].op & 0xf0);
510 mp_uint_t op_code = 0x0a00 | ((format_vfp_op_table[i].op & 0x0f) << 4);
511 mp_uint_t vd = get_arg_vfpreg(emit, op_str, pn_args[0]);
512 mp_uint_t vn = get_arg_vfpreg(emit, op_str, pn_args[1]);
513 mp_uint_t vm = get_arg_vfpreg(emit, op_str, pn_args[2]);
515 op_code_hi | ((vd & 1) << 6) | (vn >> 1),
516 op_code | (vm >> 1) | ((vm & 1) << 5) | ((vd & 0x1e) << 11) | ((vn & 1) << 7));
527 if (op == MP_QSTR_nop) {
529 }
else if (op == MP_QSTR_wfi) {
535 }
else if (n_args == 1) {
536 if (op == MP_QSTR_b) {
537 int label_num = get_arg_label(emit, op_str, pn_args[0]);
539 goto branch_not_in_range;
541 }
else if (op == MP_QSTR_bl) {
542 int label_num = get_arg_label(emit, op_str, pn_args[0]);
544 goto branch_not_in_range;
546 }
else if (op == MP_QSTR_bx) {
547 mp_uint_t r = get_arg_reg(emit, op_str, pn_args[0], 15);
549 }
else if (op_str[0] ==
'b' && (op_len == 3
550 || (op_len == 5 && op_str[3] ==
'_' 551 && (op_str[4] ==
'n' || (ARMV7M && op_str[4] ==
'w'))))) {
554 if (op_str[1] == cc_name_table[i].name[0] && op_str[2] == cc_name_table[i].name[1]) {
555 cc = cc_name_table[i].cc;
561 int label_num = get_arg_label(emit, op_str, pn_args[0]);
563 goto branch_not_in_range;
565 }
else if (ARMV7M && op_str[0] ==
'i' && op_str[1] ==
't') {
566 const char *arg_str = get_arg_str(pn_args[0]);
569 if (arg_str[0] == cc_name_table[i].name[0]
570 && arg_str[1] == cc_name_table[i].name[1]
571 && arg_str[2] ==
'\0') {
572 cc = cc_name_table[i].cc;
579 const char *os = op_str + 2;
580 while (*os !=
'\0') {
583 if (os > op_str + 5) {
587 while (--os >= op_str + 2) {
590 it_mask |= (cc & 1) << 3;
591 }
else if (*os ==
'e') {
592 it_mask |= ((~cc) & 1) << 3;
597 asm_thumb_it_cc(&emit->as, cc, it_mask);
598 }
else if (op == MP_QSTR_cpsid) {
601 }
else if (op == MP_QSTR_cpsie) {
604 }
else if (op == MP_QSTR_push) {
605 mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);
606 if ((reglist & 0xff00) == 0) {
614 }
else if (op == MP_QSTR_pop) {
615 mp_uint_t reglist = get_arg_reglist(emit, op_str, pn_args[0]);
616 if ((reglist & 0xff00) == 0) {
628 }
else if (n_args == 2) {
632 if (op == MP_QSTR_mov) {
633 mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
634 mp_uint_t reg_src = get_arg_reg(emit, op_str, pn_args[1], 15);
636 }
else if (ARMV7M && op == MP_QSTR_clz) {
641 rd = get_arg_reg(emit, op_str, pn_args[0], 15);
642 rm = get_arg_reg(emit, op_str, pn_args[1], 15);
643 asm_thumb_op32(&emit->as, op_code_hi | rm, op_code | (rd << 8) | rm);
644 }
else if (ARMV7M && op == MP_QSTR_rbit) {
648 }
else if (ARMV7M && op == MP_QSTR_mrs){
649 mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 12);
650 mp_uint_t reg_src = get_arg_special_reg(emit, op_str, pn_args[1]);
651 asm_thumb_op32(&emit->as, 0xf3ef, 0x8000 | (reg_dest << 8) | reg_src);
653 if (op == MP_QSTR_and_) {
657 reg_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
658 reg_src = get_arg_reg(emit, op_str, pn_args[1], 7);
664 if (strncmp(op_str, format_4_op_table[i].name, 3) == 0 && op_str[3] ==
'\0') {
665 op_code = 0x4000 | (format_4_op_table[i].op << 4);
674 if (op == MP_QSTR_mov) {
678 rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
679 i8_src = get_arg_i(emit, op_str, pn_args[1], 0xff);
680 asm_thumb_format_3(&emit->as, op_code, rlo_dest, i8_src);
681 }
else if (op == MP_QSTR_cmp) {
684 }
else if (op == MP_QSTR_add) {
687 }
else if (op == MP_QSTR_sub) {
690 }
else if (ARMV7M && op == MP_QSTR_movw) {
694 reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
695 int i_src = get_arg_i(emit, op_str, pn_args[1], 0xffff);
697 }
else if (ARMV7M && op == MP_QSTR_movt) {
700 }
else if (ARMV7M && op == MP_QSTR_movwt) {
702 mp_uint_t reg_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
703 uint32_t i_src = get_arg_i(emit, op_str, pn_args[1], 0xffffffff);
706 }
else if (ARMV7M && op == MP_QSTR_ldrex) {
707 mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
709 if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) {
710 mp_uint_t r_base = get_arg_reg(emit, op_str, pn_base, 15);
711 mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2;
712 asm_thumb_op32(&emit->as, 0xe850 | r_base, 0x0f00 | (r_dest << 12) | i8);
717 if (op == format_9_10_op_table[i].name) {
718 op_code = format_9_10_op_table[i].op;
720 mp_uint_t rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
721 if (get_arg_addr(emit, op_str, pn_args[1], &pn_base, &pn_offset)) {
722 mp_uint_t rlo_base = get_arg_reg(emit, op_str, pn_base, 7);
725 i5 = get_arg_i(emit, op_str, pn_offset, 0x1f);
727 i5 = get_arg_i(emit, op_str, pn_offset, 0x3e) >> 1;
729 i5 = get_arg_i(emit, op_str, pn_offset, 0x7c) >> 2;
731 asm_thumb_format_9_10(&emit->as, op_code, rlo_dest, rlo_base, i5);
741 }
else if (n_args == 3) {
743 if (op == MP_QSTR_lsl) {
747 rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
748 rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7);
749 i5 = get_arg_i(emit, op_str, pn_args[2], 0x1f);
750 asm_thumb_format_1(&emit->as, op_code, rlo_dest, rlo_src, i5);
751 }
else if (op == MP_QSTR_lsr) {
754 }
else if (op == MP_QSTR_asr) {
757 }
else if (op == MP_QSTR_add) {
761 rlo_dest = get_arg_reg(emit, op_str, pn_args[0], 7);
762 rlo_src = get_arg_reg(emit, op_str, pn_args[1], 7);
766 src_b = get_arg_reg(emit, op_str, pn_args[2], 7);
769 src_b = get_arg_i(emit, op_str, pn_args[2], 0x7);
771 asm_thumb_format_2(&emit->as, op_code, rlo_dest, rlo_src, src_b);
772 }
else if (ARMV7M && op == MP_QSTR_sdiv) {
776 rd = get_arg_reg(emit, op_str, pn_args[0], 15);
777 rn = get_arg_reg(emit, op_str, pn_args[1], 15);
778 rm = get_arg_reg(emit, op_str, pn_args[2], 15);
780 }
else if (ARMV7M && op == MP_QSTR_udiv) {
783 }
else if (op == MP_QSTR_sub) {
786 }
else if (ARMV7M && op == MP_QSTR_strex) {
787 mp_uint_t r_dest = get_arg_reg(emit, op_str, pn_args[0], 15);
788 mp_uint_t r_src = get_arg_reg(emit, op_str, pn_args[1], 15);
790 if (get_arg_addr(emit, op_str, pn_args[2], &pn_base, &pn_offset)) {
791 mp_uint_t r_base = get_arg_reg(emit, op_str, pn_base, 15);
792 mp_uint_t i8 = get_arg_i(emit, op_str, pn_offset, 0xff) >> 2;
793 asm_thumb_op32(&emit->as, 0xe840 | r_base, (r_src << 12) | (r_dest << 8) | i8);
810 emit_inline_thumb_error_msg(emit,
"branch not in range");
815 emit_inline_thumb_start_pass,
816 emit_inline_thumb_end_pass,
817 emit_inline_thumb_count_params,
818 emit_inline_thumb_label,
819 emit_inline_thumb_op,
822 #endif // MICROPY_EMIT_INLINE_THUMB
#define MP_ASM_PASS_COMPUTE
#define ASM_THUMB_FORMAT_9_STR
#define ASM_THUMB_FORMAT_3_MOV
void asm_thumb_format_4(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_src)
#define ASM_THUMB_FORMAT_4_LSL
#define ASM_THUMB_FORMAT_4_EOR
#define ASM_THUMB_FORMAT_4_CMN
#define ASM_THUMB_FORMAT_4_BIC
#define ASM_THUMB_FORMAT_9_WORD_TRANSFER
void * memset(void *b, int c, size_t len)
#define ASM_THUMB_FORMAT_4_ROR
const char * qstr_str(qstr q)
#define ASM_THUMB_FORMAT_2_IMM_OPERAND
void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label)
#define ASM_THUMB_FORMAT_9_LDR
#define MP_PARSE_NODE_STRUCT_KIND(pns)
#define m_del(type, ptr, num)
mp_obj_t mp_obj_new_exception_msg_varg(const mp_obj_type_t *exc_type, const char *fmt,...)
#define ASM_THUMB_FORMAT_1_ASR
#define ASM_THUMB_FORMAT_3_CMP
void mp_asm_base_init(mp_asm_base_t *as, size_t max_num_labels)
uintptr_t mp_parse_node_t
emit_inline_asm_t * emit_inline_thumb_new(mp_uint_t max_num_labels)
#define MP_PARSE_NODE_STRUCT_NUM_NODES(pns)
const emit_inline_asm_method_table_t emit_inline_thumb_method_table
#define ASM_THUMB_FORMAT_4_SBC
const mp_obj_type_t mp_type_SyntaxError
bool asm_thumb_b_n_label(asm_thumb_t *as, uint label)
bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o)
mp_obj_t mp_obj_new_exception_msg(const mp_obj_type_t *exc_type, const char *msg)
#define ASM_THUMB_FORMAT_10_STRH
#define MP_PARSE_NODE_IS_ID(pn)
#define m_del_obj(type, ptr)
void mp_asm_base_start_pass(mp_asm_base_t *as, int pass)
size_t strlen(const char *s)
#define MP_PARSE_NODE_IS_STRUCT_KIND(pn, k)
int mp_parse_node_extract_list(mp_parse_node_t *pn, size_t pn_kind, mp_parse_node_t **nodes)
#define ASM_THUMB_FORMAT_4_NEG
#define ASM_THUMB_FORMAT_4_ORR
#define ASM_THUMB_FORMAT_10_LDRH
#define ASM_THUMB_FORMAT_4_LSR
#define ASM_THUMB_FORMAT_2_ADD
#define ASM_THUMB_FORMAT_4_TST
void asm_thumb_mov_reg_reg(asm_thumb_t *as, uint reg_dest, uint reg_src)
bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide)
#define ASM_THUMB_FORMAT_2_SUB
#define ASM_THUMB_FORMAT_2_REG_OPERAND
#define ASM_THUMB_FORMAT_4_CMP
void asm_thumb_exit(asm_thumb_t *as)
void asm_thumb_mov_reg_i16(asm_thumb_t *as, uint mov_op, uint reg_dest, int i16_src)
#define ASM_THUMB_FORMAT_3_ADD
#define ASM_THUMB_FORMAT_4_ADC
bool asm_thumb_bl_label(asm_thumb_t *as, uint label)
#define ASM_THUMB_FORMAT_3_SUB
#define ASM_THUMB_FORMAT_4_ASR
#define ASM_THUMB_OP_MOVW
void asm_thumb_op16(asm_thumb_t *as, uint op)
const byte * qstr_data(qstr q, size_t *len)
#define ASM_THUMB_FORMAT_4_MUL
#define MP_PARSE_NODE_LEAF_ARG(pn)
void asm_thumb_op32(asm_thumb_t *as, uint op1, uint op2)
#define ASM_THUMB_FORMAT_4_MVN
#define MP_PARSE_NODE_IS_STRUCT(pn)
#define ASM_THUMB_OP_CPSIE_I
#define ASM_THUMB_FORMAT_9_BYTE_TRANSFER
int strcmp(const char *s1, const char *s2)
void asm_thumb_end_pass(asm_thumb_t *as)
void asm_thumb_entry(asm_thumb_t *as, int num_locals)
#define ASM_THUMB_FORMAT_1_LSR
void mp_asm_base_deinit(mp_asm_base_t *as, bool free_code)
mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg)
#define ASM_THUMB_OP_CPSID_I
#define ASM_THUMB_FORMAT_1_LSL
#define ASM_THUMB_OP_MOVT
void emit_inline_thumb_free(emit_inline_asm_t *emit)
#define ASM_THUMB_FORMAT_4_AND
struct _emit_inline_asm_t emit_inline_asm_t