shithub: rgbds

Download patch

ref: 76d6ef869582a3c714a4b8c7839c2d445b4bfcb1
parent: c67a696a87a35ba3c2fcf10468a6043c2426643c
author: Rangi <remy.oukaour+rangi42@gmail.com>
date: Sun Feb 14 11:55:19 EST 2021

Implement LOAD UNION and LOAD FRAGMENT

Fix #632

--- a/include/asm/section.h
+++ b/include/asm/section.h
@@ -43,7 +43,8 @@
 		    struct SectionSpec const *attributes,
 		    enum SectionModifier mod);
 void out_SetLoadSection(char const *name, uint32_t secttype, uint32_t org,
-			struct SectionSpec const *attributes);
+			struct SectionSpec const *attributes,
+			enum SectionModifier mod);
 void out_EndLoadSection(void);
 
 struct Section *sect_GetSymbolSection(void);
--- a/src/asm/parser.y
+++ b/src/asm/parser.y
@@ -853,8 +853,8 @@
 		| T_POP_SHIFT const	{ macro_ShiftCurrentArgs($2); }
 ;
 
-load		: T_POP_LOAD string T_COMMA sectiontype sectorg sectattrs {
-			out_SetLoadSection($2, $4, $5, &$6);
+load		: T_POP_LOAD sectmod string T_COMMA sectiontype sectorg sectattrs {
+			out_SetLoadSection($3, $5, $6, &$7, $2);
 		}
 		| T_POP_ENDL	{ out_EndLoadSection(); }
 ;
--- a/src/asm/rgbasm.5
+++ b/src/asm/rgbasm.5
@@ -719,6 +719,13 @@
 You cannot nest
 .Ic LOAD
 blocks, nor can you change the current section within them.
+.Pp
+.Ic LOAD
+blocks can use the
+.Ic UNION
+or
+.Ic FRAGMENT
+modifiers, as described below.
 .Ss Unionized Sections
 When you're tight on RAM, you may want to define overlapping blocks of variables, as explained in the
 .Sx Unions
--- a/src/asm/section.c
+++ b/src/asm/section.c
@@ -30,7 +30,7 @@
 struct SectionStackEntry *sectionStack;
 uint32_t curOffset; /* Offset into the current section (see sect_GetSymbolOffset) */
 static struct Section *currentLoadSection = NULL;
-uint32_t loadOffset; /* The offset of the LOAD section within its parent */
+int32_t loadOffset; /* Offset into the LOAD section's parent (see sect_GetOutputOffset) */
 
 struct UnionStackEntry {
 	uint32_t start;
@@ -387,7 +387,8 @@
  * Set the current section by name and type
  */
 void out_SetLoadSection(char const *name, uint32_t type, uint32_t org,
-			struct SectionSpec const *attribs)
+			struct SectionSpec const *attribs,
+			enum SectionModifier mod)
 {
 	checkcodesection();
 
@@ -397,11 +398,11 @@
 	if (sect_HasData(type))
 		error("`LOAD` blocks cannot create a ROM section\n");
 
-	struct Section *sect = getSection(name, type, org, attribs, false);
+	struct Section *sect = getSection(name, type, org, attribs, mod);
 
-	loadOffset = curOffset;
-	curOffset = 0; /* curOffset -= loadOffset; */
 	changeSection();
+	loadOffset = curOffset - (mod == SECTION_UNION ? 0 : sect->size);
+	curOffset -= loadOffset;
 	currentLoadSection = sect;
 }
 
@@ -409,11 +410,11 @@
 {
 	if (!currentLoadSection)
 		error("Found `ENDL` outside of a `LOAD` block\n");
-	currentLoadSection = NULL;
 
 	changeSection();
 	curOffset += loadOffset;
 	loadOffset = 0;
+	currentLoadSection = NULL;
 }
 
 struct Section *sect_GetSymbolSection(void)
--- /dev/null
+++ b/test/asm/load-fragment.asm
@@ -1,0 +1,29 @@
+SECTION "A", ROM0
+AData::
+LOAD FRAGMENT "RAM", WRAM0
+AMem::
+	db 0, 1, 2
+AMemEnd::
+ENDL
+ADataEnd::
+	dw AMem
+
+SECTION "B", ROM0
+BData::
+LOAD FRAGMENT "RAM", WRAM0
+BMem::
+	db 3, 4, 5, 6, 7
+BMemEnd::
+ENDL
+BDataEnd::
+	dw BMem
+
+SECTION "C", ROM0
+CData::
+LOAD FRAGMENT "RAM", WRAM0
+CMem::
+	db 8, 9
+CMemEnd::
+ENDL
+CDataEnd::
+	dw CMem
binary files /dev/null b/test/asm/load-fragment.out.bin differ
--- /dev/null
+++ b/test/asm/load-union.asm
@@ -1,0 +1,29 @@
+SECTION "A", ROM0
+AData::
+LOAD UNION "RAM", WRAM0
+AMem::
+	db 0, 1, 2
+AMemEnd::
+ENDL
+ADataEnd::
+	dw AMem
+
+SECTION "B", ROM0
+BData::
+LOAD UNION "RAM", WRAM0
+BMem::
+	db 3, 4, 5, 6, 7
+BMemEnd::
+ENDL
+BDataEnd::
+	dw BMem
+
+SECTION "C", ROM0
+CData::
+LOAD UNION "RAM", WRAM0
+CMem::
+	db 8, 9
+CMemEnd::
+ENDL
+CDataEnd::
+	dw CMem
binary files /dev/null b/test/asm/load-union.out.bin differ