shithub: rgbds

Download patch

ref: b1cd730db2dc3719e451b5eb6fb91c26b3715d4d
parent: 359a048b6e235aab6e330fc6f85b118da0e9e046
author: ISSOtm <eldredhabert0@gmail.com>
date: Mon Jan 13 19:02:22 EST 2020

Add link-time RST instruction
This allows using a label as the argument to a `rst` instruction
Fixes rednex#448

--- a/include/asm/rpn.h
+++ b/include/asm/rpn.h
@@ -74,5 +74,6 @@
 void rpn_Init(struct Expression *expr);
 void rpn_Free(struct Expression *expr);
 void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
+void rpn_CheckRST(struct Expression *expr, const struct Expression *src);
 
 #endif /* RGBDS_ASM_RPN_H */
--- a/include/linkdefs.h
+++ b/include/linkdefs.h
@@ -47,6 +47,7 @@
 	RPN_BANK_SELF	= 0x52,
 
 	RPN_HRAM	= 0x60,
+	RPN_RST         = 0x61,
 
 	RPN_CONST	= 0x80,
 	RPN_SYM		= 0x81
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -2065,9 +2065,10 @@
 
 z80_rst		: T_Z80_RST const_8bit
 		{
-			if (rpn_isReloc(&$2))
-				yyerror("Address for RST must be absolute");
-			else if (($2.nVal & 0x38) != $2.nVal)
+			if (rpn_isReloc(&$2)) {
+				rpn_CheckRST(&$2, &$2);
+				out_RelByte(&$2);
+			} else if (($2.nVal & 0x38) != $2.nVal)
 				yyerror("Invalid address $%x for RST", $2.nVal);
 			else
 				out_AbsByte(0xC7 | $2.nVal);
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -242,6 +242,13 @@
 	expr->nRPNPatchSize++;
 }
 
+void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
+{
+	*expr = *src;
+	pushbyte(expr, RPN_RST);
+	expr->nRPNPatchSize++;
+}
+
 void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
 {
 	*expr = *src;
--- a/src/link/patch.c
+++ b/src/link/patch.c
@@ -284,6 +284,17 @@
 			value &= 0xFF;
 			break;
 
+		case RPN_RST:
+			value = popRPN();
+			/* Acceptable values are 0x00, 0x08, 0x10, ..., 0x38
+			 * They can be easily checked with a bitmask
+			 */
+			if (value & ~0x38)
+				errx(1, "%s(%d): Value %d is not a RST vector",
+				     patch->fileName, patch->lineNo, value);
+			value |= 0xC7;
+			break;
+
 		case RPN_CONST:
 			value = 0;
 			for (uint8_t shift = 0; shift < 32; shift += 8)
--- a/src/rgbds.5
+++ b/src/rgbds.5
@@ -170,7 +170,9 @@
 a null-terminated string follows.
 .It Li $52 Ta Li Current BANK()
 .It Li $60 Ta Li HRAMCheck .
-Checks if the value is in HRAM, AND it with 0xFF.
+Checks if the value is in HRAM, ANDs it with 0xFF.
+.It Li $61 Ta Li RSTCheck .
+Checks if the value is a RST vector, ORs it with 0xC7.
 .It Li $80 Ta Ar LONG
 integer follows.
 .It Li $81 Ta Ar LONG
--- /dev/null
+++ b/test/asm/rst.asm
@@ -1,0 +1,35 @@
+
+SECTION "calls", ROM0[0]
+
+; The values are not known at this point, forcing the assembler to emit an
+; expression
+	rst rst00
+	rst rst08
+	rst rst10
+	rst rst18
+	rst rst20
+	rst rst28
+	rst rst30
+	rst rst38
+
+	rst rst2A
+
+
+defRST: MACRO
+; FIXME: This is required, otherwise the lexer does not paste the two tokens
+ADDR equs "$\1"
+SECTION "rst\1", ROM0[ADDR]
+
+rst\1:
+	PURGE ADDR
+ENDM
+	defRST 00
+	defRST 08
+	defRST 10
+	defRST 18
+	defRST 20
+	defRST 28
+	defRST 30
+	defRST 38
+
+	defRST 2A ; Define a nonsensical RST, because RGBASM cannot catch it
--- /dev/null
+++ b/test/link/rst-bad.asm
@@ -1,0 +1,3 @@
+SECTION "bad", ROM0[0]
+	rst bad
+bad: ; This is not at a RST vector!
--- /dev/null
+++ b/test/link/rst-bad.out
@@ -1,0 +1,1 @@
+error: rst-bad.asm(2): Value 1 is not a RST vector
--- /dev/null
+++ b/test/link/rst.asm
@@ -1,0 +1,31 @@
+
+SECTION "calls", ROM0[0]
+
+; The values are not known at this point, forcing the assembler to emit an
+; expression
+	rst rst00
+	rst rst08
+	rst rst10
+	rst rst18
+	rst rst20
+	rst rst28
+	rst rst30
+	rst rst38
+
+
+defRST: MACRO
+; FIXME: This is required, otherwise the lexer does not paste the two tokens
+ADDR equs "$\1"
+SECTION "rst\1", ROM0[ADDR]
+
+rst\1:
+	PURGE ADDR
+ENDM
+	defRST 00
+	defRST 08
+	defRST 10
+	defRST 18
+	defRST 20
+	defRST 28
+	defRST 30
+	defRST 38
--- /dev/null
+++ b/test/link/rst.out.bin
@@ -1,0 +1,1 @@
+������
\ No newline at end of file