Fado, part 2 (#1012)

* Makefile adjustments and additions to build fado

* Fix typo in makefile

* Fix it, maybe?

* Update build tools

* Update build tools

* rm cfg files
This commit is contained in:
EllipticEllipsis
2022-12-06 21:15:23 -05:00
committed by GitHub
parent 90469fd442
commit ea83e49e6e
628 changed files with 317 additions and 1700 deletions
+53 -87
View File
@@ -12,45 +12,41 @@
#define ROM_SEG_START_SUFFIX ".rom_start"
#define ROM_SEG_END_SUFFIX ".rom_end"
struct RomSegment
{
const char *name;
const void *data;
struct RomSegment {
const char* name;
const void* data;
int size;
int romStart;
int romEnd;
};
static struct RomSegment *g_romSegments = NULL;
static struct RomSegment* g_romSegments = NULL;
static int g_romSegmentsCount = 0;
static int g_romSize;
static bool parse_number(const char *str, int *num)
{
char *endptr;
static bool parse_number(const char* str, int* num) {
char* endptr;
long int n = strtol(str, &endptr, 0);
*num = n;
return endptr > str;
}
static unsigned int round_up(unsigned int num, unsigned int multiple)
{
static unsigned int round_up(unsigned int num, unsigned int multiple) {
num += multiple - 1;
return num / multiple * multiple;
}
static char *sprintf_alloc(const char *fmt, ...)
{
static char* sprintf_alloc(const char* fmt, ...) {
va_list args;
int size;
char *buffer;
char* buffer;
va_start(args, fmt);
size = vsnprintf(NULL, 0, fmt, args) + 1;
va_end(args);
buffer = malloc(size);
va_start(args, fmt);
vsprintf(buffer, fmt, args);
va_end(args);
@@ -58,8 +54,7 @@ static char *sprintf_alloc(const char *fmt, ...)
return buffer;
}
static struct RomSegment *add_rom_segment(const char *name)
{
static struct RomSegment* add_rom_segment(const char* name) {
int index = g_romSegmentsCount;
g_romSegmentsCount++;
@@ -71,50 +66,44 @@ static struct RomSegment *add_rom_segment(const char *name)
return &g_romSegments[index];
}
static void find_segment_info(struct Elf32 *elf, struct RomSegment *segment)
{
static void find_segment_info(struct Elf32* elf, struct RomSegment* segment) {
int i;
char *romStartSymName = sprintf_alloc("_%sSegmentRomStart", segment->name);
char *romEndSymName = sprintf_alloc("_%sSegmentRomEnd", segment->name);
char* romStartSymName = sprintf_alloc("_%sSegmentRomStart", segment->name);
char* romEndSymName = sprintf_alloc("_%sSegmentRomEnd", segment->name);
segment->romStart = -1;
segment->romEnd = -1;
// TODO: use a hashmap for this instead of an O(n) loop
for (i = 0; i < elf->numsymbols; i++)
{
for (i = 0; i < elf->numsymbols; i++) {
struct Elf32_Symbol sym;
if (!elf32_get_symbol(elf, &sym, i))
util_fatal_error("invalid or corrupt ELF file");
if (strcmp(sym.name, romStartSymName) == 0)
{
if (strcmp(sym.name, romStartSymName) == 0) {
segment->romStart = sym.value;
if (segment->romEnd != -1)
break;
}
else if (strcmp(sym.name, romEndSymName) == 0)
{
} else if (strcmp(sym.name, romEndSymName) == 0) {
segment->romEnd = sym.value;
if (segment->romStart != -1)
break;
}
}
if (segment->romStart == -1)
util_fatal_error("ROM start address of %s is not defined\n", segment->name);
if (segment->romEnd == -1)
util_fatal_error("ROM end address of %s is not defined\n", segment->name);
free(romStartSymName);
free(romEndSymName);
}
static void parse_input_file(const char *filename)
{
static void parse_input_file(const char* filename) {
struct Elf32 elf;
const void *data;
const void* data;
size_t size;
int i;
@@ -125,45 +114,40 @@ static void parse_input_file(const char *filename)
// get ROM segments
// sections of type SHT_PROGBITS and whose name is ..secname are considered ROM segments
for (i = 0; i < elf.shnum; i++)
{
for (i = 0; i < elf.shnum; i++) {
struct Elf32_Section sec;
struct RomSegment *segment;
struct RomSegment* segment;
if (!elf32_get_section(&elf, &sec, i))
util_fatal_error("invalid or corrupt ELF file");
if (sec.type == SHT_PROGBITS && sec.name[0] == '.' && sec.name[1] == '.'
// HACK! ld sometimes marks NOLOAD sections as SHT_PROGBITS for no apparent reason,
// so we must ignore the ..secname.bss sections explicitly
&& strchr(sec.name + 2, '.') == NULL)
{
if (sec.type == SHT_PROGBITS && sec.name[0] == '.' &&
sec.name[1] == '.'
// HACK! ld sometimes marks NOLOAD sections as SHT_PROGBITS for no apparent reason,
// so we must ignore the ..secname.bss sections explicitly
&& strchr(sec.name + 2, '.') == NULL) {
segment = add_rom_segment(sec.name + 2);
find_segment_info(&elf, segment);
segment->data = elf.data + sec.offset;
}
}
// find ROM size
for (i = 0; i < elf.numsymbols; i++)
{
for (i = 0; i < elf.numsymbols; i++) {
struct Elf32_Symbol sym;
if (!elf32_get_symbol(&elf, &sym, i))
util_fatal_error("invalid or corrupt ELF file");
if (strcmp(sym.name, "_RomSize") == 0)
{
if (strcmp(sym.name, "_RomSize") == 0) {
g_romSize = sym.value;
goto got_rom_size;
}
}
util_fatal_error("could not find symbol _RomSize");
got_rom_size:
got_rom_size:
// verify segment info
for (i = 0; i < g_romSegmentsCount; i++)
{
for (i = 0; i < g_romSegmentsCount; i++) {
if (g_romSegments[i].romStart == -1)
util_fatal_error("segment %s has no ROM start address defined.", g_romSegments[i].name);
if (g_romSegments[i].romEnd == -1)
@@ -172,23 +156,21 @@ static void parse_input_file(const char *filename)
}
// Writes the N64 ROM, padding the file size to a multiple of 1 MiB
static void write_rom_file(const char *filename, int cicType)
{
static void write_rom_file(const char* filename, int cicType) {
size_t fileSize = round_up(g_romSize, 0x100000);
uint8_t *buffer = calloc(fileSize, 1);
uint8_t* buffer = calloc(fileSize, 1);
int i;
uint32_t chksum[2];
// write segments
for (i = 0; i < g_romSegmentsCount; i++)
{
for (i = 0; i < g_romSegmentsCount; i++) {
int size = g_romSegments[i].romEnd - g_romSegments[i].romStart;
memcpy(buffer + g_romSegments[i].romStart, g_romSegments[i].data, size);
}
// pad the remaining space with 0xFF
for (i = g_romSize; i < (int) fileSize; i++)
for (i = g_romSize; i < (int)fileSize; i++)
buffer[i] = 0xFF;
// write checksum
@@ -201,67 +183,51 @@ static void write_rom_file(const char *filename, int cicType)
free(buffer);
}
static void usage(const char *execname)
{
static void usage(const char* execname) {
printf("usage: %s\n", execname);
}
int main(int argc, char **argv)
{
int main(int argc, char** argv) {
int i;
const char *inputFileName = NULL;
const char *outputFileName = NULL;
const char* inputFileName = NULL;
const char* outputFileName = NULL;
int cicType = -1;
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
if (strcmp(argv[i], "-cic") == 0)
{
for (i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
if (strcmp(argv[i], "-cic") == 0) {
i++;
if (i >= argc || !parse_number(argv[i], &cicType))
{
if (i >= argc || !parse_number(argv[i], &cicType)) {
fputs("error: expected number after -cic\n", stderr);
goto bad_args;
}
}
else if (strcmp(argv[i], "-help") == 0)
{
} else if (strcmp(argv[i], "-help") == 0) {
usage(argv[0]);
return 0;
}
else
{
} else {
fprintf(stderr, "unknown option %s\n", argv[i]);
goto bad_args;
}
}
else
{
} else {
if (inputFileName == NULL)
inputFileName = argv[i];
else if (outputFileName == NULL)
outputFileName = argv[i];
else
{
else {
fputs("error: too many parameters specified\n", stderr);
goto bad_args;
}
}
}
if (inputFileName == NULL)
{
if (inputFileName == NULL) {
fputs("error: no input file specified\n", stderr);
goto bad_args;
}
if (outputFileName == NULL)
{
if (outputFileName == NULL) {
fputs("error: no output file specified\n", stderr);
goto bad_args;
}
if (cicType == -1)
{
if (cicType == -1) {
fputs("error: no CIC type specified\n", stderr);
goto bad_args;
}
+68 -93
View File
@@ -5,36 +5,23 @@
#include "elf32.h"
static uint16_t read16_le(const uint8_t *data)
{
return data[0] << 0
| data[1] << 8;
static uint16_t read16_le(const uint8_t* data) {
return data[0] << 0 | data[1] << 8;
}
static uint32_t read32_le(const uint8_t *data)
{
return data[0] << 0
| data[1] << 8
| data[2] << 16
| data[3] << 24;
static uint32_t read32_le(const uint8_t* data) {
return data[0] << 0 | data[1] << 8 | data[2] << 16 | data[3] << 24;
}
static uint16_t read16_be(const uint8_t *data)
{
return data[0] << 8
| data[1] << 0;
static uint16_t read16_be(const uint8_t* data) {
return data[0] << 8 | data[1] << 0;
}
static uint32_t read32_be(const uint8_t *data)
{
return data[0] << 24
| data[1] << 16
| data[2] << 8
| data[3] << 0;
static uint32_t read32_be(const uint8_t* data) {
return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3] << 0;
}
static const void *get_section_header(struct Elf32 *e, int secnum)
{
static const void* get_section_header(struct Elf32* e, int secnum) {
size_t secoffset = e->shoff + secnum * 0x28;
if (secnum >= e->shnum || secoffset >= e->dataSize)
@@ -42,76 +29,70 @@ static const void *get_section_header(struct Elf32 *e, int secnum)
return e->data + secoffset;
}
static const void *get_section_contents(struct Elf32 *e, int secnum)
{
static const void* get_section_contents(struct Elf32* e, int secnum) {
size_t secoffset = e->shoff + secnum * 0x28;
size_t dataoffset;
if (secnum >= e->shnum || secoffset >= e->dataSize)
return NULL;
dataoffset = e->read32(e->data + secoffset + 0x10);
return e->data + dataoffset;
}
static bool verify_magic(const uint8_t *data)
{
static bool verify_magic(const uint8_t* data) {
return (data[0] == 0x7F && data[1] == 'E' && data[2] == 'L' && data[3] == 'F');
}
bool elf32_init(struct Elf32 *e, const void *data, size_t size)
{
bool elf32_init(struct Elf32* e, const void* data, size_t size) {
unsigned int i;
e->data = data;
e->dataSize = size;
if (size < 0x34)
return false; // not big enough for header
return false; // not big enough for header
if (!verify_magic(e->data))
return false;
if (e->data[4] != 1)
return false; // must be 32-bit
return false; // must be 32-bit
e->endian = e->data[5];
switch (e->endian)
{
case 1:
e->read16 = read16_le;
e->read32 = read32_le;
break;
case 2:
e->read16 = read16_be;
e->read32 = read32_be;
break;
default:
return false;
switch (e->endian) {
case 1:
e->read16 = read16_le;
e->read32 = read32_le;
break;
case 2:
e->read16 = read16_be;
e->read32 = read32_be;
break;
default:
return false;
}
e->type = e->read16(e->data + 0x10);
e->machine = e->read16(e->data + 0x12);
e->version = e->data[6];
e->entry = e->read32(e->data + 0x18);
e->phoff = e->read32(e->data + 0x1C);
e->shoff = e->read32(e->data + 0x20);
e->ehsize = e->read16(e->data + 0x28);
e->type = e->read16(e->data + 0x10);
e->machine = e->read16(e->data + 0x12);
e->version = e->data[6];
e->entry = e->read32(e->data + 0x18);
e->phoff = e->read32(e->data + 0x1C);
e->shoff = e->read32(e->data + 0x20);
e->ehsize = e->read16(e->data + 0x28);
e->phentsize = e->read16(e->data + 0x2A);
e->phnum = e->read16(e->data + 0x2C);
e->phnum = e->read16(e->data + 0x2C);
e->shentsize = e->read16(e->data + 0x2E);
e->shnum = e->read16(e->data + 0x30);
e->shstrndx = e->read16(e->data + 0x32);
e->shnum = e->read16(e->data + 0x30);
e->shstrndx = e->read16(e->data + 0x32);
// find symbol table section
e->symtabndx = -1;
for (i = 0; i < e->shnum; i++)
{
const uint8_t *sechdr = get_section_header(e, i);
for (i = 0; i < e->shnum; i++) {
const uint8_t* sechdr = get_section_header(e, i);
uint32_t type = e->read32(sechdr + 0x04);
if (type == SHT_SYMTAB)
{
if (type == SHT_SYMTAB) {
e->symtabndx = i;
break;
}
@@ -119,59 +100,53 @@ bool elf32_init(struct Elf32 *e, const void *data, size_t size)
// find .strtab section
e->strtabndx = -1;
for (i = 0; i < e->shnum; i++)
{
const uint8_t *sechdr = get_section_header(e, i);
for (i = 0; i < e->shnum; i++) {
const uint8_t* sechdr = get_section_header(e, i);
uint32_t type = e->read32(sechdr + 0x04);
if (type == SHT_STRTAB)
{
const char *strings = get_section_contents(e, e->shstrndx);
const char *secname = strings + e->read32(sechdr + 0);
if (strcmp(secname, ".strtab") == 0)
{
if (type == SHT_STRTAB) {
const char* strings = get_section_contents(e, e->shstrndx);
const char* secname = strings + e->read32(sechdr + 0);
if (strcmp(secname, ".strtab") == 0) {
e->strtabndx = i;
break;
}
}
}
e->numsymbols = 0;
if (e->symtabndx != -1)
{
const uint8_t *sechdr = get_section_header(e, e->symtabndx);
//const uint8_t *symtab = get_section_contents(e, e->symtabndx);
if (e->symtabndx != -1) {
const uint8_t* sechdr = get_section_header(e, e->symtabndx);
// const uint8_t *symtab = get_section_contents(e, e->symtabndx);
e->numsymbols = e->read32(sechdr + 0x14) / e->read32(sechdr + 0x24);
}
if (e->shoff + e->shstrndx * 0x28 >= e->dataSize)
return false;
return true;
}
bool elf32_get_section(struct Elf32 *e, struct Elf32_Section *sec, int secnum)
{
const uint8_t *sechdr = get_section_header(e, secnum);
const char *strings = get_section_contents(e, e->shstrndx);
bool elf32_get_section(struct Elf32* e, struct Elf32_Section* sec, int secnum) {
const uint8_t* sechdr = get_section_header(e, secnum);
const char* strings = get_section_contents(e, e->shstrndx);
sec->name = strings + e->read32(sechdr + 0);
sec->type = e->read32(sechdr + 0x04);
sec->flags = e->read32(sechdr + 0x08);
sec->addr = e->read32(sechdr + 0x0C);
sec->offset = e->read32(sechdr + 0x10);
sec->name = strings + e->read32(sechdr + 0);
sec->type = e->read32(sechdr + 0x04);
sec->flags = e->read32(sechdr + 0x08);
sec->addr = e->read32(sechdr + 0x0C);
sec->offset = e->read32(sechdr + 0x10);
sec->addralign = e->read32(sechdr + 0x20);
sec->entsize = e->read32(sechdr + 0x24);
sec->entsize = e->read32(sechdr + 0x24);
return true;
}
bool elf32_get_symbol(struct Elf32 *e, struct Elf32_Symbol *sym, int symnum)
{
const uint8_t *sechdr;
const uint8_t *symtab;
const char *strings;
bool elf32_get_symbol(struct Elf32* e, struct Elf32_Symbol* sym, int symnum) {
const uint8_t* sechdr;
const uint8_t* symtab;
const char* strings;
int symcount;
if (e->symtabndx == -1)
+19 -22
View File
@@ -1,22 +1,22 @@
#ifndef _ELF_H_
#define _ELF_H_
#ifndef ELF32_H
#define ELF32_H
enum
{
#include <stddef.h>
#include <stdint.h>
enum {
ELF_MACHINE_NONE = 0,
ELF_MACHINE_MIPS = 8,
};
enum
{
enum {
ELF_TYPE_RELOC = 1,
ELF_TYPE_EXEC,
ELF_TYPE_SHARED,
ELF_TYPE_CORE,
};
struct Elf32
{
struct Elf32 {
uint8_t endian;
uint16_t type;
uint16_t machine;
@@ -34,23 +34,21 @@ struct Elf32
int strtabndx;
int numsymbols;
const uint8_t *data;
const uint8_t* data;
size_t dataSize;
uint16_t (*read16)(const uint8_t *);
uint32_t (*read32)(const uint8_t *);
uint16_t (*read16)(const uint8_t*);
uint32_t (*read32)(const uint8_t*);
};
enum
{
enum {
SHT_NULL = 0,
SHT_PROGBITS,
SHT_SYMTAB,
SHT_STRTAB,
};
struct Elf32_Section
{
const char *name;
struct Elf32_Section {
const char* name;
uint32_t type;
uint32_t flags;
uint32_t addr;
@@ -59,14 +57,13 @@ struct Elf32_Section
uint32_t entsize;
};
struct Elf32_Symbol
{
const char *name;
struct Elf32_Symbol {
const char* name;
uint32_t value;
};
bool elf32_init(struct Elf32 *e, const void *data, size_t size);
bool elf32_get_section(struct Elf32 *e, struct Elf32_Section *sec, int secnum);
bool elf32_get_symbol(struct Elf32 *e, struct Elf32_Symbol *sym, int symnum);
bool elf32_init(struct Elf32* e, const void* data, size_t size);
bool elf32_get_section(struct Elf32* e, struct Elf32_Section* sec, int secnum);
bool elf32_get_symbol(struct Elf32* e, struct Elf32_Symbol* sym, int symnum);
#endif
+103 -141
View File
@@ -12,18 +12,16 @@
#define ROM_SIZE 0x02000000
enum InputObjType
{
enum InputObjType {
OBJ_NULL,
OBJ_FILE,
OBJ_TABLE,
};
struct InputFile
{
struct InputFile {
enum InputObjType type;
const char *name;
uint8_t *data;
const char* name;
uint8_t* data;
size_t size;
unsigned int valign;
@@ -33,73 +31,58 @@ struct InputFile
uint32_t physEnd;
};
static struct InputFile *g_inputFiles = NULL;
static struct InputFile* g_inputFiles = NULL;
static int g_inputFilesCount = 0;
static unsigned int round_up(unsigned int num, unsigned int multiple)
{
static unsigned int round_up(unsigned int num, unsigned int multiple) {
num += multiple - 1;
return num / multiple * multiple;
}
static bool is_yaz0_header(const uint8_t *data)
{
return data[0] == 'Y'
&& data[1] == 'a'
&& data[2] == 'z'
&& data[3] == '0';
static bool is_yaz0_header(const uint8_t* data) {
return data[0] == 'Y' && data[1] == 'a' && data[2] == 'z' && data[3] == '0';
}
static void compute_offsets(void)
{
static void compute_offsets(void) {
size_t physOffset = 0;
size_t virtOffset = 0;
int i;
for (i = 0; i < g_inputFilesCount; i++)
{
for (i = 0; i < g_inputFilesCount; i++) {
bool compressed = false;
if (g_inputFiles[i].type == OBJ_FILE)
{
if (g_inputFiles[i].type == OBJ_FILE) {
if (is_yaz0_header(g_inputFiles[i].data))
compressed = true;
}
else if (g_inputFiles[i].type == OBJ_TABLE)
{
} else if (g_inputFiles[i].type == OBJ_TABLE) {
g_inputFiles[i].size = g_inputFilesCount * 16;
}
virtOffset = round_up(virtOffset, g_inputFiles[i].valign);
if (g_inputFiles[i].type == OBJ_NULL)
{
if (g_inputFiles[i].type == OBJ_NULL) {
g_inputFiles[i].virtStart = 0;
g_inputFiles[i].virtEnd = 0;
g_inputFiles[i].virtEnd = 0;
g_inputFiles[i].physStart = 0;
g_inputFiles[i].physEnd = 0;
}
else if (compressed)
{
g_inputFiles[i].physEnd = 0;
} else if (compressed) {
size_t compSize = round_up(g_inputFiles[i].size, 16);
size_t uncompSize = util_read_uint32_be(g_inputFiles[i].data + 4);
g_inputFiles[i].virtStart = virtOffset;
g_inputFiles[i].virtEnd = virtOffset + uncompSize;
g_inputFiles[i].virtEnd = virtOffset + uncompSize;
g_inputFiles[i].physStart = physOffset;
g_inputFiles[i].physEnd = physOffset + compSize;
g_inputFiles[i].physEnd = physOffset + compSize;
physOffset += compSize;
virtOffset += uncompSize;
}
else
{
} else {
size_t size = g_inputFiles[i].size;
g_inputFiles[i].virtStart = virtOffset;
g_inputFiles[i].virtEnd = virtOffset + size;
g_inputFiles[i].virtEnd = virtOffset + size;
g_inputFiles[i].physStart = physOffset;
g_inputFiles[i].physEnd = 0;
g_inputFiles[i].physEnd = 0;
physOffset += size;
virtOffset += size;
@@ -107,17 +90,15 @@ static void compute_offsets(void)
}
}
static void build_rom(const char *filename)
{
uint8_t *romData = calloc(ROM_SIZE, 1);
static void build_rom(const char* filename) {
uint8_t* romData = calloc(ROM_SIZE, 1);
size_t pos = 0;
int i;
int j;
uint32_t chksum[2];
FILE *outFile;
FILE* outFile;
for (i = 0; i < g_inputFilesCount; i++)
{
for (i = 0; i < g_inputFilesCount; i++) {
size_t size = g_inputFiles[i].size;
if (pos + round_up(size, 16) > ROM_SIZE)
@@ -125,34 +106,31 @@ static void build_rom(const char *filename)
assert(pos % 16 == 0);
switch (g_inputFiles[i].type)
{
case OBJ_FILE:
// write file data
memcpy(romData + pos, g_inputFiles[i].data, size);
pos += round_up(size, 16);
switch (g_inputFiles[i].type) {
case OBJ_FILE:
// write file data
memcpy(romData + pos, g_inputFiles[i].data, size);
pos += round_up(size, 16);
free(g_inputFiles[i].data);
break;
case OBJ_TABLE:
for (j = 0; j < g_inputFilesCount; j++)
{
util_write_uint32_be(romData + pos + 0, g_inputFiles[j].virtStart);
util_write_uint32_be(romData + pos + 4, g_inputFiles[j].virtEnd);
util_write_uint32_be(romData + pos + 8, g_inputFiles[j].physStart);
util_write_uint32_be(romData + pos + 12, g_inputFiles[j].physEnd);
free(g_inputFiles[i].data);
break;
case OBJ_TABLE:
for (j = 0; j < g_inputFilesCount; j++) {
util_write_uint32_be(romData + pos + 0, g_inputFiles[j].virtStart);
util_write_uint32_be(romData + pos + 4, g_inputFiles[j].virtEnd);
util_write_uint32_be(romData + pos + 8, g_inputFiles[j].physStart);
util_write_uint32_be(romData + pos + 12, g_inputFiles[j].physEnd);
pos += 16;
}
break;
case OBJ_NULL:
break;
pos += 16;
}
break;
case OBJ_NULL:
break;
}
}
// Pad the rest of the ROM
while (pos < ROM_SIZE)
{
while (pos < ROM_SIZE) {
// This is such a weird thing to pad with. Whatever, Nintendo.
romData[pos] = pos & 0xFF;
pos++;
@@ -173,8 +151,7 @@ static void build_rom(const char *filename)
free(romData);
}
static struct InputFile *new_file(void)
{
static struct InputFile* new_file(void) {
int index = g_inputFilesCount;
g_inputFilesCount++;
@@ -186,15 +163,13 @@ static struct InputFile *new_file(void)
}
// null terminates the current token and returns a pointer to the next token
static char *token_split(char *str)
{
while (!isspace(*str))
{
static char* token_split(char* str) {
while (!isspace(*str)) {
if (*str == 0)
return str; // end of string
return str; // end of string
str++;
}
*str = 0; // terminate token
*str = 0; // terminate token
str++;
// skip remaining whitespace
@@ -204,104 +179,94 @@ static char *token_split(char *str)
}
// null terminates the current line and returns a pointer to the next line
static char *line_split(char *str)
{
while (*str != '\n')
{
static char* line_split(char* str) {
while (*str != '\n') {
if (*str == 0)
return str; // end of string
return str; // end of string
str++;
}
*str = 0; // terminate line
*str = 0; // terminate line
return str + 1;
}
static void parse_line(char *line, int lineNum)
{
char *token = line;
static void parse_line(char* line, int lineNum) {
char* token = line;
int i = 0;
char *filename = NULL;
char* filename = NULL;
enum InputObjType type = -1;
int valign = 1;
struct InputFile *file;
struct InputFile* file;
// iterate through each token
while (token[0] != 0)
{
char *nextToken = token_split(token);
while (token[0] != 0) {
char* nextToken = token_split(token);
if (token[0] == '#') // comment - ignore rest of line
if (token[0] == '#') // comment - ignore rest of line
return;
switch (i)
{
case 0:
if (strcmp(token, "file") == 0)
type = OBJ_FILE;
else if (strcmp(token, "filetable") == 0)
type = OBJ_TABLE;
else if (strcmp(token, "null") == 0)
type = OBJ_NULL;
else
util_fatal_error("unknown object type '%s' on line %i", token, lineNum);
break;
case 1:
filename = token;
break;
case 2:
{
switch (i) {
case 0:
if (strcmp(token, "file") == 0)
type = OBJ_FILE;
else if (strcmp(token, "filetable") == 0)
type = OBJ_TABLE;
else if (strcmp(token, "null") == 0)
type = OBJ_NULL;
else
util_fatal_error("unknown object type '%s' on line %i", token, lineNum);
break;
case 1:
filename = token;
break;
case 2: {
int n;
if (sscanf(token, "align(%i)", &n) == 1)
valign = n;
else
goto junk;
}
break;
default:
junk:
util_fatal_error("junk '%s' on line %i", token, lineNum);
break;
} break;
default:
junk:
util_fatal_error("junk '%s' on line %i", token, lineNum);
break;
}
token = nextToken;
i++;
}
if (i == 0) // empty line
if (i == 0) // empty line
return;
file = new_file();
file->valign = valign;
switch (type)
{
case OBJ_FILE:
if (filename == NULL)
util_fatal_error("no filename specified on line %i", lineNum);
file->type = OBJ_FILE;
file->data = util_read_whole_file(filename, &file->size);
break;
case OBJ_TABLE:
file->type = OBJ_TABLE;
break;
case OBJ_NULL:
file->type = OBJ_NULL;
file->size = 0;
break;
switch (type) {
case OBJ_FILE:
if (filename == NULL)
util_fatal_error("no filename specified on line %i", lineNum);
file->type = OBJ_FILE;
file->data = util_read_whole_file(filename, &file->size);
break;
case OBJ_TABLE:
file->type = OBJ_TABLE;
break;
case OBJ_NULL:
file->type = OBJ_NULL;
file->size = 0;
break;
}
}
static void parse_list(char *list)
{
char *line = list;
static void parse_list(char* list) {
char* line = list;
int lineNum = 1;
// iterate through each line
while (line[0] != 0)
{
char *nextLine = line_split(line);
while (line[0] != 0) {
char* nextLine = line_split(line);
parse_line(line, lineNum);
@@ -310,8 +275,7 @@ static void parse_list(char *list)
}
}
static void usage(const char *execName)
{
static void usage(const char* execName) {
printf("usage: %s FILE_LIST OUTPUT_FILE\n"
"where FILE_LIST is a list of files to include\n"
"and OUTPUT_FILE is the name of the output ROM\n"
@@ -319,12 +283,10 @@ static void usage(const char *execName)
execName);
}
int main(int argc, char **argv)
{
char *list;
int main(int argc, char** argv) {
char* list;
if (argc != 3)
{
if (argc != 3) {
puts("invalid args");
usage(argv[0]);
return 1;
+22 -30
View File
@@ -6,12 +6,11 @@
#include "n64chksum.h"
#include "util.h"
//Based on uCON64's N64 checksum algorithm by Andreas Sterbenz
// Based on uCON64's N64 checksum algorithm by Andreas Sterbenz
#define ROL(i, b) (((i) << (b)) | ((i) >> (32 - (b))))
bool n64chksum_calculate(const uint8_t *romData, int cicType, uint32_t *chksum)
{
bool n64chksum_calculate(const uint8_t* romData, int cicType, uint32_t* chksum) {
unsigned int seed;
unsigned int t1, t2, t3, t4, t5, t6;
size_t pos;
@@ -20,29 +19,27 @@ bool n64chksum_calculate(const uint8_t *romData, int cicType, uint32_t *chksum)
const size_t END = START + 0x100000;
// determine initial seed
switch (cicType)
{
case 6101:
case 6102:
seed = 0xF8CA4DDC;
break;
case 6103:
seed = 0xA3886759;
break;
case 6105:
seed = 0xDF26F436;
break;
case 6106:
seed = 0x1FEA617A;
break;
default:
return false; // unknown CIC type
switch (cicType) {
case 6101:
case 6102:
seed = 0xF8CA4DDC;
break;
case 6103:
seed = 0xA3886759;
break;
case 6105:
seed = 0xDF26F436;
break;
case 6106:
seed = 0x1FEA617A;
break;
default:
return false; // unknown CIC type
}
t1 = t2 = t3 = t4 = t5 = t6 = seed;
for (pos = START; pos < END; pos += 4)
{
for (pos = START; pos < END; pos += 4) {
unsigned int d = util_read_uint32_be(romData + pos);
unsigned int r = ROL(d, (d & 0x1F));
@@ -65,18 +62,13 @@ bool n64chksum_calculate(const uint8_t *romData, int cicType, uint32_t *chksum)
t1 += t5 ^ d;
}
if (cicType == 6103)
{
if (cicType == 6103) {
chksum[0] = (t6 ^ t4) + t3;
chksum[1] = (t5 ^ t2) + t1;
}
else if (cicType == 6106)
{
} else if (cicType == 6106) {
chksum[0] = (t6 * t4) + t3;
chksum[1] = (t5 * t2) + t1;
}
else
{
} else {
chksum[0] = t6 ^ t4 ^ t3;
chksum[1] = t5 ^ t2 ^ t1;
}
+3 -3
View File
@@ -1,6 +1,6 @@
#ifndef _N64CHKSUM_H_
#define _N64CHKSUM_H_
#ifndef N64CHKSUM_H
#define N64CHKSUM_H
bool n64chksum_calculate(const uint8_t *romData, int cicType, uint32_t *chksum);
bool n64chksum_calculate(const uint8_t* romData, int cicType, uint32_t* chksum);
#endif
+2 -2
View File
@@ -55,9 +55,9 @@ typedef struct Segment {
void parse_rom_spec(char* spec, struct Segment** segments, int* segment_count);
bool get_single_segment_by_name(struct Segment* dstSegment, char *spec, const char *segmentName);
bool get_single_segment_by_name(struct Segment* dstSegment, char* spec, const char* segmentName);
void free_single_segment_elements(struct Segment *segment);
void free_single_segment_elements(struct Segment* segment);
void free_rom_spec(struct Segment* segments, int segment_count);
+9 -17
View File
@@ -8,8 +8,7 @@
#include "util.h"
// displays an error message and exits
void util_fatal_error(const char *msgfmt, ...)
{
void util_fatal_error(const char* msgfmt, ...) {
va_list args;
fputs(ERRMSG_START, stderr);
@@ -24,10 +23,9 @@ void util_fatal_error(const char *msgfmt, ...)
}
// reads a whole file into memory, and returns a malloc'd pointer to the data.
void *util_read_whole_file(const char *filename, size_t *pSize)
{
FILE *file = fopen(filename, "rb");
uint8_t *buffer;
void* util_read_whole_file(const char* filename, size_t* pSize) {
FILE* file = fopen(filename, "rb");
uint8_t* buffer;
size_t size;
if (file == NULL)
@@ -56,9 +54,8 @@ void *util_read_whole_file(const char *filename, size_t *pSize)
}
// writes data to file
void util_write_whole_file(const char *filename, const void *data, size_t size)
{
FILE *file = fopen(filename, "wb");
void util_write_whole_file(const char* filename, const void* data, size_t size) {
FILE* file = fopen(filename, "wb");
if (file == NULL)
util_fatal_error("failed to open file '%s' for writing: %s", filename, strerror(errno));
@@ -69,17 +66,12 @@ void util_write_whole_file(const char *filename, const void *data, size_t size)
fclose(file);
}
uint32_t util_read_uint32_be(const uint8_t *data)
{
return data[0] << 24
| data[1] << 16
| data[2] << 8
| data[3] << 0;
uint32_t util_read_uint32_be(const uint8_t* data) {
return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3] << 0;
}
// writes a big-endian 32-bit integer
void util_write_uint32_be(uint8_t *data, uint32_t val)
{
void util_write_uint32_be(uint8_t* data, uint32_t val) {
data[0] = val >> 24;
data[1] = val >> 16;
data[2] = val >> 8;
+4 -4
View File
@@ -13,12 +13,12 @@ __attribute__((format(printf, 1, 2), noreturn))
#endif
void util_fatal_error(const char *msgfmt, ...);
void *util_read_whole_file(const char *filename, size_t *pSize);
void* util_read_whole_file(const char* filename, size_t* pSize);
void util_write_whole_file(const char *filename, const void *data, size_t size);
void util_write_whole_file(const char* filename, const void* data, size_t size);
uint32_t util_read_uint32_be(const uint8_t *data);
uint32_t util_read_uint32_be(const uint8_t* data);
void util_write_uint32_be(uint8_t *data, uint32_t val);
void util_write_uint32_be(uint8_t* data, uint32_t val);
#endif
+29 -55
View File
@@ -10,31 +10,25 @@
// src points to the yaz0 source data (to the "real" source data, not at the header!)
// dst points to a buffer uncompressedSize bytes large (you get uncompressedSize from
// the second 4 bytes in the Yaz0 header).
void yaz0_decode(uint8_t* src, uint8_t* dst, int uncompressedSize)
{
int srcPlace = 0, dstPlace = 0; // current read/write positions
void yaz0_decode(uint8_t* src, uint8_t* dst, int uncompressedSize) {
int srcPlace = 0, dstPlace = 0; // current read/write positions
unsigned int validBitCount = 0; // number of valid bits left in "code" byte
unsigned int validBitCount = 0; // number of valid bits left in "code" byte
uint8_t currCodeByte;
while (dstPlace < uncompressedSize)
{
while (dstPlace < uncompressedSize) {
// read new "code" byte if the current one is used up
if (validBitCount == 0)
{
if (validBitCount == 0) {
currCodeByte = src[srcPlace];
++srcPlace;
validBitCount = 8;
}
if ((currCodeByte & 0x80) != 0)
{
if ((currCodeByte & 0x80) != 0) {
// straight copy
dst[dstPlace] = src[srcPlace];
dstPlace++;
srcPlace++;
}
else
{
} else {
// RLE part
uint8_t byte1 = src[srcPlace];
uint8_t byte2 = src[srcPlace + 1];
@@ -44,19 +38,15 @@ void yaz0_decode(uint8_t* src, uint8_t* dst, int uncompressedSize)
unsigned int copySource = dstPlace - (dist + 1);
unsigned int numBytes = byte1 >> 4;
if (numBytes == 0)
{
if (numBytes == 0) {
numBytes = src[srcPlace] + 0x12;
srcPlace++;
}
else
{
} else {
numBytes += 2;
}
// copy run
for (unsigned int i = 0; i < numBytes; ++i)
{
for (unsigned int i = 0; i < numBytes; ++i) {
dst[dstPlace] = dst[copySource];
copySource++;
dstPlace++;
@@ -77,8 +67,7 @@ typedef uint8_t uint8_t;
#define MAX_RUNLEN (0xFF + 0x12)
// simple and straight encoding scheme for Yaz0
static uint32_t simpleEnc(uint8_t *src, int size, int pos, uint32_t *pMatchPos)
{
static uint32_t simpleEnc(uint8_t* src, int size, int pos, uint32_t* pMatchPos) {
int numBytes = 1;
int matchPos = 0;
@@ -92,17 +81,14 @@ static uint32_t simpleEnc(uint8_t *src, int size, int pos, uint32_t *pMatchPos)
if (end > MAX_RUNLEN)
end = MAX_RUNLEN;
for (int i = startPos; i < pos; i++)
{
for (int i = startPos; i < pos; i++) {
int j;
for (j = 0; j < end; j++)
{
for (j = 0; j < end; j++) {
if (src[i + j] != src[j + pos])
break;
}
if (j > numBytes)
{
if (j > numBytes) {
numBytes = j;
matchPos = i;
}
@@ -117,8 +103,7 @@ static uint32_t simpleEnc(uint8_t *src, int size, int pos, uint32_t *pMatchPos)
}
// a lookahead encoding scheme for ngc Yaz0
static uint32_t nintendoEnc(uint8_t *src, int size, int pos, uint32_t *pMatchPos)
{
static uint32_t nintendoEnc(uint8_t* src, int size, int pos, uint32_t* pMatchPos) {
uint32_t numBytes = 1;
static uint32_t numBytes1;
static uint32_t matchPos;
@@ -128,8 +113,7 @@ static uint32_t nintendoEnc(uint8_t *src, int size, int pos, uint32_t *pMatchPos
// was determined by look-ahead try.
// so just use it. this is not the best optimization,
// but nintendo's choice for speed.
if (prevFlag == 1)
{
if (prevFlag == 1) {
*pMatchPos = matchPos;
prevFlag = 0;
return numBytes1;
@@ -140,13 +124,11 @@ static uint32_t nintendoEnc(uint8_t *src, int size, int pos, uint32_t *pMatchPos
*pMatchPos = matchPos;
// if this position is RLE encoded, then compare to copying 1 byte and next position(pos+1) encoding
if (numBytes >= 3)
{
if (numBytes >= 3) {
numBytes1 = simpleEnc(src, size, pos + 1, &matchPos);
// if the next position encoding is +2 longer than current position, choose it.
// this does not guarantee the best optimization, but fairly good optimization with speed.
if (numBytes1 >= numBytes + 2)
{
if (numBytes1 >= numBytes + 2) {
numBytes = 1;
prevFlag = 1;
}
@@ -154,8 +136,7 @@ static uint32_t nintendoEnc(uint8_t *src, int size, int pos, uint32_t *pMatchPos
return numBytes;
}
int yaz0_encode(uint8_t *src, uint8_t *dst, int srcSize)
{
int yaz0_encode(uint8_t* src, uint8_t* dst, int srcSize) {
int srcPos = 0;
int dstPos = 0;
int bufPos = 0;
@@ -163,30 +144,26 @@ int yaz0_encode(uint8_t *src, uint8_t *dst, int srcSize)
uint8_t buf[24]; // 8 codes * 3 bytes maximum
uint32_t validBitCount = 0; // number of valid bits left in "code" byte
uint8_t currCodeByte = 0; // a bitfield, set bits meaning copy, unset meaning RLE
uint8_t currCodeByte = 0; // a bitfield, set bits meaning copy, unset meaning RLE
while (srcPos < srcSize)
{
while (srcPos < srcSize) {
uint32_t numBytes;
uint32_t matchPos;
numBytes = nintendoEnc(src, srcSize, srcPos, &matchPos);
if (numBytes < 3)
{
if (numBytes < 3) {
// straight copy
buf[bufPos] = src[srcPos];
bufPos++;
srcPos++;
//set flag for straight copy
// set flag for straight copy
currCodeByte |= (0x80 >> validBitCount);
}
else
{
//RLE part
} else {
// RLE part
uint32_t dist = srcPos - matchPos - 1;
uint8_t byte1, byte2, byte3;
if (numBytes >= 0x12) // 3 byte encoding
if (numBytes >= 0x12) // 3 byte encoding
{
byte1 = 0 | (dist >> 8);
byte2 = dist & 0xFF;
@@ -197,8 +174,7 @@ int yaz0_encode(uint8_t *src, uint8_t *dst, int srcSize)
numBytes = MAX_RUNLEN;
byte3 = numBytes - 0x12;
buf[bufPos++] = byte3;
}
else // 2 byte encoding
} else // 2 byte encoding
{
byte1 = ((numBytes - 2) << 4) | (dist >> 8);
byte2 = dist & 0xFF;
@@ -211,8 +187,7 @@ int yaz0_encode(uint8_t *src, uint8_t *dst, int srcSize)
validBitCount++;
// write eight codes
if (validBitCount == 8)
{
if (validBitCount == 8) {
dst[dstPos++] = currCodeByte;
for (int j = 0; j < bufPos; j++)
dst[dstPos++] = buf[j];
@@ -223,8 +198,7 @@ int yaz0_encode(uint8_t *src, uint8_t *dst, int srcSize)
}
}
if (validBitCount > 0)
{
if (validBitCount > 0) {
dst[dstPos++] = currCodeByte;
for (int j = 0; j < bufPos; j++)
dst[dstPos++] = buf[j];
+5 -5
View File
@@ -1,10 +1,10 @@
#ifndef _YAZ0_H_
#define _YAZ0_H_
#ifndef YAZ0_H
#define YAZ0_H
int yaz0_encode2(uint8_t *src, uint8_t *dest, int uncompressedSize);
int yaz0_encode2(uint8_t* src, uint8_t* dest, int uncompressedSize);
void yaz0_decode(uint8_t* src, uint8_t* dst, int uncompressedSize);
int yaz0_encode(uint8_t *src, uint8_t *dest, int srcSize);
int yaz0_encode(uint8_t* src, uint8_t* dest, int srcSize);
#endif // _YAZ0_H_
#endif // YAZ0_H