oot/tools/n64chksum.c
2020-03-17 00:31:30 -04:00

86 lines
1.7 KiB
C

#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "n64chksum.h"
#include "util.h"
//Based on uCON64's N64 checksum algorithm by Andreas Sterbenz
#define ROL(i, b) (((i) << (b)) | ((i) >> (32 - (b))))
bool n64chksum_calculate(const uint8_t *romData, int cicType, uint32_t *chksum)
{
unsigned int seed;
unsigned int t1, t2, t3, t4, t5, t6;
size_t pos;
const size_t START = 0x1000;
const size_t END = START + 0x100000;
// determine initial seed
switch (cicType)
{
case 6101:
case 6102:
seed = 0xF8CA4DDC;
break;
case 6103:
seed = 0xA3886759;
break;
case 6105:
seed = 0xDF26F436;
break;
case 6106:
seed = 0x1FEA617A;
break;
default:
return false; // unknown CIC type
}
t1 = t2 = t3 = t4 = t5 = t6 = seed;
for (pos = START; pos < END; pos += 4)
{
unsigned int d = util_read_uint32_be(romData + pos);
unsigned int r = ROL(d, (d & 0x1F));
// increment t4 if t6 overflows
if ((t6 + d) < t6)
t4++;
t6 += d;
t3 ^= d;
t5 += r;
if (t2 > d)
t2 ^= r;
else
t2 ^= t6 ^ d;
if (cicType == 6105)
t1 += util_read_uint32_be(&romData[0x0750 + (pos & 0xFF)]) ^ d;
else
t1 += t5 ^ d;
}
if (cicType == 6103)
{
chksum[0] = (t6 ^ t4) + t3;
chksum[1] = (t5 ^ t2) + t1;
}
else if (cicType == 6106)
{
chksum[0] = (t6 * t4) + t3;
chksum[1] = (t5 * t2) + t1;
}
else
{
chksum[0] = t6 ^ t4 ^ t3;
chksum[1] = t5 ^ t2 ^ t1;
}
return true;
}