diff options
-rw-r--r-- | gbafix.c | 124 | ||||
-rw-r--r-- | readme | 3 |
2 files changed, 127 insertions, 0 deletions
diff --git a/gbafix.c b/gbafix.c new file mode 100644 index 0000000..e1eb83d --- /dev/null +++ b/gbafix.c @@ -0,0 +1,124 @@ +#include <u.h> +#include <libc.h> + +enum { + AROM = 0x00, + ALOGO = 0x04, + ATITLE = 0xA0, + AGAME = 0xAC, + AMAKER = 0xB0, + AFIXED = 0xB2, + AUNIT = 0xB3, + ADEVTYPE = 0xB4, + ARES0 = 0xB5, + AVERSION = 0xBC, + ACKSUM = 0xBD, + ARES1 = 0xBE, + AEND = 0xC0 +}; + +typedef struct Header Header; + +struct Header +{ + u32int start; /* ARM entry point branch opcode */ + u8int logo[156]; /* the Nintendo logo */ + u8int title[12]; + u32int game; + u16int maker; + u8int fixed; /* 0x96 */ + u8int unit; + u8int devtype; + u8int r0[7]; /* reserved area */ + u8int version; + u8int cksum; + u8int r1[2]; /* reserved area */ +}; + +u8int nintendō[156] = { + 0x24,0xFF,0xAE,0x51,0x69,0x9A,0xA2,0x21,0x3D,0x84,0x82,0x0A,0x84,0xE4,0x09,0xAD, + 0x11,0x24,0x8B,0x98,0xC0,0x81,0x7F,0x21,0xA3,0x52,0xBE,0x19,0x93,0x09,0xCE,0x20, + 0x10,0x46,0x4A,0x4A,0xF8,0x27,0x31,0xEC,0x58,0xC7,0xE8,0x33,0x82,0xE3,0xCE,0xBF, + 0x85,0xF4,0xDF,0x94,0xCE,0x4B,0x09,0xC1,0x94,0x56,0x8A,0xC0,0x13,0x72,0xA7,0xFC, + 0x9F,0x84,0x4D,0x73,0xA3,0xCA,0x9A,0x61,0x58,0x97,0xA3,0x27,0xFC,0x03,0x98,0x76, + 0x23,0x1D,0xC7,0x61,0x03,0x04,0xAE,0x56,0xBF,0x38,0x84,0x00,0x40,0xA7,0x0E,0xFD, + 0xFF,0x52,0xFE,0x03,0x6F,0x95,0x30,0xF1,0x97,0xFB,0xC0,0x85,0x60,0xD6,0x80,0x25, + 0xA9,0x63,0xBE,0x03,0x01,0x4E,0x38,0xE2,0xF9,0xA2,0x34,0xFF,0xBB,0x3E,0x03,0x44, + 0x78,0x00,0x90,0xCB,0x88,0x11,0x3A,0x94,0x65,0xC0,0x7C,0x63,0x87,0xF0,0x3C,0xAF, + 0xD6,0x25,0xE4,0x8B,0x38,0x0A,0xAC,0x72,0x21,0xD4,0xF8,0x07 +}; + +char +cksum(Header *h) +{ + int n; + char c, *p; + + c = 0; + p = (char*)h; + p += ATITLE; + for(n = 0; n < ACKSUM-ATITLE; n++) + c += *p++; + return -(0x19+c); +} + +void +usage(void) +{ + fprint(2, "usage: %s [-t title] [-g gamecode] [-m makercode] [-v version] rom\n", argv0); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + Header h; + char *title; + u32int gcode; + u16int mcode; + u8int vcode; + int fd; + + title = nil; + gcode = mcode = vcode = 0; + ARGBEGIN{ + case 't': + title = EARGF(usage()); + break; + case 'g': + gcode = strtoul(EARGF(usage()), nil, 0); + break; + case 'm': + mcode = strtoul(EARGF(usage()), nil, 0); + break; + case 'v': + vcode = strtoul(EARGF(usage()), nil, 0); + break; + default: usage(); + }ARGEND; + if(argc != 1) + usage(); + fd = open(argv[0], ORDWR); + if(fd < 0) + sysfatal("open: %r"); + memset(&h, 0, sizeof h); + if(readn(fd, &h, sizeof(Header)) != sizeof(Header)) + sysfatal("readn: %r"); + memmove(h.logo, nintendō, sizeof(nintendō)); + if(title) + memmove(h.title, title, strlen(title) < sizeof(h.title)? strlen(title): sizeof(h.title)); + if(gcode) + h.game = gcode; + if(mcode) + h.maker = mcode; + h.fixed = 0x96; + h.devtype = 0x00; + if(vcode) + h.version = vcode; + h.cksum = cksum(&h); + seek(fd, 0, 0); + if(write(fd, &h, sizeof(Header)) != sizeof(Header)) + sysfatal("write: %r"); + close(fd); + exits(0); +} @@ -0,0 +1,3 @@ +Tools for GBA ROM development + +so far i've got gbafix(1). more should come later. |