mm/tools/buildtools/makeromfs.c
Tharo 7743e5a2c4
Overhaul the build system (#234)
* wip

* fix

* add disassembler

* Disasm builds OK

* Variable addends

* More wip

* Rodata migration implemented

* Cleanup old tools

* Try fix submodule -> subrepo merge

* git subrepo pull --force --remote=https://github.com/zeldaret/ZAPD.git tools/ZAPD

subrepo:
  subdir:   "tools/ZAPD"
  merged:   "602e609"
upstream:
  origin:   "https://github.com/zeldaret/ZAPD.git"
  branch:   "master"
  commit:   "602e609"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* Builds again but assets are totally broken

* git subrepo pull --force tools/asm-processor

subrepo:
  subdir:   "tools/asm-processor"
  merged:   "1ffdb08a"
upstream:
  origin:   "https://github.com/simonlindholm/asm-processor.git"
  branch:   "master"
  commit:   "1ffdb08a"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* More cleanup, move functions.txt and variables.txt to tools/disasm and rm tables

* rm z64compress in preparation for subrepo

* git subrepo clone (merge) https://github.com/z64me/z64compress.git tools/z64compress

subrepo:
  subdir:   "tools/z64compress"
  merged:   "eb11085c"
upstream:
  origin:   "https://github.com/z64me/z64compress.git"
  branch:   "main"
  commit:   "eb11085c"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* Fix asset extraction

* Fix diff-init make rule

* Split code bss

* Split assumed linker bug padding from assembly files

* add filelists for mm.us.rev1

* Maybe working, but I'm not sure

* add overlays to spec

* Add rodata to actos

* Everything compiles

* Make a lot of C files for code

* Add almost every file in code to spec

* whoops

* 3 code files left

* add scenes to spec

* More progress on progress.py

* Fix skelanime in spec

* audio files!

* Fix merge issues

* Fix some C files in code

* Fix remaining code files

* Use existing O1 C files in spec

* reorder boot order in spec

* update spec

* fault.c

* Convert relocs on completed actors, fixbaserom uses current rom name

* more boot files

* Add VT macros and script

* finish already existing boot files

* most of  libultra

* fix 64bits libultra files

* Use C files for libultra, wrap some functions in NON_MATCHING

* Remove duplicate of OS_CLOCK_RATE from fault.c

* C files for fbdemos

* delete dumb files

* bootstrap C files, still need to add them to the spec

* update fixbaserom

* boot OK?

* I forgot to commit the spec

* C for gamestates

* C for kaleido

* Change all includes to ""

* copy actor sizes script from oot

* I forgot to delete those files

* Basic C files for effects

* Add effects initvars names

* Remove mislabelled boot functions from header/txt

* Begin porting bootstrap_fx, some sizes

* Fix <>

* Fix enum

* Fix diff.py

* fix libultra stuff

* update regconvert

* update setup warnings

* add some missing ;

* Fix some makefile stuff and other fixes on some non_matching functions

* add executable flag in extract_baserom and fixbaserom

* fix relative path

* copy assist from oot

* fix map path

* another assist path fix

* Delete C files for handwritten files

* add code_801A51F0 to spec

* add gfxbuffers to spec

* Move rodata to top of each file when possible

* UNK_TYPEs for func_801A51F0

* Remove kaleido rodata from spec

* Update spec and undefined_syms for recent merge

* GCC warnings and fix errors in nonmatchings,

* round percentage numbers

* progress script: format changes

* progress: error on non-existing files

* fix warning in z_scene_table

* Match 2 nonmatchings in z_actor

* Warnings in lightswitch and invadepoh

* Fix warning in z_actor_dlftbls

* I though I fixed this one

* whoops

* Comment out CC_CHECK

* Removed redundant ultra64.h includes

* Update asm_processor, sorted boot_O1 into other folders, completed the fbdemo bootstrap, cleaned up undefined_syms

* Completed gamestates bootstrap

* Split kaleido_scope

* Remove section.h and segment.h, move keep object externs to a common location in variables.h

* Completed effects bootstrap

* Segmented address externs for effects, fbdemos, gamestates and kaleido

* Move actor data externs out of the if 0

* Segmented address externs for actors

* Prepare actionfunc detection

* fix script, how did it even work before

* Fix actionfunc script again, re-introduce some more intermediate prints to the disassembler

* Automated actionFunc detection in actors

* Segmented addresses from player .text

* rm old segment addrs script and fix build

* Move sizes folder to tools

* Make build.py executable

* New Jenkinsfile Prayge

* Remove numpy dependencies

* Add warnings_disasm_current.txt

* my bad

* Update spec and undefined_syms

* Add z_eff_ss_hahen to pametfrog

* git subrepo pull (merge) --force tools/z64compress

subrepo:
  subdir:   "tools/z64compress"
  merged:   "163ca2af"
upstream:
  origin:   "https://github.com/z64me/z64compress.git"
  branch:   "main"
  commit:   "163ca2af"
git-subrepo:
  version:  "0.4.3"
  origin:   "https://github.com/ingydotnet/git-subrepo"
  commit:   "2f68596"

* Make z64compress print to stdout

* sneeky commit to update warnings tooling

* test

* Another test

* Mark fixing overlay reloc generating as a TODO

* Update warnings stuff

* Communicate the return code from running z64compress back to the Makefile through the wrapper

* Run formatter, remove extra commented copy of function

* Re-fix some includes

* Convert atan to hex to conform to decided style

* Some tidying up, remove c for fp and the other two handwritten code files

* BSS in z_collision_check & z_scene_proc

* add static back in

* Fix timerintr bss, add file to spec, some cleanup

* Remove externs

* Newline

* Readd enums

* Typo

* Colours

* Comments for hitmark enum values

Co-authored-by: EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com>

* Improvements and suggestions

* Organize and remove unused imports and use env for python3 scripts, delete unused overlay.py

Co-authored-by: angie <angheloalf95@gmail.com>
Co-authored-by: Elliptic Ellipsis <elliptic.ellipsis@gmail.com>
Co-authored-by: engineer124 <engineer124engineer124@gmail.com>
Co-authored-by: EllipticEllipsis <73679967+EllipticEllipsis@users.noreply.github.com>
2021-08-03 23:21:31 -04:00

343 lines
7.8 KiB
C

#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "n64chksum.h"
#include "util.h"
#define ROM_SIZE 0x02000000
enum InputObjType
{
OBJ_NULL,
OBJ_FILE,
OBJ_TABLE,
};
struct InputFile
{
enum InputObjType type;
const char *name;
uint8_t *data;
size_t size;
unsigned int valign;
uint32_t virtStart;
uint32_t virtEnd;
uint32_t physStart;
uint32_t physEnd;
};
static struct InputFile *g_inputFiles = NULL;
static int g_inputFilesCount = 0;
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 void compute_offsets(void)
{
size_t physOffset = 0;
size_t virtOffset = 0;
int i;
for (i = 0; i < g_inputFilesCount; i++)
{
bool compressed = false;
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)
{
g_inputFiles[i].size = g_inputFilesCount * 16;
}
virtOffset = round_up(virtOffset, g_inputFiles[i].valign);
if (g_inputFiles[i].type == OBJ_NULL)
{
g_inputFiles[i].virtStart = 0;
g_inputFiles[i].virtEnd = 0;
g_inputFiles[i].physStart = 0;
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].physStart = physOffset;
g_inputFiles[i].physEnd = physOffset + compSize;
physOffset += compSize;
virtOffset += uncompSize;
}
else
{
size_t size = g_inputFiles[i].size;
g_inputFiles[i].virtStart = virtOffset;
g_inputFiles[i].virtEnd = virtOffset + size;
g_inputFiles[i].physStart = physOffset;
g_inputFiles[i].physEnd = 0;
physOffset += size;
virtOffset += size;
}
}
}
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;
for (i = 0; i < g_inputFilesCount; i++)
{
size_t size = g_inputFiles[i].size;
if (pos + round_up(size, 16) > ROM_SIZE)
util_fatal_error("size exceeds max ROM size of 32 KiB");
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);
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;
}
}
// Pad the rest of the ROM
while (pos < ROM_SIZE)
{
// This is such a weird thing to pad with. Whatever, Nintendo.
romData[pos] = pos & 0xFF;
pos++;
}
// calculate checksum
n64chksum_calculate(romData, 6105, chksum);
util_write_uint32_be(romData + 0x10, chksum[0]);
util_write_uint32_be(romData + 0x14, chksum[1]);
// write file
outFile = fopen(filename, "wb");
if (outFile == NULL)
util_fatal_error("failed to open file '%s' for writing", filename);
fwrite(romData, ROM_SIZE, 1, outFile);
fclose(outFile);
free(romData);
}
static struct InputFile *new_file(void)
{
int index = g_inputFilesCount;
g_inputFilesCount++;
g_inputFiles = realloc(g_inputFiles, g_inputFilesCount * sizeof(*g_inputFiles));
g_inputFiles[index].valign = 1;
return &g_inputFiles[index];
}
// null terminates the current token and returns a pointer to the next token
static char *token_split(char *str)
{
while (!isspace(*str))
{
if (*str == 0)
return str; // end of string
str++;
}
*str = 0; // terminate token
str++;
// skip remaining whitespace
while (isspace(*str))
str++;
return str;
}
// null terminates the current line and returns a pointer to the next line
static char *line_split(char *str)
{
while (*str != '\n')
{
if (*str == 0)
return str; // end of string
str++;
}
*str = 0; // terminate line
return str + 1;
}
static void parse_line(char *line, int lineNum)
{
char *token = line;
int i = 0;
char *filename = NULL;
enum InputObjType type = -1;
int valign = 1;
struct InputFile *file;
// iterate through each token
while (token[0] != 0)
{
char *nextToken = token_split(token);
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:
{
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;
}
token = nextToken;
i++;
}
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;
}
}
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);
parse_line(line, lineNum);
line = nextLine;
lineNum++;
}
}
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"
"note that 'dmadata' refers to the file list itself and not an external file\n",
execName);
}
int main(int argc, char **argv)
{
char *list;
if (argc != 3)
{
puts("invalid args");
usage(argv[0]);
return 1;
}
list = util_read_whole_file(argv[1], NULL);
parse_list(list);
compute_offsets();
build_rom(argv[2]);
free(list);
return 0;
}