Mercurial > hg-old > index.cgi
view lwasm/insn_gen.c @ 282:2ca46690162b 2.3
Branched for 2.3 release
author | lost |
---|---|
date | Fri, 24 Apr 2009 22:14:47 +0000 |
parents | bae1e3ecdce1 |
children | 2b254f02b252 |
line wrap: on
line source
/* 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 <config.h> #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; } // for compatibility with asxxxx // * followed by a digit, alpha, or _, or ., or ?, or another * is "f8" else if (**optr == '*') { tv = *(*optr + 1); if (isdigit(tv) || isalpha(tv) || tv == '_' || tv == '.' || tv == '?' || tv == '@' || tv == '*' || tv == '+' || tv == '-') { f8 = 1; (*optr)++; } } 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); l -> relocoff = as -> addr - l -> codeaddr; l -> reloc8bit = 1; 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"); }