forked from sm64pc/sm64ex
-
Notifications
You must be signed in to change notification settings - Fork 48
/
Copy pathn64cksum.c
142 lines (122 loc) · 3.15 KB
/
n64cksum.c
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <stdio.h>
#include <stdlib.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"
"\n"
"n64cksum v" N64CKSUM_VERSION ": N64 ROM checksum calculator\n"
"\n"
"File arguments:\n"
" ROM input ROM file\n"
" ROM_OUT output ROM file (default: overwrites input ROM)\n");
}
int main(int argc, char *argv[])
{
unsigned char *rom_data;
char *file_in;
char *file_out;
long length;
long write_length;
if (argc < 2) {
print_usage();
return EXIT_FAILURE;
}
file_in = argv[1];
if (argc > 2) {
file_out = argv[2];
} else {
file_out = argv[1];
}
length = read_file(file_in, &rom_data);
if (length < 0) {
ERROR("Error reading input file \"%s\"\n", file_in);
return EXIT_FAILURE;
}
n64cksum_update_checksums(rom_data);
write_length = write_file(file_out, rom_data, length);
free(rom_data);
if (write_length != length) {
ERROR("Error writing to output file \"%s\"\n", file_out);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
#endif // N64CKSUM_STANDALONE