From c5c2800f1726f26cb53ecfa18df1b61468aff89a Mon Sep 17 00:00:00 2001 From: Rangi42 Date: Wed, 3 Sep 2025 22:36:00 -0400 Subject: [PATCH] Move RPN buffer encoding logic into rpn.cpp --- include/asm/output.hpp | 2 ++ include/asm/rpn.hpp | 8 +++-- src/asm/output.cpp | 78 ++---------------------------------------- src/asm/rpn.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 77 deletions(-) diff --git a/include/asm/output.hpp b/include/asm/output.hpp index ba457a60..906c5c4c 100644 --- a/include/asm/output.hpp +++ b/include/asm/output.hpp @@ -12,10 +12,12 @@ struct Expression; struct FileStackNode; +struct Symbol; enum StateFeature { STATE_EQU, STATE_VAR, STATE_EQUS, STATE_CHAR, STATE_MACRO, NB_STATE_FEATURES }; void out_RegisterNode(std::shared_ptr node); +void out_RegisterSymbol(Symbol &sym); void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift); void out_CreateAssert( AssertionType type, Expression const &expr, std::string const &message, uint32_t ofs diff --git a/include/asm/rpn.hpp b/include/asm/rpn.hpp index ac6ad130..e296b596 100644 --- a/include/asm/rpn.hpp +++ b/include/asm/rpn.hpp @@ -13,8 +13,10 @@ struct Symbol; struct RPNValue { - RPNCommand command; - std::variant data; + RPNCommand command; // The RPN_* command ID + std::variant data; // Data after the ID, if any + + void appendEncoded(std::vector &buffer) const; }; struct Expression { @@ -48,6 +50,8 @@ struct Expression { void addCheckBitIndex(uint8_t mask); void checkNBit(uint8_t n) const; + + void encode(std::vector &buffer) const; }; bool checkNBit(int32_t v, uint8_t n, char const *name); diff --git a/src/asm/output.cpp b/src/asm/output.cpp index f9b2dd7c..aa11fc25 100644 --- a/src/asm/output.cpp +++ b/src/asm/output.cpp @@ -124,7 +124,7 @@ static void writeSymbol(Symbol const &sym, FILE *file) { } } -static void registerUnregisteredSymbol(Symbol &sym) { +void out_RegisterSymbol(Symbol &sym) { // Check for `sym.src`, to skip any built-in symbol from rgbasm if (sym.src && sym.ID == UINT32_MAX && !sym_IsPC(&sym)) { sym.ID = objectSymbols.size(); // Set the symbol's ID within the object file @@ -142,79 +142,7 @@ static void initPatch(Patch &patch, uint32_t type, Expression const &expr, uint3 patch.offset = ofs; patch.pcSection = sect_GetSymbolSection(); patch.pcOffset = sect_GetSymbolOffset(); - - if (expr.isKnown()) { - // If the RPN expr's value is known, output a constant directly - uint32_t val = expr.value(); - patch.rpn.resize(5); - patch.rpn[0] = RPN_CONST; - patch.rpn[1] = val & 0xFF; - patch.rpn[2] = val >> 8; - patch.rpn[3] = val >> 16; - patch.rpn[4] = val >> 24; - return; - } - - // If the RPN expr's value is not known, serialize its RPN values - patch.rpn.clear(); - patch.rpn.reserve(expr.rpn.size() * 2); // Rough estimate of the serialized size - - for (RPNValue const &value : expr.rpn) { - // Every command starts with its own ID - patch.rpn.push_back(value.command); - - switch (value.command) { - case RPN_CONST: { - // The command ID is followed by a four-byte integer - assume(std::holds_alternative(value.data)); - uint32_t v = std::get(value.data); - patch.rpn.push_back(v & 0xFF); - patch.rpn.push_back(v >> 8); - patch.rpn.push_back(v >> 16); - patch.rpn.push_back(v >> 24); - break; - } - - case RPN_SYM: - case RPN_BANK_SYM: { - // The command ID is followed by a four-byte symbol ID - assume(std::holds_alternative(value.data)); - // The symbol name is always written expanded - Symbol *sym = sym_FindExactSymbol(std::get(value.data)); - registerUnregisteredSymbol(*sym); // Ensure that `sym->ID` is set - patch.rpn.push_back(sym->ID & 0xFF); - patch.rpn.push_back(sym->ID >> 8); - patch.rpn.push_back(sym->ID >> 16); - patch.rpn.push_back(sym->ID >> 24); - break; - } - - case RPN_BANK_SECT: - case RPN_SIZEOF_SECT: - case RPN_STARTOF_SECT: { - // The command ID is followed by a NUL-terminated section name string - assume(std::holds_alternative(value.data)); - for (char c : std::get(value.data)) { - patch.rpn.push_back(c); - } - patch.rpn.push_back('\0'); - break; - } - - case RPN_SIZEOF_SECTTYPE: - case RPN_STARTOF_SECTTYPE: - case RPN_BIT_INDEX: - // The command ID is followed by a byte value - assume(std::holds_alternative(value.data)); - patch.rpn.push_back(std::get(value.data)); - break; - - default: - // Other command IDs are not followed by anything - assume(std::holds_alternative(value.data)); - break; - } - } + expr.encode(patch.rpn); } void out_CreatePatch(uint32_t type, Expression const &expr, uint32_t ofs, uint32_t pcShift) { @@ -286,7 +214,7 @@ void out_WriteObject() { Defer closeFile{[&] { fclose(file); }}; // Also write symbols that weren't written above - sym_ForEach(registerUnregisteredSymbol); + sym_ForEach(out_RegisterSymbol); fputs(RGBDS_OBJECT_VERSION_STRING, file); putLong(RGBDS_OBJECT_REV, file); diff --git a/src/asm/rpn.cpp b/src/asm/rpn.cpp index 8924df85..04f38374 100644 --- a/src/asm/rpn.cpp +++ b/src/asm/rpn.cpp @@ -512,3 +512,81 @@ bool checkNBit(int32_t v, uint8_t n, char const *name) { return true; } + +void Expression::encode(std::vector &buffer) const { + assume(buffer.empty()); + + if (isKnown()) { + // If the RPN expression's value is known, output a constant directly + uint32_t val = value(); + buffer.resize(5); + buffer[0] = RPN_CONST; + buffer[1] = val & 0xFF; + buffer[2] = val >> 8; + buffer[3] = val >> 16; + buffer[4] = val >> 24; + } else { + // If the RPN expression's value is not known, serialize its RPN values + buffer.reserve(rpn.size() * 2); // Rough estimate of the serialized size + for (RPNValue const &val : rpn) { + val.appendEncoded(buffer); + } + } +} + +void RPNValue::appendEncoded(std::vector &buffer) const { + // Every command starts with its own ID + buffer.push_back(command); + + switch (command) { + case RPN_CONST: { + // The command ID is followed by a four-byte integer + assume(std::holds_alternative(data)); + uint32_t val = std::get(data); + buffer.push_back(val & 0xFF); + buffer.push_back(val >> 8); + buffer.push_back(val >> 16); + buffer.push_back(val >> 24); + break; + } + + case RPN_SYM: + case RPN_BANK_SYM: { + // The command ID is followed by a four-byte symbol ID + assume(std::holds_alternative(data)); + // The symbol name is always written expanded + Symbol *sym = sym_FindExactSymbol(std::get(data)); + out_RegisterSymbol(*sym); // Ensure that `sym->ID` is set + buffer.push_back(sym->ID & 0xFF); + buffer.push_back(sym->ID >> 8); + buffer.push_back(sym->ID >> 16); + buffer.push_back(sym->ID >> 24); + break; + } + + case RPN_BANK_SECT: + case RPN_SIZEOF_SECT: + case RPN_STARTOF_SECT: { + // The command ID is followed by a NUL-terminated section name string + assume(std::holds_alternative(data)); + std::string const &name = std::get(data); + buffer.reserve(buffer.size() + name.length() + 1); + buffer.insert(buffer.end(), RANGE(name)); + buffer.push_back('\0'); + break; + } + + case RPN_SIZEOF_SECTTYPE: + case RPN_STARTOF_SECTTYPE: + case RPN_BIT_INDEX: + // The command ID is followed by a byte value + assume(std::holds_alternative(data)); + buffer.push_back(std::get(data)); + break; + + default: + // Other command IDs are not followed by anything + assume(std::holds_alternative(data)); + break; + } +}