Added full image format, include some debug information at the tail of functions
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
1566c33d58
commit
e76befaed7
|
@ -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
|
||||
|
|
|
@ -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
9
asm/config.asm
Normal 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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
};
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
Loading…
Reference in a new issue