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");	
+}