aboutsummaryrefslogtreecommitdiff
path: root/gbafix.c
blob: e1eb83dd7b651c26801f69f46565f418b69e9767 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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);
}