From e76befaed778735115a0faa1559511368ba7b350 Mon Sep 17 00:00:00 2001 From: WeebDataHoarder <57538841+weebdatahoarder@users.noreply.github.com> Date: Mon, 4 Jan 2021 08:16:02 +0100 Subject: [PATCH] Added full image format, include some debug information at the tail of functions --- CMakeLists.txt | 1 + README.md | 1 + asm/config.asm | 9 +++ asm/init.asm | 6 +- src/Assembler.cpp | 139 +++++++++++++++++++++++++++++++++------------- src/Assembler.h | 93 +++++++++++++++++++++++++++++-- src/Linker.cpp | 34 ++++++++++++ src/Linker.h | 4 ++ src/rrcas.cpp | 29 +++++++++- 9 files changed, 263 insertions(+), 53 deletions(-) create mode 100644 asm/config.asm diff --git a/CMakeLists.txt b/CMakeLists.txt index 03d3385..6ab7f6d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ set(SOURCE_FILES ADD_RESOURCES(embeddedResources asm/registers.asm + asm/config.asm asm/api.asm asm/init.asm asm/stdlib.asm diff --git a/README.md b/README.md index a9035ef..e767491 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Assembler and linker, kind-of 2-Pass. Quite loose token syntax defined in [Token * Directives like `.constant` are passed to the next files. * These files will be automatically included in front every time: * *[asm/registers.asm](asm/registers.asm)*: Base named registers for platform. + * *[asm/config.asm](asm/config.asm)*: Contains user-configurable parameters. * *[asm/api.asm](asm/api.asm)*: Registers used for some driver/switch manager operations. * *[asm/stdlib.asm](asm/stdlib.asm)*: Standard library and other miscellaneous utilities. * *[asm/init.asm](asm/init.asm)*: Sets up some required registers and other config. diff --git a/asm/config.asm b/asm/config.asm new file mode 100644 index 0000000..71eee92 --- /dev/null +++ b/asm/config.asm @@ -0,0 +1,9 @@ +; Base platform config. These values can be overriden elsewhere. + +.constant rrcc_SPI_TRANSFER_MODE 0 +.constant rrcc_SPI_TRANSFER_SPEED 7 +.constant rrcc_BASE_ADDRESS @0x080000 +.constant rrcc_ENTRYPOINT @__rrcc_init +.constant rrcc_USER_ENTRYPOINT @entrypoint + +.constant rrcc_IMAGE_VERSION 0x0000 \ No newline at end of file diff --git a/asm/init.asm b/asm/init.asm index 4c5d2a4..14b991b 100644 --- a/asm/init.asm +++ b/asm/init.asm @@ -1,8 +1,6 @@ ; Initialization function -.constant rrcc_ENTRYPOINT @__init - -__init: +__rrcc_init: WRITE rrcc_STACK_POINTER, rrcc_STACK_START ; Reset Stack pointer to its starting position - CALL @entrypoint ; Calls user-defined entrypoint + CALL rrcc_USER_ENTRYPOINT ; Calls user-defined entrypoint END ; Stops execution if it ever returns \ No newline at end of file diff --git a/src/Assembler.cpp b/src/Assembler.cpp index 06e98c2..835df01 100644 --- a/src/Assembler.cpp +++ b/src/Assembler.cpp @@ -27,37 +27,21 @@ #include "Assembler.h" #include "instructions/End.h" +#include "instructions/Load.h" -void Assembler::assemble(uint32_t baseAddress, uint32_t imageSize) { +void Assembler::assemble(const std::string& entrypointName, const ImageConfig& config, uint32_t maxImageSize) { entries.clear(); bytes.clear(); - bytes.resize(imageSize - 1, 0x00); - //bytes.resize(imageSize - 1, (uint8_t) Instruction::Instruction::CommandOp::END); - - uint32_t freeOffsetLocation = baseAddress; - - if(linker.getVariables().find("rrcc_ENTRYPOINT") == linker.getVariables().end()){ - throw std::runtime_error("rrcc_ENTRYPOINT is not defined"); - } - - std::string entrypointName; - - for(auto& t : linker.getVariables().at("rrcc_ENTRYPOINT")){ - if(t.getType() == Token::Type::CodeLabel){ - entrypointName = t.getTextValue(); - break; - } - } - - if(entrypointName.empty()){ - throw std::runtime_error("rrcc_ENTRYPOINT is not set"); - } + //bytes.resize(maxImageSize - 1, 0x00); + bytes.resize(maxImageSize - 1, (uint8_t) Instruction::Instruction::CommandOp::END); + uint32_t startAddress = config.header.baseAddress; + uint32_t freeOffsetLocation = startAddress; if (placementMode == FunctionPlacementMode::PlaceAll) { for (auto &f : linker.getTree()) { if (f.label == entrypointName) { - baseAddress = freeOffsetLocation; + startAddress = freeOffsetLocation; } freeOffsetLocation = placeFunction(freeOffsetLocation, f); } @@ -101,13 +85,64 @@ void Assembler::assemble(uint32_t baseAddress, uint32_t imageSize) { } } - setSignature("Image generated with rrc-as."); + size_t offset = 0; + bytes[offset++] = ((uint8_t) config.header.spiTransferSpeed << 3) | ((uint8_t) config.header.spiTransferMode << 6); + bytes[offset++] = (startAddress >> 16) & 0xFF; + bytes[offset++] = (startAddress >> 8) & 0xFF; + bytes[offset++] = startAddress & 0xFF; + bytes[offset++] = (config.buildVersion >> 24) & 0xFF; + bytes[offset++] = (config.buildVersion >> 16) & 0xFF; + bytes[offset++] = (config.buildVersion >> 8) & 0xFF; + bytes[offset++] = config.buildVersion & 0xFF; - bytes[0] = 0x38; - bytes[1] = (baseAddress >> 16) & 0xFF; - bytes[2] = (baseAddress >> 8) & 0xFF; - bytes[3] = baseAddress & 0xFF; + bytes[offset++] = 0x00; + bytes[offset++] = 0x00; + bytes[offset++] = 0x00; + bytes[offset++] = 0x00; + bytes[offset++] = 0x01; + bytes[offset++] = 0x00; + bytes[offset++] = 0x10; + bytes[offset++] = 0x00; + + const uint32_t headerLength = offset + 4 + config.headerExtraBytes.size(); + + bytes[offset++] = headerLength >> 2; // Length in words + bytes[offset++] = (config.properties.baseAddress >> 16) & 0xFF; + bytes[offset++] = (config.properties.baseAddress >> 8) & 0xFF; + bytes[offset++] = config.properties.baseAddress & 0xFF; + + for(auto& c : config.headerExtraBytes){ + bytes[offset++] = c; + } + std::copy(config.buildSignature.begin(), config.buildSignature.end(), bytes.begin() + offset); + + offset = config.properties.baseAddress - 2; + + bytes[offset++] = (config.properties.headerPrevShort >> 8) & 0xFF; + bytes[offset++] = config.properties.headerPrevShort & 0xFF; + + bytes[offset++] = 1; // fileFormat + bytes[offset++] = 0; // version + bytes[offset++] = 0; // lengthInWords To be written again + bytes[offset++] = 0; // lengthInWords To be written again + + for(auto& c : config.properties.headerExtraBytes){ + bytes[offset++] = c; + } + + uint32_t totalSize = 0; + for(auto& s : config.properties.entries){ + std::copy(s.begin(), s.end(), bytes.begin() + offset); + offset += s.size(); + totalSize += s.size(); + } + + totalSize >>= 2; //Length in words + + offset = config.properties.baseAddress + 2; + bytes[offset++] = (totalSize >> 8) & 0xFF; + bytes[offset++] = totalSize & 0xFF; } uint32_t Assembler::placeFunction(uint32_t base, const Function &function) { @@ -194,13 +229,43 @@ uint32_t Assembler::placeFunction(uint32_t base, const Function &function) { offset += data.size(); } - if (padEndFunction) { - auto endInstruction = Instruction::End(); - endInstruction.reserved = base; // Tag start of function - auto data = endInstruction.toBytes(); + if (placeSymbols) { + uint32_t endOffset = offset; + + { + auto endInstruction = Instruction::End(); + endInstruction.reserved = base; // Tag start of function + auto data = endInstruction.toBytes(); + + std::copy(data.begin(), data.end(), bytes.begin() + offset); + offset += data.size(); + } + + { + std::vector debugData; + uint8_t off = 4; + uint32_t v = 0; + for(uint8_t c : function.label){ + --off; + v |= (uint32_t)c << (off * 8); + if(off == 0){ + debugData.emplace_back(v); + off = 4; + v = 0; + } + } + if(off != 4){ + debugData.emplace_back(v); + } + + auto loadInstruction = Instruction::Load({endOffset, 0}, 0, debugData); //Tag end of function, and data + auto data = loadInstruction.toBytes(); + + std::copy(data.begin(), data.end(), bytes.begin() + offset); + offset += data.size(); + } + - std::copy(data.begin(), data.end(), bytes.begin() + offset); - offset += data.size(); } entries[function.label] = {base, needsReLabeling}; @@ -217,9 +282,3 @@ const Function *Assembler::getFunctionByLabel(const std::string &l) { return nullptr; } - -void Assembler::setSignature(const std::string &str) { - const uint32_t signatureOffset = 0x100; - std::copy(str.begin(), str.end(), bytes.begin() + signatureOffset); - bytes[signatureOffset + str.size()] = 0xFF; -} diff --git a/src/Assembler.h b/src/Assembler.h index 4e817fd..4603644 100644 --- a/src/Assembler.h +++ b/src/Assembler.h @@ -33,7 +33,7 @@ class Assembler { private: const Linker &linker; - bool padEndFunction = true; + bool placeSymbols = true; std::vector bytes; std::unordered_map knownRegisters; std::unordered_map> entries; @@ -48,13 +48,94 @@ public: } + typedef struct ImageConfig{ + struct { + uint8_t spiTransferMode = 0; + uint8_t spiTransferSpeed = 7; + uint32_t baseAddress = 0x080000; + } header; + uint32_t buildVersion = 0x0000; + + struct { + uint32_t baseAddress = 0x2000; + std::vector entries; + uint16_t headerPrevShort = 0x0B52; //Have seen 0x0B52, 0x7B52, and 0x616E on FM10420 + std::vector headerExtraBytes = { + 0x12, 0xE1, //Have seen 0x12E1, 0x0AE1, and 0x05E7 on FM10420 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + } properties; + + std::vector headerExtraBytes = { + 0x40,0x08,0x00,0x00, // location 0x0014 + 0x40,0x0C,0x00,0x00, + 0xDC/**0x44 in FM10420-QDA2*/,0x00,0x80,0x08, + 0xDC/**0x44 in FM10420-QDA2*/,0x00,0x81,0xCF, + 0xDC/**0x44 in FM10420-QDA2*/,0x00,0x83,0x96, + 0xDC/**0x44 in FM10420-QDA2*/,0x00,0x85,0x5D, + 0xDC/**0x44 in FM10420-QDA2*/,0x00,0x87,0x24, + 0xDC/**0x44 in FM10420-QDA2*/,0x00,0x88,0xEB, + 0xDC/**0x44 in FM10420-QDA2*/,0x00,0x8A,0xB2, + 0xDC/**0x44 in FM10420-QDA2*/,0x00,0x8C,0x79, + 0xDC/**0x44 in FM10420-QDA2*/,0x00,0x8E,0x40, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, // location 0x0048, here a null terminated string can be placed with manufacturer info + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x02, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0xD3,0xEF, /**0x00,0x00,0x2B,0x6E in FM10420-QDA2*/ + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00 + }; + std::string buildSignature; + + } ImageConfig; + //Default max size 1 MiB - void assemble(uint32_t baseAddress = 0x080000, uint32_t imageSize = 0x100000); + void assemble(const std::string& entrypointName, const ImageConfig& imageConfig, uint32_t maxImageSize = 0x100000); - void setSignature(const std::string &str); - - void setDoFunctionPadding(bool pad) { - padEndFunction = pad; + void setPlaceSymbols(bool place) { + placeSymbols = place; } const auto &getImage() const { diff --git a/src/Linker.cpp b/src/Linker.cpp index 27e4763..1c09069 100644 --- a/src/Linker.cpp +++ b/src/Linker.cpp @@ -49,3 +49,37 @@ void Linker::addFunction(const Function &f) { void Linker::addVariable(const std::string &k, const std::vector &v) { variables[k] = v; } + +std::string Linker::getTextConstant(const std::string &name, const std::string &defaultValue, bool throwOnNotFound) const { + if(getVariables().find(name) == getVariables().end()){ + if(throwOnNotFound){ + throw std::runtime_error(name + " is not defined"); + } + return defaultValue; + } + for(auto& t : getVariables().at(name)){ + return t.getTextValue(); + } + if(throwOnNotFound){ + throw std::runtime_error(name + " is not set properly"); + } + return defaultValue; +} + +uint32_t Linker::getIntegerConstant(const std::string &name, uint32_t defaultValue, bool throwOnNotFound) const { + if(getVariables().find(name) == getVariables().end()){ + if(throwOnNotFound){ + throw std::runtime_error(name + " is not defined"); + } + return defaultValue; + } + for(auto& t : getVariables().at(name)){ + if(t.getType() == Token::Type::Immediate || t.getType() == Token::Type::RegisterLocation || t.getType() == Token::Type::CodeLocation){ + return t.getNumericValue(); + } + } + if(throwOnNotFound){ + throw std::runtime_error(name + " is not set properly"); + } + return defaultValue; +} diff --git a/src/Linker.h b/src/Linker.h index aa293ed..29189cf 100644 --- a/src/Linker.h +++ b/src/Linker.h @@ -51,4 +51,8 @@ public: return variables; } + std::string getTextConstant(const std::string& name, const std::string& defaultValue = "", bool throwOnNotFound = false) const; + + uint32_t getIntegerConstant(const std::string& name, uint32_t defaultValue = 0, bool throwOnNotFound = false) const; + }; diff --git a/src/rrcas.cpp b/src/rrcas.cpp index a34ee11..0641128 100644 --- a/src/rrcas.cpp +++ b/src/rrcas.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include "Parser.h" #include "Assembler.h" #include "instructions/virtual/Stack.h" @@ -18,9 +20,9 @@ int main(int argc, char *argv[]) { std::vector embeddedResources = { LOAD_RESOURCE(asm_registers_asm), + LOAD_RESOURCE(asm_config_asm), LOAD_RESOURCE(asm_api_asm), - LOAD_RESOURCE(asm_stdlib_asm), - LOAD_RESOURCE(asm_init_asm) + LOAD_RESOURCE(asm_stdlib_asm) }; Instruction::Instruction::addDefaultOperators(); @@ -60,8 +62,29 @@ int main(int argc, char *argv[]) { } } + //Load base init + auto res = LOAD_RESOURCE(asm_init_asm); + std::vector bytes(res.begin(), res.end()); + Parser parser(bytes, linker.getVariables()); + parser.parse(); + linker.addFromParser(parser); + Assembler assembler(linker); - assembler.assemble(); + + Assembler::ImageConfig config; + + config.header.baseAddress = linker.getIntegerConstant("rrcc_BASE_ADDRESS", 0x080000, false); + config.header.spiTransferMode = linker.getIntegerConstant("rrcc_SPI_TRANSFER_MODE", 0, false); + config.header.spiTransferSpeed = linker.getIntegerConstant("rrcc_SPI_TRANSFER_SPEED", 7, false); + config.buildVersion = linker.getIntegerConstant("rrcc_IMAGE_VERSION", 0, false); + + std::stringstream s; + s << "Image generated with rrc-as. EEPROM Image Version: 0x" << std::hex << std::setw(4) << std::setfill('0') << config.buildVersion; + config.buildSignature = s.str(); + + auto entrypointName = linker.getTextConstant("rrcc_ENTRYPOINT", "", true); + + assembler.assemble(entrypointName, config); std::ofstream patchedImage(argv[argc - 1]);