Added full image format, include some debug information at the tail of functions
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
DataHoarder 2021-01-04 08:16:02 +01:00
parent 1566c33d58
commit e76befaed7
9 changed files with 263 additions and 53 deletions

View file

@ -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

View file

@ -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.

9
asm/config.asm Normal file
View file

@ -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

View file

@ -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

View file

@ -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<uint32_t> 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;
}

View file

@ -33,7 +33,7 @@
class Assembler {
private:
const Linker &linker;
bool padEndFunction = true;
bool placeSymbols = true;
std::vector<uint8_t> bytes;
std::unordered_map<std::string, uint32_t> knownRegisters;
std::unordered_map<std::string, std::pair<uint32_t, bool>> 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<std::string> entries;
uint16_t headerPrevShort = 0x0B52; //Have seen 0x0B52, 0x7B52, and 0x616E on FM10420
std::vector<uint8_t> headerExtraBytes = {
0x12, 0xE1, //Have seen 0x12E1, 0x0AE1, and 0x05E7 on FM10420
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
} properties;
std::vector<uint8_t> 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 {

View file

@ -49,3 +49,37 @@ void Linker::addFunction(const Function &f) {
void Linker::addVariable(const std::string &k, const std::vector<Token> &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;
}

View file

@ -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;
};

View file

@ -1,6 +1,8 @@
#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>
#include <iomanip>
#include "Parser.h"
#include "Assembler.h"
#include "instructions/virtual/Stack.h"
@ -18,9 +20,9 @@ int main(int argc, char *argv[]) {
std::vector<EmbeddedResource> 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<uint8_t> 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]);