Mercurial > hg-old > index.cgi
diff src/insn_indexed.c @ 101:f59c0916753d
Fixed relative branches and PCR addressing to handle constant intra-section references properly
author | lost |
---|---|
date | Fri, 23 Jan 2009 03:36:27 +0000 |
parents | e12edcfbebd5 |
children |
line wrap: on
line diff
--- a/src/insn_indexed.c Sat Jan 17 07:35:18 2009 +0000 +++ b/src/insn_indexed.c Fri Jan 23 03:36:27 2009 +0000 @@ -67,6 +67,7 @@ int f8 = 0, f16 = 0, f0 = 0; int r, v; int indir = 0; + int fs8 = 0, fs16 = 0; // initialize output bytes *b1 = *b2 = *b3 = -1; @@ -156,12 +157,12 @@ if (**p == '<') { - f8 = 1; + fs8 = 1; (*p)++; } else if (**p == '>') { - f16 = 1; + fs16 = 1; (*p)++; } @@ -176,13 +177,6 @@ { return; } - if (f8 && r != 0) - { - register_error(as, l, 2, "Illegal external or inter-section reference"); - r = 0; - v = 0; - } - // now look for a comma; if not present, explode if (*(*p)++ != ',') { @@ -264,8 +258,36 @@ // PCR? then we have PC relative addressing (like B??, LB??) if (rn == 5) { - // FIXME: handle external references sensibly - v -= as -> addr; + lwasm_expr_term_t *t; + // external references are handled exactly the same as for + // relative addressing modes + // on pass 1, adjust the expression for a subtraction of the + // current address + + // need to re-evaluate the expression with "SECTCONST"... + r = lwasm_expr_result2(as, l, (char **)p, EXPR_SECTCONST | EXPR_REEVAL, &v, 0); + if (r != 0) + v = 0; + if (as -> passnum == 1) + { + l -> fsize = 0; + } + f8 = f16 = 0; + if (r == 1 && as -> passnum == 1 && !fs8) + { + l -> fsize = 2; + f16 = 1; + } + if (fs8) + f8 = 1; + if (fs16) + f16 = 1; + if (l -> fsize == 2) + f16 = 1; + else if (l -> fsize == 1) + f8 = 1; + if (as -> passnum == 1) + v -= as -> addr; // we have a slight problem here // PCR based on current insn loc is really @@ -276,22 +298,71 @@ // (and that also avoids errors with two byte opcodes, etc) if (f8 || (!f16 && v >= -125 && v <= 130)) { + f8 = 1; + l -> fsize = 1; *b1 = indir | 0x8C; - v -= 2; + if (as -> passnum == 1) + v -= 2; if (v < -128 || v > 127) register_error(as, l, 2, "Byte overflow"); *b2 = v & 0xff; - return; + if (r != 0 && as -> passnum == 2) + { + register_error(as, l, 2, "Illegal incomplete reference"); + } + goto finpcr; } // anything else is 16 bit offset // need 16 bit + + l -> fsize = 2; *b1 = indir | 0x8D; - v -= 3; + if (as -> passnum == 1) + v -= 3; *b2 = (v >> 8) & 0xff; *b3 = v & 0xff; + if (as -> passnum == 2 && r == 1) + { + t = lwasm_expr_term_create_secbase(); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + } + + finpcr: + if (as -> passnum == 1) + { + // need to adjust the expression + if (l -> exprs[0]) + { + t = lwasm_expr_term_create_int(as -> addr + (f8 ? 2 : 3)); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + t = lwasm_expr_term_create_oper(LWASM_OPER_MINUS); + lwasm_expr_stack_push(l -> exprs[0], t); + lwasm_expr_term_free(t); + } + else + { + l -> exprvals[0] -= as -> addr + (f8 ? 2 : 3); + } + } return; } + if (fs16) + f16 = 1; + if (fs8) + f8 = 1; + + if (f8 && r != 0) + { + register_error(as, l, 2, "Illegal external or inter-section reference"); + r = 0; + v = 0; + } // constant offset from PC (using PC as regular register :) ) // FIXME: handle external references intelligently