CacheMemory.hh revision 6285
12497SN/A/*
212780Snikos.nikoleris@arm.com * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
38711SN/A * All rights reserved.
48711SN/A *
58711SN/A * Redistribution and use in source and binary forms, with or without
68711SN/A * modification, are permitted provided that the following conditions are
78711SN/A * met: redistributions of source code must retain the above copyright
88711SN/A * notice, this list of conditions and the following disclaimer;
98711SN/A * redistributions in binary form must reproduce the above copyright
108711SN/A * notice, this list of conditions and the following disclaimer in the
118711SN/A * documentation and/or other materials provided with the distribution;
128711SN/A * neither the name of the copyright holders nor the names of its
138711SN/A * contributors may be used to endorse or promote products derived from
142497SN/A * this software without specific prior written permission.
152497SN/A *
162497SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172497SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182497SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192497SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202497SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212497SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222497SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232497SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242497SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252497SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262497SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272497SN/A */
282497SN/A
292497SN/A/*
302497SN/A * CacheMemory.hh
312497SN/A *
322497SN/A * Description:
332497SN/A *
342497SN/A * $Id: CacheMemory.hh,v 3.7 2004/06/18 20:15:15 beckmann Exp $
352497SN/A *
362497SN/A */
372497SN/A
382497SN/A#ifndef CACHEMEMORY_H
392665SN/A#define CACHEMEMORY_H
402665SN/A
418715SN/A#include "mem/ruby/common/Global.hh"
428922SN/A#include "mem/protocol/AccessPermission.hh"
4312351Snikos.nikoleris@arm.com#include "mem/ruby/common/Address.hh"
442497SN/A#include "mem/ruby/recorder/CacheRecorder.hh"
452497SN/A#include "mem/protocol/CacheRequestType.hh"
462497SN/A#include "mem/gems_common/Vector.hh"
472982SN/A#include "mem/ruby/common/DataBlock.hh"
4810405Sandreas.hansson@arm.com#include "mem/protocol/MachineType.hh"
492497SN/A#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
502497SN/A#include "mem/ruby/system/PseudoLRUPolicy.hh"
5111793Sbrandon.potter@amd.com#include "mem/ruby/system/LRUPolicy.hh"
5211793Sbrandon.potter@amd.com#include "mem/ruby/slicc_interface/AbstractCacheEntry.hh"
5312334Sgabeblack@google.com#include "mem/ruby/system/System.hh"
542548SN/A#include "mem/ruby/slicc_interface/AbstractController.hh"
5510405Sandreas.hansson@arm.com#include <vector>
5610405Sandreas.hansson@arm.com
579524SN/Aclass CacheMemory {
582497SN/Apublic:
5910405Sandreas.hansson@arm.com
6010719SMarco.Balboni@ARM.com  // Constructors
6111334Sandreas.hansson@arm.com  CacheMemory(const string & name);
6212341Snikos.nikoleris@arm.com  void init(const vector<string> & argv);
6312341Snikos.nikoleris@arm.com
647523SN/A  // Destructor
658851SN/A  ~CacheMemory();
668948SN/A
678948SN/A  // factory
688851SN/A  //  static CacheMemory* createCache(int level, int num, char split_type, AbstractCacheEntry* (*entry_factory)());
699095SN/A  //  static CacheMemory* getCache(int cache_id);
7010405Sandreas.hansson@arm.com
718922SN/A  // Public Methods
729715SN/A  void printConfig(ostream& out);
739715SN/A
7413808Sgabeblack@google.com  // perform a cache access and see if we hit or not.  Return true on a hit.
7513808Sgabeblack@google.com  bool tryCacheAccess(const Address& address, CacheRequestType type, DataBlock*& data_ptr);
768851SN/A
778851SN/A  // similar to above, but doesn't require full access check
788948SN/A  bool testCacheAccess(const Address& address, CacheRequestType type, DataBlock*& data_ptr);
798948SN/A
808915SN/A  // tests to see if an address is present in the cache
819031SN/A  bool isTagPresent(const Address& address) const;
829095SN/A
8310405Sandreas.hansson@arm.com  // Returns true if there is:
8413808Sgabeblack@google.com  //   a) a tag match on this address or there is
858922SN/A  //   b) an unused line in the same cache "way"
869715SN/A  bool cacheAvail(const Address& address) const;
8713808Sgabeblack@google.com
8810713Sandreas.hansson@arm.com  // find an unused entry and sets the tag appropriate for the address
8910713Sandreas.hansson@arm.com  void allocate(const Address& address, AbstractCacheEntry* new_entry);
9010713Sandreas.hansson@arm.com
918915SN/A  // Explicitly free up this address
928915SN/A  void deallocate(const Address& address);
938948SN/A
948851SN/A  // Returns with the physical address of the conflicting cache line
959095SN/A  Address cacheProbe(const Address& address) const;
9610888Sandreas.hansson@arm.com
978922SN/A  // looks an address up in the cache
989715SN/A  AbstractCacheEntry& lookup(const Address& address);
999715SN/A  const AbstractCacheEntry& lookup(const Address& address) const;
1009716SN/A
1018851SN/A  // Get/Set permission of cache block
1027523SN/A  AccessPermission getPermission(const Address& address) const;
1037523SN/A  void changePermission(const Address& address, AccessPermission new_perm);
10410405Sandreas.hansson@arm.com
1059715SN/A  int getLatency() const { return m_latency; }
10610405Sandreas.hansson@arm.com
10710405Sandreas.hansson@arm.com  // Hook for checkpointing the contents of the cache
10810405Sandreas.hansson@arm.com  void recordCacheContents(CacheRecorder& tr) const;
10910405Sandreas.hansson@arm.com  void setAsInstructionCache(bool is_icache) { m_is_instruction_only_cache = is_icache; }
11010405Sandreas.hansson@arm.com
11110405Sandreas.hansson@arm.com  // Set this address to most recently used
11210405Sandreas.hansson@arm.com  void setMRU(const Address& address);
11310405Sandreas.hansson@arm.com
1149715SN/A  void getMemoryValue(const Address& addr, char* value,
1159715SN/A                      unsigned int size_in_bytes );
1162568SN/A  void setMemoryValue(const Address& addr, char* value,
11710405Sandreas.hansson@arm.com                      unsigned int size_in_bytes );
1182568SN/A
11910405Sandreas.hansson@arm.com  // Print cache contents
1209278SN/A  void print(ostream& out) const;
1218948SN/A  void printData(ostream& out) const;
1228948SN/A
12310405Sandreas.hansson@arm.comprivate:
1249088SN/A  // Private Methods
12510405Sandreas.hansson@arm.com
12610405Sandreas.hansson@arm.com  // convert a Address to its location in the cache
12710405Sandreas.hansson@arm.com  Index addressToCacheSet(const Address& address) const;
12810405Sandreas.hansson@arm.com
1298711SN/A  // Given a cache tag: returns the index of the tag in a set.
1308711SN/A  // returns -1 if the tag is not found.
1312568SN/A  int findTagInSet(Index line, const Address& tag) const;
1329036SN/A  int findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const;
13310405Sandreas.hansson@arm.com
13411133Sandreas.hansson@arm.com  // Private copy constructor and assignment operator
13511133Sandreas.hansson@arm.com  CacheMemory(const CacheMemory& obj);
13611133Sandreas.hansson@arm.com  CacheMemory& operator=(const CacheMemory& obj);
13711133Sandreas.hansson@arm.com
13811133Sandreas.hansson@arm.comprivate:
1393244SN/A  const string m_cache_name;
1403244SN/A  AbstractController* m_controller;
1418948SN/A  int m_latency;
14210405Sandreas.hansson@arm.com
1433244SN/A  // Data Members (m_prefix)
1448975SN/A  bool m_is_instruction_only_cache;
1459032SN/A  bool m_is_data_only_cache;
1463244SN/A
1479091SN/A  // The first index is the # of cache lines.
1489091SN/A  // The second index is the the amount associativity.
14911284Sandreas.hansson@arm.com  Vector<Vector<AbstractCacheEntry*> > m_cache;
15010656Sandreas.hansson@arm.com
15111284Sandreas.hansson@arm.com  AbstractReplacementPolicy *m_replacementPolicy_ptr;
15211284Sandreas.hansson@arm.com
1539091SN/A  int m_cache_num_sets;
15412780Snikos.nikoleris@arm.com  int m_cache_num_set_bits;
15513856Sodanrc@yahoo.com.br  int m_cache_assoc;
1569612SN/A
15710405Sandreas.hansson@arm.com  static Vector< CacheMemory* > m_all_caches;
1589033SN/A};
1599715SN/A/*
16011744Snikos.nikoleris@arm.cominline
16111744Snikos.nikoleris@arm.comCacheMemory* CacheMemory::getCache(int cache_id)
1623244SN/A{
1633244SN/A  assert(cache_id < RubyConfig::getNumberOfCaches());
1643244SN/A  if (m_all_caches[cache_id] == NULL) {
16511744Snikos.nikoleris@arm.com    cerr << "ERROR: Tried to obtain CacheMemory that hasn't been created yet." << endl;
16611744Snikos.nikoleris@arm.com    assert(0);
1675197SN/A  }
1689712SN/A  return m_all_caches[cache_id];
1699712SN/A}
1709712SN/A
1719712SN/Ainline
1729712SN/ACacheMemory* CacheMemory::createCache(int level, int num, char split_type_c, AbstractCacheEntry* (*entry_factory)())
17310719SMarco.Balboni@ARM.com{
17410719SMarco.Balboni@ARM.com  string split_type;
17510719SMarco.Balboni@ARM.com  switch(split_type_c) {
17610719SMarco.Balboni@ARM.com  case 'i':
17710719SMarco.Balboni@ARM.com    split_type = "instruction"; break;
17810719SMarco.Balboni@ARM.com  case 'd':
17910719SMarco.Balboni@ARM.com    split_type = "data"; break;
18010719SMarco.Balboni@ARM.com  default:
18110719SMarco.Balboni@ARM.com    split_type = "unified"; break;
18210719SMarco.Balboni@ARM.com  }
18310719SMarco.Balboni@ARM.com  int cache_id = RubyConfig::getCacheIDFromParams(level, num, split_type);
1844912SN/A  assert(cache_id < RubyConfig::getNumberOfCaches());
18512346Snikos.nikoleris@arm.com  if (m_all_caches.size() == 0) {
18612346Snikos.nikoleris@arm.com    m_all_caches.setSize(RubyConfig::getNumberOfCaches());
18712346Snikos.nikoleris@arm.com    for (int i=0; i<m_all_caches.size(); i++)
18812346Snikos.nikoleris@arm.com      m_all_caches[i] = NULL;
18912346Snikos.nikoleris@arm.com  }
19012346Snikos.nikoleris@arm.com
19112345Snikos.nikoleris@arm.com  string type = RubyConfig::getCacheType(cache_id);
19212345Snikos.nikoleris@arm.com  if ( type == "SetAssociativeCache" ) {
19312345Snikos.nikoleris@arm.com    m_all_caches[cache_id] = new CacheMemory(cache_id, entry_factory);
19411127Sandreas.hansson@arm.com  }
19511127Sandreas.hansson@arm.com  return m_all_caches[cache_id];
19612351Snikos.nikoleris@arm.com}
19712351Snikos.nikoleris@arm.com*/
19812351Snikos.nikoleris@arm.com// Output operator declaration
19912351Snikos.nikoleris@arm.com//ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj);
20012351Snikos.nikoleris@arm.com
20112351Snikos.nikoleris@arm.com// ******************* Definitions *******************
20212351Snikos.nikoleris@arm.com
20312351Snikos.nikoleris@arm.com// Output operator definition
20412351Snikos.nikoleris@arm.cominline
20512351Snikos.nikoleris@arm.comostream& operator<<(ostream& out, const CacheMemory& obj)
20612351Snikos.nikoleris@arm.com{
20712351Snikos.nikoleris@arm.com  obj.print(out);
20812351Snikos.nikoleris@arm.com  out << flush;
20912351Snikos.nikoleris@arm.com  return out;
21012351Snikos.nikoleris@arm.com}
21112351Snikos.nikoleris@arm.com
2128979SN/A
2138979SN/A// ****************************************************************
21410402SN/A
21510402SN/Ainline
21610402SN/ACacheMemory::CacheMemory(const string & name)
21711126Sandreas.hansson@arm.com  : m_cache_name(name)
21811126Sandreas.hansson@arm.com{
21911126Sandreas.hansson@arm.com}
22010719SMarco.Balboni@ARM.com
22111744Snikos.nikoleris@arm.cominline
22211744Snikos.nikoleris@arm.comvoid CacheMemory::init(const vector<string> & argv)
22311744Snikos.nikoleris@arm.com{
22411196Sali.jafri@arm.com  int cache_size = 0;
22511199Sandreas.hansson@arm.com  string policy;
22611196Sali.jafri@arm.com
22711196Sali.jafri@arm.com  m_controller = NULL;
22811196Sali.jafri@arm.com  for (uint32 i=0; i<argv.size(); i+=2) {
22911196Sali.jafri@arm.com    if (argv[i] == "size_kb") {
23011196Sali.jafri@arm.com      cache_size = atoi(argv[i+1].c_str());
23111196Sali.jafri@arm.com    } else if (argv[i] == "latency") {
23211196Sali.jafri@arm.com      m_latency = atoi(argv[i+1].c_str());
23311196Sali.jafri@arm.com    } else if (argv[i] == "assoc") {
23411196Sali.jafri@arm.com      m_cache_assoc = atoi(argv[i+1].c_str());
23511196Sali.jafri@arm.com    } else if (argv[i] == "replacement_policy") {
23610402SN/A      policy = argv[i+1];
23710402SN/A    } else if (argv[i] == "controller") {
23810402SN/A      m_controller = RubySystem::getController(argv[i+1]);
23911127Sandreas.hansson@arm.com    } else {
24011127Sandreas.hansson@arm.com      cerr << "WARNING: CacheMemory: Unknown configuration parameter: " << argv[i] << endl;
24111127Sandreas.hansson@arm.com    }
24211127Sandreas.hansson@arm.com  }
2438979SN/A
2448948SN/A  m_cache_num_sets = cache_size / m_cache_assoc;
24511334Sandreas.hansson@arm.com  m_cache_num_set_bits = log_int(m_cache_num_sets);
24611334Sandreas.hansson@arm.com
24710883Sali.jafri@arm.com  if(policy == "PSEUDO_LRU")
24811284Sandreas.hansson@arm.com    m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc);
24911284Sandreas.hansson@arm.com  else if (policy == "LRU")
25011284Sandreas.hansson@arm.com    m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc);
25111284Sandreas.hansson@arm.com  else
25211334Sandreas.hansson@arm.com    assert(false);
2538915SN/A
25411334Sandreas.hansson@arm.com  m_cache.setSize(m_cache_num_sets);
25511334Sandreas.hansson@arm.com  for (int i = 0; i < m_cache_num_sets; i++) {
25611334Sandreas.hansson@arm.com    m_cache[i].setSize(m_cache_assoc);
25711334Sandreas.hansson@arm.com    for (int j = 0; j < m_cache_assoc; j++) {
25811544Snikos.nikoleris@arm.com      m_cache[i][j] = NULL;
25911544Snikos.nikoleris@arm.com    }
26011544Snikos.nikoleris@arm.com  }
26111334Sandreas.hansson@arm.com}
26211744Snikos.nikoleris@arm.com/*
26311744Snikos.nikoleris@arm.cominline
26411334Sandreas.hansson@arm.comCacheMemory::CacheMemory(int cache_id, AbstractCacheEntry* (*entry_factory)())
26511334Sandreas.hansson@arm.com{
26611334Sandreas.hansson@arm.com  string split_type;
26712346Snikos.nikoleris@arm.com
26811334Sandreas.hansson@arm.com  m_cache_id = cache_id;
26911334Sandreas.hansson@arm.com  m_entry_factory = entry_factory;
27011334Sandreas.hansson@arm.com
27111334Sandreas.hansson@arm.com  m_cache_num_set_bits = RubyConfig::getNumberOfCacheSetBits(cache_id);
27211334Sandreas.hansson@arm.com  m_cache_num_sets = RubyConfig::getNumberOfCacheSets(cache_id);
27311334Sandreas.hansson@arm.com  m_cache_assoc = RubyConfig::getCacheAssoc(cache_id);
27411334Sandreas.hansson@arm.com  split_type = RubyConfig::getCacheSplitType(cache_id);
27511334Sandreas.hansson@arm.com  m_is_instruction_only_cache = m_is_data_only_cache = false;
27611334Sandreas.hansson@arm.com  if (split_type == "instruction")
27712346Snikos.nikoleris@arm.com    m_is_instruction_only_cache = true;
27812346Snikos.nikoleris@arm.com  else if (split_type == "data")
27912346Snikos.nikoleris@arm.com    m_is_data_only_cache = true;
28012346Snikos.nikoleris@arm.com  else
28112346Snikos.nikoleris@arm.com    assert(split_type == "unified");
28212346Snikos.nikoleris@arm.com
28312346Snikos.nikoleris@arm.com  if(RubyConfig::getCacheReplacementPolicy(cache_id) == "PSEUDO_LRU")
28411334Sandreas.hansson@arm.com    m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc);
28511334Sandreas.hansson@arm.com  else if(RubyConfig::getCacheReplacementPolicy(cache_id) == "LRU")
28611334Sandreas.hansson@arm.com    m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc);
28711334Sandreas.hansson@arm.com  else
28811334Sandreas.hansson@arm.com    assert(false);
28911334Sandreas.hansson@arm.com
29011334Sandreas.hansson@arm.com  m_cache.setSize(m_cache_num_sets);
29111334Sandreas.hansson@arm.com  for (int i = 0; i < m_cache_num_sets; i++) {
29211334Sandreas.hansson@arm.com    m_cache[i].setSize(m_cache_assoc);
29311334Sandreas.hansson@arm.com    for (int j = 0; j < m_cache_assoc; j++) {
29411334Sandreas.hansson@arm.com      m_cache[i][j] = m_entry_factory();
29511334Sandreas.hansson@arm.com    }
2968948SN/A  }
29712345Snikos.nikoleris@arm.com}
29810402SN/A*/
29911605Snikos.nikoleris@arm.cominline
30010402SN/ACacheMemory::~CacheMemory()
30110402SN/A{
30210656Sandreas.hansson@arm.com  if(m_replacementPolicy_ptr != NULL)
30310656Sandreas.hansson@arm.com    delete m_replacementPolicy_ptr;
30411284Sandreas.hansson@arm.com}
30510656Sandreas.hansson@arm.com
30610656Sandreas.hansson@arm.cominline
30710719SMarco.Balboni@ARM.comvoid CacheMemory::printConfig(ostream& out)
30810719SMarco.Balboni@ARM.com{
30910656Sandreas.hansson@arm.com  out << "Cache config: " << m_cache_name << endl;
31011744Snikos.nikoleris@arm.com  if (m_controller != NULL)
31111744Snikos.nikoleris@arm.com    out << "  controller: " << m_controller->getName() << endl;
31210656Sandreas.hansson@arm.com  out << "  cache_associativity: " << m_cache_assoc << endl;
31310656Sandreas.hansson@arm.com  out << "  num_cache_sets_bits: " << m_cache_num_set_bits << endl;
31410656Sandreas.hansson@arm.com  const int cache_num_sets = 1 << m_cache_num_set_bits;
31510719SMarco.Balboni@ARM.com  out << "  num_cache_sets: " << cache_num_sets << endl;
3169091SN/A  out << "  cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl;
31710656Sandreas.hansson@arm.com  out << "  cache_set_size_Kbytes: "
31810656Sandreas.hansson@arm.com      << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl;
31910656Sandreas.hansson@arm.com  out << "  cache_set_size_Mbytes: "
32010656Sandreas.hansson@arm.com      << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl;
32110656Sandreas.hansson@arm.com  out << "  cache_size_bytes: "
32210656Sandreas.hansson@arm.com      << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl;
32310656Sandreas.hansson@arm.com  out << "  cache_size_Kbytes: "
32410656Sandreas.hansson@arm.com      << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl;
32510656Sandreas.hansson@arm.com  out << "  cache_size_Mbytes: "
3268948SN/A      << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl;
32710656Sandreas.hansson@arm.com}
32810656Sandreas.hansson@arm.com
32910656Sandreas.hansson@arm.com// PRIVATE METHODS
33010656Sandreas.hansson@arm.com
3318948SN/A// convert a Address to its location in the cache
33210656Sandreas.hansson@arm.cominline
33310656Sandreas.hansson@arm.comIndex CacheMemory::addressToCacheSet(const Address& address) const
33410656Sandreas.hansson@arm.com{
33510656Sandreas.hansson@arm.com  assert(address == line_address(address));
3369549SN/A  Index temp = -1;
33710656Sandreas.hansson@arm.com  return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1);
33810656Sandreas.hansson@arm.com}
33910656Sandreas.hansson@arm.com
3408948SN/A// Given a cache index: returns the index of the tag in a set.
34110405Sandreas.hansson@arm.com// returns -1 if the tag is not found.
3429715SN/Ainline
3439091SN/Aint CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const
3448975SN/A{
34510656Sandreas.hansson@arm.com  assert(tag == line_address(tag));
3469712SN/A  // search the set for the tags
34710405Sandreas.hansson@arm.com  for (int i=0; i < m_cache_assoc; i++) {
3489712SN/A    if ((m_cache[cacheSet][i] != NULL) &&
34910656Sandreas.hansson@arm.com        (m_cache[cacheSet][i]->m_Address == tag) &&
35011564Sdavid.guillen@arm.com        (m_cache[cacheSet][i]->m_Permission != AccessPermission_NotPresent)) {
35110656Sandreas.hansson@arm.com      return i;
35211564Sdavid.guillen@arm.com    }
35311564Sdavid.guillen@arm.com  }
3549712SN/A  return -1; // Not found
3559712SN/A}
35611334Sandreas.hansson@arm.com
35711334Sandreas.hansson@arm.com// Given a cache index: returns the index of the tag in a set.
35811334Sandreas.hansson@arm.com// returns -1 if the tag is not found.
35911334Sandreas.hansson@arm.cominline
36012351Snikos.nikoleris@arm.comint CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const
36112351Snikos.nikoleris@arm.com{
36212351Snikos.nikoleris@arm.com  assert(tag == line_address(tag));
36312351Snikos.nikoleris@arm.com  // search the set for the tags
36412351Snikos.nikoleris@arm.com  for (int i=0; i < m_cache_assoc; i++) {
36512351Snikos.nikoleris@arm.com    if (m_cache[cacheSet][i] != NULL && m_cache[cacheSet][i]->m_Address == tag)
36612351Snikos.nikoleris@arm.com      return i;
36712351Snikos.nikoleris@arm.com  }
36812351Snikos.nikoleris@arm.com  return -1; // Not found
36912351Snikos.nikoleris@arm.com}
37012351Snikos.nikoleris@arm.com
37112351Snikos.nikoleris@arm.com// PUBLIC METHODS
37212351Snikos.nikoleris@arm.cominline
37312351Snikos.nikoleris@arm.combool CacheMemory::tryCacheAccess(const Address& address,
37412351Snikos.nikoleris@arm.com                                 CacheRequestType type,
37512351Snikos.nikoleris@arm.com                                 DataBlock*& data_ptr)
37612351Snikos.nikoleris@arm.com{
37712351Snikos.nikoleris@arm.com  assert(address == line_address(address));
37812351Snikos.nikoleris@arm.com  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
37912351Snikos.nikoleris@arm.com  Index cacheSet = addressToCacheSet(address);
38012351Snikos.nikoleris@arm.com  int loc = findTagInSet(cacheSet, address);
38112351Snikos.nikoleris@arm.com  if(loc != -1){ // Do we even have a tag match?
38212351Snikos.nikoleris@arm.com    AbstractCacheEntry* entry = m_cache[cacheSet][loc];
38312351Snikos.nikoleris@arm.com    m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
38412351Snikos.nikoleris@arm.com    data_ptr = &(entry->getDataBlk());
38512351Snikos.nikoleris@arm.com
38612351Snikos.nikoleris@arm.com    if(entry->m_Permission == AccessPermission_Read_Write) {
38712351Snikos.nikoleris@arm.com      return true;
38812351Snikos.nikoleris@arm.com    }
38912351Snikos.nikoleris@arm.com    if ((entry->m_Permission == AccessPermission_Read_Only) &&
39012351Snikos.nikoleris@arm.com        (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) {
39112351Snikos.nikoleris@arm.com      return true;
39212351Snikos.nikoleris@arm.com    }
39312351Snikos.nikoleris@arm.com    // The line must not be accessible
39412351Snikos.nikoleris@arm.com  }
39512351Snikos.nikoleris@arm.com  data_ptr = NULL;
39612351Snikos.nikoleris@arm.com  return false;
39712351Snikos.nikoleris@arm.com}
39812351Snikos.nikoleris@arm.com
39912351Snikos.nikoleris@arm.cominline
40012351Snikos.nikoleris@arm.combool CacheMemory::testCacheAccess(const Address& address,
40112351Snikos.nikoleris@arm.com                                  CacheRequestType type,
40212351Snikos.nikoleris@arm.com                                  DataBlock*& data_ptr)
40312351Snikos.nikoleris@arm.com{
40412351Snikos.nikoleris@arm.com  assert(address == line_address(address));
40512351Snikos.nikoleris@arm.com  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
40612351Snikos.nikoleris@arm.com  Index cacheSet = addressToCacheSet(address);
40712351Snikos.nikoleris@arm.com  int loc = findTagInSet(cacheSet, address);
40812351Snikos.nikoleris@arm.com  if(loc != -1){ // Do we even have a tag match?
40912351Snikos.nikoleris@arm.com    AbstractCacheEntry* entry = m_cache[cacheSet][loc];
41012351Snikos.nikoleris@arm.com    m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
41111334Sandreas.hansson@arm.com    data_ptr = &(entry->getDataBlk());
41212351Snikos.nikoleris@arm.com
41311334Sandreas.hansson@arm.com    return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent);
41411334Sandreas.hansson@arm.com  }
41512351Snikos.nikoleris@arm.com  data_ptr = NULL;
41611334Sandreas.hansson@arm.com  return false;
41711334Sandreas.hansson@arm.com}
41811334Sandreas.hansson@arm.com
41912351Snikos.nikoleris@arm.com// tests to see if an address is present in the cache
42011334Sandreas.hansson@arm.cominline
42111334Sandreas.hansson@arm.combool CacheMemory::isTagPresent(const Address& address) const
42212351Snikos.nikoleris@arm.com{
42312351Snikos.nikoleris@arm.com  assert(address == line_address(address));
42412351Snikos.nikoleris@arm.com  Index cacheSet = addressToCacheSet(address);
42512351Snikos.nikoleris@arm.com  int location = findTagInSet(cacheSet, address);
42611334Sandreas.hansson@arm.com
42712351Snikos.nikoleris@arm.com  if (location == -1) {
42811334Sandreas.hansson@arm.com    // We didn't find the tag
42912351Snikos.nikoleris@arm.com    DEBUG_EXPR(CACHE_COMP, LowPrio, address);
43011334Sandreas.hansson@arm.com    DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match");
43111334Sandreas.hansson@arm.com    return false;
4329091SN/A  }
4338975SN/A  DEBUG_EXPR(CACHE_COMP, LowPrio, address);
4348975SN/A  DEBUG_MSG(CACHE_COMP, LowPrio, "found");
4358975SN/A  return true;
43610405Sandreas.hansson@arm.com}
4378975SN/A
4388975SN/A// Returns true if there is:
4399032SN/A//   a) a tag match on this address or there is
4408975SN/A//   b) an unused line in the same cache "way"
44110656Sandreas.hansson@arm.cominline
44210656Sandreas.hansson@arm.combool CacheMemory::cacheAvail(const Address& address) const
44310656Sandreas.hansson@arm.com{
44410656Sandreas.hansson@arm.com  assert(address == line_address(address));
44510572Sandreas.hansson@arm.com
44610572Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
4479713SN/A
44810405Sandreas.hansson@arm.com  for (int i=0; i < m_cache_assoc; i++) {
44910405Sandreas.hansson@arm.com    AbstractCacheEntry* entry = m_cache[cacheSet][i];
4509715SN/A    if (entry != NULL) {
45111744Snikos.nikoleris@arm.com      if (entry->m_Address == address ||                         // Already in the cache
45211744Snikos.nikoleris@arm.com          entry->m_Permission == AccessPermission_NotPresent) {  // We found an empty entry
4538975SN/A        return true;
4548975SN/A      }
4558975SN/A    } else {
45611744Snikos.nikoleris@arm.com      return true;
45711744Snikos.nikoleris@arm.com    }
4588975SN/A  }
4599712SN/A  return false;
4609712SN/A}
4619712SN/A
4629712SN/Ainline
4639712SN/Avoid CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry)
46410719SMarco.Balboni@ARM.com{
46510719SMarco.Balboni@ARM.com  assert(address == line_address(address));
46610719SMarco.Balboni@ARM.com  assert(!isTagPresent(address));
46710719SMarco.Balboni@ARM.com  assert(cacheAvail(address));
46810719SMarco.Balboni@ARM.com  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
46910719SMarco.Balboni@ARM.com
47010719SMarco.Balboni@ARM.com  // Find the first open slot
47110719SMarco.Balboni@ARM.com  Index cacheSet = addressToCacheSet(address);
4728975SN/A  for (int i=0; i < m_cache_assoc; i++) {
47310821Sandreas.hansson@arm.com    if (m_cache[cacheSet][i] == NULL ||
47410402SN/A        m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) {
47510402SN/A      m_cache[cacheSet][i] = entry;  // Init entry
47610402SN/A      m_cache[cacheSet][i]->m_Address = address;
47710402SN/A      m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid;
47810888Sandreas.hansson@arm.com
47910888Sandreas.hansson@arm.com      m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime());
48010888Sandreas.hansson@arm.com
48110888Sandreas.hansson@arm.com      return;
48210888Sandreas.hansson@arm.com    }
4838975SN/A  }
48410656Sandreas.hansson@arm.com  ERROR_MSG("Allocate didn't find an available entry");
48510656Sandreas.hansson@arm.com}
48610656Sandreas.hansson@arm.com
4879715SN/Ainline
4888975SN/Avoid CacheMemory::deallocate(const Address& address)
4899712SN/A{
4909712SN/A  assert(address == line_address(address));
49110405Sandreas.hansson@arm.com  assert(isTagPresent(address));
4929712SN/A  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
4939712SN/A  Index cacheSet = addressToCacheSet(address);
4948975SN/A  int location = findTagInSet(cacheSet, address);
4958975SN/A  if (location != -1){
4968975SN/A    delete m_cache[cacheSet][location];
4978975SN/A    m_cache[cacheSet][location] = NULL;
49810405Sandreas.hansson@arm.com  }
4998975SN/A}
50011744Snikos.nikoleris@arm.com
50111744Snikos.nikoleris@arm.com// Returns with the physical address of the conflicting cache line
5028975SN/Ainline
5039712SN/AAddress CacheMemory::cacheProbe(const Address& address) const
50411564Sdavid.guillen@arm.com{
5059712SN/A  assert(address == line_address(address));
50610405Sandreas.hansson@arm.com  assert(!cacheAvail(address));
50711564Sdavid.guillen@arm.com
5089712SN/A  Index cacheSet = addressToCacheSet(address);
5098975SN/A  return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address;
5108975SN/A}
5118975SN/A
51211127Sandreas.hansson@arm.com// looks an address up in the cache
51311127Sandreas.hansson@arm.cominline
51411127Sandreas.hansson@arm.comAbstractCacheEntry& CacheMemory::lookup(const Address& address)
51511127Sandreas.hansson@arm.com{
51611284Sandreas.hansson@arm.com  assert(address == line_address(address));
51711284Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
51811284Sandreas.hansson@arm.com  int loc = findTagInSet(cacheSet, address);
5199032SN/A  assert(loc != -1);
52011127Sandreas.hansson@arm.com  return *m_cache[cacheSet][loc];
52111127Sandreas.hansson@arm.com}
52210402SN/A
52310402SN/A// looks an address up in the cache
52410402SN/Ainline
52511126Sandreas.hansson@arm.comconst AbstractCacheEntry& CacheMemory::lookup(const Address& address) const
52611126Sandreas.hansson@arm.com{
52711126Sandreas.hansson@arm.com  assert(address == line_address(address));
52811126Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
52911744Snikos.nikoleris@arm.com  int loc = findTagInSet(cacheSet, address);
53011744Snikos.nikoleris@arm.com  assert(loc != -1);
53111744Snikos.nikoleris@arm.com  return *m_cache[cacheSet][loc];
53210402SN/A}
53310402SN/A
53410402SN/Ainline
53510402SN/AAccessPermission CacheMemory::getPermission(const Address& address) const
53610402SN/A{
53710402SN/A  assert(address == line_address(address));
5388975SN/A  return lookup(address).m_Permission;
53911127Sandreas.hansson@arm.com}
54011127Sandreas.hansson@arm.com
54111127Sandreas.hansson@arm.cominline
54211127Sandreas.hansson@arm.comvoid CacheMemory::changePermission(const Address& address, AccessPermission new_perm)
54310656Sandreas.hansson@arm.com{
54411284Sandreas.hansson@arm.com  assert(address == line_address(address));
54510656Sandreas.hansson@arm.com  lookup(address).m_Permission = new_perm;
54610656Sandreas.hansson@arm.com  assert(getPermission(address) == new_perm);
54710656Sandreas.hansson@arm.com}
54810656Sandreas.hansson@arm.com
5498975SN/A// Sets the most recently used bit for a cache block
5508975SN/Ainline
5518975SN/Avoid CacheMemory::setMRU(const Address& address)
5528975SN/A{
5538975SN/A  Index cacheSet;
55413856Sodanrc@yahoo.com.br
5558975SN/A  cacheSet = addressToCacheSet(address);
5568975SN/A  m_replacementPolicy_ptr->touch(cacheSet,
5578975SN/A                                 findTagInSet(cacheSet, address),
55810405Sandreas.hansson@arm.com                                 g_eventQueue_ptr->getTime());
5598975SN/A}
5608975SN/A
5619032SN/Ainline
5628975SN/Avoid CacheMemory::recordCacheContents(CacheRecorder& tr) const
56310656Sandreas.hansson@arm.com{
56410656Sandreas.hansson@arm.com  for (int i = 0; i < m_cache_num_sets; i++) {
56510656Sandreas.hansson@arm.com    for (int j = 0; j < m_cache_assoc; j++) {
56610656Sandreas.hansson@arm.com      AccessPermission perm = m_cache[i][j]->m_Permission;
56710572Sandreas.hansson@arm.com      CacheRequestType request_type = CacheRequestType_NULL;
5689714SN/A      if (perm == AccessPermission_Read_Only) {
5699714SN/A        if (m_is_instruction_only_cache) {
5709714SN/A          request_type = CacheRequestType_IFETCH;
57110656Sandreas.hansson@arm.com        } else {
5729714SN/A          request_type = CacheRequestType_LD;
57310656Sandreas.hansson@arm.com        }
57410656Sandreas.hansson@arm.com      } else if (perm == AccessPermission_Read_Write) {
5759714SN/A        request_type = CacheRequestType_ST;
57610405Sandreas.hansson@arm.com      }
57710405Sandreas.hansson@arm.com
57810405Sandreas.hansson@arm.com      if (request_type != CacheRequestType_NULL) {
57910405Sandreas.hansson@arm.com        //        tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address,
5809715SN/A        //                     Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j));
58110572Sandreas.hansson@arm.com      }
5829715SN/A    }
58311744Snikos.nikoleris@arm.com  }
58411744Snikos.nikoleris@arm.com}
5859715SN/A
5869715SN/Ainline
5879716SN/Avoid CacheMemory::print(ostream& out) const
5889716SN/A{
5899716SN/A  out << "Cache dump: " << m_cache_name << endl;
59010572Sandreas.hansson@arm.com  for (int i = 0; i < m_cache_num_sets; i++) {
5919716SN/A    for (int j = 0; j < m_cache_assoc; j++) {
59211744Snikos.nikoleris@arm.com      if (m_cache[i][j] != NULL) {
59311744Snikos.nikoleris@arm.com        out << "  Index: " << i
5949716SN/A            << " way: " << j
5959716SN/A            << " entry: " << *m_cache[i][j] << endl;
5968975SN/A      } else {
5978975SN/A        out << "  Index: " << i
59811744Snikos.nikoleris@arm.com            << " way: " << j
59911744Snikos.nikoleris@arm.com            << " entry: NULL" << endl;
6008975SN/A      }
6019712SN/A    }
6029712SN/A  }
6039712SN/A}
6049712SN/A
6059712SN/Ainline
6068975SN/Avoid CacheMemory::printData(ostream& out) const
6078975SN/A{
6088975SN/A  out << "printData() not supported" << endl;
60910719SMarco.Balboni@ARM.com}
61010719SMarco.Balboni@ARM.com
61110719SMarco.Balboni@ARM.cominline
61210719SMarco.Balboni@ARM.comvoid CacheMemory::getMemoryValue(const Address& addr, char* value,
61310719SMarco.Balboni@ARM.com                                 unsigned int size_in_bytes ){
61410719SMarco.Balboni@ARM.com  AbstractCacheEntry& entry = lookup(line_address(addr));
61510719SMarco.Balboni@ARM.com  unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
61610719SMarco.Balboni@ARM.com  for(unsigned int i=0; i<size_in_bytes; ++i){
61710719SMarco.Balboni@ARM.com    value[i] = entry.getDataBlk().getByte(i + startByte);
61810719SMarco.Balboni@ARM.com  }
61910719SMarco.Balboni@ARM.com}
6208975SN/A
6219714SN/Ainline
6229714SN/Avoid CacheMemory::setMemoryValue(const Address& addr, char* value,
6239714SN/A                                 unsigned int size_in_bytes ){
6249714SN/A  AbstractCacheEntry& entry = lookup(line_address(addr));
6259714SN/A  unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
62610402SN/A  assert(size_in_bytes > 0);
62710402SN/A  for(unsigned int i=0; i<size_in_bytes; ++i){
62810402SN/A    entry.getDataBlk().setByte(i + startByte, value[i]);
62910402SN/A  }
63010402SN/A
63110402SN/A  //  entry = lookup(line_address(addr));
63210402SN/A}
6339712SN/A
6349712SN/A#endif //CACHEMEMORY_H
6359712SN/A
63610405Sandreas.hansson@arm.com