shithub: rgbds

Download patch

ref: eb0d75711a93a6cdfd0bd612bf8e0c1f958d381b
parent: f121119283e746a087cc4e2d347abe7c0fb5664d
author: ISSOtm <[email protected]>
date: Sun Feb 9 11:30:25 EST 2020

Implement `LOAD`/`ENDL` blocks

Basically implements and closes rednex#274.

--- a/include/asm/section.h
+++ b/include/asm/section.h
@@ -25,6 +25,11 @@
 struct Section *out_FindSectionByName(const char *pzName);
 void out_NewSection(char const *pzName, uint32_t secttype, int32_t org,
 		    struct SectionSpec const *attributes);
+void out_SetLoadSection(char const *name, uint32_t secttype, int32_t org,
+			struct SectionSpec const *attributes);
+void out_EndLoadSection(void);
+
+struct Section *sect_GetSymbolSection(void);
 
 void out_AbsByte(uint8_t b);
 void out_AbsByteGroup(uint8_t const *s, int32_t length);
--- a/src/asm/asmy.y
+++ b/src/asm/asmy.y
@@ -575,6 +575,7 @@
 %token	T_POP_POPC
 %token	T_POP_SHIFT
 %token	T_POP_ENDR
+%token	T_POP_LOAD T_POP_ENDL
 %token	T_POP_FAIL
 %token	T_POP_WARN
 %token	T_POP_PURGE
@@ -730,6 +731,7 @@
 		| setcharmap
 		| pushc
 		| popc
+		| load
 		| rept
 		| shift
 		| fail
@@ -776,6 +778,15 @@
 
 shift		: T_POP_SHIFT		{ sym_ShiftCurrentMacroArgs(); }
 ;
+
+load		: T_POP_LOAD string comma sectiontype sectorg sectattrs
+		{
+			out_SetLoadSection($2, $4, $5, &$6);
+		}
+		| T_POP_ENDL
+		{
+			out_EndLoadSection();
+		}
 
 rept		: T_POP_REPT uconst
 		{
--- a/src/asm/globlex.c
+++ b/src/asm/globlex.c
@@ -508,6 +508,9 @@
 	/* Not needed but we have it here just to protect the name */
 	{"endr", T_POP_ENDR},
 
+	{"load", T_POP_LOAD},
+	{"endl", T_POP_ENDL},
+
 	{"if", T_POP_IF},
 	{"else", T_POP_ELSE},
 	{"elif", T_POP_ELIF},
--- a/src/asm/section.c
+++ b/src/asm/section.c
@@ -19,6 +19,7 @@
 };
 
 struct SectionStackEntry *pSectionStack;
+static struct Section *currentLoadSection = NULL;
 
 /*
  * A quick check to see if we have an initialized section
@@ -82,9 +83,39 @@
 /*
  * Find a section by name and type. If it doesn't exist, create it
  */
-static struct Section *findSection(char const *pzName, enum SectionType type,
-				   int32_t org, int32_t bank, int32_t alignment)
+static struct Section *getSection(char const *pzName, enum SectionType type,
+				  int32_t org, int32_t bank, int32_t alignment)
 {
+	if (bank != -1) {
+		if (type != SECTTYPE_ROMX && type != SECTTYPE_VRAM
+		 && type != SECTTYPE_SRAM && type != SECTTYPE_WRAMX)
+			yyerror("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections");
+		else if (bank < bankranges[type][0]
+		      || bank > bankranges[type][1])
+			yyerror("%s bank value $%x out of range ($%x to $%x)",
+				typeNames[type], bank,
+				bankranges[type][0], bankranges[type][1]);
+	}
+
+	if (alignment != 1) {
+		/* It doesn't make sense to have both set */
+		uint32_t mask = alignment - 1;
+
+		if (org != -1) {
+			if (org & mask)
+				yyerror("Section \"%s\"'s fixed address doesn't match its alignment",
+					pzName);
+			else
+				alignment = 1; /* Ignore it if it's satisfied */
+		}
+	}
+
+	if (org != -1) {
+		if (org < startaddr[type] || org > endaddr(type))
+			yyerror("Section \"%s\"'s fixed address %#x is outside of range [%#x; %#x]",
+				pzName, org, startaddr[type], endaddr(type));
+	}
+
 	struct Section *pSect = out_FindSectionByName(pzName);
 
 	if (pSect) {
@@ -140,15 +171,14 @@
 /*
  * Set the current section
  */
-static void setCurrentSection(struct Section *pSect)
+static void setSection(struct Section *pSect)
 {
 	if (nUnionDepth > 0)
 		fatalerror("Cannot change the section within a UNION");
 
-	pCurrentSection = pSect;
 	nPC = (pSect != NULL) ? pSect->nPC : 0;
 
-	pPCSymbol->pSection = pCurrentSection;
+	pPCSymbol->pSection = pSect;
 	pPCSymbol->isConstant = pSect && pSect->nOrg != -1;
 }
 
@@ -155,54 +185,61 @@
 /*
  * Set the current section by name and type
  */
-void out_NewSection(char const *pzName, uint32_t secttype, int32_t org,
+void out_NewSection(char const *pzName, uint32_t type, int32_t org,
 		    struct SectionSpec const *attributes)
 {
-	uint32_t align = 1 << attributes->alignment;
+	if (currentLoadSection)
+		fatalerror("Cannot change the section within a `LOAD` block");
 
-	if (attributes->bank != -1) {
-		if (secttype != SECTTYPE_ROMX && secttype != SECTTYPE_VRAM
-		 && secttype != SECTTYPE_SRAM && secttype != SECTTYPE_WRAMX)
-			yyerror("BANK only allowed for ROMX, WRAMX, SRAM, or VRAM sections");
-		else if (attributes->bank < bankranges[secttype][0]
-		      || attributes->bank > bankranges[secttype][1])
-			yyerror("%s bank value $%x out of range ($%x to $%x)",
-				typeNames[secttype], attributes->bank,
-				bankranges[secttype][0],
-				bankranges[secttype][1]);
-	}
+	struct Section *pSect = getSection(pzName, type, org, attributes->bank,
+					   1 << attributes->alignment);
 
-	if (align != 1) {
-		/* It doesn't make sense to have both set */
-		uint32_t mask = align - 1;
+	nPC = pSect->nPC;
+	setSection(pSect);
+	pCurrentSection = pSect;
+}
 
-		if (org != -1) {
-			if (org & mask)
-				yyerror("Section \"%s\"'s fixed address doesn't match its alignment",
-					pzName);
-			else
-				align = 1; /* Ignore it if it's satisfied */
-		}
-	}
+/*
+ * Set the current section by name and type
+ */
+void out_SetLoadSection(char const *name, uint32_t type, int32_t org,
+			struct SectionSpec const *attributes)
+{
+	if (currentLoadSection)
+		fatalerror("`LOAD` blocks cannot be nested");
 
-	if (org != -1) {
-		if (org < startaddr[secttype] || org > endaddr(secttype))
-			yyerror("Section \"%s\"'s fixed address %#x is outside of range [%#x; %#x]",
-				pzName, org, startaddr[secttype],
-				endaddr(secttype));
-	}
+	struct Section *pSect = getSection(name, type, org, attributes->bank,
+					   1 << attributes->alignment);
 
-	setCurrentSection(findSection(pzName, secttype, org, attributes->bank,
-				      1 << attributes->alignment));
+	nPC = pSect->nPC;
+	setSection(pSect);
+	currentLoadSection = pSect;
 }
 
+void out_EndLoadSection(void)
+{
+	if (!currentLoadSection)
+		yyerror("Found `ENDL` outside of a `LOAD` block");
+	currentLoadSection = NULL;
+	sym_SetCurrentSymbolScope(NULL);
+
+	nPC = pCurrentSection->nPC;
+	setSection(pCurrentSection);
+}
+
+struct Section *sect_GetSymbolSection(void)
+{
+	return currentLoadSection ? currentLoadSection : pCurrentSection;
+}
+
 /*
  * Output an absolute byte (bypassing ROM/union checks)
  */
 static void absByteBypassCheck(uint8_t b)
 {
-	pCurrentSection->tData[nPC] = b;
-	pCurrentSection->nPC++;
+	pCurrentSection->tData[pCurrentSection->nPC++] = b;
+	if (currentLoadSection)
+		currentLoadSection->nPC++;
 	nPC++;
 }
 
@@ -233,6 +270,8 @@
 	checksectionoverflow(skip);
 	if (!sect_HasData(pCurrentSection->nType)) {
 		pCurrentSection->nPC += skip;
+		if (currentLoadSection)
+			currentLoadSection->nPC += skip;
 		nPC += skip;
 	} else if (nUnionDepth > 0) {
 		while (skip--)
@@ -277,9 +316,10 @@
 {
 	checkcodesection();
 	checksectionoverflow(2);
-	pCurrentSection->tData[nPC] = b & 0xFF;
-	pCurrentSection->tData[nPC + 1] = b >> 8;
-	pCurrentSection->nPC += 2;
+	pCurrentSection->tData[pCurrentSection->nPC++] = b & 0xFF;
+	pCurrentSection->tData[pCurrentSection->nPC++] = b >> 8;
+	if (currentLoadSection)
+		currentLoadSection->nPC += 2;
 	nPC += 2;
 }
 
@@ -305,11 +345,12 @@
 {
 	checkcodesection();
 	checksectionoverflow(4);
-	pCurrentSection->tData[nPC] = b & 0xFF;
-	pCurrentSection->tData[nPC + 1] = b >> 8;
-	pCurrentSection->tData[nPC + 2] = b >> 16;
-	pCurrentSection->tData[nPC + 3] = b >> 24;
-	pCurrentSection->nPC += 4;
+	pCurrentSection->tData[pCurrentSection->nPC++] = b & 0xFF;
+	pCurrentSection->tData[pCurrentSection->nPC++] = b >> 8;
+	pCurrentSection->tData[pCurrentSection->nPC++] = b >> 16;
+	pCurrentSection->tData[pCurrentSection->nPC++] = b >> 24;
+	if (currentLoadSection)
+		currentLoadSection->nPC += 4;
 	nPC += 4;
 }
 
@@ -337,9 +378,10 @@
 	checkcodesection();
 	checksectionoverflow(1);
 	if (!rpn_isKnown(expr) || pCurrentSection->nOrg == -1) {
-		pCurrentSection->tData[nPC] = 0;
 		out_CreatePatch(PATCHTYPE_JR, expr);
-		pCurrentSection->nPC++;
+		pCurrentSection->tData[pCurrentSection->nPC++] = 0;
+		if (currentLoadSection)
+			currentLoadSection->nPC++;
 		nPC++;
 	} else {
 		/* Target is relative to the byte *after* the operand */
@@ -382,13 +424,13 @@
 	checkcodesection();
 	checksectionoverflow(fsize);
 
-	int32_t dest = nPC;
 	int32_t todo = fsize;
 
 	while (todo--)
-		pCurrentSection->tData[dest++] = fgetc(f);
+		pCurrentSection->tData[pCurrentSection->nPC++] = fgetc(f);
 
-	pCurrentSection->nPC += fsize;
+	if (currentLoadSection)
+		currentLoadSection->nPC += fsize;
 	nPC += fsize;
 	fclose(f);
 }
@@ -428,13 +470,13 @@
 	checkcodesection();
 	checksectionoverflow(length);
 
-	int32_t dest = nPC;
 	int32_t todo = length;
 
 	while (todo--)
-		pCurrentSection->tData[dest++] = fgetc(f);
+		pCurrentSection->tData[pCurrentSection->nPC++] = fgetc(f);
 
-	pCurrentSection->nPC += length;
+	if (currentLoadSection)
+		currentLoadSection->nPC += length;
 	nPC += length;
 
 	fclose(f);
@@ -465,7 +507,8 @@
 	struct SectionStackEntry *pSect;
 
 	pSect = pSectionStack;
-	setCurrentSection(pSect->pSection);
+	setSection(pSect->pSection);
+	pCurrentSection = pSect->pSection;
 	sym_SetCurrentSymbolScope(pSect->pScope);
 	pSectionStack = pSect->pNext;
 	free(pSect);
--- a/src/asm/symbol.c
+++ b/src/asm/symbol.c
@@ -578,7 +578,7 @@
 		nsym->isExported = true;
 
 	nsym->pScope = scope;
-	nsym->pSection = pCurrentSection;
+	nsym->pSection = sect_GetSymbolSection();
 	/* Labels need to be assigned a section, except PC */
 	if (!pCurrentSection && strcmp(tzSym, "@"))
 		yyerror("Label \"%s\" created outside of a SECTION",