Mercurial > hg > index.cgi
diff lwasm/insn_rel.c @ 116:7b0716264251
Pragma autobranchlength implementation completed
author | lost@l-w.ca |
---|---|
date | Tue, 09 Aug 2011 18:08:55 -0600 |
parents | 95181f1ad183 |
children | 2be2649841f8 |
line wrap: on
line diff
--- a/lwasm/insn_rel.c Mon Aug 08 23:00:27 2011 -0600 +++ b/lwasm/insn_rel.c Tue Aug 09 18:08:55 2011 -0600 @@ -22,98 +22,205 @@ for handling relative mode instructions */ +#include <ctype.h> #include <stdlib.h> +#include <stdio.h> #include <lw_expr.h> #include "lwasm.h" #include "instab.h" -PARSEFUNC(insn_parse_rel8) +/* +For generic relative, the first "opcode" is the natural opcode for the +mneumonic. The second "opcode" is the natural size of the relative offset. +These will be used when pragma autobranchlength is NOT in effect. + +The third "opcode" is the short (8 bit) version of the branch. The final one +is the long (16 bit) version of the branch. These will be used when pragma +autobranchlength is in effect. + +When autobranchlength is in effect, the branch target can be prefixed with +either < or > to force a short or long branch. Note that in this mode, +a > or < on its own still specifies a branch point. + +*/ +PARSEFUNC(insn_parse_relgen) { -// int v; lw_expr_t t, e1, e2; -// int r; - + + l -> lint = -1; + if (CURPRAGMA(l, PRAGMA_AUTOBRANCHLENGTH) == 0) + { + l -> lint = instab[l -> insn].ops[1]; + } + else + { + if (**p == '>' && (((*p)[1]) && !isspace((*p)[1]))) + { + (*p)++; + l -> lint = 16; + } + else if (**p == '<' && (((*p)[1]) && !isspace((*p)[1]))) + { + (*p)++; + l -> lint = 8; + } + } + + /* forced sizes handled */ + // sometimes there is a "#", ignore if there if (**p == '#') (*p)++; t = lwasm_parse_expr(as, p); + if (!t) { lwasm_register_error(as, l, "Bad operand"); return; } - l -> len = OPLEN(instab[l -> insn].ops[0]) + 1; - - e1 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l); - e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, l -> addr); - lw_expr_destroy(e1); + + // if we know the length of the instruction, set it now + if (l -> lint == 8) + { + l -> len = OPLEN(instab[l -> insn].ops[2]) + 1; + } + else if (l -> lint == 16) + { + l -> len = OPLEN(instab[l -> insn].ops[3]) + 1; + } + + // the offset calculation here depends on the length of this line! + // how to calculate requirements? + // this is the same problem faced by ,pcr indexing + e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l); e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, t, e2); lw_expr_destroy(e2); + e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, e1, l -> addr); + lw_expr_destroy(e1); + lwasm_save_expr(l, 0, e2); lw_expr_destroy(t); - lwasm_save_expr(l, 0, e1); + + if (l -> len == -1) + { + e1 = lw_expr_copy(e2); + l -> len = OPLEN(instab[l -> insn].ops[2]) + 1; + lwasm_reduce_expr(as, e1); + l -> len = -1; + if (lw_expr_istype(e1, lw_expr_type_int)) + { + int v; + v = lw_expr_intval(e1); + if (v >= -128 && v <= 127) + { + l -> lint = 8; + l -> len = OPLEN(instab[l -> insn].ops[2]) + 1; + } + else + { + l -> lint = 16; + l -> len = OPLEN(instab[l -> insn].ops[3]) + 2; + } + } + lw_expr_destroy(e1); + } } -EMITFUNC(insn_emit_rel8) +RESOLVEFUNC(insn_resolve_relgen) +{ + lw_expr_t e, e2; + int offs; + + if (l -> lint == -1) + { + e = lwasm_fetch_expr(l, 0); + if (!lw_expr_istype(e, lw_expr_type_int)) + { + // temporarily set the instruction length to see if we get a + // constant for our expression; if so, we can select an instruction + // size + e2 = lw_expr_copy(e); + // size of 8-bit opcode + 8 bit offset + l -> len = OPLEN(instab[l -> insn].ops[2]) + 1; + lwasm_reduce_expr(as, e2); + l -> len = -1; + if (lw_expr_istype(e2, lw_expr_type_int)) + { + // it reduced to an integer; is it in 8 bit range? + offs = lw_expr_intval(e2); + if (offs >= -128 && offs <= 127) + { + // fits in 8 bits + l -> len = OPLEN(instab[l -> insn].ops[2]) + 1; + l -> lint = 8; + } + else + { + // requires 16 bits + l -> len = OPLEN(instab[l -> insn].ops[3]) + 2; + l -> lint = 16; + } + } + lw_expr_destroy(e2); + } + if (lw_expr_istype(e, lw_expr_type_int)) + { + // it reduced to an integer; is it in 8 bit range? + offs = lw_expr_intval(e); + if (offs >= -128 && offs <= 127) + { + // fits in 8 bits + l -> len = OPLEN(instab[l -> insn].ops[2]) + 1; + l -> lint = 8; + } + else + { + // requires 16 bits + l -> len = OPLEN(instab[l -> insn].ops[3]) + 2; + l -> lint = 16; + } + } + } + if (!force) + return; + + if (l -> len == -1) + { + l -> len = OPLEN(instab[l -> insn].ops[3]) + 2; + l -> lint = 16; + } +} + +EMITFUNC(insn_emit_relgen) { lw_expr_t e; int offs; e = lwasm_fetch_expr(l, 0); - if (!lw_expr_istype(e, lw_expr_type_int)) + if (l -> lint == 8) { - lwasm_register_error(as, l, "Illegal non-constant expression"); - return; - } - - offs = lw_expr_intval(e); - if (offs < -128 || offs > 127) - { - lwasm_register_error(as, l, "Byte overflow"); - return; - } + if (!lw_expr_istype(e, lw_expr_type_int)) + { + lwasm_register_error(as, l, "Illegal non-constant expression"); + return; + } - lwasm_emitop(l, instab[l -> insn].ops[0]); - lwasm_emit(l, offs); -} - -PARSEFUNC(insn_parse_rel16) -{ -// int v; - lw_expr_t t, e1, e2; -// int r; - - // sometimes there is a "#", ignore if there - if (**p == '#') - (*p)++; + offs = lw_expr_intval(e); + if (l -> lint == 8 && (offs < -128 || offs > 127)) + { + lwasm_register_error(as, l, "Byte overflow"); + return; + } + - t = lwasm_parse_expr(as, p); - if (!t) - { - lwasm_register_error(as, l, "Bad operand"); - lw_expr_destroy(t); - return; + lwasm_emitop(l, instab[l -> insn].ops[2]); + lwasm_emit(l, offs); } - l -> len = OPLEN(instab[l -> insn].ops[0]) + 2; - - e1 = lw_expr_build(lw_expr_type_special, lwasm_expr_linelen, l); - e2 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, l -> addr); - lw_expr_destroy(e1); - e1 = lw_expr_build(lw_expr_type_oper, lw_expr_oper_minus, t, e2); - lw_expr_destroy(e2); - lw_expr_destroy(t); - lwasm_save_expr(l, 0, e1); + else + { + lwasm_emitop(l, instab[l -> insn].ops[3]); + lwasm_emitexpr(l, e, 2); + } } - -EMITFUNC(insn_emit_rel16) -{ - lw_expr_t e; -// int offs; - - e = lwasm_fetch_expr(l, 0); - - lwasm_emitop(l, instab[l -> insn].ops[0]); - lwasm_emitexpr(l, e, 2); -}