For non power of two sizes the idea is to take the largest power of two block, then look at the remaining size in power of two parts, and mirror until you have another block of the largest size. Then the end result is also a power of two.
If you have multiple smaller parts you always mirror the smallest part first until it matches the next largest part, then mirror that whole group. (Which is the same as calculating the checksum recursively, which is what the function does)
So as you said for your 20MBit ROM you have one 16MBit part, then you take the remaining 4Mbit part and mirror this until you have another 16MBit part, and the end result is 32MBit.
For the 27MBit ROM you have one 16MBit part, one 8MBit part, one 2MBit part and one 1MBit part. You take the largest part, then try to create another 16MBit part from the rest. We already have an 8MBit part, so we need to create another 8MBit from the rest. We mirror the 1MBit part, which then matches the 2MBit part, and thus have a 4MBit part. We mirror this resulting 4MBit part, creating a 8MBit part, which combined with the existing 8MBit part creates the 16MBit part we need to end up with 32MBit.
xprism wrote: ↑Fri Nov 20, 2020 11:06 amAs for checksum_mirror_sum, this is what I think its doing:
- mask is defined to be 64MBit in memmap.h, its divided by 2 until its equal to the largest power of 2 within the size of the ROM (not sure about this part, i'm making a guess)
Correct, that is looking for the largest remaining power of two block.
xprism wrote: ↑Fri Nov 20, 2020 11:06 am
Code: Select all
checksum_mirror_sum(start + mask, next_length, mask >> 1);
not sure what happens here
It calculates the checksum over the remaining part, starting with one power of two size smaller than currently used. So in your 20MBit example above you start with the 16MBit block, then this calculates the checksum for the remaining 4MBit (and also returns the created length, in the example this would be 4MBit - the created length will always be a power of 2).
In the 27MBit example this would calculate the checksum over the remaining 11MBit, and would already return 16MBit (with sub-calls in the 8MBit part, where it would return 4MBit, and in the 2MBit part where it would return 2MBit).
xprism wrote: ↑Fri Nov 20, 2020 11:06 am
Code: Select all
while (next_length < mask){ next_length += next_length; part2 += part2;}
part2 is added to itself as next_length advances to the end of the ROM
not sure what's the purpose of this either
This takes care of doing the mirroring until the created block is as large as the current block (and skips the mirroring if the created sub-block is already large enough).
In your 20MBit example the sub-checksum is for 4MBit, so this would be added four times to match the 16MBit part.
In the 27MBit example this would mirror the 1MBit part once to match the 2MBit part, then mirror the returned 4MBit part once to match the 8MBit part.