#include "../include/Cache.h"

namespace environment {
namespace cache {
  
  // Return the time to have the data
  // latence is call on the same port in a single cycle, only the last access is save
  // { NOTE } : type_cache = 0 : icache, 1 : dcache
  uint32_t Cache::latence (cache_t               type_cache, 
			   uint32_t              num_entity, 
			   uint32_t              num_port  , 
			   uint32_t              address   , 
			   uint32_t              trdid     , 
			   type_req_cache_t      type      ,
			   direction_req_cache_t dir    )
  {
    if (num_entity >= param->nb_cache_dedicated)
      {
	std::cerr << "<Cache.latence> {ERROR} num_entity must be >= nb_cache_dedicated" << std::endl;
	exit (1);
      }

    cache_multilevel::Cache_MultiLevel * cache;
    cache_multilevel::Parameters * param_cache_dedicated;
    _cout(CACHE," * Access Cache_Dedicated_");
    if (type_cache == INSTRUCTION_CACHE)
      {
	__cout(CACHE,"Instruction");
	cache                 = icache_dedicated [num_entity];
	param_cache_dedicated = param->param_icache_dedicated [num_entity];
      }
    else
      {
	__cout(CACHE,"Data");
	cache                 = dcache_dedicated [num_entity];
	param_cache_dedicated = param->param_dcache_dedicated [num_entity];
      }
    __cout(CACHE," [%d] - entity : %d, address : 0x%.x\n",num_port,num_entity,address);

    if (num_port >= cache->param->nb_port)
      {
	std::cerr << "<Cache.latence> {ERROR} num_port can be >= nb_port" << std::endl;
	exit (1);
      }

    // Make a access with this level "dedicated"
    cache_multilevel::Access access_dedicated = cache->access(num_port,address,trdid,type,dir);

    if (access_dedicated.hit == MISS)
      {
	_cout(CACHE," * Access Cache_shared\n");

	// Make a access with this level "shared"
	cache_multilevel::Access access_shared  = cache_shared->access(range_port (type_cache,num_entity)+num_port,address,trdid,type,dir);
	
	cache_shared->update_access (access_shared);
	
	access_dedicated.last_nb_level = param_cache_dedicated->nb_level; // Update all cache
	access_dedicated.latence += access_shared.latence;
      }

    cache->update_access (access_dedicated);

    _cout(CACHE,"Access latence : %d\n",access_dedicated.latence);
    return access_dedicated.latence;
  }

};
};
