changeset 81:b6b1e79cc277

Moved indexed modes to new expression framework
author lost
date Sat, 10 Jan 2009 19:05:15 +0000
parents 8929e1ee99cf
children 03be43ae19cf
files src/insn_indexed.c
diffstat 1 files changed, 113 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/src/insn_indexed.c	Sat Jan 10 07:18:59 2009 +0000
+++ b/src/insn_indexed.c	Sat Jan 10 19:05:15 2009 +0000
@@ -63,17 +63,15 @@
 		{ "", -1 }
 	};
 	char stbuf[25];
-	int i;
-	int f8 = 0, f16 = 0;
-	int rn;
+	int i, j, rn;
+	int f8 = 0, f16 = 0, f0 = 0;
+	int r, v;
 	int indir = 0;
-	int rval;
-	int f0 = 0;
- 	const char *p2;
- 	lwasm_expr_stack_t *s;
- 	
+	
+	// initialize output bytes
 	*b1 = *b2 = *b3 = -1;
 	
+	// fetch out operand for lookup
 	for (i = 0; i < 24; i++)
 	{
 		if (*((*p) + i) && !isspace(*((*p) + i)))
@@ -82,9 +80,10 @@
 			break;
 	}
 	stbuf[i] = '\0';
+	
+	// now look up operand in "simple" table
 	if (!*((*p) + i) || isspace(*((*p) + i)))
 	{
-		int j;
 		// do simple lookup
 		for (j = 0; simpleindex[j].opstr[0]; j++)
 		{
@@ -98,21 +97,17 @@
 			return;
 		}
 	}
-	
-	// now we have the hard ones to work out here
-	
-	// if we've previously forced the sizes, make a note of it
-	if (l -> fsize == 1)
-		f8 = 1;
-	else if (l -> fsize == 2)
-		f16 = 1;
-	
+
+	// now do the "hard" ones
+
+	// is it indirect?
 	if (**p == '[')
 	{
 		indir = 1;
 		(*p)++;
 	}
 	
+	// look for a "," - all indexed modes have a "," except extended indir
 	rn = 0;
 	for (i = 0; (*p)[i] && !isspace((*p)[i]); i++)
 	{
@@ -122,37 +117,45 @@
 			break;
 		}
 	}
-		
+
+	// if no "," and indirect, do extended indir
 	if (!rn && indir)
 	{
 		// extended indir
 		*b1 = 0x9f;
 		*b2 = 0;
 		*b3 = 0;
-		s = lwasm_evaluate_expr(as, l, *p, &p2);
-		if (!s)
+		
+		r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0);
+		if (r < 0)
 		{
-			register_error(as, l, 1, "Bad expression");
 			return;
 		}
-		*p = p2;
+
 		if (**p != ']')
 		{
 			register_error(as, l, 1, "Bad operand");
 			return;
 		}
+		
 		(*p)++;
-		if (!lwasm_expr_is_constant(s))
+		
+		if (r == 1 && as -> passnum == 2)
 		{
-			register_error(as, l, 2, "Incomplete reference");
+			l -> relocoff = as -> addr - l -> codeaddr + 1;
 		}
-		rn = lwasm_expr_get_value(s);
-		lwasm_expr_stack_free(s);
-		*b2 = (rn >> 8) & 0xff;
-		*b3 = rn & 0xff;
+		
+		*b2 = (v >> 8) & 0xff;
+		*b3 = v & 0xff;
 		return;
 	}
 
+	// if we've previously forced the offset size, make a note of it
+	if (l -> fsize == 1)
+		f8 = 1;
+	else if (l -> fsize == 2)
+		f16 = 1;
+
 	if (**p == '<')
 	{
 		f8 = 1;
@@ -170,52 +173,76 @@
 	}
 	
 	// now we have to evaluate the expression
-	s = lwasm_evaluate_expr(as, l, *p, &p2);
-	*p = p2;
-	if (!s)
+	r = lwasm_expr_result2(as, l, (char **)p, 0, &v, 0);
+	if (r < 0)
 	{
-		register_error(as, l, 1, "Bad expression");
 		return;
 	}
-	if (!lwasm_expr_is_constant(s))
+	if (f8 && r != 0)
 	{
-		register_error(as, l, 2, "Incomplete reference");
-		if (!f8 && !f0)
-		{
-			f16 = 1;
-			l -> fsize = 2;
-		}
+		register_error(as, l, 2, "Illegal external or inter-section reference");
+		r = 0;
+		v = 0;
 	}
-	rval = lwasm_expr_get_value(s);
-	lwasm_expr_stack_free(s);
-	
+
 	// now look for a comma; if not present, explode
 	if (*(*p)++ != ',')
 	{
 		// syntax error; force 0 bit
 		*b1 = 00;
+		l -> fsize = 0;
 		return;
 	}
 	
 	// now get the register
 	rn = lwasm_lookupreg3(regs, p);
 	if (rn < 0)
-		goto reterr;
-
+	{
+		*b1 = 0;
+		l -> fsize = 0;
+		register_error(as, l, 1, "Bad register");
+		return;
+	}
+	
 	if (indir)
 	{
 		if (**p != ']')
-			goto reterr;
+		{
+			register_error(as, l, 1, "Bad operand");
+			l -> fsize = 0;
+			*b1 = 0;
+			return;
+		}
 		else
 			(*p)++;
 	}
 	
-	// nnnn,W is only 16 bit
+	// incomplete reference on pass 1 forces 16 bit
+	if (r == 1 && as -> passnum == 1)
+	{
+		f16 = 1;
+		l -> fsize = 2;
+	}
+	
+	// incomplete reference on pass 2 needs relocoff set
+	if (r == 1 && as -> passnum == 2)
+	{
+		l -> relocoff = as -> addr - l -> codeaddr + 1;
+	}
+
+	// nnnn,W is only 16 bit (or 0 bit)
 	if (rn == 4)
 	{
 		if (f8)
-			goto reterr;
-		if (!f16 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE) && rval == 0)
+		{
+			register_error(as, l, 1, "n,W cannot be 8 bit");
+			l -> fsize = 0;
+			*b1 = 0;
+			return;
+		}
+		// note: set f16 above for incomplete references
+		// also set reloc offset
+		if (!f16 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE) && v == 0)
 		{
 			if (indir)
 				*b1 = 0x90;
@@ -223,21 +250,24 @@
 				*b1 = 0x8f;
 			return;
 		}
+		
 		if (indir)
 			*b1 = 0xb0;
 		else
 			*b1 = 0xcf;
-		*b2 = (rval >> 8) & 0xff;
-		*b3 = rval & 0xff;
+		*b2 = (v >> 8) & 0xff;
+		*b3 = v & 0xff;
 		return;
 	}
 	
+	// set indir to correct bit value
 	if (indir) indir = 0x10;
 	
-	// PCR? redo v1, v2 relative to current address
+	// PCR? then we have PC relative addressing (like B??, LB??)
 	if (rn == 5)
 	{
-		rval -= as -> addr;
+		// FIXME: handle external references sensibly
+		v -= as -> addr;
 		
 		// we have a slight problem here
 		// PCR based on current insn loc is really
@@ -246,80 +276,85 @@
 		// so we only need to worry about the size of the operand
 		// hence the 2 and 3 magic numbers below instead of 3 and 4
 		// (and that also avoids errors with two byte opcodes, etc)
-		if (f8 || (!f16 && rval >= -125 && rval <= 130))
+		if (f8 || (!f16 && v >= -125 && v <= 130))
 		{
 			*b1 = indir | 0x8C;
-			rval -= 2;
-			if (rval < -128 || rval > 127)
+			v -= 2;
+			if (v < -128 || v > 127)
 				register_error(as, l, 2, "Byte overflow");
-			*b2 = rval & 0xff;
+			*b2 = v & 0xff;
 			return;
 		}
 		
 		// anything else is 16 bit offset
 		// need 16 bit
 		*b1 = indir | 0x8D;
-		rval -= 3;
-		*b2 = (rval >> 8) & 0xff;
-		*b3 = rval & 0xff;
+		v -= 3;
+		*b2 = (v >> 8) & 0xff;
+		*b3 = v & 0xff;
 		return;
 	}
 
-	// constant offset from PC
+	// constant offset from PC (using PC as regular register :) )
+	// FIXME: handle external references intelligently
 	if (rn == 6)
 	{
-		if (f8 || (!f16 && rval >= -128 && rval <= 127))
+		if (f8 || (!f16 && v >= -128 && v <= 127))
 		{
 			*b1 = indir | 0x8C;
-			if (rval < -128 || rval > 127)
+			if (v < -128 || v > 127)
 				register_error(as, l, 2, "Byte overflow");
-			*b2 = rval & 0xff;
+			*b2 = v & 0xff;
 			return;
 		}
 		
 		// everything else must be 16 bit
 		// need 16 bit
 		*b1 = indir | 0x8D;
-		*b2 = (rval >> 8) & 0xff;
-		*b3 = rval & 0xff;
+		*b2 = (v >> 8) & 0xff;
+		*b3 = v & 0xff;
 		return;
 	}
 
 	// we only have to deal with x,y,u,s here
-	if (!f8 && !f16 && rval >= -16 && rval <= 15)
+	if (!f8 && !f16 && v >= -16 && v <= 15)
 	{
-		if (rval == 0 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE))
+		// zero offset going to ,R?
+		if (v == 0 && !f0 && !(as -> pragmas & PRAGMA_NOINDEX0TONONE))
 		{
 			*b1 = rn << 5 | indir | 0x80 | 0x04;
 			return;
 		}
-		// we pick the smallest value here
+		
+		// no 5 bit on indirect
 		if (indir)
 		{
 			f8 = 1;
+			l -> fsize = 1;
 			goto no5bit;
 		}
-		*b1 = rn << 5 | (rval & 0x1F);
+		
+		// 5 bit addressing
+		*b1 = rn << 5 | (v & 0x1F);
 		return;
 	}
+
 no5bit:
-	if (f16 || (!f8 && (rval < -128 || rval > 127)))
+	if (f16 || (!f8 && (v < -128 || v > 127)))
 	{
 		// must be a 16 bit offset here
 		*b1 = rn << 5 | indir | 0x80 | 0x09;
-		*b2 = (rval >> 8) & 0xff;
-		*b3 = rval & 0xff;
+		*b2 = (v >> 8) & 0xff;
+		*b3 = v & 0xff;
 		return;
 	}
 	
 	// if we're here, we have an 8 bit offset
+	// note: cannot get here if incomplete reference detected above
 	*b1 = rn << 5 | indir | 0x80 | 0x08;
-	if (rval < -128 || rval > 127)
+	if (v < -128 || v > 127)
 		register_error(as, l, 2, "Byte overflow");
-	*b2 = rval & 0xff;
-	return;
-reterr:
-	*b1 = 0;
+	*b2 = v & 0xff;
 	return;
 }