mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Implement ENDSECTION (#1211)
This commit is contained in:
@@ -74,6 +74,7 @@ void sect_PCRelByte(struct Expression *expr, uint32_t pcShift);
|
|||||||
void sect_BinaryFile(char const *s, int32_t startPos);
|
void sect_BinaryFile(char const *s, int32_t startPos);
|
||||||
void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length);
|
void sect_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length);
|
||||||
|
|
||||||
|
void sect_EndSection(void);
|
||||||
void sect_PushSection(void);
|
void sect_PushSection(void);
|
||||||
void sect_PopSection(void);
|
void sect_PopSection(void);
|
||||||
|
|
||||||
|
|||||||
@@ -714,6 +714,11 @@ SECTION "OAM Data",WRAM0,ALIGN[8] ;\ align to 256 bytes
|
|||||||
SECTION "VRAM Data",ROMX,BANK[2],ALIGN[4] ;\ align to 16 bytes
|
SECTION "VRAM Data",ROMX,BANK[2],ALIGN[4] ;\ align to 16 bytes
|
||||||
.Ed
|
.Ed
|
||||||
.El
|
.El
|
||||||
|
.Pp
|
||||||
|
The current section can be ended without starting a new section by using
|
||||||
|
.Ic ENDSECTION .
|
||||||
|
This directive will clear the section context, so you can no longer write code until you start another section.
|
||||||
|
It can be useful to avoid accidentally defining code or data in the wrong section.
|
||||||
.Ss Section stack
|
.Ss Section stack
|
||||||
.Ic POPS
|
.Ic POPS
|
||||||
and
|
and
|
||||||
@@ -785,7 +790,7 @@ The former is situated in ROM, where the code is stored, the latter in RAM, wher
|
|||||||
.Pp
|
.Pp
|
||||||
You cannot nest
|
You cannot nest
|
||||||
.Ic LOAD
|
.Ic LOAD
|
||||||
blocks, nor can you change the current section within them.
|
blocks, nor can you change or stop the current section within them.
|
||||||
.Pp
|
.Pp
|
||||||
.Ic LOAD
|
.Ic LOAD
|
||||||
blocks can use the
|
blocks can use the
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ size_t charmap_ConvertNext(char const **input, uint8_t **output)
|
|||||||
*input);
|
*input);
|
||||||
|
|
||||||
if (codepointLen == 0)
|
if (codepointLen == 0)
|
||||||
error("Input string is not valid UTF-8!\n");
|
error("Input string is not valid UTF-8\n");
|
||||||
|
|
||||||
// OK because UTF-8 has no NUL in multi-byte chars
|
// OK because UTF-8 has no NUL in multi-byte chars
|
||||||
*input += codepointLen;
|
*input += codepointLen;
|
||||||
|
|||||||
@@ -569,7 +569,7 @@ void fstk_Init(char const *mainPath, size_t maxDepth)
|
|||||||
struct LexerState *state = lexer_OpenFile(mainPath);
|
struct LexerState *state = lexer_OpenFile(mainPath);
|
||||||
|
|
||||||
if (!state)
|
if (!state)
|
||||||
fatalerror("Failed to open main file!\n");
|
fatalerror("Failed to open main file\n");
|
||||||
lexer_SetState(state);
|
lexer_SetState(state);
|
||||||
char const *fileName = lexer_GetFileName();
|
char const *fileName = lexer_GetFileName();
|
||||||
size_t len = strlen(fileName);
|
size_t len = strlen(fileName);
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ static struct KeywordMapping {
|
|||||||
{"DW", T_POP_DW},
|
{"DW", T_POP_DW},
|
||||||
{"DL", T_POP_DL},
|
{"DL", T_POP_DL},
|
||||||
{"SECTION", T_POP_SECTION},
|
{"SECTION", T_POP_SECTION},
|
||||||
|
{"ENDSECTION", T_POP_ENDSECTION},
|
||||||
{"PURGE", T_POP_PURGE},
|
{"PURGE", T_POP_PURGE},
|
||||||
|
|
||||||
{"RSRESET", T_POP_RSRESET},
|
{"RSRESET", T_POP_RSRESET},
|
||||||
@@ -572,7 +573,7 @@ struct KeywordDictNode {
|
|||||||
uint16_t children[0x60 - ' '];
|
uint16_t children[0x60 - ' '];
|
||||||
struct KeywordMapping const *keyword;
|
struct KeywordMapping const *keyword;
|
||||||
// Since the keyword structure is invariant, the min number of nodes is known at compile time
|
// Since the keyword structure is invariant, the min number of nodes is known at compile time
|
||||||
} keywordDict[370] = {0}; // Make sure to keep this correct when adding keywords!
|
} keywordDict[377] = {0}; // Make sure to keep this correct when adding keywords!
|
||||||
|
|
||||||
// Convert a char into its index into the dict
|
// Convert a char into its index into the dict
|
||||||
static uint8_t dictIndex(char c)
|
static uint8_t dictIndex(char c)
|
||||||
|
|||||||
@@ -632,6 +632,7 @@ enum {
|
|||||||
%token T_POP_EXPORT "EXPORT"
|
%token T_POP_EXPORT "EXPORT"
|
||||||
%token T_POP_DB "DB" T_POP_DS "DS" T_POP_DW "DW" T_POP_DL "DL"
|
%token T_POP_DB "DB" T_POP_DS "DS" T_POP_DW "DW" T_POP_DL "DL"
|
||||||
%token T_POP_SECTION "SECTION" T_POP_FRAGMENT "FRAGMENT"
|
%token T_POP_SECTION "SECTION" T_POP_FRAGMENT "FRAGMENT"
|
||||||
|
%token T_POP_ENDSECTION "ENDSECTION"
|
||||||
%token T_POP_RB "RB" T_POP_RW "RW" // There is no T_POP_RL, only T_Z80_RL
|
%token T_POP_RB "RB" T_POP_RW "RW" // There is no T_POP_RL, only T_Z80_RL
|
||||||
%token T_POP_MACRO "MACRO"
|
%token T_POP_MACRO "MACRO"
|
||||||
%token T_POP_ENDM "ENDM"
|
%token T_POP_ENDM "ENDM"
|
||||||
@@ -936,6 +937,7 @@ directive : endc
|
|||||||
| purge
|
| purge
|
||||||
| pops
|
| pops
|
||||||
| pushs
|
| pushs
|
||||||
|
| endsection
|
||||||
| popo
|
| popo
|
||||||
| pusho
|
| pusho
|
||||||
| opt
|
| opt
|
||||||
@@ -1056,6 +1058,9 @@ pops : T_POP_POPS { sect_PopSection(); }
|
|||||||
pushs : T_POP_PUSHS { sect_PushSection(); }
|
pushs : T_POP_PUSHS { sect_PushSection(); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
endsection : T_POP_ENDSECTION { sect_EndSection(); }
|
||||||
|
;
|
||||||
|
|
||||||
fail : T_POP_FAIL string { fatalerror("%s\n", $2); }
|
fail : T_POP_FAIL string { fatalerror("%s\n", $2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -598,7 +598,7 @@ void sect_EndUnion(void)
|
|||||||
void sect_CheckUnionClosed(void)
|
void sect_CheckUnionClosed(void)
|
||||||
{
|
{
|
||||||
if (unionStack)
|
if (unionStack)
|
||||||
error("Unterminated UNION construct!\n");
|
error("Unterminated UNION construct\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output an absolute byte
|
// Output an absolute byte
|
||||||
@@ -965,7 +965,7 @@ void sect_PopSection(void)
|
|||||||
fatalerror("No entries in the section stack\n");
|
fatalerror("No entries in the section stack\n");
|
||||||
|
|
||||||
if (currentLoadSection)
|
if (currentLoadSection)
|
||||||
fatalerror("Cannot change the section within a `LOAD` block!\n");
|
fatalerror("Cannot change the section within a `LOAD` block\n");
|
||||||
|
|
||||||
struct SectionStackEntry *entry = sectionStack;
|
struct SectionStackEntry *entry = sectionStack;
|
||||||
|
|
||||||
@@ -981,6 +981,22 @@ void sect_PopSection(void)
|
|||||||
free(entry);
|
free(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sect_EndSection(void)
|
||||||
|
{
|
||||||
|
if (!currentSection)
|
||||||
|
fatalerror("Cannot end the section outside of a SECTION\n");
|
||||||
|
|
||||||
|
if (currentLoadSection)
|
||||||
|
fatalerror("Cannot end the section within a `LOAD` block\n");
|
||||||
|
|
||||||
|
if (unionStack)
|
||||||
|
fatalerror("Cannot end the section within a UNION\n");
|
||||||
|
|
||||||
|
// Reset the section scope
|
||||||
|
currentSection = NULL;
|
||||||
|
sym_SetCurrentSymbolScope(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
bool sect_IsSizeKnown(struct Section const NONNULL(sect))
|
bool sect_IsSizeKnown(struct Section const NONNULL(sect))
|
||||||
{
|
{
|
||||||
// SECTION UNION and SECTION FRAGMENT can still grow
|
// SECTION UNION and SECTION FRAGMENT can still grow
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ static void registerInput(char const *arg) {
|
|||||||
printUsage();
|
printUsage();
|
||||||
exit(1);
|
exit(1);
|
||||||
} else if (arg[0] == '\0') { // Empty input path
|
} else if (arg[0] == '\0') { // Empty input path
|
||||||
fprintf(stderr, "FATAL: input image path cannot be empty!\n");
|
fprintf(stderr, "FATAL: input image path cannot be empty\n");
|
||||||
printUsage();
|
printUsage();
|
||||||
exit(1);
|
exit(1);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -109,8 +109,8 @@ void reverse() {
|
|||||||
auto const tiles = readInto(options.output);
|
auto const tiles = readInto(options.output);
|
||||||
uint8_t tileSize = 8 * options.bitDepth;
|
uint8_t tileSize = 8 * options.bitDepth;
|
||||||
if (tiles.size() % tileSize != 0) {
|
if (tiles.size() % tileSize != 0) {
|
||||||
fatal("Tile data size must be a multiple of %" PRIu8 " bytes! (Read %zu)", tileSize,
|
fatal("Tile data size (%zu bytes) is not a multiple of %" PRIu8 " bytes",
|
||||||
tiles.size());
|
tiles.size(), tileSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// By default, assume tiles are not deduplicated, and add the (allegedly) trimmed tiles
|
// By default, assume tiles are not deduplicated, and add the (allegedly) trimmed tiles
|
||||||
|
|||||||
4
test/asm/endsection.asm
Normal file
4
test/asm/endsection.asm
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
SECTION "test", ROM0
|
||||||
|
db 1
|
||||||
|
ENDSECTION
|
||||||
|
db 2
|
||||||
3
test/asm/endsection.err
Normal file
3
test/asm/endsection.err
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
error: endsection.asm(4):
|
||||||
|
Cannot output data outside of a SECTION
|
||||||
|
error: Assembly aborted (1 error)!
|
||||||
0
test/asm/endsection.out
Normal file
0
test/asm/endsection.out
Normal file
Reference in New Issue
Block a user