#include "cache_controller.h"

PspeCacheController :: PspeCacheController(sc_module_name name, const cache_param_st & parameters, ofstream * file): sc_module(name)
{
	_secbus_debug(cout, TRACE, "BUILDING "<<parameters.name<<" CACHE CONTROLLER ..."<<"\n");

	SC_METHOD(ps);
	sensitive << clk.pos();
	SC_METHOD(pc);
	sensitive << clk.neg();

	cache_param = parameters;
	output = file;


	block_s = new int[parameters.block_size];
		
	if (parameters.enable)
		cache0 = new Cache(parameters);
	
	_secbus_debug(cout, TRACE, parameters.name<<" CACHE CONTROLLER BUILT"<<"\n");
}


void PspeCacheController::pc()
{	
	out_ack.rack = false;
	out_ack.wack = false;
	out_cmd.enable = false;

	switch (read_state) //0
	{
	case R_IDLE:
		out_ack.hit = hit_s;
		out_ack.rack = true;
		out_rdata.data[0] = block_s[0];
		out_rdata.data[1] = block_s[1];
		break;

	case R_START_READ_BLOCK :
		out_cmd.enable = true;
		out_cmd.cmd = READ;
		out_cmd.start_address = address_in_s;
		out_cmd.plen = cache_param.block_size * 4;
		break;

	case R_START_WRITE_BACK_BLOCK : 
		//cache enabled : write victim block to memory
		out_cmd.enable = true;
		out_cmd.cmd = WRITE;
		out_cmd.start_address = victim_block->getBaseAddress();
		out_cmd.plen = cache_param.block_size * 4;
		out_wdata.data[0] = victim_block->getData()[0];
		out_wdata.data[1] = victim_block->getData()[1];
		break;

	default : 
		break;
	}

	switch (write_state) 
	{

	case W_IDLE :
		out_ack.hit = hit_s;
		out_ack.wack = true;
		break;

	case W_START_WRITE_BLOCK :
		//cache disabled : write input block to memory
		out_cmd.enable = true;
		out_cmd.cmd = WRITE;
		out_cmd.start_address = address_in_s;
		out_cmd.plen = cache_param.block_size * 4;
		out_wdata.data[0] = block_s[0];
		out_wdata.data[1] = block_s[1];
		break;

	case W_START_WRITE_THROUGH_BLOCK :
		//cache enabled : write input block to memory		
		out_cmd.enable = true;
		out_cmd.cmd = WRITE;
		out_cmd.start_address = address_in_s;
		out_cmd.plen = cache_param.block_size * 4;
		out_wdata.data[0] = block_s[0];
		out_wdata.data[1] = block_s[1];
		break;

	case W_START_WRITE_BACK_BLOCK :
		//cache enabled : write victim block to memory	
		out_cmd.enable = true;
		out_cmd.cmd = WRITE;
		out_cmd.start_address = victim_block->getBaseAddress();
		out_cmd.plen = cache_param.block_size * 4;
		out_wdata.data[0] = victim_block->getData()[0];
		out_wdata.data[1] = victim_block->getData()[1];
		break;

	default :
		break;
	}


}

void PspeCacheController::ps()
{	
	
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER READ STATE: "<<read_state<<"\n");
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER WRITE STATE: "<<write_state<<"\n");
		

	if (!reset) 
	{
		read_misses = 0;
		write_misses = 0;
		write_back = 0;
		read_accesses = 0;
		write_accesses = 0;
		address_in_s = 0xFFFFFFFF;
		address_256_s = 0xFFFFFFFF;
		memset(block_s, 0, cache_param.block_size * sizeof(int));
		read_state = R_IDLE;
		write_state = W_IDLE;
		return;
	}

	switch (read_state) 
	{
	case R_IDLE ://0
		if(in_cmd.enable && in_cmd.cmd == READ)
		{
			address_in_s = in_cmd.address;

			if (cache_param.enable)
			{
				//cache statistics
				read_accesses++;

				hit_s = cache0->lookup(in_cmd.address, victim_block);

				if (hit_s)
					memcpy(block_s, cache0->readCache(in_cmd.address), cache_param.block_size*sizeof(int));
				else
				{
					//cache statistics
					read_misses++;

					if (cache_param.write_policy == WRITE_THROUGH)
						//No need to check dirty bits
						read_state = R_START_READ_BLOCK;
					else
						//Write back
					{
						if (!victim_block->isDirty())
							//block clean
							read_state = R_START_READ_BLOCK;
						else
						{
							//cache statistics
							write_back++;
							read_state = R_START_WRITE_BACK_BLOCK;
						}
					}
				}
			}
			else
					read_state = R_START_READ_BLOCK;

		}
		break;

	case R_START_READ_BLOCK :
		read_state = R_WAIT_READ_BLOCK;
		break;

	case R_START_WRITE_BACK_BLOCK : 
		read_state = R_WAIT_WRITE_BACK_BLOCK;
		break;

	case R_WAIT_WRITE_BACK_BLOCK:
		if (in_ack.wack)
			//Ram is updated
			//Now read missing block
			read_state = R_START_READ_BLOCK;
		break;

	case R_WAIT_READ_BLOCK :
		if (in_ack.rack)
		{
			block_s[0] = in_rdata.data[0];
			block_s[1] = in_rdata.data[1];
			if (cache_param.enable)
				//Write into cache
				cache0->replace(address_in_s, block_s, false);
			read_state = R_IDLE;
		}
		break;

	default : 
		break;
	}

	switch (write_state) 
	{
	case W_IDLE :
		if(in_cmd.enable && in_cmd.cmd == WRITE)
		{
      cout << "PSPE cache controller received WRITE cmd" << endl;

			address_in_s = in_cmd.address;
			block_s[0] = in_wdata.data[0];
			block_s[1] = in_wdata.data[1];

			
			if (cache_param.enable)
			{
				//cache statistics
				write_accesses++;
				hit_s = cache0->lookup(in_cmd.address, victim_block);

				if (cache_param.write_policy == WRITE_THROUGH)
					//Write in Ram
					write_state =  W_START_WRITE_THROUGH_BLOCK;
				else
					//WRITE-BACK
				{
					if (hit_s)
					{	
						cache0->writeCache(in_cmd.address, block_s, cache_param.block_size);
						write_state = W_IDLE;
					}
					else
					{
						//cache statistics
						write_misses++;

						if (!victim_block->isDirty())
							//clean
						{
							cache0->replace(in_cmd.address, block_s, true);
							write_state = W_IDLE;
						}
						else
						{
							//cache statistics
							write_back++;
							write_state = W_START_WRITE_BACK_BLOCK;
						}
					}		
				}
			}
			else
				write_state = W_START_WRITE_BLOCK;
		}
		break;

	case W_START_WRITE_BLOCK :
		write_state = W_WAIT_WRITE_BLOCK;
		break;

	case W_START_WRITE_THROUGH_BLOCK :
		//Write or replace cache
		if (hit_s)	cache0->writeCache(address_in_s, block_s, cache_param.block_size);
		else 
		{
			write_misses++;
			cache0->replace(address_in_s, block_s, true);
		}
		write_state = W_WAIT_WRITE_THROUGH_BLOCK;
		break;

	case W_START_WRITE_BACK_BLOCK :
		write_state = W_WAIT_WRITE_BACK_BLOCK;
		break;

	case W_WAIT_WRITE_BLOCK :
		if (in_ack.wack)
			write_state = W_IDLE;
		break;

	case W_WAIT_WRITE_THROUGH_BLOCK :
		if (in_ack.wack)
			write_state = W_IDLE;
		break;

	case W_WAIT_WRITE_BACK_BLOCK :
		if (in_ack.wack)
		{
			cache0->replace(address_in_s, block_s, true);
			write_state = W_IDLE;
		}
		break;

	default :
		break;
	}

}

void PspeCacheController::print_stats(ofstream & file)
{
//Store in file
    _secbus_debug(file, NONE, cache_param.name << "\n");
	_secbus_debug(file, NONE, "- CAHE ENABLED			    = " <<cache_param.enable<< "\n");
	_secbus_debug(file, NONE, "- ASSOCIATIVITY			    = " <<cache_param.associativity<< "\n");
	_secbus_debug(file, NONE, "- SET NUMBER			    = " <<cache_param.set_number<< "\n");
	_secbus_debug(file, NONE, "- BLOCK SIZE			    = " <<cache_param.block_size<< "\n");
	_secbus_debug(file, NONE, "- WRITE POLICY			    = ");
	if (cache_param.write_policy == WRITE_BACK)	_secbus_debug(file, NONE, "WRITE-BACK"<<"\n");
	else 	_secbus_debug(file, NONE, "WRITE-THROUGH"<<"\n");
		_secbus_debug(file, NONE, "- REPLACEMENT POLICY		= ");
	if (cache_param.replacement_policy == LRU) 	_secbus_debug(file, NONE, "LRU"<<"\n");
	else 	_secbus_debug(file, NONE, "FIFO"<<"\n");
	_secbus_debug(file, NONE, "- CACHE ACCESS NUMBER		= " <<read_accesses + write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE ACCESS NUMBER	= " <<write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ ACCESS NUMBER	= " <<read_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE MISS NUMBER		    = " <<write_misses+read_misses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE MISS NUMBER	= " <<write_misses<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ MISS NUMBER	= " <<read_misses<< "\n");
	_secbus_debug(file, NONE, "- CACHE MISS RATE		    = " <<(float)(write_misses+read_misses)/(read_accesses + write_accesses)<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ MISS RATE		= " <<(float)read_misses/read_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE MISS RATE		= " <<(float)write_misses/write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE BACK NUMBER	= " <<write_back<<"\n");
	
}
void PspeCacheController::reset_stats()
{
        read_misses = 0;
		write_misses = 0;
		write_back = 0;
		read_accesses = 0;
		write_accesses = 0;
}



SpCacheController :: SpCacheController(sc_module_name name, const cache_param_st & parameters, ofstream * file): sc_module(name)
{
	_secbus_debug(cout, TRACE, "BUILDING "<<parameters.name<<" CACHE CONTROLLER ..."<<"\n");

	SC_METHOD(ps);
	sensitive << clk.pos();
	SC_METHOD(pc);
	sensitive << clk.neg();

	cache_param = parameters;
	output = file;


	block_s = new int[parameters.block_size];
		
	if (parameters.enable)
		cache0 = new Cache(parameters);
	
	_secbus_debug(cout, TRACE, parameters.name<<" CACHE CONTROLLER BUILT"<<"\n");
}


void SpCacheController::pc()
{	
	out_ack.rack = false;
	out_ack.wack = false;
	out_cmd.enable = false;

	switch (read_state) 
	{
	case R_IDLE:
		out_ack.hit			= hit_s;
		out_ack.rack		= true;
		out_rdata.data[0]	= block_s[0];
		out_rdata.data[1]	= block_s[1];
		out_rdata.data[2]	= block_s[2];
		out_rdata.data[3]	= block_s[3];
		break;

	case R_START_READ_BLOCK :
		
		out_cmd.enable			= true;
		out_cmd.cmd				= READ;
		out_cmd.start_address	= address_in_s;
		out_cmd.plen			= cache_param.block_size * 4;
		break;

	case R_START_WRITE_BACK_BLOCK : 
		//cache enabled : write victim block to memory
		out_cmd.enable			= true;
		out_cmd.cmd				= WRITE;
		out_cmd.start_address	= victim_block->getBaseAddress();
		out_cmd.plen			= cache_param.block_size * 4;
		out_wdata.data[0]		= victim_block->getData()[0];
		out_wdata.data[1]		= victim_block->getData()[1];
		out_wdata.data[2]		= victim_block->getData()[2];
		out_wdata.data[3]		= victim_block->getData()[3];
		break;

	default : 
		break;
	}

	switch (write_state) 
	{

	case W_IDLE :
		out_ack.hit = hit_s;
		out_ack.wack = true;
		break;

	case W_START_WRITE_BLOCK :
		//cache disabled : write input block to memory
		
		out_cmd.enable			= true;
		out_cmd.cmd				= WRITE;
		out_cmd.start_address	= address_in_s;
		out_cmd.plen			= cache_param.block_size * 4;
		out_wdata.data[0]		= block_s[0];
		out_wdata.data[1]		= block_s[1];
		break;

	case W_START_WRITE_THROUGH_BLOCK :
		//cache enabled : write input block to memory
		
		out_cmd.enable			= true;
		out_cmd.cmd				= WRITE;
		out_cmd.start_address	= address_in_s;
		out_cmd.plen			= cache_param.block_size * 4;
		out_wdata.data[0]		= block_s[0];
		out_wdata.data[1]		= block_s[1];
		break;

	case W_START_WRITE_BACK_BLOCK :
		//cache enabled : write victim block to memory
		out_cmd.enable			= true;
		out_cmd.cmd				= WRITE;
		out_cmd.start_address	= victim_block->getBaseAddress();
		out_cmd.plen			= cache_param.block_size * 4;
		out_wdata.data[0]		= victim_block->getData()[0];
		out_wdata.data[1]		= victim_block->getData()[1];
		break;

	default :
		break;
	}


}



void SpCacheController::ps()
{	
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER READ STATE: "<<read_state<<"\n");
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER WRITE STATE: "<<write_state<<"\n");
	
	if (!reset) 
	{
		read_misses				= 0;
		write_misses			= 0;
		write_back				= 0;
		read_accesses			= 0;
		write_accesses			= 0;
		address_in_s			= 0xFFFFFFFF;
		address_256_s			= 0xFFFFFFFF;
		memset(block_s, 0, cache_param.block_size * sizeof(int));
		read_state				= R_IDLE;
		write_state				= W_IDLE;
		return;
	}

	switch (read_state) 
	{
	case R_IDLE ://0
		if(in_cmd.enable && in_cmd.cmd == READ)
		{
			address_in_s = in_cmd.address;

			if (cache_param.enable)
			{
				//cache statistics
				read_accesses++;

				hit_s = cache0->lookup(in_cmd.address, victim_block);

				read_state = R_TEST_HIT_SIGNAL;
			}
			else
				read_state = R_START_READ_BLOCK;

		}
		break;

	case R_TEST_HIT_SIGNAL :
		if (hit_s)
		{	
			memcpy(block_s, cache0->readCache(address_in_s), cache_param.block_size*sizeof(int));
			read_state = R_IDLE;
		}
		else
		{
			//cache statistics
			read_misses++;

			if (cache_param.write_policy == WRITE_THROUGH)
				//No need to check dirty bit before reading memory
					read_state = R_START_READ_BLOCK;
			else
				//Write back
			{
				if (!victim_block->isDirty())
					//clean
					read_state = R_START_READ_BLOCK;
				else
				{
					//cache statistics
					write_back++;
					read_state = R_START_WRITE_BACK_BLOCK;
				}
			}
		}
		break;

	case R_START_READ_BLOCK ://2
		read_state = R_WAIT_READ_BLOCK;
		break;

	case R_START_WRITE_BACK_BLOCK : //3
		read_state = R_WAIT_WRITE_BACK_BLOCK;
		break;

	case R_WAIT_WRITE_BACK_BLOCK://4
		if (in_ack.wack)
			//Ram is updated
			//Now read missing block
			read_state = R_START_READ_BLOCK;
		break;

	case R_WAIT_READ_BLOCK ://5
		if (in_ack.rack)
		{
			for(int i=0;i<cache_param.block_size;i++)
				block_s[i] = in_rdata.data[i];
			if (cache_param.enable)
				//Write into cache
				cache0->replace(address_in_s, block_s, false);
			read_state = R_IDLE;
		}
		break;

	default : 
		break;
	}

	switch (write_state) 
	{
	case W_IDLE :
		if(in_cmd.enable && in_cmd.cmd == WRITE)
		{
			address_in_s = in_cmd.address;

			for(int i=0;i<cache_param.block_size;i++)
				block_s[i] = in_wdata.data[i];
			
			if (cache_param.enable)
			{
				//cache statistics
				write_accesses++;

				hit_s = cache0->lookup(in_cmd.address, victim_block);

				if (cache_param.write_policy == WRITE_THROUGH)
					//Write in Ram
					write_state =  W_START_WRITE_THROUGH_BLOCK;
				else
					//WRITE-BACK
					write_state = W_TEST_HIT_SIGNAL;
			}
			else
				write_state = W_START_WRITE_BLOCK;
		}
		break;

	case W_START_WRITE_BLOCK :
		write_state = W_WAIT_WRITE_BLOCK;
		break;

	case W_START_WRITE_THROUGH_BLOCK :
		//Write or replace cache
		if (hit_s)	cache0->writeCache(address_in_s, block_s, cache_param.block_size);
		else 
		{
			write_misses++;
			cache0->replace(address_in_s, block_s, true);
		}
		write_state = W_WAIT_WRITE_THROUGH_BLOCK;
		break;

	case W_START_WRITE_BACK_BLOCK :
		write_state = W_WAIT_WRITE_BACK_BLOCK;
		break;

	case W_TEST_HIT_SIGNAL :
		if (hit_s)
		{	
			cache0->writeCache(address_in_s, block_s, cache_param.block_size);
			write_state = W_IDLE;
		}
		else
		{
			//cache statistics
			write_misses++;

			if (!victim_block->isDirty())
				//clean
			{
				cache0->replace(address_in_s, block_s, true);
				write_state = W_IDLE;
			}
			else
			{
				//cache statistics
				write_back++;
				write_state = W_START_WRITE_BACK_BLOCK;
			}
		}		
		break;

	case W_WAIT_WRITE_BLOCK :
		if (in_ack.wack)
			write_state = W_IDLE;
		break;

	case W_WAIT_WRITE_THROUGH_BLOCK :
		if (in_ack.wack)
			write_state = W_IDLE;
		break;

	case W_WAIT_WRITE_BACK_BLOCK :
		if (in_ack.wack)
		{
			cache0->replace(address_in_s, block_s, true);
			write_state = W_IDLE;
		}
		break;

	default :
		break;
	}

}



void SpCacheController::print_stats(ofstream & file)
{
	//Store in file
    _secbus_debug(file, NONE, cache_param.name << "\n");
	_secbus_debug(file, NONE, "- CAHE ENABLED			    = " <<cache_param.enable<< "\n");
	_secbus_debug(file, NONE, "- ASSOCIATIVITY			    = " <<cache_param.associativity<< "\n");
	_secbus_debug(file, NONE, "- SET NUMBER			    = " <<cache_param.set_number<< "\n");
	_secbus_debug(file, NONE, "- BLOCK SIZE			    = " <<cache_param.block_size<< "\n");
	_secbus_debug(file, NONE, "- WRITE POLICY			    = ");
	if (cache_param.write_policy == WRITE_BACK)	_secbus_debug(file, NONE, "WRITE-BACK"<<"\n");
	else 	_secbus_debug(file, NONE, "WRITE-THROUGH"<<"\n");
		_secbus_debug(file, NONE, "- REPLACEMENT POLICY		= ");
	if (cache_param.replacement_policy == LRU) 	_secbus_debug(file, NONE, "LRU"<<"\n");
	else 	_secbus_debug(file, NONE, "FIFO"<<"\n");
	_secbus_debug(file, NONE, "- CACHE ACCESS NUMBER		= " <<read_accesses + write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE ACCESS NUMBER	= " <<write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ ACCESS NUMBER	= " <<read_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE MISS NUMBER		    = " <<write_misses+read_misses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE MISS NUMBER	= " <<write_misses<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ MISS NUMBER	= " <<read_misses<< "\n");
	_secbus_debug(file, NONE, "- CACHE MISS RATE		    = " <<(float)(write_misses+read_misses)/(read_accesses + write_accesses)<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ MISS RATE		= " <<(float)read_misses/read_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE MISS RATE		= " <<(float)write_misses/write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE BACK NUMBER	= " <<write_back<<"\n");
}
void SpCacheController::reset_stats()
{
        read_misses = 0;
		write_misses = 0;
		write_back = 0;
		read_accesses = 0;
		write_accesses = 0;
}


MacCacheController :: MacCacheController(sc_module_name name, const cache_param_st & parameters, ofstream * file): sc_module(name)
{
	_secbus_debug(cout, TRACE, "BUILDING "<<parameters.name<<" CACHE CONTROLLER ..."<<"\n");

	SC_METHOD(ps);
	sensitive << clk.pos();
	SC_METHOD(pc);
	sensitive << clk.neg();

	cache_param = parameters;
	output = file;

	block_s = new int[parameters.block_size];
		
	if (parameters.enable)
		cache0 = new Cache(parameters);
	
	_secbus_debug(cout, TRACE, parameters.name<<" CACHE CONTROLLER BUILT"<<"\n");
}

void MacCacheController::pc()
{	
	out_ack.rack			= false;
	out_ack.wack			= false;
	out_cmd.enable			= false;


	switch (read_state) 
	{
	case R_IDLE:
		out_ack.hit			= hit_s;
		out_ack.rack		= true;
		out_rdata.data[0]	= block_s[0];
		out_rdata.data[1]	= block_s[1];
		break;

	case R_START_READ_BLOCK :
		out_cmd.id					= 3;
		out_cmd.enable				= true;
		out_cmd.cmd					= READ;
		out_cmd.start_address		= address_in_s;
		out_cmd.plen				= SIZE_64_IN_BYTES;
		break;

	case R_START_WRITE_BACK_BLOCK : 
		//cache enabled : write victim block_s to memory
		out_cmd.id					= 3;
		out_cmd.enable				= true;
		out_cmd.cmd					= WRITE;
		out_cmd.start_address		= victim_block->getBaseAddress();
		out_cmd.plen				= cache_param.block_size * 4;
		out_wdata.data[0]			= victim_block->getData()[0];
		out_wdata.data[1]			= victim_block->getData()[1];
		break;

	default : 
		break;
	}

	switch (write_state) 
	{

	case W_IDLE :
		out_ack.hit = hit_s;
		out_ack.wack = true;
		break;

	case W_START_WRITE_BLOCK :
		//cache disabled : write input block to memory
		out_cmd.id					= 3;
		out_cmd.enable				= true;
		out_cmd.cmd					= WRITE;
		out_cmd.start_address		= address_in_s;
		out_cmd.plen				= cache_param.block_size * 4;
		out_wdata.data[0]			= block_s[0];
		out_wdata.data[1]			= block_s[1];
		break;

	case W_START_WRITE_THROUGH_BLOCK :
		//cache enabled : write input block to memory
		out_cmd.id					= 3;
		out_cmd.enable				= true;
		out_cmd.cmd					= WRITE;
		out_cmd.start_address		= address_in_s;
		out_cmd.plen				= cache_param.block_size * 4;
		out_wdata.data[0]			= block_s[0];
		out_wdata.data[1]			= block_s[1];
		break;

	case W_START_WRITE_BACK_BLOCK :
		//cache enabled : write victim block to memory
		out_cmd.id					= 3;
		out_cmd.enable				= true;
		out_cmd.cmd					= WRITE;
		out_cmd.start_address		= victim_block->getBaseAddress();
		out_cmd.plen				= cache_param.block_size * 4;
		out_wdata.data[0]			= victim_block->getData()[0];
		out_wdata.data[1]			= victim_block->getData()[1];
		break;

	default :
		break;
	}


}

void MacCacheController::ps()
{	
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER READ STATE: "<<read_state<<"\n");
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER WRITE STATE: "<<write_state<<"\n");

	if (!reset) 
	{
    read_misses = 0;
    write_misses = 0;
    write_back = 0;
    read_accesses = 0;
    write_accesses = 0;
    address_in_s = 0xFFFFFFFF;
    address_256_s = 0xFFFFFFFF;
    memset(block_s, 0, cache_param.block_size * sizeof(int));
    read_state = R_IDLE;
    write_state = W_IDLE;
    return;
  }

  switch (read_state) 
  {
    case R_IDLE ://0
      if(in_cmd.enable && in_cmd.cmd == READ)
      {
        address_in_s    = in_cmd.address;
        index_s         = index(in_cmd.address, MS_SIZE_IN_BYTES);
        address_256_s   = aligned(in_cmd.address, MS_SIZE_IN_BYTES);

        if (cache_param.enable)
        {
          //cache statistics
          read_accesses++;

          hit_s = cache0->lookup(in_cmd.address, victim_block);
          read_state = R_TEST_HIT_SIGNAL;
        }
        else
        {
          if (register_2_in.address == aligned(in_cmd.address, MS_SIZE_IN_BYTES) && fill_64(register_2_in.be, index(in_cmd.address, MS_SIZE_IN_BYTES)))
          {
            block_s[0] = register_2_in.data[index(in_cmd.address, MS_SIZE_IN_BYTES)];
            block_s[1] = register_2_in.data[1 + index(in_cmd.address, MS_SIZE_IN_BYTES)];
            read_state = R_IDLE;
          }
          else
            read_state = R_START_READ_BLOCK;
        }
      }
      break;

    case R_TEST_HIT_SIGNAL :
      if (hit_s)
      {	
        memcpy(block_s, cache0->readCache(address_in_s), cache_param.block_size*sizeof(int));
        read_state = R_IDLE;
      }
      else
      {
        //cache statistics
        read_misses++;

        if (cache_param.write_policy == WRITE_THROUGH)
          //No need to check dirty bit before reading memory
        {
          if ((register_2_in.address == address_256_s) && fill_64(register_2_in.be, index_s))
          {
            block_s[0] = register_2_in.data[index_s];
            block_s[1] = register_2_in.data[1 + index_s];
            //Write into cache
            cache0->replace(address_in_s, block_s, false);
            read_state = R_IDLE;
          }
          else
            read_state = R_START_READ_BLOCK;
        }
        else
          //Write back
        {
          if (!victim_block->isDirty())
            //clean
          {
            if ((register_2_in.address == address_256_s) && fill_64(register_2_in.be, index_s))
            {
              block_s[0] = register_2_in.data[index_s];
              block_s[1] = register_2_in.data[1 + index_s];
              //Write into cache
              cache0->replace(address_in_s, block_s, false);
              read_state = R_IDLE;
            }
            else
              read_state = R_START_READ_BLOCK;

          }
          else
          {
            //cache statistics
            write_back++;
            read_state = R_START_WRITE_BACK_BLOCK;
          }
        }
      }
      break;

    case R_START_READ_BLOCK :
      read_state = R_WAIT_READ_BLOCK;
      break;

    case R_START_WRITE_BACK_BLOCK : 
      read_state = R_WAIT_WRITE_BACK_BLOCK;
      break;

    case R_WAIT_WRITE_BACK_BLOCK:
      if (in_ack.wack)
        //Ram is updated
        //Now read missing block
        read_state = R_START_READ_BLOCK;
      break;

    case R_WAIT_READ_BLOCK :
      if (in_ack.rack)
      {
        block_s[0] = register_2_in.data[index_s];
        block_s[1] = register_2_in.data[1 + index_s];
        //Copy to cache
        if (cache_param.enable)
          //Write into cache
          cache0->replace(address_in_s, block_s, false);
        read_state = R_IDLE;
      }
      break;

	default : 
		break;
	}

	switch (write_state) 
	{
	case W_IDLE :
		if(in_cmd.enable && in_cmd.cmd == WRITE)
		{

			address_in_s = in_cmd.address;
			block_s[0] = in_wdata.data[0];
			block_s[1] = in_wdata.data[1];
			index_s = index(in_cmd.address, MS_SIZE_IN_BYTES);
			address_256_s = aligned(in_cmd.address, MS_SIZE_IN_BYTES);
			
			if (cache_param.enable)
			{
				//cache statistics
				write_accesses++;

				hit_s = cache0->lookup(in_cmd.address, victim_block);

				if (cache_param.write_policy == WRITE_THROUGH)
					//Write in Ram
					write_state =  W_START_WRITE_THROUGH_BLOCK;
				else
					//WRITE-BACK
					write_state = W_TEST_HIT_SIGNAL;
			}
			else
      {
				write_state = W_START_WRITE_BLOCK;
      }
		}
		break;

	case W_START_WRITE_BLOCK :
		write_state = W_WAIT_WRITE_BLOCK;
		break;

	case W_START_WRITE_THROUGH_BLOCK :
		//Write or replace cache
		if (hit_s)	cache0->writeCache(address_in_s, block_s, cache_param.block_size);
		else 
		{
			write_misses++;
			cache0->replace(address_in_s, block_s, true);
		}
		write_state = W_WAIT_WRITE_THROUGH_BLOCK;
		break;

	case W_START_WRITE_BACK_BLOCK :
		write_state = W_WAIT_WRITE_BACK_BLOCK;
		break;

	case W_TEST_HIT_SIGNAL :
		if (hit_s)
		{	
			cache0->writeCache(address_in_s, block_s, cache_param.block_size);
			write_state = W_IDLE;
		}
		else
		{
			//cache statistics
			write_misses++;

			if (!victim_block->isDirty())
				//clean
			{
				cache0->replace(address_in_s, block_s, true);
				write_state = W_IDLE;
			}
			else
			{
				index_s = index(victim_block->getBaseAddress(), MS_SIZE_IN_BYTES);
				address_256_s = aligned(victim_block->getBaseAddress(), MS_SIZE_IN_BYTES);
				//cache statistics
				write_back++;
				write_state = W_START_WRITE_BACK_BLOCK;
			}
		}		
		break;

	case W_WAIT_WRITE_BLOCK :
		if (in_ack.wack)
			write_state = W_IDLE;
		break;

	case W_WAIT_WRITE_THROUGH_BLOCK :
		if (in_ack.wack)
			write_state = W_IDLE;
		break;

	case W_WAIT_WRITE_BACK_BLOCK :
		if (in_ack.wack)
		{
			cache0->replace(address_in_s, block_s, true);
			write_state = W_IDLE;
		}
		break;

	default :
		break;
	}

}
void MacCacheController::print_stats(ofstream & file)
{
	//Store in file
    _secbus_debug(file, NONE, cache_param.name << "\n");
	_secbus_debug(file, NONE, "- CAHE ENABLED			    = " <<cache_param.enable<< "\n");
	_secbus_debug(file, NONE, "- ASSOCIATIVITY			    = " <<cache_param.associativity<< "\n");
	_secbus_debug(file, NONE, "- SET NUMBER			    = " <<cache_param.set_number<< "\n");
	_secbus_debug(file, NONE, "- BLOCK SIZE			    = " <<cache_param.block_size<< "\n");
	_secbus_debug(file, NONE, "- WRITE POLICY			    = ");
	if (cache_param.write_policy == WRITE_BACK)	_secbus_debug(file, NONE, "WRITE-BACK"<<"\n");
	else 	_secbus_debug(file, NONE, "WRITE-THROUGH"<<"\n");
		_secbus_debug(file, NONE, "- REPLACEMENT POLICY		= ");
	if (cache_param.replacement_policy == LRU) 	_secbus_debug(file, NONE, "LRU"<<"\n");
	else 	_secbus_debug(file, NONE, "FIFO"<<"\n");
	_secbus_debug(file, NONE, "- CACHE ACCESS NUMBER		= " <<read_accesses + write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE ACCESS NUMBER	= " <<write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ ACCESS NUMBER	= " <<read_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE MISS NUMBER		    = " <<write_misses+read_misses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE MISS NUMBER	= " <<write_misses<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ MISS NUMBER	= " <<read_misses<< "\n");
	_secbus_debug(file, NONE, "- CACHE MISS RATE		    = " <<(float)(write_misses+read_misses)/(read_accesses + write_accesses)<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ MISS RATE		= " <<(float)read_misses/read_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE MISS RATE		= " <<(float)write_misses/write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE BACK NUMBER	= " <<write_back<<"\n");
}
void MacCacheController::reset_stats()
{
       	read_misses = 0;
		write_misses = 0;
		write_back = 0;
		read_accesses = 0;
		write_accesses = 0;
}


HashCacheController :: HashCacheController(sc_module_name name, const cache_param_st & parameters, ofstream * file): sc_module(name)
{
	
	_secbus_debug(cout, TRACE, "BUILDING "<<parameters.name<<" CACHE CONTROLLER ..."<<"\n");

	SC_METHOD(ps);
	sensitive << clk.pos();
	SC_METHOD(pc);
	sensitive << clk.neg();

	cache_param = parameters;

	output = file;

	block_s = new int[parameters.block_size];

	if (parameters.enable)
		cache0 = new ComplexCache(parameters, file);

	_secbus_debug(cout, TRACE, parameters.name<<" CACHE CONTROLLER BUILT"<<"\n");
}

void HashCacheController::pc()
{
	out_ack.rack			= false;
	out_ack.wack			= false;
	out_ack.rstack			= false;
	out_ack.sack			= false;
	out_ack.victim_address	= 0xFFFFFFFF;
	out_cmd.enable			= false;

	switch (s_state) 
	{
	case S_IDLE :
		out_ack.sack			= true;
		out_ack.full			= full_s;
		out_ack.hit				= hit_s;
		out_ack.dirty			= dirty_s;
		out_ack.victim_address	= victim_address_s;
		out_rdata.data[0]		= block_s[0];
		out_rdata.data[1]		= block_s[1];
		break;

	case S_START_READ_BLOCK :
		out_cmd.id				= 2;
		out_cmd.cmd				= READ;
		out_cmd.enable			= true;
		out_cmd.start_address	= address_256_s;
		out_cmd.plen			= HS_SIZE_IN_BYTES;
		break;

	case S_START_WRITE_BLOCK : 
		out_cmd.id					= 2;
		out_cmd.cmd					= WRITE;
		out_cmd.enable				= true;
		out_cmd.start_address		= address_in_s;
		out_cmd.plen				= cache_param.block_size * 4;
		out_wdata.data[0]			= block_s[0];
		out_wdata.data[1]			= block_s[1];
		break;

	default : 
		break;
	}

	//End Synchronize

	switch (wr_state) 
	{
	
	case WR_IDLE :
		out_ack.wack			= true;
		out_ack.full			= full_s;
		out_ack.hit				= hit_s;
		out_ack.dirty			= dirty_s;
		out_ack.victim_address	= victim_address_s;
		break;

	default :
		break;
	}
	//End write

	switch (rst_state) 
	{
	case RST_IDLE :
		out_ack.rstack			= true;
		out_ack.full			= full_s;
		out_ack.hit				= hit_s;
		out_ack.dirty			= dirty_s;
		out_ack.victim_address	= victim_address_s;
		out_rdata.data[0]		= block_s[0];
		out_rdata.data[1]		= block_s[1];
		break;

	case RST_START_RESTORE :
		out_cmd.id				= 2;
		out_cmd.cmd				= READ;
		out_cmd.enable			= true;
		out_cmd.start_address	= address_256_s;
		out_cmd.plen			= HS_SIZE_IN_BYTES;
		break;

	case RST_START_READ_BLOCK :
		out_cmd.id				= 2;
		out_cmd.cmd				= READ;
		out_cmd.enable			= true;
		out_cmd.start_address	= address_256_s;
		out_cmd.plen			= HS_SIZE_IN_BYTES;
		break;


	default :
		break;

	}

	//End Restore 

	switch (rd_state) 
	{
	case RD_IDLE :
		out_ack.rack			= true;
		out_ack.full			= full_s;
		out_ack.hit				= hit_s;
		out_ack.dirty			= dirty_s;
		out_ack.victim_address	= victim_address_s;
		out_rdata.data[0]		= block_s[0];
		out_rdata.data[1]		= block_s[1];
		break;

	case RD_START_READ_BLOCK :
		out_cmd.id					= 2;
		out_cmd.cmd					= READ;
		out_cmd.enable				= true;
		out_cmd.start_address		= address_256_s;
		out_cmd.plen				= HS_SIZE_IN_BYTES;
		break;

	default : 
		break;
	}
}

void HashCacheController::ps()
{
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER READ STATE: "<<rd_state<<"\n");
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER WRITE STATE: "<<wr_state<<"\n");
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER SYNCHRONIZE STATE: "<<s_state<<"\n");
	_secbus_debug(*output, DEBUG, cache_param.name<<" CACHE CONTROLLER RESTORE STATE: "<<rst_state<<"\n");


	if(!reset)
	{
		invalidate_accesses = 0;
		read_accesses = 0;
		write_accesses = 0;
		restore_accesses = 0;
		synchronize_accesses = 0;
		read_misses = 0;
		write_misses = 0;
		restore_misses = 0;
		synchronize_misses = 0;
		address_in_s = 0xFFFFFFFF;
		address_256_s = 0xFFFFFFFF;
		memset(block_s, 0, cache_param.block_size * sizeof(int));
		s_state = S_IDLE;
		i_state = I_IDLE;
		rd_state = RD_IDLE;
		rst_state = rst_state;
		wr_state = WR_IDLE;
		return;
	}

	switch (i_state) 
	{
	case I_IDLE :
		if(in_cmd.enable && in_cmd.cmd == INVALIDATE)
		{
			invalidate_accesses++;

			address_in_s = in_cmd.address;

			hit_s = cache0->lookup(in_cmd.address, dirty_s);
			i_state = I_TEST_HIT_SIGNAL;
		}
		break;

	case I_TEST_HIT_SIGNAL :
		if (hit_s)
		{	
			cache0->freeBlock(address_in_s);
			if (dirty_s)
				//decrease dirty counter
				cache0->UpdSetCounter(address_in_s, false);
		}
		i_state = I_IDLE;
		break;

	default : 
		break;
	}
	//End invalidate

	switch (s_state) 
	{
	case S_IDLE :
		if(in_cmd.enable && in_cmd.cmd == SYNCHRONIZE)
		{
			synchronize_accesses++;

			address_in_s = in_cmd.address;
			address_256_s = aligned(in_cmd.address, HS_SIZE_IN_BYTES);
			index_s = index(in_cmd.address, HS_SIZE_IN_BYTES);
			//Lookup in Cache
			hit_s = cache0->lookup(in_cmd.address, dirty_s);
			s_state = S_TEST_HIT_SIGNAL;
		}
		break;

	case S_TEST_HIT_SIGNAL :
		if (hit_s)
		{	
			if (dirty_s)
				//Write RAM
			{
				//provide data from cache 
				memcpy(block_s, cache0->readCache(address_in_s), cache_param.block_size*sizeof(int));
				//Send selected block to memory
				s_state = S_START_WRITE_BLOCK;
			}
			else
				//Read Cache
			{
				cout<<"WARNING ! SYNCHRONIZATION OF A NON DIRTY HASH VALUE"<<"\n";

				memcpy(block_s, cache0->readCache(address_in_s), cache_param.block_size*sizeof(int));
				s_state = S_IDLE;
			}
		}
		else
			//Block is not in cache : Read RAM
		{
			synchronize_misses++;
			
			cout<<"WARNING ! SYNCHRONIZATION OF A HASH VALUE NOT IN CACHE"<<"\n";
			
			//Read RAM
			if (register_2_in.address == address_256_s)
			{
				block_s[0] = register_2_in.data[index_s];
				block_s[1] = register_2_in.data[1 + index_s];
				//Store into cache
				cache0->storeCache(address_in_s, block_s, false);
				dirty_s = false;
				s_state = S_IDLE;	
			}
			else
				s_state = S_START_READ_BLOCK;
		}	
		break;

	case S_START_READ_BLOCK :
		s_state = S_WAIT_READ_BLOCK;
		break;

	case S_START_WRITE_BLOCK : 
		s_state = S_WAIT_WRITE_BLOCK;
		break;

	case S_WAIT_WRITE_BLOCK:
		if (in_ack.wack)
		{
			//RAM is synchronized : Clean dirty bit
			cache0->cleanBlock(address_in_s);
			//decrease dirty counter
			cache0->UpdSetCounter(address_in_s, false);
			s_state = S_IDLE;
		}
		break;

	case S_WAIT_READ_BLOCK :
		if (in_ack.rack)
		{
			block_s[0] = register_2_in.data[index_s];
			block_s[1] = register_2_in.data[1 + index_s];
			//Store into cache
			cache0->storeCache(address_in_s, block_s, false);
			dirty_s = false;
			s_state = S_IDLE;	
		}
		break;

	default : 
		break;
	}

	//End Synchronize

	switch (wr_state) 
	{
	case WR_IDLE :
		if(in_cmd.enable && in_cmd.cmd == WRITE)
		{
			write_accesses++;

			address_in_s = in_cmd.address;
			block_s[0] = in_wdata.data[0];
			block_s[1] = in_wdata.data[1];
			address_256_s = aligned(in_cmd.address, HS_SIZE_IN_BYTES);
			index_s = index(in_cmd.address, HS_SIZE_IN_BYTES);
			//Lookup in Cache
			hit_s = cache0->lookup(in_cmd.address, dirty_s);
			wr_state = WR_TEST_HIT_SIGNAL;
		}
		break;


	case WR_TEST_HIT_SIGNAL :
		if (hit_s)
			//Write HV in cache
		{	
			cache0->writeCache(address_in_s, block_s);
			if (dirty_s)
				//Dirty already set
			{
				wr_state = WR_IDLE;
				full_s = false;
			}
			else
			{
				cache0->UpdSetCounter(address_in_s, true);
				wr_state = WR_TEST_FULL_SIGNAL;
			}
		}
		else
			//Store HV in cache
		{
			write_misses++;

			cache0->storeCache(address_in_s, block_s, true);
			//Increase dirty counter
			cache0->UpdSetCounter(address_in_s, true);
			wr_state = WR_WRITE_CACHE;
		}
		break;

	case WR_WRITE_CACHE :
		wr_state = WR_TEST_FULL_SIGNAL;
		break;


	case WR_TEST_FULL_SIGNAL :
		wr_state = WR_IDLE;
		//consult dirty counter value of current cache set
		if (cache0->readNHVdirty(address_in_s, victim_address_s) >= cache_param.threshold)
			//inform HTM that this cache set is currently satured with dirty HV
			full_s = true;
		else
			//informs HTM that cache this set is not currently satured with dirty HV
			full_s = false;
		break;

	default :
		break;
	}
	//End write

	switch (rst_state) 
	{
	case RST_IDLE :
		if(in_cmd.enable && in_cmd.cmd == RESTORE)
		{
			restore_accesses++;
			address_in_s = in_cmd.address;
			address_256_s = aligned(in_cmd.address, HS_SIZE_IN_BYTES);
			index_s = index(in_cmd.address, HS_SIZE_IN_BYTES);
			//Lookup in Cache
			hit_s = cache0->lookup(in_cmd.address, dirty_s);
			rst_state = RST_TEST_HIT_SIGNAL;
		}
		break;

	case RST_TEST_HIT_SIGNAL :
		if (hit_s)
		{	
			if (dirty_s)
				//Read RAM 
			{
				if (register_2_in.address == address_256_s)
				{
					block_s[0] = register_2_in.data[index_s];
					block_s[1] = register_2_in.data[1 + index_s];
					//Do not store into cache
					rst_state = RST_IDLE;	
				}
				else
					rst_state = RST_START_RESTORE;

			}	
			else
				//Read Cache
			{
				memcpy(block_s, cache0->readCache(address_in_s), cache_param.block_size*sizeof(int));
				rst_state = RST_IDLE;
				
			}
		}
		else
		{
			restore_misses++;

			if (register_2_in.address == address_256_s)
			{
				block_s[0] = register_2_in.data[index_s];
				block_s[1] = register_2_in.data[1 + index_s];
				//Store into cache : Select cache block to write
				cache0->storeCache(address_in_s, block_s, false);
				dirty_s		= false;
				rst_state	= RST_IDLE;
				
			}
			else 
				//Read external memory
				rst_state = RST_START_READ_BLOCK;
		}
		break;


	case RST_START_RESTORE :
		rst_state = RST_WAIT_RESTORE;
		break;

	case RST_WAIT_RESTORE :
		if (in_ack.rack)
			//Read block is in temp block
		{
			block_s[0] = register_2_in.data[index_s];
			block_s[1] = register_2_in.data[1 + index_s];
			//Do not store into cache
			rst_state = RST_IDLE;
		}
		break;

	case RST_START_READ_BLOCK :
		rst_state = RST_WAIT_READ_BLOCK;
		break;

	case RST_WAIT_READ_BLOCK :
		if (in_ack.rack)
		{
			block_s[0] = register_2_in.data[index_s];
			block_s[1] = register_2_in.data[1 + index_s];
			//Store into cache : Select cache block to write
			cache0->storeCache(address_in_s, block_s, false);
			dirty_s = false;
			rst_state = RST_IDLE;
		}
		break;

	default ://5
		break;

	}

	//End Restore 

	switch (rd_state) 
	{
	case RD_IDLE :
		if(in_cmd.enable && in_cmd.cmd == READ)
		{
			read_accesses++;

			address_in_s = in_cmd.address;
			address_256_s = aligned(in_cmd.address, HS_SIZE_IN_BYTES);
			index_s = index(in_cmd.address, HS_SIZE_IN_BYTES);
			//Lookup in Cache
			hit_s = cache0->lookup(in_cmd.address, dirty_s);
			rd_state = RD_TEST_HIT_SIGNAL;
		}
		break;

	case RD_TEST_HIT_SIGNAL :
		if (hit_s)
		{	
			memcpy(block_s, cache0->readCache(address_in_s), cache_param.block_size*sizeof(int));
			rd_state = RD_IDLE;
		}
		else
		{
			read_misses++;

			if (register_2_in.address == address_256_s)
			{
				block_s[0] = register_2_in.data[index_s];
				block_s[1] = register_2_in.data[1 + index_s];
				//Store into Cache
				cache0->storeCache(address_in_s, block_s, false);
				dirty_s = false;
				rd_state = RD_IDLE;	
			}
			else 
				//Read RAM
				rd_state = RD_START_READ_BLOCK;
		}
		break;

	case RD_START_READ_BLOCK :
		rd_state = RD_WAIT_READ_BLOCK;
		break;

	case RD_WAIT_READ_BLOCK :
		if (in_ack.rack)
		{
			block_s[0] = register_2_in.data[index_s];
			block_s[1] = register_2_in.data[1 + index_s];
			//Store into Cache
			cache0->storeCache(address_in_s, block_s, false);
			dirty_s = false;
			rd_state = RD_IDLE;	
		}
		break;;

	default : 
		break;
	}
}

void HashCacheController::print_stats(ofstream & file)
{
	//Store in file
    _secbus_debug(file, NONE, cache_param.name << "\n");
	_secbus_debug(file, NONE, "- CAHE ENABLED			            = " <<cache_param.enable<< "\n");
	_secbus_debug(file, NONE, "- ASSOCIATIVITY			            = " <<cache_param.associativity<< "\n");
	_secbus_debug(file, NONE, "- SET NUMBER			            = " <<cache_param.set_number<< "\n");
	_secbus_debug(file, NONE, "- BLOCK SIZE			            = " <<cache_param.block_size<< "\n");
	_secbus_debug(file, NONE, "- WRITE POLICY			            = ");
	if (cache_param.write_policy == WRITE_BACK)	_secbus_debug(file, NONE, "WRITE-BACK"<<"\n");
	else 	_secbus_debug(file, NONE, "WRITE-THROUGH"<<"\n");
		_secbus_debug(file, NONE, "- REPLACEMENT POLICY		        = ");
	if (cache_param.replacement_policy == LRU) 	_secbus_debug(file, NONE, "LRU"<<"\n");
	else 	_secbus_debug(file, NONE, "FIFO"<<"\n");
	_secbus_debug(file, NONE, "- CACHE ACCESS NUMBER		        = " <<read_accesses + write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE WRITE ACCESS NUMBER	        = " <<write_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE READ ACCESS NUMBER	        = " <<read_accesses<< "\n");
	_secbus_debug(file, NONE, "- CACHE RESTORE ACCESS NUMBER		= " <<restore_accesses<<"\n");
	_secbus_debug(file, NONE, "- CACHE SYNCHRONIZE ACCESS NUMBER	= " <<synchronize_accesses<<"\n");
	_secbus_debug(file, NONE, "- CACHE MISS NUMBER			        = " <<read_misses+write_misses+restore_misses+synchronize_misses<<"\n");
	_secbus_debug(file, NONE, "- CACHE WRITE MISS NUMBER		    = " <<write_misses<<"\n");
	_secbus_debug(file, NONE, "- CACHE READ MISS NUMBER		    = " <<read_misses<<"\n");
	_secbus_debug(file, NONE, "- CACHE RESTORE MISS NUMBER		    = " <<restore_misses<<"\n");
	_secbus_debug(file, NONE, "- CACHE SYNCHRONIZE MISS NUMBER     = " <<synchronize_misses<<"\n");
	_secbus_debug(file, NONE, "- CACHE MISS RATE		        	= " <<(float)(read_misses+write_misses+restore_misses+synchronize_misses)/(read_accesses+write_accesses+restore_accesses+synchronize_accesses)<<"\n");
	_secbus_debug(file, NONE, "- CACHE READ MISS RATE		    	= " <<(float)read_misses/read_accesses<<"\n");
	_secbus_debug(file, NONE, "- CACHE WRITE MISS RATE		    	= " <<(float)write_misses/write_accesses<<"\n");
	_secbus_debug(file, NONE, "- CACHE RESTORE MISS RATE	    	= " <<(float)restore_misses/restore_accesses<<"\n");
    _secbus_debug(file, NONE, "- CACHE SYNCHORONIZE MISS RATE		= " <<(float)synchronize_misses/synchronize_accesses<<"\n");
}
void HashCacheController::reset_stats()
{
        invalidate_accesses = 0;
		read_accesses = 0;
		write_accesses = 0;
		restore_accesses = 0;
		synchronize_accesses = 0;
		read_misses = 0;
		write_misses = 0;
		restore_misses = 0;
		synchronize_misses = 0;
}
