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) { asm_xtensa_op_ret_n(&emit->as); } else { goto unknown_op; } } else if (n_args == 1) { if (op == MP_QSTR_callx0) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); asm_xtensa_op_callx0(&emit->as, r0); } else if (op == MP_QSTR_j) { int label = get_arg_label(emit, op_str, pn_args[0]); asm_xtensa_j_label(&emit->as, label); } 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 { 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) { // 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); } else if (op == MP_QSTR_movi) { // 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 { goto unknown_op; } } else if (n_args == 3) { // search table for 3 arg instructions for (uint i = 0; i < MP_ARRAY_SIZE(opcode_table_3arg); i++) { const opcode_table_3arg_t *o = &opcode_table_3arg[i]; if (op == o->name) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); uint r1 = get_arg_reg(emit, op_str, pn_args[1]); if (o->type == RRR) { uint r2 = get_arg_reg(emit, op_str, pn_args[2]); asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, o->a0, o->a1, r0, r1, r2)); } else if (o->type == RRI8_B) { int label = get_arg_label(emit, op_str, pn_args[2]); asm_xtensa_bcc_reg_reg_label(&emit->as, o->a0, r0, r1, label); } else { int shift, min, max; if ((o->type & 0xf0) == 0) { shift = 0; min = -128; max = 127; } else { shift = (o->type & 0xf0) >> 5; min = 0; max = 0xff << shift; } uint32_t imm = get_arg_i(emit, op_str, pn_args[2], min, max); asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(o->a0, o->a1, r1, r0, (imm >> shift) & 0xff)); } return; } } goto unknown_op; } else {
STATIC void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, mp_parse_node_t *pn_args) { // TODO perhaps make two tables: // one_args = // "b", LAB, asm_thumb_b_n, // "bgt", LAB, asm_thumb_bgt_n, // two_args = // "movs", RLO, I8, asm_thumb_movs_reg_i8 // "movw", REG, REG, asm_thumb_movw_reg_i16 // three_args = // "subs", RLO, RLO, I3, asm_thumb_subs_reg_reg_i3 // 1 arg if (strcmp(qstr_str(op), "b") == 0) { if (!check_n_arg(op, n_args, 1)) { return; } int label_num = get_arg_label(emit, op, pn_args, 0); // TODO check that this succeeded, ie branch was within range asm_thumb_b_n(emit->as, label_num); } else if (strcmp(qstr_str(op), "bgt") == 0) { if (!check_n_arg(op, n_args, 1)) { return; } int label_num = get_arg_label(emit, op, pn_args, 0); // TODO check that this succeeded, ie branch was within range asm_thumb_bcc_n(emit->as, THUMB_CC_GT, label_num); // 2 args } else if (strcmp(qstr_str(op), "movs") == 0) { if (!check_n_arg(op, n_args, 2)) { return; } uint rlo_dest = get_arg_rlo(op, pn_args, 0); int i_src = get_arg_i(op, pn_args, 1, 0xff); asm_thumb_movs_rlo_i8(emit->as, rlo_dest, i_src); } else if (strcmp(qstr_str(op), "movw") == 0) { if (!check_n_arg(op, n_args, 2)) { return; } uint rlo_dest = get_arg_rlo(op, pn_args, 0); // TODO can be reg lo or hi int i_src = get_arg_i(op, pn_args, 1, 0xffff); asm_thumb_movw_reg_i16(emit->as, rlo_dest, i_src); } else if (strcmp(qstr_str(op), "cmp") == 0) { if (!check_n_arg(op, n_args, 2)) { return; } uint rlo = get_arg_rlo(op, pn_args, 0); int i8 = get_arg_i(op, pn_args, 1, 0xff); asm_thumb_cmp_rlo_i8(emit->as, rlo, i8); // 3 args } else if (strcmp(qstr_str(op), "subs") == 0) { if (!check_n_arg(op, n_args, 3)) { return; } uint rlo_dest = get_arg_rlo(op, pn_args, 0); uint rlo_src = get_arg_rlo(op, pn_args, 1); int i3_src = get_arg_i(op, pn_args, 2, 0x7); asm_thumb_subs_rlo_rlo_i3(emit->as, rlo_dest, rlo_src, i3_src); // unknown op } else { printf("SyntaxError: unsupported ARM Thumb instruction '%s'\n", qstr_str(op)); return; } }