summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorAkira Akashi <rubenru09@aol.com>2021-06-02 22:13:57 +0100
committerGitHub <noreply@github.com>2021-06-02 22:13:57 +0100
commit9d3d4a2acff67f43896e9e0dcd26e7aaeb55e3b3 (patch)
treed707aa8fead427dadbbb29b886875e6c8961bd5a /tools
parenta2a17a9426f16ee601ff17840b8bb7851fef7138 (diff)
parent7e32d3758e7e36d7a67a1442cdb9386f9aa18a6e (diff)
Merge branch 'master' into 0202A1E0
Diffstat (limited to 'tools')
-rwxr-xr-xtools/asm_processor/asm_processor.py14
-rw-r--r--tools/fixrom/fixrom.c125
-rw-r--r--tools/knarc/Narc.cpp46
-rw-r--r--tools/knarc/Source.cpp5
-rw-r--r--tools/nitrogfx/gfx.c3
-rw-r--r--tools/nitrogfx/json.c3
-rw-r--r--tools/nitrogfx/options.h1
-rw-r--r--tools/o2narc/o2narc.cpp64
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{