Example #1
0
STATIC mp_uint_t get_arg_reglist(emit_inline_asm_t *emit, const char *op, mp_parse_node_t pn) {
    // a register list looks like {r0, r1, r2} and is parsed as a Python set

    if (!MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_brace)) {
        goto bad_arg;
    }

    mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
    assert(MP_PARSE_NODE_STRUCT_NUM_NODES(pns) == 1); // should always be
    pn = pns->nodes[0];

    mp_uint_t reglist = 0;

    if (MP_PARSE_NODE_IS_ID(pn)) {
        // set with one element
        reglist |= 1 << get_arg_reg(emit, op, pn, 15);
    } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
        pns = (mp_parse_node_struct_t*)pn;
        if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dictorsetmaker) {
            assert(MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])); // should succeed
            mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
            if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_dictorsetmaker_list) {
                // set with multiple elements

                // get first element of set (we rely on get_arg_reg to catch syntax errors)
                reglist |= 1 << get_arg_reg(emit, op, pns->nodes[0], 15);

                // get tail elements (2nd, 3rd, ...)
                mp_parse_node_t *nodes;
                int n = mp_parse_node_extract_list(&pns1->nodes[0], PN_dictorsetmaker_list2, &nodes);

                // process rest of elements
                for (int i = 0; i < n; i++) {
                    reglist |= 1 << get_arg_reg(emit, op, nodes[i], 15);
                }
            } else {
                goto bad_arg;
            }
        } else {
            goto bad_arg;
        }
    } else {
        goto bad_arg;
    }

    return reglist;

bad_arg:
    emit_inline_thumb_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, "'%s' expects {r0, r1, ...}", op));
    return 0;
}
Example #2
0
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 {