Mercurial > hg > index.cgi
diff lwasm/insn_rel.c @ 377:67373a053c49
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 <erik@6809.org> for the patch.
author | William Astle <lost@l-w.ca> |
---|---|
date | Mon, 13 Jul 2015 20:50:02 -0600 |
parents | 35d4213e6657 |
children | 0af33282b518 |
line wrap: on
line diff
--- 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 <ctype.h> #include <stdlib.h> #include <stdio.h> +#include <string.h> #include <lw_expr.h> @@ -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 {