#include	"precomp.h"

// instantiate the cache
Cache cache;

// helper functions; forward all requests to the cache
uint LOADUINT( uint* address ) { return cache.Read32bit( (uint)address ); }
void STOREUINT( uint* address, uint value ) { cache.Write32bit( (uint)address, value ); }

// artificial delay to feel some pain on cache misses
void Delay() { static int* x = new int[20000]; memcpy( x + 10000, x, 40000 ); }

// ============================================================================
// CACHE SIMULATOR IMPLEMENTATION
// ============================================================================

// cache constructor
Cache::Cache()
{
}

// cache destructor
Cache::~Cache()
{
	printf( "%f\n", dummy ); // prevent dead code elimination
}

// reading 32-bit values
uint Cache::Read32bit( uint address )
{
	// TODO: prevent reads from RAM using a cache
	// ...

	// cache read miss: read data from RAM
	__declspec(align(64)) CacheLine line;
	LoadLineFromMem( address, line );
	return line.data[(address & 63) >> 2];

	// TODO: store the data in the cache
	// ...
}

// writing 32-bit values
void Cache::Write32bit( uint address, uint value )
{
	// TODO: prevent writes to RAM using a cache
	// ...

	// cache write miss: write data to RAM
	__declspec(align(64)) CacheLine line;
	LoadLineFromMem( address, line );
	line.data[(address & 63) >> 2] = value;
	WriteLineToMem( address, line );

	// TODO: write to cache instead of RAM; evict to RAM if necessary
	// ...
}

// ============================================================================
// CACHE SIMULATOR LOW LEVEL MEMORY ACCESS WITH LATENCY SIMULATION
// ============================================================================

// load a cache line from memory; simulate RAM latency
void Cache::LoadLineFromMem( uint address, CacheLine& line )
{
    uint lineAddress = address & 0xFFFFFFC0; // set last six bit to 0
    memcpy( line.data, (void*)lineAddress, 64 ); // fetch 64 bytes into line
    Delay();
}

// write a cache line to memory; simulate RAM latency
void Cache::WriteLineToMem( uint address, CacheLine& line )
{
    uint lineAddress = address & 0xFFFFFFC0; // set last six bit to 0
    memcpy( (void*)lineAddress, line.data, 64 ); // fetch 64 bytes into line
    Delay();
}