shithub: rgbds

Download patch

ref: a67f5d6e019252b37e2f6ab0e45b500f9e5e2a28
parent: 06b57aa1ce8e69a9e4ef96317f65de85c0540c3a
author: Rangi <[email protected]>
date: Sun Jun 20 12:10:27 EDT 2021

SIZEOF("Section") and STARTOF("Section") can be known

Fixes #890

--- a/include/asm/section.h
+++ b/include/asm/section.h
@@ -13,6 +13,7 @@
 #include <stdbool.h>
 
 #include "linkdefs.h"
+#include "platform.h" // NONNULL
 
 extern uint8_t fillByte;
 
@@ -75,5 +76,7 @@
 
 void sect_PushSection(void);
 void sect_PopSection(void);
+
+bool sect_IsSizeKnown(struct Section const NONNULL(name));
 
 #endif
--- a/include/platform.h
+++ b/include/platform.h
@@ -49,8 +49,10 @@
 /* MSVC doesn't support `[static N]` for array arguments from C99 */
 #ifdef _MSC_VER
 # define MIN_NB_ELMS(N)
+# define NONNULL(ptr) *ptr
 #else
 # define MIN_NB_ELMS(N) static (N)
+# define NONNULL(ptr) ptr[static 1]
 #endif
 
 // MSVC uses a different name for O_RDWR, and needs an additional _O_BINARY flag
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -205,14 +205,20 @@
 {
 	rpn_Init(expr);
 
-	makeUnknown(expr, "Section \"%s\"'s size is not known", sectionName);
+	struct Section *section = sect_FindSectionByName(sectionName);
 
-	size_t nameLen = strlen(sectionName) + 1; /* Room for NUL! */
-	uint8_t *ptr = reserveSpace(expr, nameLen + 1);
+	if (section && sect_IsSizeKnown(section)) {
+		expr->val = section->size;
+	} else {
+		makeUnknown(expr, "Section \"%s\"'s size is not known", sectionName);
 
-	expr->rpnPatchSize += nameLen + 1;
-	*ptr++ = RPN_SIZEOF_SECT;
-	memcpy(ptr, sectionName, nameLen);
+		size_t nameLen = strlen(sectionName) + 1; /* Room for NUL! */
+		uint8_t *ptr = reserveSpace(expr, nameLen + 1);
+
+		expr->rpnPatchSize += nameLen + 1;
+		*ptr++ = RPN_SIZEOF_SECT;
+		memcpy(ptr, sectionName, nameLen);
+	}
 }
 
 void rpn_StartOfSection(struct Expression *expr, char const *sectionName)
@@ -219,14 +225,20 @@
 {
 	rpn_Init(expr);
 
-	makeUnknown(expr, "Section \"%s\"'s start is not known", sectionName);
+	struct Section *section = sect_FindSectionByName(sectionName);
 
-	size_t nameLen = strlen(sectionName) + 1; /* Room for NUL! */
-	uint8_t *ptr = reserveSpace(expr, nameLen + 1);
+	if (section && section->org != (uint32_t)-1) {
+		expr->val = section->org;
+	} else {
+		makeUnknown(expr, "Section \"%s\"'s start is not known", sectionName);
 
-	expr->rpnPatchSize += nameLen + 1;
-	*ptr++ = RPN_STARTOF_SECT;
-	memcpy(ptr, sectionName, nameLen);
+		size_t nameLen = strlen(sectionName) + 1; /* Room for NUL! */
+		uint8_t *ptr = reserveSpace(expr, nameLen + 1);
+
+		expr->rpnPatchSize += nameLen + 1;
+		*ptr++ = RPN_STARTOF_SECT;
+		memcpy(ptr, sectionName, nameLen);
+	}
 }
 
 void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
--- a/src/asm/section.c
+++ b/src/asm/section.c
@@ -1016,3 +1016,22 @@
 	sectionStack = entry->next;
 	free(entry);
 }
+
+bool sect_IsSizeKnown(struct Section const NONNULL(sect))
+{
+	// SECTION UNION and SECTION FRAGMENT can still grow
+	if (sect->modifier != SECTION_NORMAL)
+		return false;
+
+	// The current section (or current load section if within one) is still growing
+	if (sect == currentSection || sect == currentLoadSection)
+		return false;
+
+	// Any section on the stack is still growing
+	for (struct SectionStackEntry *stack = sectionStack; stack; stack = stack->next) {
+		if (stack->section && !strcmp(sect->name, stack->section->name))
+			return false;
+	}
+
+	return true;
+}
--- a/test/asm/section-sizeof-startof.asm
+++ b/test/asm/section-sizeof-startof.asm
@@ -2,7 +2,32 @@
 	ds 42
 
 W = BANK("sect")
+X = SIZEOF("sect") ; unknown
+Y = STARTOF("sect")
+
+	println "sect1: {W} {X} {Y}"
+
+SECTION "sect2", ROMX
+
+W = BANK("sect")
 X = SIZEOF("sect")
 Y = STARTOF("sect")
 
-	println "{W} {X} {Y}"
+	println "sect1: {W} {X} {Y}"
+
+PUSHS
+SECTION FRAGMENT "sect3", ROMX[$4567], BANK[$12]
+
+W = BANK("sect2") ; unknown
+X = SIZEOF("sect2") ; unknown
+Y = STARTOF("sect2") ; unknown
+
+	println "sect2: {W} {X} {Y}"
+
+POPS
+
+W = BANK("sect3")
+X = SIZEOF("sect3") ; unknown
+Y = STARTOF("sect3")
+
+	println "sect3: {W} {X} {Y}"
--- a/test/asm/section-sizeof-startof.err
+++ b/test/asm/section-sizeof-startof.err
@@ -1,5 +1,11 @@
 ERROR: section-sizeof-startof.asm(5):
     Expected constant expression: Section "sect"'s size is not known
-ERROR: section-sizeof-startof.asm(6):
-    Expected constant expression: Section "sect"'s start is not known
-error: Assembly aborted (2 errors)!
+ERROR: section-sizeof-startof.asm(21):
+    Expected constant expression: Section "sect2"'s bank is not known
+ERROR: section-sizeof-startof.asm(22):
+    Expected constant expression: Section "sect2"'s size is not known
+ERROR: section-sizeof-startof.asm(23):
+    Expected constant expression: Section "sect2"'s start is not known
+ERROR: section-sizeof-startof.asm(30):
+    Expected constant expression: Section "sect3"'s size is not known
+error: Assembly aborted (5 errors)!
--- a/test/asm/section-sizeof-startof.out
+++ b/test/asm/section-sizeof-startof.out
@@ -1,1 +1,4 @@
-$23 $0 $0
+sect1: $23 $0 $4567
+sect1: $23 $2A $4567
+sect2: $0 $0 $0
+sect3: $12 $0 $4567