diff options
author | Akira Akashi <rubenru09@aol.com> | 2021-06-02 22:13:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-02 22:13:57 +0100 |
commit | 9d3d4a2acff67f43896e9e0dcd26e7aaeb55e3b3 (patch) | |
tree | d707aa8fead427dadbbb29b886875e6c8961bd5a /tools | |
parent | a2a17a9426f16ee601ff17840b8bb7851fef7138 (diff) | |
parent | 7e32d3758e7e36d7a67a1442cdb9386f9aa18a6e (diff) |
Merge branch 'master' into 0202A1E0
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/asm_processor/asm_processor.py | 14 | ||||
-rw-r--r-- | tools/fixrom/fixrom.c | 125 | ||||
-rw-r--r-- | tools/knarc/Narc.cpp | 46 | ||||
-rw-r--r-- | tools/knarc/Source.cpp | 5 | ||||
-rw-r--r-- | tools/nitrogfx/gfx.c | 3 | ||||
-rw-r--r-- | tools/nitrogfx/json.c | 3 | ||||
-rw-r--r-- | tools/nitrogfx/options.h | 1 | ||||
-rw-r--r-- | tools/o2narc/o2narc.cpp | 64 |
8 files changed, 194 insertions, 67 deletions
diff --git a/tools/asm_processor/asm_processor.py b/tools/asm_processor/asm_processor.py index ec01c68e..5c909388 100755 --- a/tools/asm_processor/asm_processor.py +++ b/tools/asm_processor/asm_processor.py @@ -9,7 +9,7 @@ import os from collections import namedtuple, defaultdict from io import StringIO -MAX_FN_SIZE = 100 +MAX_FN_SIZE = 3000 SLOW_CHECKS = False EI_NIDENT = 16 @@ -375,14 +375,14 @@ def is_temp_name(name): # https://stackoverflow.com/a/241506 def re_comment_replacer(match): s = match.group(0) - if s[0] in "/#": + if s[0] in "/#;": return " " else: return s re_comment_or_string = re.compile( - r'#.*|/\*.*?\*/|"(?:\\.|[^\\"])*"' + r';.*|#.*|/\*.*?\*/|"(?:\\.|[^\\"])*"' ) @@ -584,8 +584,12 @@ class GlobalAsmBlock: elif line.startswith('.byte'): self.add_sized(len(line.split(',')), real_line) # Branches are 4 bytes long - elif line.startswith('bl'): + elif line.startswith('bl') and not line.startswith('bls'): self.add_sized(4, real_line) + elif line.startswith('.word'): + self.add_sized(4, real_line) + elif line.startswith('.extern'): + pass else: # Unfortunately, macros are hard to support for .rodata -- # we don't know how how space they will expand to before @@ -820,7 +824,7 @@ def repl_float_hex(m): def parse_source(f, opt, framepointer, input_enc, output_enc, print_source=None): opt = "O4" min_instr_count = 3 # idk - skip_instr_count = 2 # idk + skip_instr_count = 3 # mandatory instructions: push, pop and mov r0, 0 use_jtbl_for_rodata = False if opt in ['O2', 'g3'] and not framepointer: diff --git a/tools/fixrom/fixrom.c b/tools/fixrom/fixrom.c index 6c5f5da1..59fbd327 100644 --- a/tools/fixrom/fixrom.c +++ b/tools/fixrom/fixrom.c @@ -6,8 +6,12 @@ #include <stdnoreturn.h> #include <stdarg.h> -#define HEADER_SIZE 0x4000 +#define HEADER_SIZE 0x4000 +#define HEADER_CODE_OFFSET 0xC +#define HEADER_SECURE_CRC_OFFSET 0x6C +#define HEADER_CRC_OFFSET 0x15E +// ROM header buffer uint8_t RomHeader[HEADER_SIZE]; static inline noreturn __attribute__((format(printf, 1, 2))) void fatal_error(const char * message, ...) @@ -21,6 +25,9 @@ static inline noreturn __attribute__((format(printf, 1, 2))) void fatal_error(co exit(EXIT_FAILURE); } +// Pedantic check to make sure you're writing to or reading from a valid range +// within the ROM header buffer. +// Call twice, once with the first offset and again with the last address. static inline void OffsetCheck(int offset) { if (offset < 0 || offset >= HEADER_SIZE) @@ -29,80 +36,77 @@ static inline void OffsetCheck(int offset) } } +// Wrapper for memcpy that writes to the ROM header buffer +static inline uint8_t * SafeCopyToHeader(int offset, const void * src, size_t size) +{ + OffsetCheck(offset); + OffsetCheck(offset + size - 1); + return memcpy(RomHeader + offset, src, size); +} + +// Read a 16-bit word from the header buffer static inline uint16_t HeaderReadU16LE(int offset) { OffsetCheck(offset); + OffsetCheck(offset + 1); return RomHeader[offset] | (RomHeader[offset + 1] << 8); } +// Read a 32-bit word from the header buffer static inline uint32_t HeaderReadU32LE(int offset) { OffsetCheck(offset); + OffsetCheck(offset + 3); return RomHeader[offset] | (RomHeader[offset + 1] << 8) | (RomHeader[offset + 2] << 16) | (RomHeader[offset + 3] << 24); } +// Write a 16-bit word to the header buffer static inline void HeaderWriteU16LE(int offset, uint16_t value) { OffsetCheck(offset); + OffsetCheck(offset + 1); RomHeader[offset] = value; RomHeader[offset + 1] = value >> 8; } +// Write a 32-bit word to the header buffer static inline void HeaderWriteU32LE(int offset, uint32_t value) { OffsetCheck(offset); + OffsetCheck(offset + 3); RomHeader[offset] = value; RomHeader[offset + 1] = value >> 8; RomHeader[offset + 2] = value >> 16; RomHeader[offset + 3] = value >> 24; } +// Standard CRC16 routine +#define CRC16_POLYNOMIAL 0xA001 + static uint16_t Calc_CRC16(uint8_t * data, size_t length, uint16_t crc) { - static uint16_t CrcTable[16] = { - 0x0000, - 0xCC01, - 0xD801, - 0x1400, - 0xF001, - 0x3C00, - 0x2800, - 0xE401, - 0xA001, - 0x6C00, - 0x7800, - 0xB401, - 0x5000, - 0x9C01, - 0x8801, - 0x4400, - }; - - uint16_t x = 0; - uint16_t y; - uint16_t bit = 0; - uint8_t * end = data + length; - while (data < end) - { - if (bit == 0) - { - x = data[0] | (data[1] << 8); - } - y = CrcTable[crc & 15]; - crc >>= 4; - crc ^= y; - y = CrcTable[(x >> bit) & 15]; - crc ^= y; - bit += 4; - if (bit == 16) - { - data += 2; - bit = 0; + static uint16_t CrcTable[256] = {}; + static int initialized = 0; + int i; + + if (!initialized) { + for (i = 0; i < 256; i++) { + int c = i; + for (int j = 0; j < 8; j++) { + c = (c >> 1) ^ ((c & 1) ? CRC16_POLYNOMIAL : 0); + } + CrcTable[i] = c; } + initialized = 1; } + + for (i = 0; i < length; i++) { + crc = (crc >> 8) ^ CrcTable[(uint8_t)crc] ^ CrcTable[data[i]]; + } + return crc; } @@ -114,20 +118,24 @@ int main(int argc, char ** argv) int override_code = 0; FILE * rom = NULL; + // Parse arguments for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "--secure-crc") == 0) { + // Enforce zero or one if (override_crc) { fatal_error("multiple --secure-crc options specified"); } + // Parse integer char * endptr; unsigned long secure_crc_l = strtoul(argv[++i], &endptr, 0); if (secure_crc_l == 0 && endptr == argv[i]) { fatal_error("argument to --secure-crc must be an integer"); } - if (secure_crc_l >= 0x10000) + // Enforce width + if (secure_crc_l > UINT16_MAX) { fatal_error("argument to --secure-crc must be a 16-bit integer"); } @@ -136,55 +144,66 @@ int main(int argc, char ** argv) } else if (strcmp(argv[i], "--game-code") == 0) { + // Enforce zero or one if (override_code) { fatal_error("multiple --game-code options specified"); } - if (strlen(argv[++i]) > 4) + // Enforce max length + if (strlen(argv[++i]) > sizeof(game_code)) { fatal_error("argument to --game-code must be 4 characters or fewer"); } - strncpy(game_code, argv[i], 4); + memset(game_code, 0, sizeof(game_code)); + strncpy(game_code, argv[i], sizeof(game_code)); override_code = 1; } - else + // Positional arguments + else if (rom == NULL) { - if (rom != NULL) - { - fatal_error("unrecognized %s argument: %s", argv[i][0] == '-' ? "flag" : "positional", argv[i]); - } rom = fopen(argv[i], "r+b"); if (rom == NULL) { fatal_error(argv[i][0] == '-' ? "unrecognized flag argument: %s" : "unable to open file '%s' for reading", argv[i]); } } + else + { + // Invalid argument, complain about it + fatal_error("unrecognized %s argument: %s", argv[i][0] == '-' ? "flag" : "positional", argv[i]); + } } + // Read header to buffer if (fread(RomHeader, 1, HEADER_SIZE, rom) != HEADER_SIZE) { fatal_error("error reading the ROM header"); } + // Update CRC if (override_crc) { - HeaderWriteU16LE(0x6C, secure_crc); + HeaderWriteU16LE(HEADER_SECURE_CRC_OFFSET, secure_crc); } - + + // Update code if (override_code) { - memcpy(RomHeader + 0xC, game_code, 4); + SafeCopyToHeader(HEADER_CODE_OFFSET, game_code, sizeof(game_code)); } - uint16_t header_crc = Calc_CRC16((uint8_t *)RomHeader, 0x15E, 0xFFFF); - HeaderWriteU16LE(0x15E, header_crc); + // Recompute CRC of header not including the crc offset + uint16_t header_crc = Calc_CRC16((uint8_t *)RomHeader, HEADER_CRC_OFFSET, 0xFFFF); + HeaderWriteU16LE(HEADER_CRC_OFFSET, header_crc); + // Write the header back fseek(rom, 0, SEEK_SET); if (fwrite(RomHeader, 1, HEADER_SIZE, rom) != HEADER_SIZE) { fatal_error("error writing the ROM header"); } + // Hooray, we done did it! fclose(rom); return EXIT_SUCCESS; } diff --git a/tools/knarc/Narc.cpp b/tools/knarc/Narc.cpp index 7e698571..cce7cdea 100644 --- a/tools/knarc/Narc.cpp +++ b/tools/knarc/Narc.cpp @@ -29,6 +29,7 @@ using namespace std; extern bool debug; extern bool pack_no_fnt; +extern bool output_header; void Narc::AlignDword(ofstream& ofs, uint8_t paddingChar) { @@ -145,6 +146,39 @@ bool Narc::Pack(const fs::path& fileName, const fs::path& directory) if (!ofs.good()) { return Cleanup(ofs, NarcError::InvalidOutputFile); } + ofstream ofhs; + string stem; + string stem_upper; + // Pikalax 29 May 2021 + // Output an includable header that enumerates the NARC contents + if (output_header) + { + fs::path naixfname = fileName; + naixfname.replace_extension(".naix"); + + ofhs.open(naixfname); + if (!ofhs.good()) + { + ofhs.close(); + return Cleanup(ofs, NarcError::InvalidOutputFile); + } + + stem = fileName.stem().string(); + stem_upper = stem; + for (char &c : stem_upper) + { c = toupper(c); } + + ofhs << "/*\n" + " * THIS FILE WAS AUTOMATICALLY\n" + " * GENERATED BY tools/knarc\n" + " * DO NOT MODIFY!!!\n" + " */\n" + "\n" + "#ifndef NARC_" << stem_upper << "_NAIX_\n" + "#define NARC_" << stem_upper << "_NAIX_\n" + "\n" + "enum {\n"; + } vector<FileAllocationTableEntry> fatEntries; uint16_t directoryCounter = 1; @@ -153,6 +187,7 @@ bool Narc::Pack(const fs::path& fileName, const fs::path& directory) ignore_patterns.push_back(".*keep"); WildcardVector keep_patterns(directory / ".knarckeep"); + int memberNo = 0; for (const auto& de : OrderedDirectoryIterator(directory, true)) { if (is_directory(de)) @@ -164,6 +199,12 @@ bool Narc::Pack(const fs::path& fileName, const fs::path& directory) if (debug) { cerr << "DEBUG: adding file " << de.path() << endl; } + if (output_header) + { + string de_stem = de.path().filename().string(); + std::replace(de_stem.begin(), de_stem.end(), '.', '_'); + ofhs << "\tNARC_" << stem << "_" << de_stem << " = " << (memberNo++) << ",\n"; + } fatEntries.push_back(FileAllocationTableEntry { .Start = 0x0, @@ -183,6 +224,11 @@ bool Narc::Pack(const fs::path& fileName, const fs::path& directory) fatEntries.back().End = fatEntries.back().Start + static_cast<uint32_t>(file_size(de)); } } + if (output_header) + { + ofhs << "};\n\n#endif //NARC_" << stem_upper << "_NAIX_\n"; + ofhs.close(); + } FileAllocationTable fat { diff --git a/tools/knarc/Source.cpp b/tools/knarc/Source.cpp index d9a5cf83..587c8527 100644 --- a/tools/knarc/Source.cpp +++ b/tools/knarc/Source.cpp @@ -8,6 +8,7 @@ using namespace std; bool debug = false; bool pack_no_fnt = true; +bool output_header = false; void PrintError(NarcError error) { @@ -40,6 +41,7 @@ static inline void usage() { cout << "\t-n\tBuild the filename table (default: discards filenames)" << endl; cout << "\t-D/--debug\tPrint additional debug messages" << endl; cout << "\t-h/--help\tPrint this message and exit" << endl; + cout << "\t-i\tOutput a .naix header" << endl; } int main(int argc, char* argv[]) @@ -104,6 +106,9 @@ int main(int argc, char* argv[]) else if (!strcmp(argv[i], "-n")) { pack_no_fnt = false; } + else if (!strcmp(argv[i], "-i")) { + output_header = true; + } else { usage(); cerr << "ERROR: Unrecognized argument: " << argv[i] << endl; diff --git a/tools/nitrogfx/gfx.c b/tools/nitrogfx/gfx.c index 305fbeb2..f5ff30e7 100644 --- a/tools/nitrogfx/gfx.c +++ b/tools/nitrogfx/gfx.c @@ -774,8 +774,9 @@ void WriteNtrCell(char *path, struct JsonToCellOptions *options) KBECHeader[4] = (size + 0x20) & 0xFF; //size KBECHeader[5] = (size + 0x20) >> 8; //unlikely to be more than 16 bits, but there are 32 allocated, change if necessary - fwrite(KBECHeader, 1, 0x20, fp); + KBECHeader[16] = (options->mappingType & 0xFF); //not possible to be more than 8 bits, though 32 are allocated + fwrite(KBECHeader, 1, 0x20, fp); unsigned char *KBECContents = malloc(size); diff --git a/tools/nitrogfx/json.c b/tools/nitrogfx/json.c index aad325be..b825c363 100644 --- a/tools/nitrogfx/json.c +++ b/tools/nitrogfx/json.c @@ -51,16 +51,17 @@ struct JsonToCellOptions *ParseNCERJson(char *path) cJSON *imageHeight = cJSON_GetObjectItemCaseSensitive(json, "imageHeight"); cJSON *imageWidth = cJSON_GetObjectItemCaseSensitive(json, "imageWidth"); cJSON *cellCount = cJSON_GetObjectItemCaseSensitive(json, "cellCount"); + cJSON *mappingType = cJSON_GetObjectItemCaseSensitive(json, "mappingType"); options->labelEnabled = GetBool(labelBool); options->extended = GetBool(extended); options->imageHeight = GetInt(imageHeight); options->imageWidth = GetInt(imageWidth); options->cellCount = GetInt(cellCount); + options->mappingType = GetInt(mappingType); options->cells = malloc(sizeof(struct Cell *) * options->cellCount); - if (options->labelEnabled) { cJSON *labelCount = cJSON_GetObjectItemCaseSensitive(json, "labelCount"); diff --git a/tools/nitrogfx/options.h b/tools/nitrogfx/options.h index 780c83e6..66e9895d 100644 --- a/tools/nitrogfx/options.h +++ b/tools/nitrogfx/options.h @@ -74,6 +74,7 @@ struct Cell { struct JsonToCellOptions { bool labelEnabled; bool extended; + int mappingType; int imageHeight; int imageWidth; int cellCount; diff --git a/tools/o2narc/o2narc.cpp b/tools/o2narc/o2narc.cpp index 1381788a..60e4e242 100644 --- a/tools/o2narc/o2narc.cpp +++ b/tools/o2narc/o2narc.cpp @@ -3,6 +3,7 @@ #include <getopt.h> #include <cstring> #include <vector> +#include <iomanip> #include "elf.h" #include "Narc.h" @@ -49,6 +50,7 @@ class Elf { public: ShdrTab shdr; Symtab symtab; + Elf(string const& filename) : Elf(filename.c_str()) {} Elf(const char * filename) { // Read the ELF header phdr = nullptr; @@ -155,25 +157,29 @@ static inline void usage() { cout << "\toutfile\tOutput NARC file" << endl; cout << "Options:" << endl; cout << "\t-f|--flatten\tDon't generate NARC headers" << endl; + cout << "\t-i|--output-header\tCreate a .naix file" << endl; } int main(int argc, char ** argv) { // CLI arguments - int flatten = 0; + int flatten = 0, output_header = 0; char padding = '\xFF'; static option options [] { { "flatten", no_argument, &flatten, 1 }, { "padding", required_argument, nullptr, 'p' }, + { "output_header", no_argument, &output_header, 1 }, {nullptr, 0, nullptr, 0} }; int opt_index; int c; - while ((c = getopt_long(argc, argv, "fp:", options, &opt_index)) != -1) + while ((c = getopt_long(argc, argv, "fp:i", options, &opt_index)) != -1) { if (c == 'f') { flatten = 1; } else if (c == 'p') { padding = strtol(optarg, NULL, 0); + } else if (c == 'i') { + output_header = 1; } } argv += optind; @@ -188,8 +194,13 @@ int main(int argc, char ** argv) { cerr << "Excess arguments: first unrecognized '" << argv[2] << "'" << endl; return 1; } - char * infname = argv[0]; - char * outfname = argv[1]; + if (output_header && flatten) { + usage(); + cerr << "Incompatible flags: -i, -f" << endl; + return 1; + } + const char * infname = argv[0]; + const char * outfname = argv[1]; // Read the ELF file Elf elf(infname); @@ -201,15 +212,45 @@ int main(int argc, char ** argv) { exit(1); } - fstream ofile; - ofile.open(outfname, ios_base::out | ios_base::binary); + ofstream ofile; + ofile.open(outfname, ios_base::binary); if (!ofile.good()) { cerr << "ERROR: Unable to open '" << outfname << "' for writing" << endl; exit(1); } - if (!flatten) // then build the NARC chunks { + string stem, stem_upper; + ofstream ofheader; + if (output_header) + { + string outhname = outfname; + outhname.replace(outhname.find(".narc"), 5, ".naix"); + ofheader.open(outhname); + if (!ofheader.good()) + { + ofile.close(); + cerr << "ERROR: Unable to open '" << outhname << "' for writing" << endl; + exit(1); + } + stem = outfname; + stem = stem.substr(0, stem.rfind(".")); + stem = stem.substr(stem.rfind("/") + 1); + stem_upper = stem; + for (char &_c : stem_upper) + { _c = toupper(_c); } + + ofheader << "/*\n" + " * THIS FILE WAS AUTOMATICALLY\n" + " * GENERATED BY tools/o2narc\n" + " * DO NOT MODIFY!!!\n" + " */\n" + "\n" + "#ifndef NARC_" << stem_upper << "_NAIX_\n" + "#define NARC_" << stem_upper << "_NAIX_\n" + "\n" + "enum {\n"; + } // .data contains the size table Elf32_Shdr & data_sec = elf.shdr[".data"]; uint32_t * _data = (uint32_t *)elf.read(data_sec); @@ -275,6 +316,15 @@ int main(int argc, char ** argv) { { _rodata[fat_entries[i].Start + j] = padding; } + if (output_header) + { + ofheader << "\tNARC_" << stem << "_narc_" << setw(4) << setfill('0') << i << " = " << i << ",\n"; + } + } + if (output_header) + { + ofheader << "};\n\n#endif //NARC_" << stem_upper << "_NAIX_\n"; + ofheader.close(); } // These NARCs have empty FNTs FileNameTable fnt{ |