From a2f2f7db1f42f9229df9d4f353689f24685e5dc4 Mon Sep 17 00:00:00 2001 From: Damien Date: Sun, 6 Oct 2013 00:14:13 +0100 Subject: [PATCH] Almost supports arguments for inline asm functions. --- py/compile.c | 19 +++++++++----- py/emit.h | 3 ++- py/emitinlinethumb.c | 61 +++++++++++++++++++++++++++++--------------- 3 files changed, 55 insertions(+), 28 deletions(-) diff --git a/py/compile.c b/py/compile.c index 6a3a66946..8adfcd2a0 100644 --- a/py/compile.c +++ b/py/compile.c @@ -2507,25 +2507,30 @@ void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass return; } + if (comp->pass > PASS_1) { + EMIT_INLINE_ASM(start_pass, comp->pass, comp->scope_cur); + } + // get the function definition parse node assert(PY_PARSE_NODE_IS_STRUCT(scope->pn)); py_parse_node_struct_t *pns = (py_parse_node_struct_t*)scope->pn; assert(PY_PARSE_NODE_STRUCT_KIND(pns) == PN_funcdef); - //qstr f_id = PY_PARSE_NODE_LEAF_ARG(pns->nodes[0]); // name + //qstr f_id = PY_PARSE_NODE_LEAF_ARG(pns->nodes[0]); // function name + + // parameters are in pns->nodes[1] + if (comp->pass == PASS_2) { + py_parse_node_t *pn_params; + int n_params = list_get(&pns->nodes[1], PN_typedargslist, &pn_params); + scope->num_params = EMIT_INLINE_ASM(count_params, n_params, pn_params); + } - scope->num_params = 0; - assert(PY_PARSE_NODE_IS_NULL(pns->nodes[1])); // arguments assert(PY_PARSE_NODE_IS_NULL(pns->nodes[2])); // type py_parse_node_t pn_body = pns->nodes[3]; // body py_parse_node_t *nodes; int num = list_get(&pn_body, PN_suite_block_stmts, &nodes); - if (comp->pass > PASS_1) { - EMIT_INLINE_ASM(start_pass, comp->pass, comp->scope_cur); - } - if (comp->pass == PASS_3) { //printf("----\n"); scope_print_info(scope); diff --git a/py/emit.h b/py/emit.h index 106a0a242..221fdb378 100644 --- a/py/emit.h +++ b/py/emit.h @@ -134,8 +134,9 @@ typedef struct _emit_inline_asm_t emit_inline_asm_t; typedef struct _emit_inline_asm_method_table_t { void (*start_pass)(emit_inline_asm_t *emit, pass_kind_t pass, scope_t *scope); void (*end_pass)(emit_inline_asm_t *emit); + int (*count_params)(emit_inline_asm_t *emit, int n_params, py_parse_node_t *pn_params); void (*label)(emit_inline_asm_t *emit, int label_num, qstr label_id); - void (*op)(emit_inline_asm_t *emit, qstr op, int n_args, py_parse_node_t *args); + void (*op)(emit_inline_asm_t *emit, qstr op, int n_args, py_parse_node_t *pn_args); } emit_inline_asm_method_table_t; extern const emit_inline_asm_method_table_t emit_inline_thumb_method_table; diff --git a/py/emitinlinethumb.c b/py/emitinlinethumb.c index 9950f4a33..1e739a34d 100644 --- a/py/emitinlinethumb.c +++ b/py/emitinlinethumb.c @@ -50,6 +50,25 @@ static void emit_inline_thumb_end_pass(emit_inline_asm_t *emit) { } } +static int emit_inline_thumb_count_params(emit_inline_asm_t *emit, int n_params, py_parse_node_t *pn_params) { + if (n_params > 4) { + printf("SyntaxError: can only have up to 3 parameters to inline assembler\n"); + return 0; + } + for (int i = 0; i < n_params; i++) { + if (!PY_PARSE_NODE_IS_ID(pn_params[i])) { + printf("SyntaxError: parameter to inline assembler must be an identifier %d\n", PY_PARSE_NODE_STRUCT_KIND((py_parse_node_struct_t*)pn_params[i])); + return 0; + } + const char *p = qstr_str(PY_PARSE_NODE_LEAF_ARG(pn_params[i])); + if (!(strlen(p) == 2 && p[0] == 'r' && p[1] == '0' + i)) { + printf("SyntaxError: parameter %d to inline assembler must be r%d\n", i, i); + return 0; + } + } + return n_params; +} + static void emit_inline_thumb_label(emit_inline_asm_t *emit, int label_num, qstr label_id) { assert(label_num < emit->max_num_labels); emit->label_lookup[label_num] = label_id; @@ -65,12 +84,12 @@ static bool check_n_arg(qstr op, int n_args, int wanted_n_args) { } } -static uint get_arg_rlo(qstr op, py_parse_node_t *pn_arg, int wanted_arg_num) { - if (!PY_PARSE_NODE_IS_ID(pn_arg[wanted_arg_num])) { +static uint get_arg_rlo(qstr op, py_parse_node_t *pn_args, int wanted_arg_num) { + if (!PY_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) { printf("SyntaxError: '%s' expects a register in position %d\n", qstr_str(op), wanted_arg_num); return 0; } - qstr reg_qstr = PY_PARSE_NODE_LEAF_ARG(pn_arg[wanted_arg_num]); + qstr reg_qstr = PY_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]); const char *reg_str = qstr_str(reg_qstr); if (!(strlen(reg_str) == 2 && reg_str[0] == 'r' && ('0' <= reg_str[1] && reg_str[1] <= '7'))) { printf("SyntaxError: '%s' expects a register in position %d\n", qstr_str(op), wanted_arg_num); @@ -79,12 +98,12 @@ static uint get_arg_rlo(qstr op, py_parse_node_t *pn_arg, int wanted_arg_num) { return reg_str[1] - '0'; } -static int get_arg_i(qstr op, py_parse_node_t *pn_arg, int wanted_arg_num, int fit_mask) { - if (!PY_PARSE_NODE_IS_SMALL_INT(pn_arg[wanted_arg_num])) { +static int get_arg_i(qstr op, py_parse_node_t *pn_args, int wanted_arg_num, int fit_mask) { + if (!PY_PARSE_NODE_IS_SMALL_INT(pn_args[wanted_arg_num])) { printf("SyntaxError: '%s' expects an integer in position %d\n", qstr_str(op), wanted_arg_num); return 0; } - int i = PY_PARSE_NODE_LEAF_ARG(pn_arg[wanted_arg_num]); + int i = PY_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]); if ((i & (~fit_mask)) != 0) { printf("SyntaxError: '%s' integer 0x%x does not fit in mask 0x%x\n", qstr_str(op), i, fit_mask); return 0; @@ -92,12 +111,12 @@ static int get_arg_i(qstr op, py_parse_node_t *pn_arg, int wanted_arg_num, int f return i; } -static int get_arg_label(emit_inline_asm_t *emit, qstr op, py_parse_node_t *pn_arg, int wanted_arg_num) { - if (!PY_PARSE_NODE_IS_ID(pn_arg[wanted_arg_num])) { +static int get_arg_label(emit_inline_asm_t *emit, qstr op, py_parse_node_t *pn_args, int wanted_arg_num) { + if (!PY_PARSE_NODE_IS_ID(pn_args[wanted_arg_num])) { printf("SyntaxError: '%s' expects a label in position %d\n", qstr_str(op), wanted_arg_num); return 0; } - qstr label_qstr = PY_PARSE_NODE_LEAF_ARG(pn_arg[wanted_arg_num]); + qstr label_qstr = PY_PARSE_NODE_LEAF_ARG(pn_args[wanted_arg_num]); for (int i = 0; i < emit->max_num_labels; i++) { if (emit->label_lookup[i] == label_qstr) { return i; @@ -107,7 +126,7 @@ static int get_arg_label(emit_inline_asm_t *emit, qstr op, py_parse_node_t *pn_a return 0; } -static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, py_parse_node_t *pn_arg) { +static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, py_parse_node_t *pn_args) { // TODO perhaps make two tables: // two_args = // "movs", RLO, I8, asm_thumb_movs_reg_i8 @@ -120,7 +139,8 @@ static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, p if (!check_n_arg(op, n_args, 1)) { return; } - int label_num = get_arg_label(emit, op, pn_arg, 0); + int label_num = get_arg_label(emit, op, pn_args, 0); + // TODO check that this succeeded, ie branch was within range asm_thumb_bgt_n(emit->as, label_num); // 2 args @@ -128,22 +148,22 @@ static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, p if (!check_n_arg(op, n_args, 2)) { return; } - uint rlo_dest = get_arg_rlo(op, pn_arg, 0); - int i_src = get_arg_i(op, pn_arg, 1, 0xff); + 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_arg, 0); // TODO can be reg lo or hi - int i_src = get_arg_i(op, pn_arg, 1, 0xffff); + 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_arg, 0); - int i8 = get_arg_i(op, pn_arg, 1, 0xff); + 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 @@ -151,9 +171,9 @@ static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, p if (!check_n_arg(op, n_args, 3)) { return; } - uint rlo_dest = get_arg_rlo(op, pn_arg, 0); - uint rlo_src = get_arg_rlo(op, pn_arg, 1); - int i3_src = get_arg_i(op, pn_arg, 2, 0x7); + 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 @@ -166,6 +186,7 @@ static void emit_inline_thumb_op(emit_inline_asm_t *emit, qstr op, int n_args, p const emit_inline_asm_method_table_t emit_inline_thumb_method_table = { emit_inline_thumb_start_pass, emit_inline_thumb_end_pass, + emit_inline_thumb_count_params, emit_inline_thumb_label, emit_inline_thumb_op, };