shithub: rgbds

Download patch

ref: 762474d3ac55df88584a4e663ad3b4f73304671e
parent: b1adbcc77c5ca8f5fbc8d52150979777560565ba
author: ISSOtm <[email protected]>
date: Mon Jul 27 14:11:42 EDT 2020

Let RGBASM write JR offsets in floating sections

This requires some special-casing for `jr @` because the `jr` opcode has
already been emitted, but not the operand, so PC points to the middle.
Moved the RGBLINK test to RGBASM's folder, and created a new RGBLINK test.

--- a/include/asm/rpn.h
+++ b/include/asm/rpn.h
@@ -49,6 +49,8 @@
 void rpn_Symbol(struct Expression *expr, char *tzSym);
 void rpn_Number(struct Expression *expr, uint32_t i);
 void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
+struct Symbol const *rpn_SymbolOf(struct Expression const *expr);
+bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym);
 void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
 		  const struct Expression *src1,
 		  const struct Expression *src2);
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -297,7 +297,7 @@
 	}
 }
 
-static struct Symbol const *symbolOf(struct Expression const *expr)
+struct Symbol const *rpn_SymbolOf(struct Expression const *expr)
 {
 	if (!rpn_isSymbol(expr))
 		return NULL;
@@ -304,20 +304,23 @@
 	return sym_FindSymbol((char *)expr->tRPN + 1);
 }
 
-static bool isDiffConstant(struct Expression const *src1,
-			   struct Expression const *src2)
+bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym)
 {
 	/* Check if both expressions only refer to a single symbol */
-	struct Symbol const *symbol1 = symbolOf(src1);
-	struct Symbol const *symbol2 = symbolOf(src2);
+	struct Symbol const *sym1 = rpn_SymbolOf(src);
 
-	if (!symbol1 || !symbol2
-	 || symbol1->type != SYM_LABEL || symbol2->type != SYM_LABEL)
+	if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL)
 		return false;
 
-	return sym_GetSection(symbol1) == sym_GetSection(symbol2);
+	return sym_GetSection(sym1) == sym_GetSection(sym);
 }
 
+static bool isDiffConstant(struct Expression const *src1,
+			   struct Expression const *src2)
+{
+	return rpn_IsDiffConstant(src1, rpn_SymbolOf(src2));
+}
+
 void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
 		  const struct Expression *src1, const struct Expression *src2)
 {
@@ -428,8 +431,8 @@
 		}
 
 	} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
-		struct Symbol const *symbol1 = symbolOf(src1);
-		struct Symbol const *symbol2 = symbolOf(src2);
+		struct Symbol const *symbol1 = rpn_SymbolOf(src1);
+		struct Symbol const *symbol2 = rpn_SymbolOf(src2);
 
 		expr->nVal = sym_GetValue(symbol1) - sym_GetValue(symbol2);
 		expr->isKnown = true;
--- a/src/asm/section.c
+++ b/src/asm/section.c
@@ -553,15 +553,21 @@
 {
 	checkcodesection();
 	reserveSpace(1);
+	struct Symbol const *pc = sym_FindSymbol("@");
 
-	if (!rpn_isKnown(expr) || pCurrentSection->nOrg == -1) {
+	if (!rpn_IsDiffConstant(expr, pc)) {
 		createPatch(PATCHTYPE_JR, expr);
 		writebyte(0);
 	} else {
-		/* Target is relative to the byte *after* the operand */
-		uint16_t address = sym_GetPCValue() + 1;
-		/* The offset wraps (jump from ROM to HRAM, for loopexample) */
-		int16_t offset = expr->nVal - address;
+		struct Symbol const *sym = rpn_SymbolOf(expr);
+		/* The offset wraps (jump from ROM to HRAM, for example) */
+		int16_t offset;
+
+		/* Offset is relative to the byte *after* the operand */
+		if (sym == pc)
+			offset = -2; /* PC as operand to `jr` is lower than reference PC by 2 */
+		else
+			offset = sym_GetValue(sym) - (sym_GetValue(pc) + 1);
 
 		if (offset < -128 || offset > 127) {
 			yyerror("jr target out of reach (expected -129 < %" PRId16 " < 128)",
--- /dev/null
+++ b/test/asm/[email protected]
@@ -1,0 +1,7 @@
+SECTION "fixed", ROM0[0]
+	jr @
+; We need this section to be floating because RGBASM can know the value of PC
+; otherwise, leading to different behavior
+; FIXME: we rely on this landing at address 2, which isn't *guaranteed*...
+SECTION "floating", ROM0
+	jr @
--- /dev/null
+++ b/test/asm/[email protected]
@@ -1,0 +1,1 @@
+
\ No newline at end of file
--- /dev/null
+++ b/test/asm/jr-section.asm
@@ -1,0 +1,5 @@
+SECTION "Test", ROM0
+
+Label:
+	jr Label
+	PRINTV Label - @
--- /dev/null
+++ b/test/asm/jr-section.out
@@ -1,0 +1,1 @@
+$FFFFFFFE
\ No newline at end of file
--- /dev/null
+++ b/test/asm/jr-section.out.bin
@@ -1,0 +1,1 @@
+
\ No newline at end of file
--- a/test/link/[email protected]
+++ b/test/link/[email protected]
@@ -1,7 +1,3 @@
-SECTION "fixed", ROM0[0]
-	jr @
-; We need this section to be floating because RGBASM can know the value of PC
-; otherwise, leading to different behavior
-; FIXME: we rely on this landing at address 2, which isn't *guaranteed*...
-SECTION "floating", ROM0
-	jr @
+SECTION "Floating", ROM0
+	; RGBASM knows how to compute `jr @` by itself, but this will evade it
+	jr @ - 1 + 1
--- a/test/link/[email protected]
+++ b/test/link/[email protected]
@@ -1,1 +1,1 @@
-
\ No newline at end of file
+
\ No newline at end of file