Mercurial > hg-old > index.cgi
diff lwasm/insn_gen.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_gen.c@81fc353d4d69 |
children | 2e6a1e914104 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lwasm/insn_gen.c Fri Jan 30 04:01:55 2009 +0000 @@ -0,0 +1,228 @@ +/* +insn_gen.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/>. + +Contains code for parsing general addressing modes (IMM+DIR+EXT+IND) +*/ + +#include <ctype.h> +#include <stdlib.h> + +#include "lwasm.h" +#include "instab.h" +#include "expr.h" + +extern void insn_indexed_aux(asmstate_t *as, lwasm_line_t *l, const char **p, int *b1, int *b2, int *b3); + +// "extra" is required due to the way OIM, EIM, TIM, and AIM work +void insn_gen_aux(asmstate_t *as, lwasm_line_t *l, char **optr, int opnum, int extra) +{ + int b1 = -1, b2 = -1, b3 = -1; + + const char *optr2; + int v1, tv, rval; + lwasm_expr_stack_t *s; + int f8 = 0; + int f16 = 0; + int isdp = 0; + + optr2 = *optr; + while (*optr2 && !isspace(*optr2) && *optr2 != ',') optr2++ + /* do nothing */ ; + + if (*optr2 != ',' && **optr != '[') + { + // not indexed + if (l -> fsize == 1) + f8 = 1; + else if (l -> fsize == 2) + f16 = 1; + + if (**optr == '<') + { + (*optr)++; + f8 = 1; + } + else if (**optr == '>') + { + (*optr)++; + f16 = 1; + } + rval = lwasm_expr_result2(as, l, optr, 0, &v1, 0); + if (rval != 0) + { + f16 = 1; + v1 = 0; + l -> fsize = 2; + } + + if (((v1 >> 8) & 0xff) == (as -> dpval & 0xff)) + isdp = 1; + + // disallow non-explicit DP in obj target + if (as -> outformat == OUTPUT_OBJ && !f8) + f16 = 1; + + if (f8 || (!f16 && isdp)) + { + v1 = v1 & 0xffff; + tv = v1 - ((as -> dpval) << 8); + if (tv < 0 || tv > 0xff) + { + register_error(as, l, 2, "Byte overflow"); + } + v1 = v1 & 0xff; + lwasm_emitop(as, l, instab[opnum].ops[0]); + if (extra != -1) + lwasm_emit(as, l, extra); + lwasm_emit(as, l, v1 & 0xff); + return; + } + else + { + // everything else is 16 bit.... + lwasm_emitop(as, l, instab[opnum].ops[2]); + if (extra != -1) + lwasm_emit(as, l, extra); + l -> relocoff = as -> addr - l -> codeaddr; + lwasm_emit(as, l, v1 >> 8); + lwasm_emit(as, l, v1 & 0xff); + return; + } + } + + lwasm_emitop(as, l, instab[opnum].ops[1]); + if (extra != -1) + lwasm_emit(as, l, extra); + insn_indexed_aux(as, l, (const char **)optr, &b1, &b2, &b3); + if (b1 != -1) + lwasm_emit(as, l, b1); + if (b2 != -1) + lwasm_emit(as, l, b2); + if (b3 != -1) + lwasm_emit(as, l, b3); + return; +} + +// the various insn_gen? functions have an immediate mode of ? bits +OPFUNC(insn_gen0) +{ + if (**p == '#') + { + register_error(as, l, 1, "Immediate mode not allowed"); + return; + } + + // handle non-immediate + insn_gen_aux(as, l, p, opnum, -1); +} + +OPFUNC(insn_gen8) +{ + int rval; + int r; + + if (**p == '#') + { + lwasm_emitop(as, l, instab[opnum].ops[3]); + (*p)++; + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) + rval = 0; + if (r == 1 && as -> passnum == 2) + register_error(as, l, 2, "Illegal external or intersegment reference"); + lwasm_emit(as, l, rval & 0xff); + return; + } + + insn_gen_aux(as, l, p, opnum, -1); +} + +OPFUNC(insn_gen16) +{ + int rval, r; + + if (**p == '#') + { + lwasm_emitop(as, l, instab[opnum].ops[3]); + (*p)++; + + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) + rval = 0; + if (r == 1 && as -> passnum == 2) + { + l -> relocoff = as -> addr - l -> codeaddr; + } + lwasm_emit(as, l, (rval >> 8) & 0xff); + lwasm_emit(as, l, rval & 0xff); + return; + } + + insn_gen_aux(as, l, p, opnum, -1); +} + +OPFUNC(insn_gen32) +{ + int r, rval; + + if (**p == '#') + { + lwasm_emitop(as, l, instab[opnum].ops[3]); + (*p)++; + + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) + rval = 0; + if (r == 1 && as -> passnum == 2) + { + register_error(as, l, 2, "Illegal external or intersegment reference"); + } + + lwasm_emit(as, l, (rval >> 24) & 0xff); + lwasm_emit(as, l, (rval >> 16) & 0xff); + lwasm_emit(as, l, (rval >> 8) & 0xff); + lwasm_emit(as, l, rval & 0xff); + return; + } + + insn_gen_aux(as, l, p, opnum, -1); +} + +OPFUNC(insn_imm8) +{ + int r, rval; + + if (**p == '#') + { + lwasm_emitop(as, l, instab[opnum].ops[0]); + (*p)++; + + r = lwasm_expr_result2(as, l, p, 0, &rval, 0); + if (r != 0) + rval = 0; + if (r == 1 && as -> passnum == 2) + register_error(as, l, 2, "Illegal external or intersegment reference"); + + if (rval < -128 || rval > 255) + register_error(as, l, 2, "Byte overflow"); + lwasm_emit(as, l, rval & 0xff); + return; + } + + register_error(as, l, 1, "Bad operand"); +}