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);
}
|