changeset 101:f59c0916753d

Fixed relative branches and PCR addressing to handle constant intra-section references properly
author lost
date Fri, 23 Jan 2009 03:36:27 +0000
parents 579ac3697918
children dbf1b926c2f1
files TODO src/insn_bitbit.c src/insn_indexed.c src/insn_rel.c src/lwasm.c src/lwasm.h src/parse.c
diffstat 7 files changed, 126 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/TODO	Sat Jan 17 07:35:18 2009 +0000
+++ b/TODO	Fri Jan 23 03:36:27 2009 +0000
@@ -1,10 +1,5 @@
 * add expression simplification architecture (algebraic)
 
-* fix relative addressing to reduce to constant offsets where possible
-  instead of relying on the linker to sort everything out
-
-* fix ,PCR addressing to handle incomplete references correctly
-
 * fix FDB to handle incomplete references correctly
 
 * add ability to have multiple incomplete references per source line
--- a/src/insn_bitbit.c	Sat Jan 17 07:35:18 2009 +0000
+++ b/src/insn_bitbit.c	Fri Jan 23 03:36:27 2009 +0000
@@ -60,7 +60,7 @@
 		register_error(as, l, 1, "Bad operand");
 		return;
 	}
-	s = lwasm_evaluate_expr(as, l, *p, NULL);
+	s = lwasm_evaluate_expr(as, l, *p, NULL, 0);
 	if (!s)
 	{
 		register_error(as, l, 1, "Bad operand");
@@ -84,7 +84,7 @@
 	}
 	r = (r << 6) | (v1 << 3);
 
-	s = lwasm_evaluate_expr(as, l, *p, NULL);
+	s = lwasm_evaluate_expr(as, l, *p, NULL, 0);
 	if (!s)
 	{
 		register_error(as, l, 1, "Bad operand");
@@ -114,7 +114,7 @@
 	if (**p == '<')
 		(*p)++;
 			
-	s = lwasm_evaluate_expr(as, l, *p, NULL);
+	s = lwasm_evaluate_expr(as, l, *p, NULL, 0);
 	if (!s)
 	{
 		register_error(as, l, 1, "Bad operand");
--- a/src/insn_indexed.c	Sat Jan 17 07:35:18 2009 +0000
+++ b/src/insn_indexed.c	Fri Jan 23 03:36:27 2009 +0000
@@ -67,6 +67,7 @@
 	int f8 = 0, f16 = 0, f0 = 0;
 	int r, v;
 	int indir = 0;
+	int fs8 = 0, fs16 = 0;
 	
 	// initialize output bytes
 	*b1 = *b2 = *b3 = -1;
@@ -156,12 +157,12 @@
 
 	if (**p == '<')
 	{
-		f8 = 1;
+		fs8 = 1;
 		(*p)++;
 	}
 	else if (**p == '>')
 	{
-		f16 = 1;
+		fs16 = 1;
 		(*p)++;
 	}
 
@@ -176,13 +177,6 @@
 	{
 		return;
 	}
-	if (f8 && r != 0)
-	{
-		register_error(as, l, 2, "Illegal external or inter-section reference");
-		r = 0;
-		v = 0;
-	}
-
 	// now look for a comma; if not present, explode
 	if (*(*p)++ != ',')
 	{
@@ -264,8 +258,36 @@
 	// PCR? then we have PC relative addressing (like B??, LB??)
 	if (rn == 5)
 	{
-		// FIXME: handle external references sensibly
-		v -= as -> addr;
+		lwasm_expr_term_t *t;
+		// external references are handled exactly the same as for
+		// relative addressing modes
+		// on pass 1, adjust the expression for a subtraction of the
+		// current address
+		
+		// need to re-evaluate the expression with "SECTCONST"...
+		r = lwasm_expr_result2(as, l, (char **)p, EXPR_SECTCONST | EXPR_REEVAL, &v, 0);
+		if (r != 0)
+			v = 0;
+		if (as -> passnum == 1)
+		{
+			l -> fsize = 0;
+		}
+		f8 = f16 = 0;
+		if (r == 1 && as -> passnum == 1 && !fs8)
+		{
+			l -> fsize = 2;	
+			f16 = 1;
+		}
+		if (fs8)
+			f8 = 1;
+		if (fs16)
+			f16 = 1;
+		if (l -> fsize == 2)
+			f16 = 1;
+		else if (l -> fsize == 1)
+			f8 = 1;
+		if (as -> passnum == 1)
+			v -= as -> addr;
 		
 		// we have a slight problem here
 		// PCR based on current insn loc is really
@@ -276,22 +298,71 @@
 		// (and that also avoids errors with two byte opcodes, etc)
 		if (f8 || (!f16 && v >= -125 && v <= 130))
 		{
+			f8 = 1;
+			l -> fsize = 1;
 			*b1 = indir | 0x8C;
-			v -= 2;
+			if (as -> passnum == 1)
+				v -= 2;
 			if (v < -128 || v > 127)
 				register_error(as, l, 2, "Byte overflow");
 			*b2 = v & 0xff;
-			return;
+			if (r != 0 && as -> passnum == 2)
+			{
+				register_error(as, l, 2, "Illegal incomplete reference");
+			}
+			goto finpcr;
 		}
 		
 		// anything else is 16 bit offset
 		// need 16 bit
+		
+		l -> fsize = 2;
 		*b1 = indir | 0x8D;
-		v -= 3;
+		if (as -> passnum == 1)
+			v -= 3;
 		*b2 = (v >> 8) & 0xff;
 		*b3 = v & 0xff;
+		if (as -> passnum == 2 && r == 1)
+		{
+			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);
+		}
+
+	finpcr:
+		if (as -> passnum == 1)
+		{
+			// need to adjust the expression
+			if (l -> exprs[0])
+			{
+				t = lwasm_expr_term_create_int(as -> addr + (f8 ? 2 : 3));
+				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 + (f8 ? 2 : 3);
+			}
+		}
 		return;
 	}
+	if (fs16)
+		f16 = 1;
+	if (fs8)
+		f8 = 1;
+
+	if (f8 && r != 0)
+	{
+		register_error(as, l, 2, "Illegal external or inter-section reference");
+		r = 0;
+		v = 0;
+	}
 
 	// constant offset from PC (using PC as regular register :) )
 	// FIXME: handle external references intelligently
--- a/src/insn_rel.c	Sat Jan 17 07:35:18 2009 +0000
+++ b/src/insn_rel.c	Fri Jan 23 03:36:27 2009 +0000
@@ -38,7 +38,7 @@
 	
 	lwasm_emitop(as, l, instab[opnum].ops[0]);
 
-	if ((r = lwasm_expr_result2(as, l, p, 0, &v, 0)) < 0)
+	if ((r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST, &v, 0)) < 0)
 		v = 0;
 	else
 	{
@@ -81,7 +81,7 @@
 	
 	lwasm_emitop(as, l, instab[opnum].ops[0]);
 	
-	r = lwasm_expr_result2(as, l, p, 0, &v, 0);
+	r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST, &v, 0);
 	if (r < 0)
 		v = 0;
 	else
@@ -105,7 +105,19 @@
 		}
 	}
 	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);
 }
--- a/src/lwasm.c	Sat Jan 17 07:35:18 2009 +0000
+++ b/src/lwasm.c	Fri Jan 23 03:36:27 2009 +0000
@@ -173,6 +173,7 @@
 {
 	asmstate_t *as;
 	lwasm_line_t *l;
+	int flags;
 };	
 
 lwasm_expr_stack_t *lwasm_expr_lookup_symbol(char *sym, void *state)
@@ -225,9 +226,18 @@
 	{
 		return NULL;
 	}
+	if (st -> flags & EXPR_SECTCONST)
+	{
+		if (se -> sect == st -> l -> sect)
+		{
+			if (se -> expr)
+				goto retsym;
+			val = se -> value;
+			goto retconst;
+		}
+	}
 	if (st -> as -> outformat == OUTPUT_OBJ && se -> sect != NULL)
 	{
-		// do not resolve any section symbols in object mode
 		return NULL;
 	}
 	if (st -> as -> outformat != OUTPUT_OBJ || se -> sect == NULL)
@@ -236,6 +246,7 @@
 		val = se -> value;
 		goto retconst;
 	}
+	
 	// an intersegment reference will return as NULL (to be resolved at output/link time)
 	// if se -> expr is NULL, it has to be an intersegment reference here
 	if (se -> expr == NULL)
@@ -243,6 +254,7 @@
 		return NULL;
 	}
 	
+retsym:
 	// duplicate the expression for return
 	rs = lwasm_expr_stack_create();
 	for (n = se -> expr -> head; n; n = n -> next)
@@ -259,12 +271,13 @@
 	return rs;
 }
 
-lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp)
+lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags)
 {
 	struct symstateinfo st;
 	
 	st.as = as;
 	st.l = l;
+	st.flags = flags;
 	
 	debug_message(2, "Evaluate expression: %s", inp);
 	
@@ -272,13 +285,13 @@
 }
 
 
-int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s)
+int lwasm_reevaluate_expr(asmstate_t *as, lwasm_line_t *l, lwasm_expr_stack_t *s, int flags)
 {
 	struct symstateinfo st;
 	
 	st.as = as;
 	st.l = l;
-	
+	st.flags = flags;
 	return(lwasm_expr_reval(s, lwasm_expr_lookup_symbol, &st));
 }
 
@@ -322,9 +335,9 @@
 	const char *ep;
 	int rval;
 
-	if (as -> passnum == 1 || slot < 0)
+	if ((as -> passnum == 1 && !(flag & EXPR_REEVAL)) || slot < 0)
 	{		
-		s = lwasm_evaluate_expr(as, l, *inp, &ep);
+		s = lwasm_evaluate_expr(as, l, *inp, &ep, flag);
 		if (slot >= 0)
 			l -> exprs[slot] = s;
 		if (!s)
@@ -343,7 +356,7 @@
 	else if (l -> exprs[slot])
 	{
 		s = l -> exprs[slot];
-		lwasm_reevaluate_expr(as, l, s);
+		lwasm_reevaluate_expr(as, l, s, flag);
 		l -> exprvals[slot] = lwasm_expr_get_value(s);
 	}
 	if (as -> passnum == 2 && slot >= 0)
--- a/src/lwasm.h	Sat Jan 17 07:35:18 2009 +0000
+++ b/src/lwasm.h	Fri Jan 23 03:36:27 2009 +0000
@@ -196,7 +196,7 @@
 __lwasm_E__ int lwasm_lookupreg2(const char *reglist, char **str);
 __lwasm_E__ int lwasm_lookupreg3(const char *rlist, const char **str);
 
-__lwasm_E__ lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp);
+__lwasm_E__ lwasm_expr_stack_t *lwasm_evaluate_expr(asmstate_t *as, lwasm_line_t *l, const char *inp, const char **outp, int flags);
 
 
 // return next context number and update it
@@ -206,7 +206,8 @@
 // return 0 on ok, -1 on error, 1 if a complex expression was returned
 #define EXPR_NOFLAG			0
 #define EXPR_PASS1CONST		1	// no forward references on pass 1
-
+#define EXPR_SECTCONST		2	// resolve symbols local to section
+#define EXPR_REEVAL			4	// re-evaluate the expression
 __lwasm_E__ int lwasm_expr_result(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val);
 __lwasm_E__ int lwasm_expr_result2(asmstate_t *as, lwasm_line_t *l, char **inp, int flag, int *val, int slot);
 
--- a/src/parse.c	Sat Jan 17 07:35:18 2009 +0000
+++ b/src/parse.c	Fri Jan 23 03:36:27 2009 +0000
@@ -45,6 +45,7 @@
 		return;
 	
 	p = l -> text;
+	l -> sect = as -> csect;
 
 	// blank lines are a no brainer
 	if (!*p)