#include "../include/Cache_OneLevel.h"

namespace environment {
namespace cache {
namespace cache_onelevel {

  type_rsp_cache_t Cache_OneLevel::access_cached (uint32_t num_port, uint32_t address, uint32_t trdid, direction_req_cache_t dir)
  {
    Address  address_translate  = translate_address(address);
    uint32_t num_associativity  = hit_cache        (trdid, address_translate);
    uint32_t num_access_port    = hit_access_port  (trdid, address_translate);
    uint32_t num_write_buffer   = hit_write_buffer (trdid, address_translate);
    
    if (num_access_port == param->nb_port)
      num_access_port = num_port;
    
    uint32_t         latence            ;
    type_rsp_cache_t res                = MISS;
    
    bool             is_in_cache        = (num_associativity != param->associativity);
    bool             is_in_access_port  = (num_access_port != num_port);
    bool             is_in_write_buffer = false;
    
    if (is_in_access_port == true)
      {
	res     = HIT_BYPASS;
	latence = access_port[num_access_port].latence; //already compute
      }
    else
      if (is_in_cache == true)
	{	
	  res     = HIT_CACHE;
	  latence = 0; // Hit !!!
	}
      else
	{

	  // Search in the write buffer, and test if have a miss
	  if ( num_write_buffer == write_buffer->nb_slot_use())
	    {
	      res     = MISS;
	      latence = param->miss_penality; // miss -> access at down of cache,  + respons at the up of cache
	    }
	  else
	    {
	      res                = HIT_WRITE_BUFFER;
	      is_in_write_buffer = true;
	      latence            = write_buffer->read(num_write_buffer)._delay;
	    }
	}
    
    // access_port valid = there are a new request to update
    //  -> no previous request in the same     cycle (hit in a access port)
    //  -> no previous request in the previous cycle (hit in the write buffer)
    
    access_port[num_port].valid             = ((is_in_access_port || is_in_write_buffer) == false);
    access_port[num_port].address           = address_translate;
    access_port[num_port].trdid             = trdid;
    access_port[num_port].hit               = res;
    access_port[num_port].num_associativity = num_associativity;
    access_port[num_port].latence           = latence;
    
    return res;
  }

};
};
};
