changeset 377:67373a053c49

Add ?rts target for branch instructions Add a ?rts target for branch instructions, which brances to the nearest RTS or inverts the branch logic to branch around a generated RTS. Activated by a pragma "qrts". Thanks to Erik G <erik@6809.org> for the patch.
author William Astle <lost@l-w.ca>
date Mon, 13 Jul 2015 20:50:02 -0600
parents 35d4213e6657
children b0ec15f95563
files lwasm/insn_rel.c lwasm/lwasm.h lwasm/pragma.c lwlib/lw_expr.c lwlib/lw_expr.h
diffstat 5 files changed, 83 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/lwasm/insn_rel.c	Mon Jul 13 20:47:30 2015 -0600
+++ b/lwasm/insn_rel.c	Mon Jul 13 20:50:02 2015 -0600
@@ -25,6 +25,7 @@
 #include <ctype.h>
 #include <stdlib.h>
 #include <stdio.h>
+#include <string.h>
 
 #include <lw_expr.h>
 
@@ -47,7 +48,7 @@
 */
 PARSEFUNC(insn_parse_relgen)
 {
-	lw_expr_t t, e1, e2;
+	lw_expr_t t = NULL, e1, e2;
 	
 	l -> lint = -1;
 	l -> maxlen = OPLEN(instab[l -> insn].ops[3]) + 2;
@@ -76,7 +77,69 @@
 	if (**p == '#')
 		(*p)++;
 
-	t = lwasm_parse_expr(as, p);
+	if (CURPRAGMA(l, PRAGMA_QRTS))
+	{
+		// handle ?RTS conditional return
+		if (**p == '?')
+		{
+			if (strncasecmp(*p, "?RTS", 4) == 0)
+			{
+				(*p) += 4;
+
+				line_t *cl = l;
+				for (cl = cl->prev; cl; cl = cl->prev)
+				{
+					if (cl->insn == -1)
+						continue;
+
+					if (l->addr->value - cl->addr->value > 128)
+					{
+						cl = NULL;
+						break;
+					}
+
+					if (cl->conditional_return)
+						break;
+
+					if (instab[cl->insn].ops[0] == 0x39)
+						break;
+				}
+
+				if (cl)
+				{
+					l->lint = -1;
+					if (cl->conditional_return)
+					{
+						e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, cl);
+						e1 = lw_expr_build(lw_expr_type_int, 2);
+						t = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, e2);
+					}
+					else
+					{
+						t = lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, cl);
+					}
+				}
+				else
+				{
+					l->conditional_return = 1;
+
+					// t = * + 1
+
+					e2 = lw_expr_build(lw_expr_type_special, lwasm_expr_lineaddr, l);
+					e1 = lw_expr_build(lw_expr_type_int, 1);
+					t = lw_expr_build(lw_expr_type_oper, lw_expr_oper_plus, e1, e2);
+
+					lw_expr_destroy(e1);
+					lw_expr_destroy(e2);
+				}
+			}
+		}
+	}
+	
+	if (!t)
+	{
+		t = lwasm_parse_expr(as, p);
+	}
 
 	if (!t)
 	{
@@ -88,6 +151,7 @@
 	if (l -> lint == 8)
 	{
 		l -> len = OPLEN(instab[l -> insn].ops[2]) + 1;
+		if (l->conditional_return) l->len++;
 	}
 	else if (l -> lint == 16)
 	{
@@ -233,10 +297,19 @@
 			return;
 		}
 
-		lwasm_emitop(l, instab[l -> insn].ops[2]);
-		lwasm_emit(l, offs);
-
-		l -> cycle_adj = 2;
+		if (l->conditional_return)
+		{
+			lwasm_emitop(l, instab[l->insn].ops[2] ^ 1);	/* flip branch, add RTS */
+			lwasm_emit(l, 1);
+			lwasm_emit(l, 0x39);
+			l->cycle_adj = 3;
+		}
+		else
+		{
+			lwasm_emitop(l, instab[l->insn].ops[2]);
+			lwasm_emit(l, offs);
+			l->cycle_adj = 2;
+		}
 	}
 	else
 	{
--- a/lwasm/lwasm.h	Mon Jul 13 20:47:30 2015 -0600
+++ b/lwasm/lwasm.h	Mon Jul 13 20:50:02 2015 -0600
@@ -97,7 +97,8 @@
 	PRAGMA_C					= 1 << 16,	// enable cycle counts
 	PRAGMA_CD					= 1 << 17,	// enable detailed cycle count
 	PRAGMA_CT					= 1 << 18,	// enable cycle count running total
-	PRAGMA_CC					= 1 << 19	// clear cycle count running total
+	PRAGMA_CC					= 1 << 19,	// clear cycle count running total
+	PRAGMA_QRTS					= 1 << 20	// enable BRA ?RTS support
 };
 
 enum
@@ -272,6 +273,7 @@
 	int pb;								// pass forward post byte
 	int lint;							// pass forward integer
 	int lint2;							// another pass forward integer
+	int conditional_return;				// for ?RTS handling (1 if RTS follows)
 	asmstate_t *as;						// assembler state data ptr
 	int pragmas;						// pragmas in effect for the line
 	int context;						// the symbol context number
--- a/lwasm/pragma.c	Mon Jul 13 20:47:30 2015 -0600
+++ b/lwasm/pragma.c	Mon Jul 13 20:50:02 2015 -0600
@@ -68,6 +68,7 @@
 	{ "cc", "nocc", PRAGMA_CC },
 	{ "cd", "nocd", PRAGMA_CD },
 	{ "ct", "noct", PRAGMA_CT },
+	{ "qrts", "noqrts", PRAGMA_QRTS },
 	{ 0, 0, 0 }
 };
 
--- a/lwlib/lw_expr.c	Mon Jul 13 20:47:30 2015 -0600
+++ b/lwlib/lw_expr.c	Mon Jul 13 20:50:02 2015 -0600
@@ -24,7 +24,6 @@
 #include <string.h>
 #include <ctype.h>
 
-#define ___lw_expr_c_seen___
 #include "lw_alloc.h"
 #include "lw_expr.h"
 #include "lw_error.h"
--- a/lwlib/lw_expr.h	Mon Jul 13 20:47:30 2015 -0600
+++ b/lwlib/lw_expr.h	Mon Jul 13 20:50:02 2015 -0600
@@ -55,8 +55,6 @@
 	lw_expr_oper_none = 0
 };
 
-#ifdef ___lw_expr_c_seen___
-
 typedef struct lw_expr_priv * lw_expr_t;
 
 struct lw_expr_opers
@@ -78,10 +76,6 @@
 typedef lw_expr_t lw_expr_fn3_t(char **p, void *priv);
 typedef int lw_expr_testfn_t(lw_expr_t e, void *priv);
 
-#else /* def ___lw_expr_c_seen___ */
-
-typedef void * lw_expr_t;
-
 lw_expr_t lwexpr_create(void);
 void lw_expr_destroy(lw_expr_t E);
 lw_expr_t lw_expr_copy(lw_expr_t E);
@@ -91,10 +85,6 @@
 int lw_expr_compare(lw_expr_t E1, lw_expr_t E2);
 void lw_expr_simplify(lw_expr_t E, void *priv);
 
-typedef lw_expr_t lw_expr_fn_t(int t, void *ptr, void *priv);
-typedef lw_expr_t lw_expr_fn2_t(char *var, void *priv);
-typedef lw_expr_t lw_expr_fn3_t(char **p, void *priv);
-
 void lw_expr_set_special_handler(lw_expr_fn_t *fn);
 void lw_expr_set_var_handler(lw_expr_fn2_t *fn);
 void lw_expr_set_term_parser(lw_expr_fn3_t *fn);
@@ -121,6 +111,4 @@
 
 void lw_expr_setdivzero(void (*fn)(void *priv));
 
-#endif /* def ___lw_expr_c_seen___ */
-
 #endif /* ___lw_expr_h_seen___ */