You've already forked Microtransactions64
mirror of
https://github.com/Print-and-Panic/Microtransactions64.git
synced 2026-01-21 10:17:19 -08:00
Refresh 10
This commit is contained in:
16
tools/.gitignore
vendored
16
tools/.gitignore
vendored
@@ -1,16 +1,16 @@
|
||||
/aifc_decode
|
||||
/aiff_extract_codebook
|
||||
/armips
|
||||
/extract_data_for_mio
|
||||
/mio0
|
||||
/n64cksum
|
||||
/n64graphics
|
||||
/textconv
|
||||
/patch_libultra_math
|
||||
/iplfontutil
|
||||
/n64graphics_ci
|
||||
/aifc_decode
|
||||
/aiff_extract_codebook
|
||||
/vadpcm_enc
|
||||
/tabledesign
|
||||
/extract_data_for_mio
|
||||
/patch_libultra_math
|
||||
/skyconv
|
||||
/tabledesign
|
||||
/textconv
|
||||
/vadpcm_enc
|
||||
!/ido5.3_compiler/lib/*.so
|
||||
!/ido5.3_compiler/usr/lib/*.so
|
||||
!/ido5.3_compiler/usr/lib/*.so.1
|
||||
|
||||
@@ -1,49 +1,58 @@
|
||||
CC := gcc
|
||||
CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 -O3 -s
|
||||
PROGRAMS := n64graphics n64graphics_ci mio0 n64cksum textconv patch_libultra_math iplfontutil aifc_decode aiff_extract_codebook vadpcm_enc tabledesign extract_data_for_mio skyconv
|
||||
CXX := g++
|
||||
CFLAGS := -I . -Wall -Wextra -Wno-unused-parameter -pedantic -std=c99 -O2 -s
|
||||
LDFLAGS := -lm
|
||||
PROGRAMS := n64graphics n64graphics_ci mio0 n64cksum textconv patch_libultra_math aifc_decode aiff_extract_codebook vadpcm_enc tabledesign extract_data_for_mio skyconv
|
||||
|
||||
# if armips is not found on the system, build it in tools
|
||||
ifeq (, $(shell which armips 2> /dev/null))
|
||||
CXX_PROGRAMS += armips
|
||||
endif
|
||||
|
||||
default: all
|
||||
|
||||
armips: armips.cpp
|
||||
$(CXX) $(CXXFLAGS) -fno-exceptions -fno-rtti -pipe $^ -o $@ -lpthread
|
||||
|
||||
n64graphics_SOURCES := n64graphics.c utils.c
|
||||
n64graphics_CFLAGS := -DN64GRAPHICS_STANDALONE
|
||||
|
||||
n64graphics_ci_SOURCES := n64graphics_ci_dir/n64graphics_ci.c n64graphics_ci_dir/exoquant/exoquant.c n64graphics_ci_dir/utils.c
|
||||
n64graphics_ci_CFLAGS := -O2 # 3s faster compile time
|
||||
|
||||
mio0_SOURCES := libmio0.c
|
||||
mio0_CFLAGS := -DMIO0_STANDALONE
|
||||
|
||||
n64cksum_SOURCES := n64cksum.c libmio0.c libsm64.c utils.c
|
||||
n64cksum_SOURCES := n64cksum.c utils.c
|
||||
n64cksum_CFLAGS := -DN64CKSUM_STANDALONE
|
||||
|
||||
textconv_SOURCES := textconv.c utf8.c hashtable.c
|
||||
patch_libultra_math_SOURCES := patch_libultra_math.c
|
||||
|
||||
iplfontutil_SOURCES := iplfontutil.c
|
||||
iplfontutil_CFLAGS := -O2 # faster compile time
|
||||
|
||||
aifc_decode_SOURCES := aifc_decode.c
|
||||
aifc_decode_CFLAGS := -O2 # both runs and compiles faster than -O3
|
||||
|
||||
aiff_extract_codebook_SOURCES := aiff_extract_codebook.c
|
||||
|
||||
tabledesign_SOURCES := sdk-tools/tabledesign/codebook.c sdk-tools/tabledesign/estimate.c sdk-tools/tabledesign/print.c sdk-tools/tabledesign/tabledesign.c
|
||||
tabledesign_CFLAGS := -Wno-uninitialized -laudiofile
|
||||
tabledesign_CFLAGS := -Wno-uninitialized
|
||||
tabledesign_LDFLAGS := -laudiofile
|
||||
|
||||
vadpcm_enc_SOURCES := sdk-tools/adpcm/vadpcm_enc.c sdk-tools/adpcm/vpredictor.c sdk-tools/adpcm/quant.c sdk-tools/adpcm/util.c sdk-tools/adpcm/vencode.c
|
||||
vadpcm_enc_CFLAGS := -Wno-unused-result -Wno-uninitialized -Wno-sign-compare -Wno-absolute-value
|
||||
|
||||
extract_data_for_mio_SOURCES := extract_data_for_mio.c
|
||||
extract_data_for_mio_CFLAGS := -O2
|
||||
|
||||
skyconv_SOURCES := skyconv.c n64graphics.c utils.c
|
||||
skyconv_CFLAGS := -O2 -lm
|
||||
|
||||
all: $(PROGRAMS)
|
||||
all: $(PROGRAMS) $(CXX_PROGRAMS)
|
||||
|
||||
clean:
|
||||
$(RM) $(PROGRAMS)
|
||||
$(RM) $(PROGRAMS) $(CXX_PROGRAMS)
|
||||
|
||||
define COMPILE
|
||||
$(1): $($1_SOURCES)
|
||||
$(CC) $(CFLAGS) $$^ -lm -o $$@ $($1_CFLAGS)
|
||||
$(CC) $(CFLAGS) $($1_CFLAGS) $$^ -o $$@ $(LDFLAGS) $($1_LDFLAGS)
|
||||
endef
|
||||
|
||||
$(foreach p,$(PROGRAMS),$(eval $(call COMPILE,$(p))))
|
||||
|
||||
.PHONY: all clean default
|
||||
|
||||
19906
tools/armips.cpp
Normal file
19906
tools/armips.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -481,11 +481,16 @@ def write_aifc(entry, out):
|
||||
|
||||
|
||||
def write_aiff(entry, filename):
|
||||
with tempfile.NamedTemporaryFile(suffix=".aifc") as temp:
|
||||
temp = tempfile.NamedTemporaryFile(suffix=".aifc", delete=False)
|
||||
try:
|
||||
write_aifc(entry, temp)
|
||||
temp.flush()
|
||||
temp.close()
|
||||
aifc_decode = os.path.join(os.path.dirname(__file__), "aifc_decode")
|
||||
subprocess.run([aifc_decode, temp.name, filename], check=True)
|
||||
finally:
|
||||
temp.close()
|
||||
os.remove(temp.name)
|
||||
|
||||
|
||||
# Modified from https://stackoverflow.com/a/25935321/1359139, cc by-sa 3.0
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define STBI_NO_LINEAR
|
||||
#define STBI_NO_PSD
|
||||
#define STBI_NO_TGA
|
||||
#define STBI_NO_HDR
|
||||
#define STBI_NO_PIC
|
||||
#define STBI_NO_PNM
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include <stb/stb_image_write.h>
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb/stb_image.h>
|
||||
|
||||
#define GETBIT(buf, idx) ((buf[(idx)/8] >> (7-((idx)%8))) & 1)
|
||||
#define SETBIT(buf, idx) buf[(idx)/8] |= (1 << (7-((idx)%8)))
|
||||
|
||||
#define IPL3_FONT_NCHARS 50
|
||||
#define IPL3_FONT_CHAR_W 13
|
||||
#define IPL3_FONT_CHAR_H 14
|
||||
#define IPL3_FONT_CHAR_NPIXELS (IPL3_FONT_CHAR_W * IPL3_FONT_CHAR_H)
|
||||
#define IPL3_FONT_CHAR_NBITS (IPL3_FONT_CHAR_NPIXELS + 2)
|
||||
#define IPL3_FONT_CHAR_NBYTES (IPL3_FONT_CHAR_NBITS / 8)
|
||||
|
||||
#define IPL3_FONT_FILE_SIZE ((IPL3_FONT_NCHARS * IPL3_FONT_CHAR_NBYTES) + 0x12)
|
||||
|
||||
int ipl3font_decode(const char *binPath, const char *imgPath)
|
||||
{
|
||||
FILE *binfp = fopen(binPath, "rb");
|
||||
|
||||
if(binfp == NULL)
|
||||
{
|
||||
printf("error: could not open %s for input\n", binPath);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fseek(binfp, 0, SEEK_END);
|
||||
size_t binSize = ftell(binfp);
|
||||
|
||||
if(binSize != IPL3_FONT_FILE_SIZE)
|
||||
{
|
||||
printf("error: font bin size invalid (must be 0x%X bytes)\n", IPL3_FONT_FILE_SIZE);
|
||||
fclose(binfp);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
rewind(binfp);
|
||||
|
||||
char *binBuf = (char *) malloc(binSize);
|
||||
if(fread(binBuf, 1, binSize, binfp) != binSize)
|
||||
{
|
||||
printf("error: failed to read from %s\n", binPath);
|
||||
fclose(binfp);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fclose(binfp);
|
||||
|
||||
uint32_t outSize = IPL3_FONT_NCHARS * IPL3_FONT_CHAR_NPIXELS * sizeof(uint32_t);
|
||||
uint32_t *outRgba32 = (uint32_t *) malloc(outSize);
|
||||
int outIdx = 0;
|
||||
|
||||
for(int nChar = 0; nChar < IPL3_FONT_NCHARS; nChar++)
|
||||
{
|
||||
for(int nRow = 0; nRow < IPL3_FONT_CHAR_H; nRow++)
|
||||
{
|
||||
for(int nCol = 0; nCol < IPL3_FONT_CHAR_W; nCol++)
|
||||
{
|
||||
int idx = (nChar * IPL3_FONT_CHAR_NBITS) + (nRow * IPL3_FONT_CHAR_W) + nCol;
|
||||
int bit = GETBIT(binBuf, idx);
|
||||
outRgba32[outIdx++] = (bit == 1) ? 0xFFFFFFFF : 0xFF000000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int stbres = stbi_write_png(imgPath,
|
||||
IPL3_FONT_CHAR_W,
|
||||
IPL3_FONT_NCHARS * IPL3_FONT_CHAR_H,
|
||||
4,
|
||||
outRgba32,
|
||||
IPL3_FONT_CHAR_W * sizeof(uint32_t));
|
||||
|
||||
if(stbres == 0)
|
||||
{
|
||||
printf("error: failed to write %s\n", imgPath);
|
||||
free(outRgba32);
|
||||
free(binBuf);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
free(outRgba32);
|
||||
free(binBuf);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int ipl3font_encode(const char *imgPath, const char *binPath)
|
||||
{
|
||||
int x, y, channels_in_file;
|
||||
uint32_t *inRgba32 = (uint32_t *) stbi_load(imgPath, &x, &y, &channels_in_file, 4);
|
||||
|
||||
if(inRgba32 == NULL)
|
||||
{
|
||||
printf("error: failed to load %s\n", imgPath);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(x != IPL3_FONT_CHAR_W || y != IPL3_FONT_NCHARS * IPL3_FONT_CHAR_H)
|
||||
{
|
||||
printf("error: invalid ipl3 font image dimensions (must be %dx%d)\n",
|
||||
IPL3_FONT_CHAR_W, IPL3_FONT_NCHARS * IPL3_FONT_CHAR_H);
|
||||
stbi_image_free(inRgba32);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
char *out = calloc(IPL3_FONT_FILE_SIZE, 1);
|
||||
|
||||
int inIdx = 0;
|
||||
|
||||
for(int nChar = 0; nChar < IPL3_FONT_NCHARS; nChar++)
|
||||
{
|
||||
for(int nRow = 0; nRow < IPL3_FONT_CHAR_H; nRow++)
|
||||
{
|
||||
for(int nCol = 0; nCol < IPL3_FONT_CHAR_W; nCol++)
|
||||
{
|
||||
// source pixels that are not 0xFFFFFFFF are ignored
|
||||
if(inRgba32[inIdx++] == 0xFFFFFFFF)
|
||||
{
|
||||
int idx = (nChar * IPL3_FONT_CHAR_NBITS) + (nRow * IPL3_FONT_CHAR_W) + nCol;
|
||||
SETBIT(out, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FILE * outfp = fopen(binPath, "wb");
|
||||
|
||||
if(outfp == NULL)
|
||||
{
|
||||
printf("error: failed to write to %s\n", binPath);
|
||||
stbi_image_free(inRgba32);
|
||||
free(out);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fwrite(out, 1, IPL3_FONT_FILE_SIZE, outfp);
|
||||
fclose(outfp);
|
||||
|
||||
stbi_image_free(inRgba32);
|
||||
free(out);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
if(argc < 4)
|
||||
{
|
||||
printf("error: no paths\n");
|
||||
printf("iplfontutil e <input_img> <output_bin>\n");
|
||||
printf("iplfontutil d <input_bin> <output_img>\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
const char *mode = argv[1];
|
||||
|
||||
if(strcmp(mode, "e") == 0)
|
||||
{
|
||||
return ipl3font_encode(argv[2], argv[3]);
|
||||
}
|
||||
else if(strcmp(mode, "d") == 0)
|
||||
{
|
||||
return ipl3font_decode(argv[2], argv[3]);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("error: unknown mode\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
439
tools/libsm64.c
439
tools/libsm64.c
@@ -1,439 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libmio0.h"
|
||||
#include "libsm64.h"
|
||||
#include "utils.h"
|
||||
|
||||
// TODO: make these configurable
|
||||
#define IN_START_ADDR 0x000D0000
|
||||
#define OUT_START_ADDR 0x00800000
|
||||
|
||||
// MIPS instruction decoding
|
||||
#define OPCODE(IBUF_) ((IBUF_)[0] & 0xFC)
|
||||
#define RS(IBUF_) ( (((IBUF_)[0] & 0x3) < 3) | (((IBUF_)[1] & 0xE0) > 5) )
|
||||
#define RT(IBUF_) ((IBUF_)[1] & 0x1F)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int old; // MIO0 address in original ROM
|
||||
unsigned int old_end; // ending MIO0 address in original ROM
|
||||
unsigned int new; // starting MIO0 address in extended ROM
|
||||
unsigned int new_end; // ending MIO0 address in extended ROM
|
||||
unsigned int addr; // ASM address for referenced pointer
|
||||
unsigned int a1_addiu; // ASM offset for ADDIU for A1
|
||||
unsigned char command; // command type: 0x1A or 0x18 (or 0xFF for ASM)
|
||||
} ptr_t;
|
||||
|
||||
// find a pointer in the list and return index
|
||||
// ptr: address to find in table old values
|
||||
// table: list of addresses to MIO0 data
|
||||
// count: number of addresses in table
|
||||
// returns index in table if found, -1 otherwise
|
||||
static int find_ptr(unsigned int ptr, ptr_t table[], int count)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (ptr == table[i].old) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// find locations of existing MIO0 data
|
||||
// buf: buffer containing SM64 data
|
||||
// length: length of buf
|
||||
// table: table to store MIO0 addresses in
|
||||
// returns number of MIO0 files stored in table old values
|
||||
static int find_mio0(unsigned char *buf, unsigned int length, ptr_t table[])
|
||||
{
|
||||
unsigned int addr;
|
||||
int count = 0;
|
||||
|
||||
// MIO0 data is on 16-byte boundaries
|
||||
for (addr = IN_START_ADDR; addr < length; addr += 16) {
|
||||
if (!memcmp(&buf[addr], "MIO0", 4)) {
|
||||
table[count].old = addr;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// find pointers to MIO0 files and stores command type
|
||||
// buf: buffer containing SM64 data
|
||||
// length: length of buf
|
||||
// table: list of addresses to MIO0 data
|
||||
// count: number of addresses in table
|
||||
static void find_pointers(unsigned char *buf, unsigned int length, ptr_t table[], int count)
|
||||
{
|
||||
unsigned int addr;
|
||||
unsigned int ptr;
|
||||
int idx;
|
||||
|
||||
for (addr = IN_START_ADDR; addr < length; addr += 4) {
|
||||
if ((buf[addr] == 0x18 || buf[addr] == 0x1A) && buf[addr+1] == 0x0C && buf[addr+2] == 0x00) {
|
||||
ptr = read_u32_be(&buf[addr+4]);
|
||||
idx = find_ptr(ptr, table, count);
|
||||
if (idx >= 0) {
|
||||
table[idx].command = buf[addr];
|
||||
table[idx].old_end = read_u32_be(&buf[addr+8]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int la2int(unsigned char *buf, unsigned int lui, unsigned int addiu)
|
||||
{
|
||||
unsigned short addr_low, addr_high;
|
||||
addr_high = read_u16_be(&buf[lui + 0x2]);
|
||||
addr_low = read_u16_be(&buf[addiu + 0x2]);
|
||||
// ADDIU sign extends which causes the encoded high val to be +1 if low MSb is set
|
||||
if (addr_low & 0x8000) {
|
||||
addr_high--;
|
||||
}
|
||||
return (addr_high << 16) | addr_low;
|
||||
}
|
||||
|
||||
// find references to the MIO0 blocks in ASM and store type
|
||||
// buf: buffer containing SM64 data
|
||||
// length: length of buf
|
||||
// table: list of addresses to MIO0 data
|
||||
// count: number of addresses in table
|
||||
static void find_asm_pointers(unsigned char *buf, ptr_t table[], int count)
|
||||
{
|
||||
// find the ASM references
|
||||
// looking for some code that follows one of the below patterns:
|
||||
// lui a1, start_upper lui a1, start_upper
|
||||
// lui a2, end_upper lui a2, end_upper
|
||||
// addiu a2, a2, end_lower addiu a2, a2, end_lower
|
||||
// addiu a1, a1, start_lower jal function
|
||||
// jal function addiu a1, a1, start_lower
|
||||
unsigned int addr;
|
||||
unsigned int ptr;
|
||||
unsigned int end;
|
||||
int idx;
|
||||
for (addr = 0; addr < IN_START_ADDR; addr += 4) {
|
||||
if (OPCODE(&buf[addr]) == 0x3C && OPCODE(&buf[addr+4]) == 0x3C && OPCODE(&buf[addr+8]) == 0x24) {
|
||||
unsigned int a1_addiu = 0;
|
||||
if (OPCODE(&buf[addr+0xc]) == 0x24) {
|
||||
a1_addiu = 0xc;
|
||||
} else if (OPCODE(&buf[addr+0x10]) == 0x24) {
|
||||
a1_addiu = 0x10;
|
||||
}
|
||||
if (a1_addiu) {
|
||||
if ( (RT(&buf[addr]) == RT(&buf[addr+a1_addiu]))
|
||||
&& (RT(&buf[addr+4]) == RT(&buf[addr+8])) ) {
|
||||
ptr = la2int(buf, addr, addr + a1_addiu);
|
||||
end = la2int(buf, addr + 4, addr + 0x8);
|
||||
idx = find_ptr(ptr, table, count);
|
||||
if (idx >= 0) {
|
||||
INFO("Found ASM reference to %X at %X\n", ptr, addr);
|
||||
table[idx].command = 0xFF;
|
||||
table[idx].addr = addr;
|
||||
table[idx].new_end = end;
|
||||
table[idx].a1_addiu = a1_addiu;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjust pointers to from old to new locations
|
||||
// buf: buffer containing SM64 data
|
||||
// length: length of buf
|
||||
// table: list of addresses to MIO0 data
|
||||
// count: number of addresses in table
|
||||
static void sm64_adjust_pointers(unsigned char *buf, unsigned int length, ptr_t table[], int count)
|
||||
{
|
||||
unsigned int addr;
|
||||
unsigned int old_ptr;
|
||||
int idx;
|
||||
for (addr = IN_START_ADDR; addr < length; addr += 4) {
|
||||
if ((buf[addr] == 0x17 || buf[addr] == 0x18 || buf[addr] == 0x1A) && buf[addr+1] == 0x0C && buf[addr+2] < 0x02) {
|
||||
old_ptr = read_u32_be(&buf[addr+4]);
|
||||
idx = find_ptr(old_ptr, table, count);
|
||||
if (idx >= 0) {
|
||||
INFO("Old pointer at %X = ", addr);
|
||||
INFO_HEX(&buf[addr], 12);
|
||||
INFO("\n");
|
||||
write_u32_be(&buf[addr+4], table[idx].new);
|
||||
write_u32_be(&buf[addr+8], table[idx].new_end);
|
||||
if (buf[addr] != table[idx].command) {
|
||||
buf[addr] = table[idx].command;
|
||||
}
|
||||
INFO("NEW pointer at %X = ", addr);
|
||||
INFO_HEX(&buf[addr], 12);
|
||||
INFO("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// adjust 'pointer' encoded in ASM LUI and ADDIU instructions
|
||||
static void sm64_adjust_asm(unsigned char *buf, ptr_t table[], int count)
|
||||
{
|
||||
unsigned int addr;
|
||||
int i;
|
||||
unsigned short addr_low, addr_high;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (table[i].command == 0xFF) {
|
||||
addr = table[i].addr;
|
||||
INFO("Old ASM reference at %X = ", addr);
|
||||
INFO_HEX(&buf[addr], 0x14);
|
||||
INFO("\n");
|
||||
addr_low = table[i].new & 0xFFFF;
|
||||
addr_high = (table[i].new >> 16) & 0xFFFF;
|
||||
// ADDIU sign extends which causes the summed high to be 1 less if low MSb is set
|
||||
if (addr_low & 0x8000) {
|
||||
addr_high++;
|
||||
}
|
||||
write_u16_be(&buf[addr + 0x2], addr_high);
|
||||
write_u16_be(&buf[addr + table[i].a1_addiu+2], addr_low);
|
||||
|
||||
addr_low = table[i].new_end & 0xFFFF;
|
||||
addr_high = (table[i].new_end >> 16) & 0xFFFF;
|
||||
if (addr_low & 0x8000) {
|
||||
addr_high++;
|
||||
}
|
||||
write_u16_be(&buf[addr + 0x6], addr_high);
|
||||
write_u16_be(&buf[addr + 0xa], addr_low);
|
||||
INFO("NEW ASM reference at %X = ", addr);
|
||||
INFO_HEX(&buf[addr], 0x14);
|
||||
INFO(" [%06X - %06X]\n", table[i].new, table[i].new_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compute N64 ROM checksums
|
||||
// buf: buffer with extended SM64 data
|
||||
// cksum: two element array to write CRC1 and CRC2 to
|
||||
// TODO: this could be hand optimized
|
||||
static void sm64_calc_checksums(unsigned char *buf, unsigned int cksum[]) {
|
||||
unsigned int t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
|
||||
unsigned int s0, s6;
|
||||
unsigned int a0, a1, a2, a3, at;
|
||||
unsigned int lo;
|
||||
unsigned int v0, v1;
|
||||
unsigned int ra;
|
||||
|
||||
// derived from the SM64 boot code
|
||||
s6 = 0x3f;
|
||||
a0 = 0x1000; // 59c: 8d640008 lw a0,8(t3)
|
||||
a1 = s6; // 5a0: 02c02825 move a1,s6
|
||||
at = 0x5d588b65; // 5a4: 3c015d58 lui at,0x5d58
|
||||
// 5a8: 34218b65 ori at,at,0x8b65
|
||||
lo = a1 * at; // 5ac: 00a10019 multu a1,at 16 F8CA 4DDB
|
||||
|
||||
ra = 0x100000; // 5bc: 3c1f0010 lui ra,0x10
|
||||
v1 = 0; // 5c0: 00001825 move v1,zero
|
||||
t0 = 0; // 5c4: 00004025 move t0,zero
|
||||
t1 = a0; // 5c8: 00804825 move t1,a0
|
||||
t5 = 32; // 5cc: 240d0020 li t5,32
|
||||
v0 = lo; // 5d0: 00001012 mflo v0
|
||||
v0++; // 5d4: 24420001 addiu v0,v0,1
|
||||
a3 = v0; // 5d8: 00403825 move a3,v0
|
||||
t2 = v0; // 5dc: 00405025 move t2,v0
|
||||
t3 = v0; // 5e0: 00405825 move t3,v0
|
||||
s0 = v0; // 5e4: 00408025 move s0,v0
|
||||
a2 = v0; // 5e8: 00403025 move a2,v0
|
||||
t4 = v0; // 5ec: 00406025 move t4,v0
|
||||
|
||||
do {
|
||||
v0 = read_u32_be(&buf[t1]); // 5f0: 8d220000 lw v0,0(t1)
|
||||
v1 = a3 + v0; // 5f4: 00e21821 addu v1,a3,v0
|
||||
at = (v1 < a3); // 5f8: 0067082b sltu at,v1,a3
|
||||
a1 = v1; // 600: 00602825 move a1,v1 branch delay slot
|
||||
if (at) { // 5fc: 10200002 beqz at,0x608
|
||||
t2++; // 604: 254a0001 addiu t2,t2,1
|
||||
}
|
||||
v1 = v0 & 0x1F; // 608: 3043001f andi v1,v0,0x1f
|
||||
t7 = t5 - v1; // 60c: 01a37823 subu t7,t5,v1
|
||||
t8 = v0 >> t7; // 610: 01e2c006 srlv t8,v0,t7
|
||||
t6 = v0 << v1; // 614: 00627004 sllv t6,v0,v1
|
||||
a0 = t6 | t8; // 618: 01d82025 or a0,t6,t8
|
||||
at = (a2 < v0); // 61c: 00c2082b sltu at,a2,v0
|
||||
a3 = a1; // 620: 00a03825 move a3,a1
|
||||
t3 ^= v0; // 624: 01625826 xor t3,t3,v0
|
||||
s0 += a0; // 62c: 02048021 addu s0,s0,a0 branch delay slot
|
||||
if (at) { // 628: 10200004 beqz at,0x63c
|
||||
t9 = a3 ^ v0; // 630: 00e2c826 xor t9,a3,v0
|
||||
// 634: 10000002 b 0x640
|
||||
a2 ^= t9; // 638: 03263026 xor a2,t9,a2 branch delay
|
||||
} else {
|
||||
a2 ^= a0; // 63c: 00c43026 xor a2,a2,a0
|
||||
}
|
||||
t0 += 4; // 640: 25080004 addiu t0,t0,4
|
||||
t7 = v0 ^ s0; // 644: 00507826 xor t7,v0,s0
|
||||
t1 += 4; // 648: 25290004 addiu t1,t1,4
|
||||
t4 += t7; // 650: 01ec6021 addu t4,t7,t4 branch delay
|
||||
} while (t0 != ra); // 64c: 151fffe8 bne t0,ra,0x5f0
|
||||
t6 = a3 ^ t2; // 654: 00ea7026 xor t6,a3,t2
|
||||
a3 = t6 ^ t3; // 658: 01cb3826 xor a3,t6,t3
|
||||
t8 = s0 ^ a2; // 65c: 0206c026 xor t8,s0,a2
|
||||
s0 = t8 ^ t4; // 660: 030c8026 xor s0,t8,t4
|
||||
|
||||
cksum[0] = a3;
|
||||
cksum[1] = s0;
|
||||
}
|
||||
|
||||
rom_type sm64_rom_type(unsigned char *buf, unsigned int length)
|
||||
{
|
||||
const unsigned char bs[] = {0x37, 0x80, 0x40, 0x12};
|
||||
const unsigned char be[] = {0x80, 0x37, 0x12, 0x40};
|
||||
const unsigned char le[] = {0x40, 0x12, 0x37, 0x80};
|
||||
if (!memcmp(buf, bs, sizeof(bs)) && length == (8*MB)) {
|
||||
return ROM_SM64_BS;
|
||||
}
|
||||
if (!memcmp(buf, bs, sizeof(le)) && length == (8*MB)) {
|
||||
return ROM_SM64_LE;
|
||||
}
|
||||
if (!memcmp(buf, be, sizeof(be))) {
|
||||
if (length == 8*MB) {
|
||||
return ROM_SM64_BE;
|
||||
} else if (length > 8*MB) {
|
||||
return ROM_SM64_BE_EXT;
|
||||
}
|
||||
}
|
||||
return ROM_INVALID;
|
||||
}
|
||||
|
||||
rom_version sm64_rom_version(unsigned char *buf)
|
||||
{
|
||||
typedef struct {const unsigned char cksum1[4]; const rom_version version;} version_entry;
|
||||
const version_entry version_table[] =
|
||||
{
|
||||
{ {0x63, 0x5a, 0x2b, 0xff}, VERSION_SM64_U},
|
||||
{ {0xa0, 0x3c, 0xf0, 0x36}, VERSION_SM64_E},
|
||||
{ {0x4e, 0xaa, 0x3d, 0x0e}, VERSION_SM64_J},
|
||||
{ {0xd6, 0xfb, 0xa4, 0xa8}, VERSION_SM64_SHINDOU},
|
||||
};
|
||||
for (unsigned int i = 0; i < DIM(version_table); i++) {
|
||||
if (!memcmp(&buf[0x10], version_table[i].cksum1, 4)) {
|
||||
return version_table[i].version;
|
||||
}
|
||||
}
|
||||
return VERSION_UNKNOWN;
|
||||
}
|
||||
|
||||
void sm64_decompress_mio0(const sm64_config *config,
|
||||
unsigned char *in_buf,
|
||||
unsigned int in_length,
|
||||
unsigned char *out_buf)
|
||||
{
|
||||
#define MAX_PTRS 128
|
||||
#define COMPRESSED_LENGTH 2
|
||||
mio0_header_t head;
|
||||
int bit_length;
|
||||
int move_offset;
|
||||
unsigned int in_addr;
|
||||
unsigned int out_addr = OUT_START_ADDR;
|
||||
unsigned int align_add = config->alignment - 1;
|
||||
unsigned int align_mask = ~align_add;
|
||||
ptr_t ptr_table[MAX_PTRS];
|
||||
int ptr_count;
|
||||
int i;
|
||||
|
||||
// find MIO0 locations and pointers
|
||||
ptr_count = find_mio0(in_buf, in_length, ptr_table);
|
||||
find_pointers(in_buf, in_length, ptr_table, ptr_count);
|
||||
find_asm_pointers(in_buf, ptr_table, ptr_count);
|
||||
|
||||
// extract each MIO0 block and prepend fake MIO0 header for 0x1A command and ASM references
|
||||
for (i = 0; i < ptr_count; i++) {
|
||||
in_addr = ptr_table[i].old;
|
||||
if (!memcmp(&in_buf[in_addr], "MIO0", 4)) {
|
||||
unsigned int end;
|
||||
int length;
|
||||
int is_mio0 = 0;
|
||||
// align output address
|
||||
out_addr = (out_addr + align_add) & align_mask;
|
||||
length = mio0_decode(&in_buf[in_addr], &out_buf[out_addr], &end);
|
||||
if (length > 0) {
|
||||
// dump MIO0 data and decompressed data to file
|
||||
if (config->dump) {
|
||||
char filename[FILENAME_MAX];
|
||||
sprintf(filename, MIO0_DIR "/%08X.mio", in_addr);
|
||||
write_file(filename, &in_buf[in_addr], end);
|
||||
sprintf(filename, MIO0_DIR "/%08X", in_addr);
|
||||
write_file(filename, &out_buf[out_addr], length);
|
||||
}
|
||||
// 0x1A commands and ASM references need fake MIO0 header
|
||||
// relocate data and add MIO0 header with all uncompressed data
|
||||
if (ptr_table[i].command == 0x1A || ptr_table[i].command == 0xFF) {
|
||||
bit_length = (length + 7) / 8 + 2;
|
||||
move_offset = MIO0_HEADER_LENGTH + bit_length + COMPRESSED_LENGTH;
|
||||
memmove(&out_buf[out_addr + move_offset], &out_buf[out_addr], length);
|
||||
head.dest_size = length;
|
||||
head.comp_offset = move_offset - COMPRESSED_LENGTH;
|
||||
head.uncomp_offset = move_offset;
|
||||
mio0_encode_header(&out_buf[out_addr], &head);
|
||||
memset(&out_buf[out_addr + MIO0_HEADER_LENGTH], 0xFF, head.comp_offset - MIO0_HEADER_LENGTH);
|
||||
memset(&out_buf[out_addr + head.comp_offset], 0x0, 2);
|
||||
length += head.uncomp_offset;
|
||||
is_mio0 = 1;
|
||||
} else if (ptr_table[i].command == 0x18) {
|
||||
// 0x18 commands become 0x17
|
||||
ptr_table[i].command = 0x17;
|
||||
}
|
||||
// use output from decoder to find end of ASM referenced MIO0 blocks
|
||||
if (ptr_table[i].old_end == 0x00) {
|
||||
ptr_table[i].old_end = in_addr + end;
|
||||
}
|
||||
INFO("MIO0 file %08X-%08X decompressed to %08X-%08X as raw data%s\n",
|
||||
in_addr, ptr_table[i].old_end, out_addr, out_addr + length,
|
||||
is_mio0 ? " with a MIO0 header" : "");
|
||||
if (config->fill) {
|
||||
INFO("Filling old MIO0 with 0x01 from %X length %X\n", in_addr, end);
|
||||
memset(&out_buf[in_addr], 0x01, end);
|
||||
}
|
||||
// keep track of new pointers
|
||||
ptr_table[i].new = out_addr;
|
||||
ptr_table[i].new_end = out_addr + length;
|
||||
out_addr += length + config->padding;
|
||||
} else {
|
||||
ERROR("Error decoding MIO0 block at %X\n", in_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Ending offset: %X\n", out_addr);
|
||||
|
||||
// adjust pointers and ASM pointers to new values
|
||||
sm64_adjust_pointers(out_buf, in_length, ptr_table, ptr_count);
|
||||
sm64_adjust_asm(out_buf, ptr_table, ptr_count);
|
||||
}
|
||||
|
||||
void sm64_update_checksums(unsigned char *buf)
|
||||
{
|
||||
unsigned int cksum_offsets[] = {0x10, 0x14};
|
||||
unsigned int read_cksum[2];
|
||||
unsigned int calc_cksum[2];
|
||||
int i;
|
||||
|
||||
// assume CIC-NUS-6102
|
||||
INFO("BootChip: CIC-NUS-6102\n");
|
||||
|
||||
// calculate new N64 header checksum
|
||||
sm64_calc_checksums(buf, calc_cksum);
|
||||
|
||||
// mimic the n64sums output
|
||||
for (i = 0; i < 2; i++) {
|
||||
read_cksum[i] = read_u32_be(&buf[cksum_offsets[i]]);
|
||||
INFO("CRC%d: 0x%08X ", i+1, read_cksum[i]);
|
||||
INFO("Calculated: 0x%08X ", calc_cksum[i]);
|
||||
if (calc_cksum[i] == read_cksum[i]) {
|
||||
INFO("(Good)\n");
|
||||
} else {
|
||||
INFO("(Bad)\n");
|
||||
}
|
||||
}
|
||||
|
||||
// write checksums into header
|
||||
INFO("Writing back calculated Checksum\n");
|
||||
write_u32_be(&buf[cksum_offsets[0]], calc_cksum[0]);
|
||||
write_u32_be(&buf[cksum_offsets[1]], calc_cksum[1]);
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
#ifndef LIBSM64_H_
|
||||
#define LIBSM64_H_
|
||||
|
||||
#define MIO0_DIR "mio0files"
|
||||
|
||||
// typedefs
|
||||
typedef enum
|
||||
{
|
||||
ROM_INVALID, // not valid SM64 ROM
|
||||
ROM_SM64_BS, // SM64 byte-swapped (BADC)
|
||||
ROM_SM64_BE, // SM64 big-endian (ABCD)
|
||||
ROM_SM64_LE, // SM64 little-endian
|
||||
ROM_SM64_BE_EXT, // SM64 big-endian, extended
|
||||
} rom_type;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
VERSION_UNKNOWN,
|
||||
VERSION_SM64_U,
|
||||
VERSION_SM64_E,
|
||||
VERSION_SM64_J,
|
||||
VERSION_SM64_SHINDOU,
|
||||
} rom_version;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char *in_filename;
|
||||
char *ext_filename;
|
||||
unsigned int ext_size;
|
||||
unsigned int padding;
|
||||
unsigned int alignment;
|
||||
char fill;
|
||||
char dump;
|
||||
} sm64_config;
|
||||
|
||||
// determine ROM type based on data
|
||||
// buf: buffer containing raw SM64 ROM file data
|
||||
// length: length of 'buf'
|
||||
// returns SM64 ROM type or invalid
|
||||
rom_type sm64_rom_type(unsigned char *buf, unsigned int length);
|
||||
|
||||
// determine SM64 ROM type based on cksum data
|
||||
// buf: buffer containing raw SM64 ROM file data
|
||||
// returns SM64 ROM version or unknown
|
||||
rom_version sm64_rom_version(unsigned char *buf);
|
||||
|
||||
// find and decompress all MIO0 blocks
|
||||
// config: configuration to determine alignment, padding and size
|
||||
// in_buf: buffer containing entire contents of SM64 data in big endian
|
||||
// length: length of in_buf
|
||||
// out_buf: buffer containing extended SM64
|
||||
void sm64_decompress_mio0(const sm64_config *config,
|
||||
unsigned char *in_buf,
|
||||
unsigned int in_length,
|
||||
unsigned char *out_buf);
|
||||
|
||||
// update N64 header checksums
|
||||
// buf: buffer containing ROM data
|
||||
// checksums are written into the buffer
|
||||
void sm64_update_checksums(unsigned char *buf);
|
||||
|
||||
#endif // LIBSM64_H_
|
||||
@@ -1,11 +1,95 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "libsm64.h"
|
||||
#include "n64cksum.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define N64CKSUM_VERSION "0.1"
|
||||
|
||||
// compute N64 ROM checksums
|
||||
// buf: buffer with extended SM64 data
|
||||
// cksum: two element array to write CRC1 and CRC2 to
|
||||
void n64cksum_calc_6102(unsigned char *buf, unsigned int cksum[]) {
|
||||
uint32_t t2, t3, t4, t6, t7, t8, s0;
|
||||
uint32_t a0, a1, a2, a3;
|
||||
uint32_t v0, v1;
|
||||
uint32_t seed, end_offset, cur_offset, buf_offset;
|
||||
|
||||
// derived from the SM64 boot code
|
||||
seed = 0xF8CA4DDB; // 0x3f * 0x5d588b65;
|
||||
end_offset = 0x100000;
|
||||
cur_offset = 0;
|
||||
buf_offset = 0x1000;
|
||||
seed++;
|
||||
a3 = seed;
|
||||
t2 = seed;
|
||||
t3 = seed;
|
||||
s0 = seed;
|
||||
a2 = seed;
|
||||
t4 = seed;
|
||||
|
||||
do {
|
||||
v0 = read_u32_be(&buf[buf_offset]);
|
||||
v1 = a3 + v0;
|
||||
a1 = v1;
|
||||
if (v1 < a3) {
|
||||
t2++;
|
||||
}
|
||||
v1 = v0 & 0x1F;
|
||||
t7 = 32 - v1;
|
||||
t8 = v0 >> t7;
|
||||
t6 = v0 << v1;
|
||||
a0 = t6 | t8;
|
||||
a3 = a1;
|
||||
t3 ^= v0;
|
||||
s0 += a0;
|
||||
if (a2 < v0) {
|
||||
a2 ^= a3 ^ v0;
|
||||
} else {
|
||||
a2 ^= a0;
|
||||
}
|
||||
cur_offset += 4;
|
||||
t7 = v0 ^ s0;
|
||||
buf_offset += 4;
|
||||
t4 += t7;
|
||||
} while (cur_offset != end_offset);
|
||||
|
||||
cksum[0] = (a3 ^ t2) ^ t3;
|
||||
cksum[1] = (s0 ^ a2) ^ t4;
|
||||
}
|
||||
|
||||
void n64cksum_update_checksums(uint8_t *buf)
|
||||
{
|
||||
unsigned int cksum_offsets[] = {0x10, 0x14};
|
||||
uint32_t read_cksum[2];
|
||||
uint32_t calc_cksum[2];
|
||||
int i;
|
||||
|
||||
// assume CIC-NUS-6102
|
||||
INFO("BootChip: CIC-NUS-6102\n");
|
||||
|
||||
// calculate new N64 header checksum
|
||||
n64cksum_calc_6102(buf, calc_cksum);
|
||||
|
||||
// mimic the n64sums output
|
||||
for (i = 0; i < 2; i++) {
|
||||
read_cksum[i] = read_u32_be(&buf[cksum_offsets[i]]);
|
||||
INFO("CRC%d: 0x%08X ", i+1, read_cksum[i]);
|
||||
INFO("Calculated: 0x%08X ", calc_cksum[i]);
|
||||
if (calc_cksum[i] == read_cksum[i]) {
|
||||
INFO("(Good)\n");
|
||||
} else {
|
||||
INFO("(Bad)\n");
|
||||
}
|
||||
}
|
||||
|
||||
// write checksums into header
|
||||
INFO("Writing back calculated Checksum\n");
|
||||
write_u32_be(&buf[cksum_offsets[0]], calc_cksum[0]);
|
||||
write_u32_be(&buf[cksum_offsets[1]], calc_cksum[1]);
|
||||
}
|
||||
|
||||
#ifdef N64CKSUM_STANDALONE
|
||||
static void print_usage(void)
|
||||
{
|
||||
ERROR("Usage: n64cksum ROM [ROM_OUT]\n"
|
||||
@@ -42,7 +126,7 @@ int main(int argc, char *argv[])
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
sm64_update_checksums(rom_data);
|
||||
n64cksum_update_checksums(rom_data);
|
||||
|
||||
write_length = write_file(file_out, rom_data, length);
|
||||
|
||||
@@ -55,3 +139,4 @@ int main(int argc, char *argv[])
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#endif // N64CKSUM_STANDALONE
|
||||
|
||||
16
tools/n64cksum.h
Normal file
16
tools/n64cksum.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef N64CKSUM_H_
|
||||
#define N64CKSUM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// compute N64 ROM checksums
|
||||
// buf: buffer with extended SM64 data
|
||||
// cksum: two element array to write CRC1 and CRC2 to
|
||||
void n64cksum_calc_6102(unsigned char *buf, unsigned int cksum[]);
|
||||
|
||||
// update N64 header checksums
|
||||
// buf: buffer containing ROM data
|
||||
// checksums are written into the buffer
|
||||
void n64cksum_update_checksums(uint8_t *buf);
|
||||
|
||||
#endif // N64CKSUM_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,14 @@ typedef struct _ia
|
||||
uint8_t alpha;
|
||||
} ia;
|
||||
|
||||
// CI palette
|
||||
typedef struct
|
||||
{
|
||||
uint16_t data[256];
|
||||
int max; // max number of entries
|
||||
int used; // number of entries used
|
||||
} palette_t;
|
||||
|
||||
//---------------------------------------------------------
|
||||
// N64 RGBA/IA/I/CI -> intermediate RGBA/IA
|
||||
//---------------------------------------------------------
|
||||
@@ -31,10 +39,6 @@ ia *raw2ia(const uint8_t *raw, int width, int height, int depth);
|
||||
// N64 raw I4/I8 -> intermediate IA
|
||||
ia *raw2i(const uint8_t *raw, int width, int height, int depth);
|
||||
|
||||
// N64 raw CI + palette -> intermediate RGBA
|
||||
rgba *rawci2rgba(const uint8_t *rawci, const uint8_t *palette, int width, int height, int depth);
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// intermediate RGBA/IA -> N64 RGBA/IA/I/CI
|
||||
// returns length written to 'raw' used or -1 on error
|
||||
@@ -49,9 +53,16 @@ int ia2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
|
||||
// intermediate IA -> N64 raw I4/I8
|
||||
int i2raw(uint8_t *raw, const ia *img, int width, int height, int depth);
|
||||
|
||||
// intermediate RGBA -> N64 raw CI + palette
|
||||
// TODO
|
||||
// int rgba2rawci(uint8_t *raw, uint8_t *out_palette, int *pal_len, const rgba *img, int width, int height, int depth);
|
||||
|
||||
//---------------------------------------------------------
|
||||
// N64 CI <-> N64 RGBA16/IA16
|
||||
//---------------------------------------------------------
|
||||
|
||||
// N64 CI raw data and palette to raw data (either RGBA16 or IA16)
|
||||
uint8_t *ci2raw(const uint8_t *rawci, const uint8_t *palette, int width, int height, int ci_depth);
|
||||
|
||||
// convert from raw (RGBA16 or IA16) format to CI + palette
|
||||
int raw2ci(uint8_t *rawci, palette_t *pal, const uint8_t *raw, int raw_len, int ci_depth);
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
||||
76
tools/rasm2armips.py
Executable file
76
tools/rasm2armips.py
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
|
||||
def read_file(filepath):
|
||||
with open(filepath) as f:
|
||||
lines = f.readlines()
|
||||
split_lines = [re.split(r'[ ,]+', l.strip().replace('$', '')) for l in lines]
|
||||
return split_lines
|
||||
|
||||
# jumps and branches with named targets
|
||||
jumps = ['jal', 'j']
|
||||
branches = ['beq', 'bgez', 'bgtz', 'blez', 'bltz', 'bne']
|
||||
jump_branches = jumps + branches
|
||||
# jumps and branches with delay slots
|
||||
has_delay_slot = jump_branches + ['jr']
|
||||
|
||||
def decode_references(instructions):
|
||||
refs = []
|
||||
for ins in instructions:
|
||||
if ins[3] in jump_branches:
|
||||
target = int(ins[-1], 0)
|
||||
if target not in refs:
|
||||
refs.append(target)
|
||||
return refs
|
||||
|
||||
def reassemble(args, instructions, refs):
|
||||
print('.rsp')
|
||||
print('\n.create DATA_FILE, 0x%04X' % 0x0000)
|
||||
print('\n.close // DATA_FILE\n')
|
||||
print('.create CODE_FILE, 0x%08X\n' % args.base)
|
||||
delay_slot = False
|
||||
for ins in instructions:
|
||||
addr = int(ins[0], 0)
|
||||
if (addr & 0xFFFF) in refs:
|
||||
print('%s_%08x:' % (args.name, addr))
|
||||
sys.stdout.write(' ' * args.indent)
|
||||
if delay_slot:
|
||||
sys.stdout.write(' ')
|
||||
delay_slot = False
|
||||
if ins[3] in jumps:
|
||||
target = int(ins[-1], 0) | (args.base & 0xFFFF0000)
|
||||
ins[-1] = '%s_%08x' % (args.name, target)
|
||||
elif ins[3] in branches:
|
||||
if ins[3][-1] =='z' and ins[5] == 'zero':
|
||||
del ins[5] # remove 'zero' operand from branch
|
||||
target = (int(ins[-1], 0) & 0x1FFF) + (args.base & 0xFFFF0000)
|
||||
ins[-1] = '%s_%08x' % (args.name, target)
|
||||
elif ins[3] == 'vsar': # fixup last operand of vsar
|
||||
reg_map = {'ACC_H': 0, 'ACC_M': 1, 'ACC_L': 2}
|
||||
reg = ins[4].split(r'[')[0]
|
||||
num = reg_map[ins[-1]]
|
||||
ins[-1] = '%s[%d]' % (reg, num)
|
||||
if ins[3] in has_delay_slot:
|
||||
delay_slot = True
|
||||
if len(ins) > 4: # with args
|
||||
print('%-5s %s' % (ins[3], ', '.join(ins[4:])))
|
||||
else:
|
||||
print('%s' % ins[3])
|
||||
print('\n.close // CODE_FILE')
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('input_file', help="input assembly file generated from `rasm2 -D -e -a rsp -B -o 0x04001000 -f`")
|
||||
parser.add_argument('-b', type=int, help="base address of file", dest='base', default=0x04001000)
|
||||
parser.add_argument('-i', type=int, help="amount of indentation", dest='indent', default=4)
|
||||
parser.add_argument('-n', help="name to prefex labels with", dest='name', default='f3d')
|
||||
args = parser.parse_args()
|
||||
|
||||
lines = read_file(args.input_file)
|
||||
refs = decode_references(lines)
|
||||
reassemble(args, lines, refs)
|
||||
|
||||
main()
|
||||
@@ -212,6 +212,11 @@ static void assign_tile_positions() {
|
||||
}
|
||||
}
|
||||
|
||||
// Provide a replacement for realpath on Windows
|
||||
#ifdef _WIN32
|
||||
#define realpath(path, resolved_path) _fullpath(resolved_path, path, PATH_MAX)
|
||||
#endif
|
||||
|
||||
/* write pngs to disc */
|
||||
void write_tiles() {
|
||||
const ImageProps props = IMAGE_PROPERTIES[type][true];
|
||||
@@ -479,6 +484,7 @@ static void usage() {
|
||||
|
||||
// Modified from n64split
|
||||
static int parse_arguments(int argc, char *argv[]) {
|
||||
programName = argv[0];
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "--combine") == 0) {
|
||||
if (++i >= argc || mode != InvalidMode) {
|
||||
|
||||
128
tools/util/generate_armips_cpp.py
Normal file
128
tools/util/generate_armips_cpp.py
Normal file
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
file_list = [
|
||||
'stdafx.h',
|
||||
'ext/tinyformat/tinyformat.h',
|
||||
'Commands/CAssemblerCommand.h',
|
||||
'Core/Expression.h',
|
||||
'Core/ExpressionFunctions.h',
|
||||
'Core/SymbolData.h',
|
||||
'Util/Util.h',
|
||||
'Util/FileClasses.h',
|
||||
'Util/ByteArray.h',
|
||||
'Core/FileManager.h',
|
||||
'Core/ELF/ElfTypes.h',
|
||||
'Core/ELF/ElfFile.h',
|
||||
'Core/ELF/ElfRelocator.h',
|
||||
'Archs/Architecture.h',
|
||||
'Archs/MIPS/Mips.h',
|
||||
'Archs/MIPS/MipsOpcodes.h',
|
||||
'Archs/MIPS/CMipsInstruction.h',
|
||||
'Util/EncodingTable.h',
|
||||
'Core/Misc.h',
|
||||
'Core/Assembler.h',
|
||||
'Core/SymbolTable.h',
|
||||
'Core/Common.h',
|
||||
'Parser/DirectivesParser.h',
|
||||
'Parser/Tokenizer.h',
|
||||
'Archs/MIPS/MipsMacros.h',
|
||||
'Archs/MIPS/MipsParser.h',
|
||||
'Archs/MIPS/CMipsInstruction.cpp',
|
||||
'Archs/MIPS/MipsExpressionFunctions.h',
|
||||
'Archs/MIPS/MipsElfRelocator.h',
|
||||
'Archs/MIPS/Mips.cpp',
|
||||
'Archs/MIPS/MipsElfFile.h',
|
||||
'Util/CRC.h',
|
||||
'Archs/MIPS/MipsElfFile.cpp',
|
||||
'Commands/CommandSequence.h',
|
||||
'Parser/Parser.h',
|
||||
'Archs/MIPS/MipsElfRelocator.cpp',
|
||||
'Archs/MIPS/MipsExpressionFunctions.cpp',
|
||||
'Archs/MIPS/MipsMacros.cpp',
|
||||
'Archs/MIPS/MipsOpcodes.cpp',
|
||||
'Parser/ExpressionParser.h',
|
||||
'Archs/MIPS/PsxRelocator.h',
|
||||
'Commands/CDirectiveFile.h',
|
||||
'Archs/MIPS/MipsParser.cpp',
|
||||
'Archs/MIPS/PsxRelocator.cpp',
|
||||
'Archs/Architecture.cpp',
|
||||
'Commands/CAssemblerCommand.cpp',
|
||||
'Commands/CAssemblerLabel.h',
|
||||
'Commands/CAssemblerLabel.cpp',
|
||||
'Commands/CDirectiveArea.h',
|
||||
'Commands/CDirectiveArea.cpp',
|
||||
'Commands/CDirectiveConditional.h',
|
||||
'Commands/CDirectiveConditional.cpp',
|
||||
'Commands/CDirectiveData.h',
|
||||
'Commands/CDirectiveData.cpp',
|
||||
'Commands/CDirectiveFile.cpp',
|
||||
'Commands/CDirectiveMessage.h',
|
||||
'Commands/CDirectiveMessage.cpp',
|
||||
'Commands/CommandSequence.cpp',
|
||||
'Core/ELF/ElfFile.cpp',
|
||||
'Core/ELF/ElfRelocator.cpp',
|
||||
'Core/Assembler.cpp',
|
||||
'Core/Common.cpp',
|
||||
'Core/Expression.cpp',
|
||||
'Core/ExpressionFunctions.cpp',
|
||||
'Core/FileManager.cpp',
|
||||
'Core/Misc.cpp',
|
||||
'Core/SymbolData.cpp',
|
||||
'Core/SymbolTable.cpp',
|
||||
'Parser/DirectivesParser.cpp',
|
||||
'Parser/ExpressionParser.cpp',
|
||||
'Parser/Parser.cpp',
|
||||
'Parser/Tokenizer.cpp',
|
||||
'Util/ByteArray.cpp',
|
||||
'Util/CRC.cpp',
|
||||
'Util/EncodingTable.cpp',
|
||||
'Util/FileClasses.cpp',
|
||||
'Util/Util.cpp',
|
||||
'Main/CommandLineInterface.h',
|
||||
'Main/CommandLineInterface.cpp',
|
||||
'Main/main.cpp',
|
||||
]
|
||||
|
||||
file_header = \
|
||||
"""// armips assembler v0.11
|
||||
// https://github.com/Kingcom/armips/
|
||||
// To simplify compilation, all files have been concatenated into one.
|
||||
// MIPS only, ARM is not included.\n\n"""
|
||||
|
||||
def banned(line):
|
||||
return '#pragma once' in line or '#include "' in line
|
||||
|
||||
def cat_file(fout, fin_name):
|
||||
with open(fin_name) as fin:
|
||||
lines = fin.readlines()
|
||||
lines = [l.rstrip() for l in lines if not banned(l)]
|
||||
for l in lines:
|
||||
if re.search(r'\bArm\b', l):
|
||||
fout.write("#ifdef ARMIPS_ARM\n") # must manually insert #endif
|
||||
fout.write(l + '\n')
|
||||
fout.write('\n')
|
||||
|
||||
def combine_armips(fout_name, armips_path):
|
||||
with open(fout_name, 'w') as fout:
|
||||
fout.write(file_header)
|
||||
fout.write("/*\n")
|
||||
cat_file(fout, os.path.join(armips_path, 'LICENSE.txt'))
|
||||
fout.write("*/\n\n")
|
||||
for f in file_list:
|
||||
fout.write(f"// file: {f}\n")
|
||||
cat_file(fout, os.path.join(armips_path, f))
|
||||
|
||||
def main():
|
||||
if len(sys.argv) > 1 and sys.argv[1] in ['-h', '--help']:
|
||||
print('Usage: generate_armips_cpp.py [output_filename] [armips_src_dir]')
|
||||
print('Defaults: [output_filename = "armips.cpp"] [armips_src_dir = "./armips"]')
|
||||
return
|
||||
fout_name = sys.argv[1] if len(sys.argv) > 1 else 'armips.cpp'
|
||||
armips_path = sys.argv[2] if len(sys.argv) > 2 else './armips'
|
||||
combine_armips(fout_name, os.path.expanduser(armips_path))
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user