News:

Don't forget to visit the main site! There's lots of helpful docs, patches, and more!

Main Menu

[65816] ExLoROM CheckSum calculation (solution)

Started by JAM, September 09, 2014, 08:25:59 PM

Previous topic - Next topic

JAM

Since the Google doesn't know, I'll write what I found here. This is the best I can do in this situation.

ExLoROMs are consists of 2 parts: negative part and positive part (aka bad part and good part). Negative part is all negative banks (from $80 to $FF). Positive part is all positive banks (from $00 to $00..7F). Yes, it could have just one bank over $FF and still working.

Why I wrote it?
1. Just because the CheckSum calculation is much more complex here than "Negative Sum (sum of all bytes in negative area) * 2" for a ROM size different from 6Mb or 8Mb. CheckSum calculation is close to case in which positive area works a independent ROM, but not exactly.
2. I spent about 6 hours to understand how it works (specially, the ROM with $83 banks) and it's complex.

I'll write a few cases here:

Banks (total)
$81 : CheckSum = NegativeSum + PositiveSum (Bank $00) * $80.
$82 : CheckSum = NegativeSum + PositiveSum (Banks $00..01) * $40.
$83 : CheckSum = NegativeSum + PositiveSum (Banks $00..01 + Bank $02 * 2) * $20.
$84 : CheckSum = NegativeSum + PositiveSum (Banks $00..03) * $20.
$85 : CheckSum = NegativeSum + PositiveSum (Banks $00..03 + Bank $04 * 4) * $10.
$86 : CheckSum = NegativeSum + PositiveSum (Banks $00..03 + Banks $04..05 * 2) * $10.
$87 : CheckSum = NegativeSum + PositiveSum (Banks $00..03 + Banks $04..05 + Bank $06* 2) * $10.
$88: CheckSum = NegativeSum + PositiveSum (Banks $00..07) * $10.
and so on...


As you see, the emulator read the ROM size as 8Mb from the header and when calculating the CheckSum it tries to calculate the sum of all 8Mbs. But if it's less than 8Mb, it'll virtually fill the void by mirroring the banks to get the binary cluster of right size (the power of 2) and then mirror this binary cluster to fill all void area.

P.JBoy

#1
Here's some code from snes9x that does what it looks like you've described:


uint16 CMemory::checksum_calc_sum (uint8 *data, uint32 length)
{
uint16 sum = 0;

for (uint32 i = 0; i < length; i++)
sum += data[i];

return (sum);
}

uint16 CMemory::checksum_mirror_sum (uint8 *start, uint32 &length, uint32 mask = 0x800000)
{
// from NSRT
while (!(length & mask) && mask)
mask >>= 1;

uint16 part1 = checksum_calc_sum(start, mask);
uint16 part2 = 0;

uint32 next_length = length - mask;
if (next_length)
{
part2 = checksum_mirror_sum(start + mask, next_length, mask >> 1);

while (next_length < mask)
{
next_length += next_length;
part2 += part2;
}

length = mask + mask;
}

return (part1 + part2);
}

void CMemory::Checksum_Calculate (void)
{
// from NSRT
uint16 sum = 0;

if (Settings.BS && !Settings.BSXItself)
sum = checksum_calc_sum(ROM, CalculatedSize) - checksum_calc_sum(ROM + (HiROM ? 0xffb0 : 0x7fb0), 48);
else
if (Settings.SPC7110)
{
sum = checksum_calc_sum(ROM, CalculatedSize);
if (CalculatedSize == 0x300000)
sum += sum;
}
else
{
if (CalculatedSize & 0x7fff)
sum = checksum_calc_sum(ROM, CalculatedSize);
else
{
uint32 length = CalculatedSize;
sum = checksum_mirror_sum(ROM, length);
}
}

CalculatedChecksum = sum;
}
...