# HG changeset patch # User lost # Date 1232681787 0 # Node ID f59c0916753da4c274204419d12f108e124abbc9 # Parent 579ac36979183b83ce3aa033895a180f4441b06d Fixed relative branches and PCR addressing to handle constant intra-section references properly diff -r 579ac3697918 -r f59c0916753d TODO --- a/TODO Sat Jan 17 07:35:18 2009 +0000 +++ b/TODO Fri Jan 23 03:36:27 2009 +0000 @@ -1,10 +1,5 @@ * add expression simplification architecture (algebraic) -* fix relative addressing to reduce to constant offsets where possible - instead of relying on the linker to sort everything out - -* fix ,PCR addressing to handle incomplete references correctly - * fix FDB to handle incomplete references correctly * add ability to have multiple incomplete references per source line diff -r 579ac3697918 -r f59c0916753d src/insn_bitbit.c --- a/src/insn_bitbit.c Sat Jan 17 07:35:18 2009 +0000 +++ b/src/insn_bitbit.c Fri Jan 23 03:36:27 2009 +0000 @@ -60,7 +60,7 @@ register_error(as, l, 1, "Bad operand"); return; } - s = lwasm_evaluate_expr(as, l, *p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL, 0); if (!s) { register_error(as, l, 1, "Bad operand"); @@ -84,7 +84,7 @@ } r = (r << 6) | (v1 << 3); - s = lwasm_evaluate_expr(as, l, *p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL, 0); if (!s) { register_error(as, l, 1, "Bad operand"); @@ -114,7 +114,7 @@ if (**p == '<') (*p)++; - s = lwasm_evaluate_expr(as, l, *p, NULL); + s = lwasm_evaluate_expr(as, l, *p, NULL, 0); if (!s) { register_error(as, l, 1, "Bad operand"); diff -r 579ac3697918 -r f59c0916753d src/insn_indexed.c --- 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 diff -r 579ac3697918 -r f59c0916753d src/insn_rel.c --- a/src/insn_rel.c Sat Jan 17 07:35:18 2009 +0000 +++ b/src/insn_rel.c Fri Jan 23 03:36:27 2009 +0000 @@ -38,7 +38,7 @@ lwasm_emitop(as, l, instab[opnum].ops[0]); - if ((r = lwasm_expr_result2(as, l, p, 0, &v, 0)) < 0) + if ((r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST, &v, 0)) < 0) v = 0; else { @@ -81,7 +81,7 @@ lwasm_emitop(as, l, instab[opnum].ops[0]); - r = lwasm_expr_result2(as, l, p, 0, &v, 0); + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST, &v, 0); if (r < 0) v = 0; else @@ -105,7 +105,19 @@ } } if (as -> passnum == 2 && r == 1) + { + // since we have a reference outside this section, add + // a subtract of the section base to get the right value + // upon linking + 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); + l -> relocoff = as -> addr - l -> codeaddr; + } lwasm_emit(as, l, (v >> 8) & 0xff); lwasm_emit(as, l, v & 0xff); } diff -r 579ac3697918 -r f59c0916753d src/lwasm.c --- a/src/lwasm.c Sat Jan 17 07:35:18 2009 +0000 +++ b/src/lwasm.c Fri Jan 23 03:36:27 2009 +0000 @@ -173,6 +173,7 @@ { asmstate_t *as; lwasm_line_t *l; + int flags; }; lwasm_expr_stack_t *lwasm_expr_lookup_symbol(char *sym, void *state) @@ -225,9 +226,18 @@ { return NULL; } + if (st -> flags & EXPR_SECTCONST) + { + if (se -> sect == st -> l -> sect) + { + if (se -> expr) + goto retsym; + val = se -> value; + goto retconst; + } + } if (st -> as -> outformat == OUTPUT_OBJ && se -> sect != NULL) { - // do not resolve any section symbols in object mode return NULL; } if (st -> as -> outformat != OUTPUT_OBJ || se -> sect == NULL) @@ -236,6 +246,7 @@ val = se -> value; goto retconst; } + // an intersegment reference will return as NULL (to be resolved at output/link time) // if se -> expr is NULL, it has to be an intersegment reference here if (se -> expr == NULL) @@ -243,6 +254,7 @@ return NULL; } +retsym: // duplicate the expression for return rs = lwasm_expr_stack_create(); for (n = se -> expr -> head; n; n = n -> next) @@ -259,12 +271,13 @@ return rs; } -lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp) +lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags) { struct symstateinfo st; st.as = as; st.l = l; + st.flags = flags; debug_message(2, "Evaluate expression: %s", inp); @@ -272,13 +285,13 @@ } -int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s) +int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s, int flags) { struct symstateinfo st; st.as = as; st.l = l; - + st.flags = flags; return(lwasm_expr_reval(s, lwasm_expr_lookup_symbol, &st)); } @@ -322,9 +335,9 @@ const char *ep; int rval; - if (as -> passnum == 1 || slot < 0) + if ((as -> passnum == 1 && !(flag & EXPR_REEVAL)) || slot < 0) { - s = lwasm_evaluate_expr(as, l, *inp, &ep); + s = lwasm_evaluate_expr(as, l, *inp, &ep, flag); if (slot >= 0) l -> exprs[slot] = s; if (!s) @@ -343,7 +356,7 @@ else if (l -> exprs[slot]) { s = l -> exprs[slot]; - lwasm_reevaluate_expr(as, l, s); + lwasm_reevaluate_expr(as, l, s, flag); l -> exprvals[slot] = lwasm_expr_get_value(s); } if (as -> passnum == 2 && slot >= 0) diff -r 579ac3697918 -r f59c0916753d src/lwasm.h --- a/src/lwasm.h Sat Jan 17 07:35:18 2009 +0000 +++ b/src/lwasm.h Fri Jan 23 03:36:27 2009 +0000 @@ -196,7 +196,7 @@ __lwasm_E__ int lwasm_lookupreg2(const char *reglist, char **str); __lwasm_E__ int lwasm_lookupreg3(const char *rlist, const char **str); -__lwasm_E__ lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp); +__lwasm_E__ lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags); // return next context number and update it @@ -206,7 +206,8 @@ // return 0 on ok, -1 on error, 1 if a complex expression was returned #define EXPR_NOFLAG 0 #define EXPR_PASS1CONST 1 // no forward references on pass 1 - +#define EXPR_SECTCONST 2 // resolve symbols local to section +#define EXPR_REEVAL 4 // re-evaluate the expression __lwasm_E__ int lwasm_expr_result(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val); __lwasm_E__ int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot); diff -r 579ac3697918 -r f59c0916753d src/parse.c --- a/src/parse.c Sat Jan 17 07:35:18 2009 +0000 +++ b/src/parse.c Fri Jan 23 03:36:27 2009 +0000 @@ -45,6 +45,7 @@ return; p = l -> text; + l -> sect = as -> csect; // blank lines are a no brainer if (!*p)