package audio.gme;
// Manages memory paging used by CPU emulators
// http://www.slack.net/~ant/
final class MemPager
{
public MemPager( int pageSize, int ramSize )
{
this.pageSize = pageSize;
this.romOffset = ramSize + pageSize;
}
// Loads data and returns memory array
public byte [] load( byte in [], byte [] header, int addr, int fill )
{
// allocate
int romLength = in.length - header.length;
int romSize = (romLength + addr + pageSize - 1) / pageSize * pageSize;
data = new byte [romOffset + romSize + padding];
// copy data
java.util.Arrays.fill( data, 0, romOffset + addr, (byte) fill );
java.util.Arrays.fill( data, data.length - pageSize - padding, data.length, (byte) fill );
System.arraycopy( in, header.length, data, romOffset + addr, romLength );
// addrMask
int shift = 0;
int max_addr = romSize - 1;
while ( (max_addr >> shift) != 0 )
shift++;
addrMask = (1 << shift) - 1;
// copy header
System.arraycopy( in, 0, header, 0, header.length );
return data;
}
// Size of ROM data, a multiple of pageSize
public int size() { return data.length - padding - romOffset; }
// Page of unmapped fill value
public int unmapped() { return romOffset - pageSize; }
// Masks address to nearest power of two greater than size()
public int maskAddr( int addr ) { return addr & addrMask; }
// Page starting at addr. Returns unmapped() if outside data.
public int mapAddr( int addr )
{
int offset = maskAddr( addr );
if ( offset < 0 || size() - pageSize < offset )
offset = -pageSize;
return offset + romOffset;
}
// private
static final int padding = 8; // extra at end for CPU emulators that read past end
byte [] data;
int pageSize;
int romOffset;
int addrMask;
}