From 359a048b6e235aab6e330fc6f85b118da0e9e046 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 13 Jan 2020 15:25:25 +0100 Subject: [PATCH 1/7] Bump object version number We're about to break the format, so let's do this --- src/link/object.c | 111 +++++++++++++++++++++++++++++++++++++++++++--- src/rgbds.5 | 2 +- 2 files changed, 107 insertions(+), 6 deletions(-) diff --git a/src/link/object.c b/src/link/object.c index 5082e695..cb87e044 100644 --- a/src/link/object.c +++ b/src/link/object.c @@ -426,6 +426,99 @@ static void readRGB6File(FILE *file, char const *fileName) } } +/** + * Reads a RGB7 object file. + * @param file The file to read from + * @param fileName The filename to report in errors + */ +static void readRGB7File(FILE *file, char const *fileName) +{ + uint32_t nbSymbols; + uint32_t nbSections; + + tryReadlong(nbSymbols, file, "%s: Cannot read number of symbols: %s", + fileName); + tryReadlong(nbSections, file, "%s: Cannot read number of sections: %s", + fileName); + + nbSectionsToAssign += nbSections; + + /* This file's symbols, kept to link sections to them */ + struct Symbol **fileSymbols = + malloc(sizeof(*fileSymbols) * nbSymbols + 1); + + if (!fileSymbols) + err(1, "Failed to get memory for %s's symbols", fileName); + + struct SymbolList *symbolList = malloc(sizeof(*symbolList)); + + if (!symbolList) + err(1, "Failed to register %s's symbol list", fileName); + symbolList->symbolList = fileSymbols; + symbolList->nbSymbols = nbSymbols; + symbolList->next = symbolLists; + symbolLists = symbolList; + + uint32_t nbSymPerSect[nbSections ? nbSections : 1]; + + memset(nbSymPerSect, 0, sizeof(nbSymPerSect)); + + verbosePrint("Reading %u symbols...\n", nbSymbols); + for (uint32_t i = 0; i < nbSymbols; i++) { + /* Read symbol */ + struct Symbol *symbol = malloc(sizeof(*symbol)); + + if (!symbol) + err(1, "%s: Couldn't create new symbol", fileName); + readSymbol(file, symbol, fileName); + + fileSymbols[i] = symbol; + if (symbol->type == SYMTYPE_EXPORT) + sym_AddSymbol(symbol); + if (symbol->sectionID != -1) + nbSymPerSect[symbol->sectionID]++; + } + + /* This file's sections, stored in a table to link symbols to them */ + struct Section *fileSections[nbSections ? nbSections : 1]; + + verbosePrint("Reading %u sections...\n", nbSections); + for (uint32_t i = 0; i < nbSections; i++) { + /* Read section */ + struct Section *section = malloc(sizeof(*section)); + + if (!section) + err(1, "%s: Couldn't create new section", fileName); + readSection(file, section, fileName); + section->fileSymbols = fileSymbols; + + sect_AddSection(section); + fileSections[i] = section; + if (nbSymPerSect[i]) { + section->symbols = malloc(sizeof(*section->symbols) + * nbSymPerSect[i]); + if (!section->symbols) + err(1, "%s: Couldn't link to symbols"); + } else { + section->symbols = NULL; + } + section->nbSymbols = 0; + } + + /* Give symbols pointers to their sections */ + for (uint32_t i = 0; i < nbSymbols; i++) { + int32_t sectionID = fileSymbols[i]->sectionID; + + if (sectionID == -1) { + fileSymbols[i]->section = NULL; + } else { + fileSymbols[i]->section = fileSections[sectionID]; + /* Give the section a pointer to the symbol as well */ + linkSymToSect(fileSymbols[i], fileSections[sectionID]); + } + } +} + /** * Reads an object file of any supported format * @param fileName The filename to report for errors @@ -446,16 +539,24 @@ void obj_ReadFile(char const *fileName) if (matchedElems != 1) errx(1, "\"%s\" is not a RGBDS object file", fileName); - /* TODO: support other versions? */ - if (versionNumber != 6) - errx(1, "\"%s\" is an incompatible version %hhu object file", - fileName, versionNumber); verbosePrint("Reading object file %s, version %hhu\n", fileName, versionNumber); - readRGB6File(file, fileName); + switch (versionNumber) { + case 6: + readRGB6File(file, fileName); + break; + case 7: + readRGB7File(file, fileName); + break; + + /* TODO: support older versions? */ + default: + errx(1, "\"%s\" is an incompatible version %hhu object file", + fileName, versionNumber); + } fclose(file); } diff --git a/src/rgbds.5 b/src/rgbds.5 index bde7b013..2373753d 100644 --- a/src/rgbds.5 +++ b/src/rgbds.5 @@ -33,7 +33,7 @@ is a 0‐terminated string of .Bd -literal ; Header -BYTE ID[4] ; "RGB6" +BYTE ID[4] ; "RGB7" LONG NumberOfSymbols ; The number of symbols used in this file LONG NumberOfSections ; The number of sections used in this file From b1cd730db2dc3719e451b5eb6fb91c26b3715d4d Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Tue, 14 Jan 2020 00:02:22 +0100 Subject: [PATCH 2/7] 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 From d73fa0977437e81a213bc4663aa66ff86304f868 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 27 Jan 2020 08:42:04 +0100 Subject: [PATCH 3/7] Remove RGB6 parsing --- src/link/object.c | 109 ++-------------------------------------------- 1 file changed, 4 insertions(+), 105 deletions(-) diff --git a/src/link/object.c b/src/link/object.c index cb87e044..82c8f099 100644 --- a/src/link/object.c +++ b/src/link/object.c @@ -333,99 +333,6 @@ static void linkSymToSect(struct Symbol const *symbol, struct Section *section) section->nbSymbols++; } -/** - * Reads a RGB6 object file. - * @param file The file to read from - * @param fileName The filename to report in errors - */ -static void readRGB6File(FILE *file, char const *fileName) -{ - uint32_t nbSymbols; - uint32_t nbSections; - - tryReadlong(nbSymbols, file, "%s: Cannot read number of symbols: %s", - fileName); - tryReadlong(nbSections, file, "%s: Cannot read number of sections: %s", - fileName); - - nbSectionsToAssign += nbSections; - - /* This file's symbols, kept to link sections to them */ - struct Symbol **fileSymbols = - malloc(sizeof(*fileSymbols) * nbSymbols + 1); - - if (!fileSymbols) - err(1, "Failed to get memory for %s's symbols", fileName); - - struct SymbolList *symbolList = malloc(sizeof(*symbolList)); - - if (!symbolList) - err(1, "Failed to register %s's symbol list", fileName); - symbolList->symbolList = fileSymbols; - symbolList->nbSymbols = nbSymbols; - symbolList->next = symbolLists; - symbolLists = symbolList; - - uint32_t nbSymPerSect[nbSections ? nbSections : 1]; - - memset(nbSymPerSect, 0, sizeof(nbSymPerSect)); - - verbosePrint("Reading %u symbols...\n", nbSymbols); - for (uint32_t i = 0; i < nbSymbols; i++) { - /* Read symbol */ - struct Symbol *symbol = malloc(sizeof(*symbol)); - - if (!symbol) - err(1, "%s: Couldn't create new symbol", fileName); - readSymbol(file, symbol, fileName); - - fileSymbols[i] = symbol; - if (symbol->type == SYMTYPE_EXPORT) - sym_AddSymbol(symbol); - if (symbol->sectionID != -1) - nbSymPerSect[symbol->sectionID]++; - } - - /* This file's sections, stored in a table to link symbols to them */ - struct Section *fileSections[nbSections ? nbSections : 1]; - - verbosePrint("Reading %u sections...\n", nbSections); - for (uint32_t i = 0; i < nbSections; i++) { - /* Read section */ - struct Section *section = malloc(sizeof(*section)); - - if (!section) - err(1, "%s: Couldn't create new section", fileName); - readSection(file, section, fileName); - section->fileSymbols = fileSymbols; - - sect_AddSection(section); - fileSections[i] = section; - if (nbSymPerSect[i]) { - section->symbols = malloc(sizeof(*section->symbols) - * nbSymPerSect[i]); - if (!section->symbols) - err(1, "%s: Couldn't link to symbols"); - } else { - section->symbols = NULL; - } - section->nbSymbols = 0; - } - - /* Give symbols pointers to their sections */ - for (uint32_t i = 0; i < nbSymbols; i++) { - int32_t sectionID = fileSymbols[i]->sectionID; - - if (sectionID == -1) { - fileSymbols[i]->section = NULL; - } else { - fileSymbols[i]->section = fileSections[sectionID]; - /* Give the section a pointer to the symbol as well */ - linkSymToSect(fileSymbols[i], fileSections[sectionID]); - } - } -} - /** * Reads a RGB7 object file. * @param file The file to read from @@ -543,20 +450,12 @@ void obj_ReadFile(char const *fileName) verbosePrint("Reading object file %s, version %hhu\n", fileName, versionNumber); - switch (versionNumber) { - case 6: - readRGB6File(file, fileName); - break; - - case 7: - readRGB7File(file, fileName); - break; - - /* TODO: support older versions? */ - default: + if (versionNumber != 7) errx(1, "\"%s\" is an incompatible version %hhu object file", fileName, versionNumber); - } + + readRGB7File(file, fileName); + fclose(file); } From fa1fba7fd9f61197ee7b94a5aa4b949237c7ecbc Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 27 Jan 2020 08:48:43 +0100 Subject: [PATCH 4/7] Increase object version to RGB9 --- include/linkdefs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linkdefs.h b/include/linkdefs.h index b9f6fdcd..fa33b636 100644 --- a/include/linkdefs.h +++ b/include/linkdefs.h @@ -13,7 +13,7 @@ #include #define RGBDS_OBJECT_VERSION_STRING "RGB%1hhu" -#define RGBDS_OBJECT_VERSION_NUMBER (uint8_t)6 +#define RGBDS_OBJECT_VERSION_NUMBER (uint8_t)9 enum RPNCommand { RPN_ADD = 0x00, From f3635416112b6444c0f1dd53744a72b3e05c9c19 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 27 Jan 2020 10:06:17 +0100 Subject: [PATCH 5/7] Introduce revision number field --- include/linkdefs.h | 1 + src/asm/output.c | 1 + src/link/object.c | 14 ++++++++++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/include/linkdefs.h b/include/linkdefs.h index fa33b636..f917ad81 100644 --- a/include/linkdefs.h +++ b/include/linkdefs.h @@ -14,6 +14,7 @@ #define RGBDS_OBJECT_VERSION_STRING "RGB%1hhu" #define RGBDS_OBJECT_VERSION_NUMBER (uint8_t)9 +#define RGBDS_OBJECT_REV 0 enum RPNCommand { RPN_ADD = 0x00, diff --git a/src/asm/output.c b/src/asm/output.c index 80833db1..e1839d08 100644 --- a/src/asm/output.c +++ b/src/asm/output.c @@ -542,6 +542,7 @@ void out_WriteObject(void) fatalerror("Couldn't write file '%s'\n", tzObjectname); fprintf(f, RGBDS_OBJECT_VERSION_STRING, RGBDS_OBJECT_VERSION_NUMBER); + fputlong(RGBDS_OBJECT_REV, f); fputlong(countsymbols(), f); fputlong(countsections(), f); diff --git a/src/link/object.c b/src/link/object.c index 82c8f099..01f520c7 100644 --- a/src/link/object.c +++ b/src/link/object.c @@ -340,6 +340,14 @@ static void linkSymToSect(struct Symbol const *symbol, struct Section *section) */ static void readRGB7File(FILE *file, char const *fileName) { + uint32_t revNum; + + tryReadlong(revNum, file, "%s: Cannot read revision number: %s", + fileName); + if (revNum != RGBDS_OBJECT_REV) + errx(1, "%s is a revision 0x%04x object file, only 0x%04x is supported", + fileName, revNum, RGBDS_OBJECT_REV); + uint32_t nbSymbols; uint32_t nbSections; @@ -434,10 +442,8 @@ void obj_ReadFile(char const *fileName) { FILE *file = strcmp("-", fileName) ? fopen(fileName, "rb") : stdin; - if (!file) { + if (!file) err(1, "Could not open file %s", fileName); - return; - } /* Begin by reading the magic bytes and version number */ uint8_t versionNumber; @@ -450,7 +456,7 @@ void obj_ReadFile(char const *fileName) verbosePrint("Reading object file %s, version %hhu\n", fileName, versionNumber); - if (versionNumber != 7) + if (versionNumber != RGBDS_OBJECT_VERSION_NUMBER) errx(1, "\"%s\" is an incompatible version %hhu object file", fileName, versionNumber); From a7cb0a166ad9c6844b7b0cf216278ff137846081 Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 3 Feb 2020 21:01:38 +0100 Subject: [PATCH 6/7] Inline `readRGBxObject` This was made separate with the intention of supporting multiple versions, but after some discussion this was decided against, so better improve readability instead. --- src/link/object.c | 56 +++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/src/link/object.c b/src/link/object.c index 01f520c7..7dcb2518 100644 --- a/src/link/object.c +++ b/src/link/object.c @@ -334,12 +334,31 @@ static void linkSymToSect(struct Symbol const *symbol, struct Section *section) } /** - * Reads a RGB7 object file. - * @param file The file to read from - * @param fileName The filename to report in errors + * Reads an object file of any supported format + * @param fileName The filename to report for errors */ -static void readRGB7File(FILE *file, char const *fileName) +void obj_ReadFile(char const *fileName) { + FILE *file = strcmp("-", fileName) ? fopen(fileName, "rb") : stdin; + + if (!file) + err(1, "Could not open file %s", fileName); + + /* Begin by reading the magic bytes and version number */ + uint8_t versionNumber; + int matchedElems = fscanf(file, RGBDS_OBJECT_VERSION_STRING, + &versionNumber); + + if (matchedElems != 1) + errx(1, "\"%s\" is not a RGBDS object file", fileName); + + verbosePrint("Reading object file %s, version %hhu\n", + fileName, versionNumber); + + if (versionNumber != RGBDS_OBJECT_VERSION_NUMBER) + errx(1, "\"%s\" is an incompatible version %hhu object file", + fileName, versionNumber); + uint32_t revNum; tryReadlong(revNum, file, "%s: Cannot read revision number: %s", @@ -432,35 +451,6 @@ static void readRGB7File(FILE *file, char const *fileName) linkSymToSect(fileSymbols[i], fileSections[sectionID]); } } -} - -/** - * Reads an object file of any supported format - * @param fileName The filename to report for errors - */ -void obj_ReadFile(char const *fileName) -{ - FILE *file = strcmp("-", fileName) ? fopen(fileName, "rb") : stdin; - - if (!file) - err(1, "Could not open file %s", fileName); - - /* Begin by reading the magic bytes and version number */ - uint8_t versionNumber; - int matchedElems = fscanf(file, RGBDS_OBJECT_VERSION_STRING, - &versionNumber); - - if (matchedElems != 1) - errx(1, "\"%s\" is not a RGBDS object file", fileName); - - verbosePrint("Reading object file %s, version %hhu\n", - fileName, versionNumber); - - if (versionNumber != RGBDS_OBJECT_VERSION_NUMBER) - errx(1, "\"%s\" is an incompatible version %hhu object file", - fileName, versionNumber); - - readRGB7File(file, fileName); fclose(file); } From 652db60ad6520e359dab92ef1aa53e907641666c Mon Sep 17 00:00:00 2001 From: ISSOtm Date: Mon, 3 Feb 2020 21:05:28 +0100 Subject: [PATCH 7/7] Document modifications made to object file format --- src/rgbds.5 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rgbds.5 b/src/rgbds.5 index 03ef6407..0114138f 100644 --- a/src/rgbds.5 +++ b/src/rgbds.5 @@ -33,7 +33,8 @@ is a 0‐terminated string of .Bd -literal ; Header -BYTE ID[4] ; "RGB7" +BYTE ID[4] ; "RGB9" +LONG RevisionNumber ; The format's revision number this file uses LONG NumberOfSymbols ; The number of symbols used in this file LONG NumberOfSections ; The number of sections used in this file