# HG changeset patch # User William Astle # Date 1436842202 21600 # Node ID 67373a053c496f5099d907e092825ef05396b30e # Parent 35d4213e665737ba5ada17bf8945b990c4cfeab6 Add ?rts target for branch instructions Add a ?rts target for branch instructions, which brances to the nearest RTS or inverts the branch logic to branch around a generated RTS. Activated by a pragma "qrts". Thanks to Erik G for the patch. diff -r 35d4213e6657 -r 67373a053c49 lwasm/insn_rel.c --- a/lwasm/insn_rel.c Mon Jul 13 20:47:30 2015 -0600 +++ b/lwasm/insn_rel.c Mon Jul 13 20:50:02 2015 -0600 @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -47,7 +48,7 @@ */ PARSEFUNC(insn_parse_relgen) { - lw_expr_t t, e1, e2; + lw_expr_t t = NULL, e1, e2; l -> lint = -1; l -> maxlen = OPLEN(instab[l -> insn].ops[3]) + 2; @@ -76,7 +77,69 @@ if (**p == '#') (*p)++; - t = lwasm_parse_expr(as, p); + if (CURPRAGMA(l, PRAGMA_QRTS)) + { + // handle ?RTS conditional return + if (**p == '?') + { + if (strncasecmp(*p, "?RTS", 4) == 0) + { + (*p) += 4; + + line_t *cl = l; + for (cl = cl->prev; cl; cl = cl->prev) + { + if (cl->insn == -1) + continue; + + if (l->addr->value - cl->addr->value > 128) + { + cl = NULL; + break; + } + + if (cl->conditional_return) + break; + + if (instab[cl->insn].ops[0] == 0x39) + break; + } + + if (cl) + { + l->lint = -1; + if (cl->conditional_return) + { + e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, cl); + e1 = lw_expr_build(lw_expr_type_int, 2); + t = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, e2); + } + else + { + t = lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, cl); + } + } + else + { + l->conditional_return = 1; + + // t = * + 1 + + e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, l); + e1 = lw_expr_build(lw_expr_type_int, 1); + t = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, e2); + + lw_expr_destroy(e1); + lw_expr_destroy(e2); + } + } + } + } + + if (!t) + { + t = lwasm_parse_expr(as, p); + } if (!t) { @@ -88,6 +151,7 @@ if (l -> lint == 8) { l -> len = OPLEN(instab[l -> insn].ops[2]) + 1; + if (l->conditional_return) l->len++; } else if (l -> lint == 16) { @@ -233,10 +297,19 @@ return; } - lwasm_emitop(l, instab[l -> insn].ops[2]); - lwasm_emit(l, offs); - - l -> cycle_adj = 2; + if (l->conditional_return) + { + lwasm_emitop(l, instab[l->insn].ops[2] ^ 1); /* flip branch, add RTS */ + lwasm_emit(l, 1); + lwasm_emit(l, 0x39); + l->cycle_adj = 3; + } + else + { + lwasm_emitop(l, instab[l->insn].ops[2]); + lwasm_emit(l, offs); + l->cycle_adj = 2; + } } else { diff -r 35d4213e6657 -r 67373a053c49 lwasm/lwasm.h --- a/lwasm/lwasm.h Mon Jul 13 20:47:30 2015 -0600 +++ b/lwasm/lwasm.h Mon Jul 13 20:50:02 2015 -0600 @@ -97,7 +97,8 @@ PRAGMA_C = 1 << 16, // enable cycle counts PRAGMA_CD = 1 << 17, // enable detailed cycle count PRAGMA_CT = 1 << 18, // enable cycle count running total - PRAGMA_CC = 1 << 19 // clear cycle count running total + PRAGMA_CC = 1 << 19, // clear cycle count running total + PRAGMA_QRTS = 1 << 20 // enable BRA ?RTS support }; enum @@ -272,6 +273,7 @@ int pb; // pass forward post byte int lint; // pass forward integer int lint2; // another pass forward integer + int conditional_return; // for ?RTS handling (1 if RTS follows) asmstate_t *as; // assembler state data ptr int pragmas; // pragmas in effect for the line int context; // the symbol context number diff -r 35d4213e6657 -r 67373a053c49 lwasm/pragma.c --- a/lwasm/pragma.c Mon Jul 13 20:47:30 2015 -0600 +++ b/lwasm/pragma.c Mon Jul 13 20:50:02 2015 -0600 @@ -68,6 +68,7 @@ { "cc", "nocc", PRAGMA_CC }, { "cd", "nocd", PRAGMA_CD }, { "ct", "noct", PRAGMA_CT }, + { "qrts", "noqrts", PRAGMA_QRTS }, { 0, 0, 0 } }; diff -r 35d4213e6657 -r 67373a053c49 lwlib/lw_expr.c --- a/lwlib/lw_expr.c Mon Jul 13 20:47:30 2015 -0600 +++ b/lwlib/lw_expr.c Mon Jul 13 20:50:02 2015 -0600 @@ -24,7 +24,6 @@ #include #include -#define ___lw_expr_c_seen___ #include "lw_alloc.h" #include "lw_expr.h" #include "lw_error.h" diff -r 35d4213e6657 -r 67373a053c49 lwlib/lw_expr.h --- a/lwlib/lw_expr.h Mon Jul 13 20:47:30 2015 -0600 +++ b/lwlib/lw_expr.h Mon Jul 13 20:50:02 2015 -0600 @@ -55,8 +55,6 @@ lw_expr_oper_none = 0 }; -#ifdef ___lw_expr_c_seen___ - typedef struct lw_expr_priv * lw_expr_t; struct lw_expr_opers @@ -78,10 +76,6 @@ typedef lw_expr_t lw_expr_fn3_t(char **p, void *priv); typedef int lw_expr_testfn_t(lw_expr_t e, void *priv); -#else /* def ___lw_expr_c_seen___ */ - -typedef void * lw_expr_t; - lw_expr_t lwexpr_create(void); void lw_expr_destroy(lw_expr_t E); lw_expr_t lw_expr_copy(lw_expr_t E); @@ -91,10 +85,6 @@ int lw_expr_compare(lw_expr_t E1, lw_expr_t E2); void lw_expr_simplify(lw_expr_t E, void *priv); -typedef lw_expr_t lw_expr_fn_t(int t, void *ptr, void *priv); -typedef lw_expr_t lw_expr_fn2_t(char *var, void *priv); -typedef lw_expr_t lw_expr_fn3_t(char **p, void *priv); - void lw_expr_set_special_handler(lw_expr_fn_t *fn); void lw_expr_set_var_handler(lw_expr_fn2_t *fn); void lw_expr_set_term_parser(lw_expr_fn3_t *fn); @@ -121,6 +111,4 @@ void lw_expr_setdivzero(void (*fn)(void *priv)); -#endif /* def ___lw_expr_c_seen___ */ - #endif /* ___lw_expr_h_seen___ */