Mercurial > hg-old > index.cgi
diff lwasm/insn_rel.c @ 151:427e268e876b
renamed src to lwasm to better reflect its purpose
author | lost |
---|---|
date | Fri, 30 Jan 2009 04:01:55 +0000 |
parents | src/insn_rel.c@f59c0916753d |
children | 383caf808674 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_rel.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,123 @@ +/* +insn_rel.c +Copyright © 2009 William Astle + +This file is part of LWASM. + +LWASM is free software: you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation, either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +more details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +/* +for handling relative mode instructions +*/ + +#define __insn_rel_c_seen__ + +#include <stdlib.h> + +#include "expr.h" +#include "lwasm.h" +#include "instab.h" + +OPFUNC(insn_rel8) +{ + int v; + lwasm_expr_term_t *t; + int r; + + lwasm_emitop(as, l, instab[opnum].ops[0]); + + if ((r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST, &v, 0)) < 0) + v = 0; + else + { + if (as -> passnum == 1) + { + // need to adjust the expression + if (l -> exprs[0]) + { + t = lwasm_expr_term_create_int(as -> addr + 1); + 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 + 1; + } + } + } + if (r == 1 && as -> passnum == 2) + { + register_error(as, l, 2, "Illegal external or intersegment reference"); + } + if (v < -128 || v > 127) + register_error(as, l, 2, "Byte overflow"); + lwasm_emit(as, l, v & 0xff); +} + +/* +External and intersegment references are adjusted for the relative addressing mode +by adjusting the expression on pass 1 and then treated as absolute references later +*/ +OPFUNC(insn_rel16) +{ + int v; + int r; + lwasm_expr_term_t *t; + + lwasm_emitop(as, l, instab[opnum].ops[0]); + + r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST, &v, 0); + if (r < 0) + v = 0; + else + { + if (as -> passnum == 1) + { + // need to adjust the expression + if (l -> exprs[0]) + { + t = lwasm_expr_term_create_int(as -> addr + 2); + 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 + 2; + } + } + } + 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); +}