From b1cd730db2dc3719e451b5eb6fb91c26b3715d4d Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Tue, 14 Jan 2020 00:02:22 +0100 Subject: [PATCH] Add link-time RST instruction This allows using a label as the argument to a `rst` instruction Fixes rednex#448 --- include/asm/rpn.h | 1 + include/linkdefs.h | 1 + src/asm/asmy.y | 7 ++++--- src/asm/rpn.c | 7 +++++++ src/link/patch.c | 11 +++++++++++ src/rgbds.5 | 4 +++- test/asm/rst.asm | 35 +++++++++++++++++++++++++++++++++++ test/asm/rst.err | 0 test/asm/rst.out | 0 test/link/rst-bad.asm | 3 +++ test/link/rst-bad.out | 1 + test/link/rst.asm | 31 +++++++++++++++++++++++++++++++ test/link/rst.out | 0 test/link/rst.out.bin | 1 + 14 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 test/asm/rst.asm create mode 100644 test/asm/rst.err create mode 100644 test/asm/rst.out create mode 100644 test/link/rst-bad.asm create mode 100644 test/link/rst-bad.out create mode 100644 test/link/rst.asm create mode 100644 test/link/rst.out create mode 100644 test/link/rst.out.bin diff --git a/include/asm/rpn.h b/include/asm/rpn.h index 6fdb5ddc..24fed5cb 100644 --- a/include/asm/rpn.h +++ b/include/asm/rpn.h @@ -74,5 +74,6 @@ void rpn_BankSelf(struct Expression *expr); 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 */ diff --git a/include/linkdefs.h b/include/linkdefs.h index d2fa00c7..b9f6fdcd 100644 --- a/include/linkdefs.h +++ b/include/linkdefs.h @@ -47,6 +47,7 @@ enum RPNCommand { RPN_BANK_SELF = 0x52, RPN_HRAM = 0x60, + RPN_RST = 0x61, RPN_CONST = 0x80, RPN_SYM = 0x81 diff --git a/src/asm/asmy.y b/src/asm/asmy.y index 5b5b06b7..d32873bb 100644 --- a/src/asm/asmy.y +++ b/src/asm/asmy.y @@ -2065,9 +2065,10 @@ z80_rrca : T_Z80_RRCA 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); diff --git a/src/asm/rpn.c b/src/asm/rpn.c index b4f9ba33..8adff069 100644 --- a/src/asm/rpn.c +++ b/src/asm/rpn.c @@ -242,6 +242,13 @@ void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src) 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; diff --git a/src/link/patch.c b/src/link/patch.c index 2e8c76d5..50ae73ca 100644 --- a/src/link/patch.c +++ b/src/link/patch.c @@ -284,6 +284,17 @@ static int32_t computeRPNExpr(struct Patch const *patch, 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) diff --git a/src/rgbds.5 b/src/rgbds.5 index 2373753d..03ef6407 100644 --- a/src/rgbds.5 +++ b/src/rgbds.5 @@ -170,7 +170,9 @@ Symbol ID follows. 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 diff --git a/test/asm/rst.asm b/test/asm/rst.asm new file mode 100644 index 00000000..09dafe84 --- /dev/null +++ b/test/asm/rst.asm @@ -0,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 diff --git a/test/asm/rst.err b/test/asm/rst.err new file mode 100644 index 00000000..e69de29b diff --git a/test/asm/rst.out b/test/asm/rst.out new file mode 100644 index 00000000..e69de29b diff --git a/test/link/rst-bad.asm b/test/link/rst-bad.asm new file mode 100644 index 00000000..fe713c4c --- /dev/null +++ b/test/link/rst-bad.asm @@ -0,0 +1,3 @@ +SECTION "bad", ROM0[0] + rst bad +bad: ; This is not at a RST vector! diff --git a/test/link/rst-bad.out b/test/link/rst-bad.out new file mode 100644 index 00000000..6783e4d5 --- /dev/null +++ b/test/link/rst-bad.out @@ -0,0 +1 @@ +error: rst-bad.asm(2): Value 1 is not a RST vector diff --git a/test/link/rst.asm b/test/link/rst.asm new file mode 100644 index 00000000..14df973d --- /dev/null +++ b/test/link/rst.asm @@ -0,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 diff --git a/test/link/rst.out b/test/link/rst.out new file mode 100644 index 00000000..e69de29b diff --git a/test/link/rst.out.bin b/test/link/rst.out.bin new file mode 100644 index 00000000..1df237de --- /dev/null +++ b/test/link/rst.out.bin @@ -0,0 +1 @@ +ÇÏ×ßçï÷ÿ \ No newline at end of file