fixes the L2/DRAM hashing to account for fields that may have 0-width (CCE, slice, bank, and set indices)
prevents aliasing of blocks outside the L2 capacity
The purpose of the hash function is to distribute the L2 blocks evenly across the L2 slices/banks. This algorithm distributes blocks first to CCEs, then across slices and across banks (i.e., slice 0, bank 0 - slice 1, bank 0 - slice 0, bank 1 - slice 1, bank 0, etc.).
By definition (at least for POT number of CCEs), this algorithm guarantees that if there are N total sets across all L2s, then blocks [0, N) will remap to the same range and not alias outside the the L2 capacity.
Number of CCEs can be NPOT, but number of slices, banks, and sets must be POT >= 1.
This PR does two things:
The purpose of the hash function is to distribute the L2 blocks evenly across the L2 slices/banks. This algorithm distributes blocks first to CCEs, then across slices and across banks (i.e., slice 0, bank 0 - slice 1, bank 0 - slice 0, bank 1 - slice 1, bank 0, etc.).
By definition (at least for POT number of CCEs), this algorithm guarantees that if there are N total sets across all L2s, then blocks [0, N) will remap to the same range and not alias outside the the L2 capacity.
Number of CCEs can be NPOT, but number of slices, banks, and sets must be POT >= 1.