CacheMemory.hh revision 6285
12810Srdreslin@umich.edu/*
211051Sandreas.hansson@arm.com * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
311051Sandreas.hansson@arm.com * All rights reserved.
411051Sandreas.hansson@arm.com *
511051Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
611051Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
711051Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
811051Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
911051Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
1011051Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
1111051Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
1211051Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
1311051Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
1411051Sandreas.hansson@arm.com * this software without specific prior written permission.
1511051Sandreas.hansson@arm.com *
162810Srdreslin@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172810Srdreslin@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182810Srdreslin@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192810Srdreslin@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202810Srdreslin@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212810Srdreslin@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222810Srdreslin@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232810Srdreslin@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242810Srdreslin@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252810Srdreslin@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262810Srdreslin@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272810Srdreslin@umich.edu */
282810Srdreslin@umich.edu
292810Srdreslin@umich.edu/*
302810Srdreslin@umich.edu * CacheMemory.hh
312810Srdreslin@umich.edu *
322810Srdreslin@umich.edu * Description:
332810Srdreslin@umich.edu *
342810Srdreslin@umich.edu * $Id: CacheMemory.hh,v 3.7 2004/06/18 20:15:15 beckmann Exp $
352810Srdreslin@umich.edu *
362810Srdreslin@umich.edu */
372810Srdreslin@umich.edu
382810Srdreslin@umich.edu#ifndef CACHEMEMORY_H
392810Srdreslin@umich.edu#define CACHEMEMORY_H
402810Srdreslin@umich.edu
412810Srdreslin@umich.edu#include "mem/ruby/common/Global.hh"
4211051Sandreas.hansson@arm.com#include "mem/protocol/AccessPermission.hh"
4311051Sandreas.hansson@arm.com#include "mem/ruby/common/Address.hh"
442810Srdreslin@umich.edu#include "mem/ruby/recorder/CacheRecorder.hh"
4511051Sandreas.hansson@arm.com#include "mem/protocol/CacheRequestType.hh"
4611051Sandreas.hansson@arm.com#include "mem/gems_common/Vector.hh"
472810Srdreslin@umich.edu#include "mem/ruby/common/DataBlock.hh"
482810Srdreslin@umich.edu#include "mem/protocol/MachineType.hh"
492810Srdreslin@umich.edu#include "mem/ruby/slicc_interface/RubySlicc_ComponentMapping.hh"
502810Srdreslin@umich.edu#include "mem/ruby/system/PseudoLRUPolicy.hh"
5111051Sandreas.hansson@arm.com#include "mem/ruby/system/LRUPolicy.hh"
522810Srdreslin@umich.edu#include "mem/ruby/slicc_interface/AbstractCacheEntry.hh"
532810Srdreslin@umich.edu#include "mem/ruby/system/System.hh"
5411051Sandreas.hansson@arm.com#include "mem/ruby/slicc_interface/AbstractController.hh"
552810Srdreslin@umich.edu#include <vector>
5611051Sandreas.hansson@arm.com
5711051Sandreas.hansson@arm.comclass CacheMemory {
5811051Sandreas.hansson@arm.compublic:
5911051Sandreas.hansson@arm.com
6011051Sandreas.hansson@arm.com  // Constructors
6111288Ssteve.reinhardt@amd.com  CacheMemory(const string & name);
6211051Sandreas.hansson@arm.com  void init(const vector<string> & argv);
6311051Sandreas.hansson@arm.com
6411051Sandreas.hansson@arm.com  // Destructor
6511051Sandreas.hansson@arm.com  ~CacheMemory();
6611051Sandreas.hansson@arm.com
6711053Sandreas.hansson@arm.com  // factory
6811053Sandreas.hansson@arm.com  //  static CacheMemory* createCache(int level, int num, char split_type, AbstractCacheEntry* (*entry_factory)());
6911051Sandreas.hansson@arm.com  //  static CacheMemory* getCache(int cache_id);
7011051Sandreas.hansson@arm.com
7111051Sandreas.hansson@arm.com  // Public Methods
7211197Sandreas.hansson@arm.com  void printConfig(ostream& out);
7311197Sandreas.hansson@arm.com
7411199Sandreas.hansson@arm.com  // perform a cache access and see if we hit or not.  Return true on a hit.
7511197Sandreas.hansson@arm.com  bool tryCacheAccess(const Address& address, CacheRequestType type, DataBlock*& data_ptr);
7611197Sandreas.hansson@arm.com
7711197Sandreas.hansson@arm.com  // similar to above, but doesn't require full access check
7811051Sandreas.hansson@arm.com  bool testCacheAccess(const Address& address, CacheRequestType type, DataBlock*& data_ptr);
7911051Sandreas.hansson@arm.com
8011051Sandreas.hansson@arm.com  // tests to see if an address is present in the cache
8111051Sandreas.hansson@arm.com  bool isTagPresent(const Address& address) const;
8211051Sandreas.hansson@arm.com
8311051Sandreas.hansson@arm.com  // Returns true if there is:
8411051Sandreas.hansson@arm.com  //   a) a tag match on this address or there is
8511051Sandreas.hansson@arm.com  //   b) an unused line in the same cache "way"
8611051Sandreas.hansson@arm.com  bool cacheAvail(const Address& address) const;
8711051Sandreas.hansson@arm.com
8811051Sandreas.hansson@arm.com  // find an unused entry and sets the tag appropriate for the address
8911051Sandreas.hansson@arm.com  void allocate(const Address& address, AbstractCacheEntry* new_entry);
9011051Sandreas.hansson@arm.com
9111051Sandreas.hansson@arm.com  // Explicitly free up this address
9211051Sandreas.hansson@arm.com  void deallocate(const Address& address);
9311051Sandreas.hansson@arm.com
9411051Sandreas.hansson@arm.com  // Returns with the physical address of the conflicting cache line
9511051Sandreas.hansson@arm.com  Address cacheProbe(const Address& address) const;
9611051Sandreas.hansson@arm.com
9711051Sandreas.hansson@arm.com  // looks an address up in the cache
9811051Sandreas.hansson@arm.com  AbstractCacheEntry& lookup(const Address& address);
9911051Sandreas.hansson@arm.com  const AbstractCacheEntry& lookup(const Address& address) const;
10011051Sandreas.hansson@arm.com
10111051Sandreas.hansson@arm.com  // Get/Set permission of cache block
10211051Sandreas.hansson@arm.com  AccessPermission getPermission(const Address& address) const;
10311051Sandreas.hansson@arm.com  void changePermission(const Address& address, AccessPermission new_perm);
10411051Sandreas.hansson@arm.com
10511051Sandreas.hansson@arm.com  int getLatency() const { return m_latency; }
10611051Sandreas.hansson@arm.com
10711051Sandreas.hansson@arm.com  // Hook for checkpointing the contents of the cache
10811051Sandreas.hansson@arm.com  void recordCacheContents(CacheRecorder& tr) const;
10911051Sandreas.hansson@arm.com  void setAsInstructionCache(bool is_icache) { m_is_instruction_only_cache = is_icache; }
11011051Sandreas.hansson@arm.com
11111051Sandreas.hansson@arm.com  // Set this address to most recently used
11211051Sandreas.hansson@arm.com  void setMRU(const Address& address);
11311051Sandreas.hansson@arm.com
11411051Sandreas.hansson@arm.com  void getMemoryValue(const Address& addr, char* value,
11511051Sandreas.hansson@arm.com                      unsigned int size_in_bytes );
11611051Sandreas.hansson@arm.com  void setMemoryValue(const Address& addr, char* value,
11711051Sandreas.hansson@arm.com                      unsigned int size_in_bytes );
11811051Sandreas.hansson@arm.com
11911051Sandreas.hansson@arm.com  // Print cache contents
12011051Sandreas.hansson@arm.com  void print(ostream& out) const;
12111051Sandreas.hansson@arm.com  void printData(ostream& out) const;
12211051Sandreas.hansson@arm.com
12311051Sandreas.hansson@arm.comprivate:
12411051Sandreas.hansson@arm.com  // Private Methods
12511051Sandreas.hansson@arm.com
12611051Sandreas.hansson@arm.com  // convert a Address to its location in the cache
12711051Sandreas.hansson@arm.com  Index addressToCacheSet(const Address& address) const;
12811051Sandreas.hansson@arm.com
12911051Sandreas.hansson@arm.com  // Given a cache tag: returns the index of the tag in a set.
13011051Sandreas.hansson@arm.com  // returns -1 if the tag is not found.
13111051Sandreas.hansson@arm.com  int findTagInSet(Index line, const Address& tag) const;
13211051Sandreas.hansson@arm.com  int findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const;
13311051Sandreas.hansson@arm.com
13411051Sandreas.hansson@arm.com  // Private copy constructor and assignment operator
13511051Sandreas.hansson@arm.com  CacheMemory(const CacheMemory& obj);
13611051Sandreas.hansson@arm.com  CacheMemory& operator=(const CacheMemory& obj);
13711051Sandreas.hansson@arm.com
13811051Sandreas.hansson@arm.comprivate:
13911051Sandreas.hansson@arm.com  const string m_cache_name;
14011051Sandreas.hansson@arm.com  AbstractController* m_controller;
14111051Sandreas.hansson@arm.com  int m_latency;
14211051Sandreas.hansson@arm.com
14311051Sandreas.hansson@arm.com  // Data Members (m_prefix)
14411051Sandreas.hansson@arm.com  bool m_is_instruction_only_cache;
14511051Sandreas.hansson@arm.com  bool m_is_data_only_cache;
14611051Sandreas.hansson@arm.com
14711051Sandreas.hansson@arm.com  // The first index is the # of cache lines.
14811051Sandreas.hansson@arm.com  // The second index is the the amount associativity.
14911051Sandreas.hansson@arm.com  Vector<Vector<AbstractCacheEntry*> > m_cache;
15011051Sandreas.hansson@arm.com
15111051Sandreas.hansson@arm.com  AbstractReplacementPolicy *m_replacementPolicy_ptr;
15211051Sandreas.hansson@arm.com
15311051Sandreas.hansson@arm.com  int m_cache_num_sets;
15411051Sandreas.hansson@arm.com  int m_cache_num_set_bits;
15511051Sandreas.hansson@arm.com  int m_cache_assoc;
15611051Sandreas.hansson@arm.com
15711051Sandreas.hansson@arm.com  static Vector< CacheMemory* > m_all_caches;
15811051Sandreas.hansson@arm.com};
15911051Sandreas.hansson@arm.com/*
16011051Sandreas.hansson@arm.cominline
16111284Sandreas.hansson@arm.comCacheMemory* CacheMemory::getCache(int cache_id)
16211051Sandreas.hansson@arm.com{
16311051Sandreas.hansson@arm.com  assert(cache_id < RubyConfig::getNumberOfCaches());
16411051Sandreas.hansson@arm.com  if (m_all_caches[cache_id] == NULL) {
16511051Sandreas.hansson@arm.com    cerr << "ERROR: Tried to obtain CacheMemory that hasn't been created yet." << endl;
16611051Sandreas.hansson@arm.com    assert(0);
16711051Sandreas.hansson@arm.com  }
16811051Sandreas.hansson@arm.com  return m_all_caches[cache_id];
16911284Sandreas.hansson@arm.com}
17011284Sandreas.hansson@arm.com
17111284Sandreas.hansson@arm.cominline
17211284Sandreas.hansson@arm.comCacheMemory* CacheMemory::createCache(int level, int num, char split_type_c, AbstractCacheEntry* (*entry_factory)())
17311051Sandreas.hansson@arm.com{
17411284Sandreas.hansson@arm.com  string split_type;
17511051Sandreas.hansson@arm.com  switch(split_type_c) {
17611051Sandreas.hansson@arm.com  case 'i':
17711051Sandreas.hansson@arm.com    split_type = "instruction"; break;
17811284Sandreas.hansson@arm.com  case 'd':
17911284Sandreas.hansson@arm.com    split_type = "data"; break;
18011284Sandreas.hansson@arm.com  default:
18111284Sandreas.hansson@arm.com    split_type = "unified"; break;
18211051Sandreas.hansson@arm.com  }
18311288Ssteve.reinhardt@amd.com  int cache_id = RubyConfig::getCacheIDFromParams(level, num, split_type);
18411288Ssteve.reinhardt@amd.com  assert(cache_id < RubyConfig::getNumberOfCaches());
18511051Sandreas.hansson@arm.com  if (m_all_caches.size() == 0) {
18611051Sandreas.hansson@arm.com    m_all_caches.setSize(RubyConfig::getNumberOfCaches());
18711051Sandreas.hansson@arm.com    for (int i=0; i<m_all_caches.size(); i++)
18811051Sandreas.hansson@arm.com      m_all_caches[i] = NULL;
18911286Sandreas.hansson@arm.com  }
19011286Sandreas.hansson@arm.com
19111286Sandreas.hansson@arm.com  string type = RubyConfig::getCacheType(cache_id);
19211051Sandreas.hansson@arm.com  if ( type == "SetAssociativeCache" ) {
19311286Sandreas.hansson@arm.com    m_all_caches[cache_id] = new CacheMemory(cache_id, entry_factory);
19411051Sandreas.hansson@arm.com  }
19511051Sandreas.hansson@arm.com  return m_all_caches[cache_id];
19611051Sandreas.hansson@arm.com}
19711051Sandreas.hansson@arm.com*/
19811051Sandreas.hansson@arm.com// Output operator declaration
19911051Sandreas.hansson@arm.com//ostream& operator<<(ostream& out, const CacheMemory<ENTRY>& obj);
20011051Sandreas.hansson@arm.com
20111051Sandreas.hansson@arm.com// ******************* Definitions *******************
20211051Sandreas.hansson@arm.com
20311051Sandreas.hansson@arm.com// Output operator definition
20411051Sandreas.hansson@arm.cominline
20511284Sandreas.hansson@arm.comostream& operator<<(ostream& out, const CacheMemory& obj)
20611051Sandreas.hansson@arm.com{
20711051Sandreas.hansson@arm.com  obj.print(out);
20811051Sandreas.hansson@arm.com  out << flush;
20911051Sandreas.hansson@arm.com  return out;
21011051Sandreas.hansson@arm.com}
21111284Sandreas.hansson@arm.com
21211051Sandreas.hansson@arm.com
21311284Sandreas.hansson@arm.com// ****************************************************************
21411051Sandreas.hansson@arm.com
21511197Sandreas.hansson@arm.cominline
21611197Sandreas.hansson@arm.comCacheMemory::CacheMemory(const string & name)
21711197Sandreas.hansson@arm.com  : m_cache_name(name)
21811197Sandreas.hansson@arm.com{
21911051Sandreas.hansson@arm.com}
22011284Sandreas.hansson@arm.com
22111051Sandreas.hansson@arm.cominline
22211284Sandreas.hansson@arm.comvoid CacheMemory::init(const vector<string> & argv)
22311284Sandreas.hansson@arm.com{
22411284Sandreas.hansson@arm.com  int cache_size = 0;
22511051Sandreas.hansson@arm.com  string policy;
22611051Sandreas.hansson@arm.com
22711051Sandreas.hansson@arm.com  m_controller = NULL;
22811284Sandreas.hansson@arm.com  for (uint32 i=0; i<argv.size(); i+=2) {
22911284Sandreas.hansson@arm.com    if (argv[i] == "size_kb") {
23011284Sandreas.hansson@arm.com      cache_size = atoi(argv[i+1].c_str());
23111284Sandreas.hansson@arm.com    } else if (argv[i] == "latency") {
23211051Sandreas.hansson@arm.com      m_latency = atoi(argv[i+1].c_str());
23311051Sandreas.hansson@arm.com    } else if (argv[i] == "assoc") {
23411051Sandreas.hansson@arm.com      m_cache_assoc = atoi(argv[i+1].c_str());
23511284Sandreas.hansson@arm.com    } else if (argv[i] == "replacement_policy") {
23611284Sandreas.hansson@arm.com      policy = argv[i+1];
23711284Sandreas.hansson@arm.com    } else if (argv[i] == "controller") {
23811197Sandreas.hansson@arm.com      m_controller = RubySystem::getController(argv[i+1]);
23911284Sandreas.hansson@arm.com    } else {
24011284Sandreas.hansson@arm.com      cerr << "WARNING: CacheMemory: Unknown configuration parameter: " << argv[i] << endl;
24111284Sandreas.hansson@arm.com    }
24211284Sandreas.hansson@arm.com  }
24311284Sandreas.hansson@arm.com
24411284Sandreas.hansson@arm.com  m_cache_num_sets = cache_size / m_cache_assoc;
24511284Sandreas.hansson@arm.com  m_cache_num_set_bits = log_int(m_cache_num_sets);
24611284Sandreas.hansson@arm.com
24711284Sandreas.hansson@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
25211284Sandreas.hansson@arm.com    assert(false);
25311284Sandreas.hansson@arm.com
25411197Sandreas.hansson@arm.com  m_cache.setSize(m_cache_num_sets);
25511284Sandreas.hansson@arm.com  for (int i = 0; i < m_cache_num_sets; i++) {
25611284Sandreas.hansson@arm.com    m_cache[i].setSize(m_cache_assoc);
25711284Sandreas.hansson@arm.com    for (int j = 0; j < m_cache_assoc; j++) {
25811284Sandreas.hansson@arm.com      m_cache[i][j] = NULL;
25911284Sandreas.hansson@arm.com    }
26011284Sandreas.hansson@arm.com  }
26111284Sandreas.hansson@arm.com}
26211197Sandreas.hansson@arm.com/*
26311051Sandreas.hansson@arm.cominline
26411051Sandreas.hansson@arm.comCacheMemory::CacheMemory(int cache_id, AbstractCacheEntry* (*entry_factory)())
26511051Sandreas.hansson@arm.com{
26611051Sandreas.hansson@arm.com  string split_type;
26711051Sandreas.hansson@arm.com
26811284Sandreas.hansson@arm.com  m_cache_id = cache_id;
26911284Sandreas.hansson@arm.com  m_entry_factory = entry_factory;
27011051Sandreas.hansson@arm.com
27111051Sandreas.hansson@arm.com  m_cache_num_set_bits = RubyConfig::getNumberOfCacheSetBits(cache_id);
27211051Sandreas.hansson@arm.com  m_cache_num_sets = RubyConfig::getNumberOfCacheSets(cache_id);
27311051Sandreas.hansson@arm.com  m_cache_assoc = RubyConfig::getCacheAssoc(cache_id);
27411284Sandreas.hansson@arm.com  split_type = RubyConfig::getCacheSplitType(cache_id);
27511051Sandreas.hansson@arm.com  m_is_instruction_only_cache = m_is_data_only_cache = false;
27611051Sandreas.hansson@arm.com  if (split_type == "instruction")
27711051Sandreas.hansson@arm.com    m_is_instruction_only_cache = true;
27811284Sandreas.hansson@arm.com  else if (split_type == "data")
27911051Sandreas.hansson@arm.com    m_is_data_only_cache = true;
28011197Sandreas.hansson@arm.com  else
28111197Sandreas.hansson@arm.com    assert(split_type == "unified");
28211197Sandreas.hansson@arm.com
28311197Sandreas.hansson@arm.com  if(RubyConfig::getCacheReplacementPolicy(cache_id) == "PSEUDO_LRU")
28411288Ssteve.reinhardt@amd.com    m_replacementPolicy_ptr = new PseudoLRUPolicy(m_cache_num_sets, m_cache_assoc);
28511051Sandreas.hansson@arm.com  else if(RubyConfig::getCacheReplacementPolicy(cache_id) == "LRU")
28611051Sandreas.hansson@arm.com    m_replacementPolicy_ptr = new LRUPolicy(m_cache_num_sets, m_cache_assoc);
28711051Sandreas.hansson@arm.com  else
28811051Sandreas.hansson@arm.com    assert(false);
28911051Sandreas.hansson@arm.com
29011051Sandreas.hansson@arm.com  m_cache.setSize(m_cache_num_sets);
29111051Sandreas.hansson@arm.com  for (int i = 0; i < m_cache_num_sets; i++) {
29211051Sandreas.hansson@arm.com    m_cache[i].setSize(m_cache_assoc);
29311051Sandreas.hansson@arm.com    for (int j = 0; j < m_cache_assoc; j++) {
29411051Sandreas.hansson@arm.com      m_cache[i][j] = m_entry_factory();
29511051Sandreas.hansson@arm.com    }
29611051Sandreas.hansson@arm.com  }
29711051Sandreas.hansson@arm.com}
29811284Sandreas.hansson@arm.com*/
29911051Sandreas.hansson@arm.cominline
30011284Sandreas.hansson@arm.comCacheMemory::~CacheMemory()
30111051Sandreas.hansson@arm.com{
30211051Sandreas.hansson@arm.com  if(m_replacementPolicy_ptr != NULL)
30311051Sandreas.hansson@arm.com    delete m_replacementPolicy_ptr;
30411051Sandreas.hansson@arm.com}
30511051Sandreas.hansson@arm.com
30611051Sandreas.hansson@arm.cominline
30711051Sandreas.hansson@arm.comvoid CacheMemory::printConfig(ostream& out)
30811051Sandreas.hansson@arm.com{
30911051Sandreas.hansson@arm.com  out << "Cache config: " << m_cache_name << endl;
31011051Sandreas.hansson@arm.com  if (m_controller != NULL)
31111051Sandreas.hansson@arm.com    out << "  controller: " << m_controller->getName() << endl;
31211051Sandreas.hansson@arm.com  out << "  cache_associativity: " << m_cache_assoc << endl;
31311051Sandreas.hansson@arm.com  out << "  num_cache_sets_bits: " << m_cache_num_set_bits << endl;
31411051Sandreas.hansson@arm.com  const int cache_num_sets = 1 << m_cache_num_set_bits;
31511051Sandreas.hansson@arm.com  out << "  num_cache_sets: " << cache_num_sets << endl;
31611051Sandreas.hansson@arm.com  out << "  cache_set_size_bytes: " << cache_num_sets * RubySystem::getBlockSizeBytes() << endl;
31711051Sandreas.hansson@arm.com  out << "  cache_set_size_Kbytes: "
31811051Sandreas.hansson@arm.com      << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<10) << endl;
31911051Sandreas.hansson@arm.com  out << "  cache_set_size_Mbytes: "
32011288Ssteve.reinhardt@amd.com      << double(cache_num_sets * RubySystem::getBlockSizeBytes()) / (1<<20) << endl;
32111051Sandreas.hansson@arm.com  out << "  cache_size_bytes: "
32211051Sandreas.hansson@arm.com      << cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc << endl;
32311051Sandreas.hansson@arm.com  out << "  cache_size_Kbytes: "
32411051Sandreas.hansson@arm.com      << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<10) << endl;
32511051Sandreas.hansson@arm.com  out << "  cache_size_Mbytes: "
32611051Sandreas.hansson@arm.com      << double(cache_num_sets * RubySystem::getBlockSizeBytes() * m_cache_assoc) / (1<<20) << endl;
32711051Sandreas.hansson@arm.com}
32811051Sandreas.hansson@arm.com
32911051Sandreas.hansson@arm.com// PRIVATE METHODS
33011051Sandreas.hansson@arm.com
33111199Sandreas.hansson@arm.com// convert a Address to its location in the cache
33211051Sandreas.hansson@arm.cominline
33311051Sandreas.hansson@arm.comIndex CacheMemory::addressToCacheSet(const Address& address) const
33411051Sandreas.hansson@arm.com{
33511051Sandreas.hansson@arm.com  assert(address == line_address(address));
33611051Sandreas.hansson@arm.com  Index temp = -1;
33711051Sandreas.hansson@arm.com  return address.bitSelect(RubySystem::getBlockSizeBits(), RubySystem::getBlockSizeBits() + m_cache_num_set_bits-1);
33811051Sandreas.hansson@arm.com}
33911051Sandreas.hansson@arm.com
34011051Sandreas.hansson@arm.com// Given a cache index: returns the index of the tag in a set.
34111051Sandreas.hansson@arm.com// returns -1 if the tag is not found.
34211051Sandreas.hansson@arm.cominline
34311051Sandreas.hansson@arm.comint CacheMemory::findTagInSet(Index cacheSet, const Address& tag) const
34411051Sandreas.hansson@arm.com{
34511051Sandreas.hansson@arm.com  assert(tag == line_address(tag));
34611051Sandreas.hansson@arm.com  // search the set for the tags
34711051Sandreas.hansson@arm.com  for (int i=0; i < m_cache_assoc; i++) {
34811051Sandreas.hansson@arm.com    if ((m_cache[cacheSet][i] != NULL) &&
34911051Sandreas.hansson@arm.com        (m_cache[cacheSet][i]->m_Address == tag) &&
35011051Sandreas.hansson@arm.com        (m_cache[cacheSet][i]->m_Permission != AccessPermission_NotPresent)) {
35111051Sandreas.hansson@arm.com      return i;
35211051Sandreas.hansson@arm.com    }
35311051Sandreas.hansson@arm.com  }
35411051Sandreas.hansson@arm.com  return -1; // Not found
35511051Sandreas.hansson@arm.com}
35611051Sandreas.hansson@arm.com
35711199Sandreas.hansson@arm.com// Given a cache index: returns the index of the tag in a set.
35811051Sandreas.hansson@arm.com// returns -1 if the tag is not found.
35911051Sandreas.hansson@arm.cominline
36011051Sandreas.hansson@arm.comint CacheMemory::findTagInSetIgnorePermissions(Index cacheSet, const Address& tag) const
36111051Sandreas.hansson@arm.com{
36211051Sandreas.hansson@arm.com  assert(tag == line_address(tag));
36311051Sandreas.hansson@arm.com  // search the set for the tags
36411051Sandreas.hansson@arm.com  for (int i=0; i < m_cache_assoc; i++) {
36511051Sandreas.hansson@arm.com    if (m_cache[cacheSet][i] != NULL && m_cache[cacheSet][i]->m_Address == tag)
36611051Sandreas.hansson@arm.com      return i;
36711051Sandreas.hansson@arm.com  }
36811051Sandreas.hansson@arm.com  return -1; // Not found
36911051Sandreas.hansson@arm.com}
37011199Sandreas.hansson@arm.com
37111199Sandreas.hansson@arm.com// PUBLIC METHODS
37211199Sandreas.hansson@arm.cominline
37311199Sandreas.hansson@arm.combool CacheMemory::tryCacheAccess(const Address& address,
37411199Sandreas.hansson@arm.com                                 CacheRequestType type,
37511199Sandreas.hansson@arm.com                                 DataBlock*& data_ptr)
37611199Sandreas.hansson@arm.com{
37711199Sandreas.hansson@arm.com  assert(address == line_address(address));
37811199Sandreas.hansson@arm.com  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
37911199Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
38011199Sandreas.hansson@arm.com  int loc = findTagInSet(cacheSet, address);
38111199Sandreas.hansson@arm.com  if(loc != -1){ // Do we even have a tag match?
38211199Sandreas.hansson@arm.com    AbstractCacheEntry* entry = m_cache[cacheSet][loc];
38311199Sandreas.hansson@arm.com    m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
38411199Sandreas.hansson@arm.com    data_ptr = &(entry->getDataBlk());
38511199Sandreas.hansson@arm.com
38611199Sandreas.hansson@arm.com    if(entry->m_Permission == AccessPermission_Read_Write) {
38711199Sandreas.hansson@arm.com      return true;
38811199Sandreas.hansson@arm.com    }
38911199Sandreas.hansson@arm.com    if ((entry->m_Permission == AccessPermission_Read_Only) &&
39011199Sandreas.hansson@arm.com        (type == CacheRequestType_LD || type == CacheRequestType_IFETCH)) {
39111199Sandreas.hansson@arm.com      return true;
39211199Sandreas.hansson@arm.com    }
39311199Sandreas.hansson@arm.com    // The line must not be accessible
39411051Sandreas.hansson@arm.com  }
39511051Sandreas.hansson@arm.com  data_ptr = NULL;
39611051Sandreas.hansson@arm.com  return false;
39711051Sandreas.hansson@arm.com}
39811051Sandreas.hansson@arm.com
39911199Sandreas.hansson@arm.cominline
40011051Sandreas.hansson@arm.combool CacheMemory::testCacheAccess(const Address& address,
40111199Sandreas.hansson@arm.com                                  CacheRequestType type,
40211199Sandreas.hansson@arm.com                                  DataBlock*& data_ptr)
40311199Sandreas.hansson@arm.com{
40411199Sandreas.hansson@arm.com  assert(address == line_address(address));
40511199Sandreas.hansson@arm.com  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
40611199Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
40711199Sandreas.hansson@arm.com  int loc = findTagInSet(cacheSet, address);
40811199Sandreas.hansson@arm.com  if(loc != -1){ // Do we even have a tag match?
40911199Sandreas.hansson@arm.com    AbstractCacheEntry* entry = m_cache[cacheSet][loc];
41011199Sandreas.hansson@arm.com    m_replacementPolicy_ptr->touch(cacheSet, loc, g_eventQueue_ptr->getTime());
41111199Sandreas.hansson@arm.com    data_ptr = &(entry->getDataBlk());
41211199Sandreas.hansson@arm.com
41311051Sandreas.hansson@arm.com    return (m_cache[cacheSet][loc]->m_Permission != AccessPermission_NotPresent);
41411051Sandreas.hansson@arm.com  }
41511051Sandreas.hansson@arm.com  data_ptr = NULL;
41611051Sandreas.hansson@arm.com  return false;
41711051Sandreas.hansson@arm.com}
41811051Sandreas.hansson@arm.com
41911051Sandreas.hansson@arm.com// tests to see if an address is present in the cache
42011051Sandreas.hansson@arm.cominline
42111051Sandreas.hansson@arm.combool CacheMemory::isTagPresent(const Address& address) const
42211051Sandreas.hansson@arm.com{
42311051Sandreas.hansson@arm.com  assert(address == line_address(address));
42411051Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
42511051Sandreas.hansson@arm.com  int location = findTagInSet(cacheSet, address);
42611051Sandreas.hansson@arm.com
42711051Sandreas.hansson@arm.com  if (location == -1) {
42811199Sandreas.hansson@arm.com    // We didn't find the tag
42911199Sandreas.hansson@arm.com    DEBUG_EXPR(CACHE_COMP, LowPrio, address);
43011199Sandreas.hansson@arm.com    DEBUG_MSG(CACHE_COMP, LowPrio, "No tag match");
43111199Sandreas.hansson@arm.com    return false;
43211199Sandreas.hansson@arm.com  }
43311284Sandreas.hansson@arm.com  DEBUG_EXPR(CACHE_COMP, LowPrio, address);
43411284Sandreas.hansson@arm.com  DEBUG_MSG(CACHE_COMP, LowPrio, "found");
43511284Sandreas.hansson@arm.com  return true;
43611284Sandreas.hansson@arm.com}
43711051Sandreas.hansson@arm.com
43811051Sandreas.hansson@arm.com// Returns true if there is:
43911051Sandreas.hansson@arm.com//   a) a tag match on this address or there is
44011051Sandreas.hansson@arm.com//   b) an unused line in the same cache "way"
44111051Sandreas.hansson@arm.cominline
44211051Sandreas.hansson@arm.combool CacheMemory::cacheAvail(const Address& address) const
44311051Sandreas.hansson@arm.com{
44411051Sandreas.hansson@arm.com  assert(address == line_address(address));
44511051Sandreas.hansson@arm.com
44611051Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
44711051Sandreas.hansson@arm.com
44811051Sandreas.hansson@arm.com  for (int i=0; i < m_cache_assoc; i++) {
44911051Sandreas.hansson@arm.com    AbstractCacheEntry* entry = m_cache[cacheSet][i];
45011051Sandreas.hansson@arm.com    if (entry != NULL) {
45111051Sandreas.hansson@arm.com      if (entry->m_Address == address ||                         // Already in the cache
45211051Sandreas.hansson@arm.com          entry->m_Permission == AccessPermission_NotPresent) {  // We found an empty entry
45311051Sandreas.hansson@arm.com        return true;
45411051Sandreas.hansson@arm.com      }
45511051Sandreas.hansson@arm.com    } else {
45611051Sandreas.hansson@arm.com      return true;
45711051Sandreas.hansson@arm.com    }
45811051Sandreas.hansson@arm.com  }
45911284Sandreas.hansson@arm.com  return false;
46011051Sandreas.hansson@arm.com}
46111051Sandreas.hansson@arm.com
46211051Sandreas.hansson@arm.cominline
46311051Sandreas.hansson@arm.comvoid CacheMemory::allocate(const Address& address, AbstractCacheEntry* entry)
46411051Sandreas.hansson@arm.com{
46511051Sandreas.hansson@arm.com  assert(address == line_address(address));
46611051Sandreas.hansson@arm.com  assert(!isTagPresent(address));
46711284Sandreas.hansson@arm.com  assert(cacheAvail(address));
46811051Sandreas.hansson@arm.com  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
46911051Sandreas.hansson@arm.com
47011051Sandreas.hansson@arm.com  // Find the first open slot
47111051Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
47211051Sandreas.hansson@arm.com  for (int i=0; i < m_cache_assoc; i++) {
47311051Sandreas.hansson@arm.com    if (m_cache[cacheSet][i] == NULL ||
47411051Sandreas.hansson@arm.com        m_cache[cacheSet][i]->m_Permission == AccessPermission_NotPresent) {
47511051Sandreas.hansson@arm.com      m_cache[cacheSet][i] = entry;  // Init entry
47611051Sandreas.hansson@arm.com      m_cache[cacheSet][i]->m_Address = address;
47711051Sandreas.hansson@arm.com      m_cache[cacheSet][i]->m_Permission = AccessPermission_Invalid;
47811051Sandreas.hansson@arm.com
47911051Sandreas.hansson@arm.com      m_replacementPolicy_ptr->touch(cacheSet, i, g_eventQueue_ptr->getTime());
48011051Sandreas.hansson@arm.com
48111051Sandreas.hansson@arm.com      return;
48211051Sandreas.hansson@arm.com    }
48311051Sandreas.hansson@arm.com  }
48411051Sandreas.hansson@arm.com  ERROR_MSG("Allocate didn't find an available entry");
48511051Sandreas.hansson@arm.com}
48611051Sandreas.hansson@arm.com
48711051Sandreas.hansson@arm.cominline
48811051Sandreas.hansson@arm.comvoid CacheMemory::deallocate(const Address& address)
48911051Sandreas.hansson@arm.com{
49011051Sandreas.hansson@arm.com  assert(address == line_address(address));
49111051Sandreas.hansson@arm.com  assert(isTagPresent(address));
49211051Sandreas.hansson@arm.com  DEBUG_EXPR(CACHE_COMP, HighPrio, address);
49311051Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
49411051Sandreas.hansson@arm.com  int location = findTagInSet(cacheSet, address);
49511051Sandreas.hansson@arm.com  if (location != -1){
49611199Sandreas.hansson@arm.com    delete m_cache[cacheSet][location];
49711199Sandreas.hansson@arm.com    m_cache[cacheSet][location] = NULL;
49811199Sandreas.hansson@arm.com  }
49911199Sandreas.hansson@arm.com}
50011199Sandreas.hansson@arm.com
50111051Sandreas.hansson@arm.com// Returns with the physical address of the conflicting cache line
50211199Sandreas.hansson@arm.cominline
50311051Sandreas.hansson@arm.comAddress CacheMemory::cacheProbe(const Address& address) const
50411051Sandreas.hansson@arm.com{
50511051Sandreas.hansson@arm.com  assert(address == line_address(address));
50611051Sandreas.hansson@arm.com  assert(!cacheAvail(address));
50711051Sandreas.hansson@arm.com
50811051Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
50911051Sandreas.hansson@arm.com  return m_cache[cacheSet][m_replacementPolicy_ptr->getVictim(cacheSet)]->m_Address;
51011051Sandreas.hansson@arm.com}
51111051Sandreas.hansson@arm.com
51211051Sandreas.hansson@arm.com// looks an address up in the cache
51311051Sandreas.hansson@arm.cominline
51411051Sandreas.hansson@arm.comAbstractCacheEntry& CacheMemory::lookup(const Address& address)
51511051Sandreas.hansson@arm.com{
51611051Sandreas.hansson@arm.com  assert(address == line_address(address));
51711051Sandreas.hansson@arm.com  Index cacheSet = addressToCacheSet(address);
51811051Sandreas.hansson@arm.com  int loc = findTagInSet(cacheSet, address);
51911051Sandreas.hansson@arm.com  assert(loc != -1);
52011130Sali.jafri@arm.com  return *m_cache[cacheSet][loc];
52111130Sali.jafri@arm.com}
52211130Sali.jafri@arm.com
52311130Sali.jafri@arm.com// looks an address up in the cache
52411130Sali.jafri@arm.cominline
52511130Sali.jafri@arm.comconst AbstractCacheEntry& CacheMemory::lookup(const Address& address) const
52611130Sali.jafri@arm.com{
52711130Sali.jafri@arm.com  assert(address == line_address(address));
52811130Sali.jafri@arm.com  Index cacheSet = addressToCacheSet(address);
52911199Sandreas.hansson@arm.com  int loc = findTagInSet(cacheSet, address);
53011130Sali.jafri@arm.com  assert(loc != -1);
53111130Sali.jafri@arm.com  return *m_cache[cacheSet][loc];
53211130Sali.jafri@arm.com}
53311130Sali.jafri@arm.com
53411130Sali.jafri@arm.cominline
53511130Sali.jafri@arm.comAccessPermission CacheMemory::getPermission(const Address& address) const
53611130Sali.jafri@arm.com{
53711130Sali.jafri@arm.com  assert(address == line_address(address));
53811130Sali.jafri@arm.com  return lookup(address).m_Permission;
53911130Sali.jafri@arm.com}
54011130Sali.jafri@arm.com
54111130Sali.jafri@arm.cominline
54211130Sali.jafri@arm.comvoid CacheMemory::changePermission(const Address& address, AccessPermission new_perm)
54311130Sali.jafri@arm.com{
54411130Sali.jafri@arm.com  assert(address == line_address(address));
54511130Sali.jafri@arm.com  lookup(address).m_Permission = new_perm;
54611130Sali.jafri@arm.com  assert(getPermission(address) == new_perm);
54711130Sali.jafri@arm.com}
54811130Sali.jafri@arm.com
54911130Sali.jafri@arm.com// Sets the most recently used bit for a cache block
55011130Sali.jafri@arm.cominline
55111130Sali.jafri@arm.comvoid CacheMemory::setMRU(const Address& address)
55211130Sali.jafri@arm.com{
55311051Sandreas.hansson@arm.com  Index cacheSet;
55411051Sandreas.hansson@arm.com
55511051Sandreas.hansson@arm.com  cacheSet = addressToCacheSet(address);
55611051Sandreas.hansson@arm.com  m_replacementPolicy_ptr->touch(cacheSet,
55711051Sandreas.hansson@arm.com                                 findTagInSet(cacheSet, address),
55811051Sandreas.hansson@arm.com                                 g_eventQueue_ptr->getTime());
55911051Sandreas.hansson@arm.com}
56011051Sandreas.hansson@arm.com
56111051Sandreas.hansson@arm.cominline
56211051Sandreas.hansson@arm.comvoid CacheMemory::recordCacheContents(CacheRecorder& tr) const
56311276Sandreas.hansson@arm.com{
56411276Sandreas.hansson@arm.com  for (int i = 0; i < m_cache_num_sets; i++) {
56511276Sandreas.hansson@arm.com    for (int j = 0; j < m_cache_assoc; j++) {
56611276Sandreas.hansson@arm.com      AccessPermission perm = m_cache[i][j]->m_Permission;
56711276Sandreas.hansson@arm.com      CacheRequestType request_type = CacheRequestType_NULL;
56811276Sandreas.hansson@arm.com      if (perm == AccessPermission_Read_Only) {
56911276Sandreas.hansson@arm.com        if (m_is_instruction_only_cache) {
57011276Sandreas.hansson@arm.com          request_type = CacheRequestType_IFETCH;
57111276Sandreas.hansson@arm.com        } else {
57211051Sandreas.hansson@arm.com          request_type = CacheRequestType_LD;
57311276Sandreas.hansson@arm.com        }
57411276Sandreas.hansson@arm.com      } else if (perm == AccessPermission_Read_Write) {
57511276Sandreas.hansson@arm.com        request_type = CacheRequestType_ST;
57611276Sandreas.hansson@arm.com      }
57711276Sandreas.hansson@arm.com
57811051Sandreas.hansson@arm.com      if (request_type != CacheRequestType_NULL) {
57911051Sandreas.hansson@arm.com        //        tr.addRecord(m_chip_ptr->getID(), m_cache[i][j].m_Address,
58011051Sandreas.hansson@arm.com        //                     Address(0), request_type, m_replacementPolicy_ptr->getLastAccess(i, j));
58111051Sandreas.hansson@arm.com      }
58211051Sandreas.hansson@arm.com    }
58311051Sandreas.hansson@arm.com  }
58411051Sandreas.hansson@arm.com}
58511051Sandreas.hansson@arm.com
58611051Sandreas.hansson@arm.cominline
58711051Sandreas.hansson@arm.comvoid CacheMemory::print(ostream& out) const
58811051Sandreas.hansson@arm.com{
58911051Sandreas.hansson@arm.com  out << "Cache dump: " << m_cache_name << endl;
59011051Sandreas.hansson@arm.com  for (int i = 0; i < m_cache_num_sets; i++) {
59111051Sandreas.hansson@arm.com    for (int j = 0; j < m_cache_assoc; j++) {
59211051Sandreas.hansson@arm.com      if (m_cache[i][j] != NULL) {
59311051Sandreas.hansson@arm.com        out << "  Index: " << i
59411051Sandreas.hansson@arm.com            << " way: " << j
59511051Sandreas.hansson@arm.com            << " entry: " << *m_cache[i][j] << endl;
59611051Sandreas.hansson@arm.com      } else {
59711051Sandreas.hansson@arm.com        out << "  Index: " << i
59811051Sandreas.hansson@arm.com            << " way: " << j
59911051Sandreas.hansson@arm.com            << " entry: NULL" << endl;
60011051Sandreas.hansson@arm.com      }
60111051Sandreas.hansson@arm.com    }
60211051Sandreas.hansson@arm.com  }
60311051Sandreas.hansson@arm.com}
60411051Sandreas.hansson@arm.com
60511051Sandreas.hansson@arm.cominline
60611051Sandreas.hansson@arm.comvoid CacheMemory::printData(ostream& out) const
60711051Sandreas.hansson@arm.com{
60811051Sandreas.hansson@arm.com  out << "printData() not supported" << endl;
60911051Sandreas.hansson@arm.com}
61011051Sandreas.hansson@arm.com
61111051Sandreas.hansson@arm.cominline
61211051Sandreas.hansson@arm.comvoid CacheMemory::getMemoryValue(const Address& addr, char* value,
61311051Sandreas.hansson@arm.com                                 unsigned int size_in_bytes ){
61411051Sandreas.hansson@arm.com  AbstractCacheEntry& entry = lookup(line_address(addr));
61511051Sandreas.hansson@arm.com  unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
61611051Sandreas.hansson@arm.com  for(unsigned int i=0; i<size_in_bytes; ++i){
61711051Sandreas.hansson@arm.com    value[i] = entry.getDataBlk().getByte(i + startByte);
61811051Sandreas.hansson@arm.com  }
61911051Sandreas.hansson@arm.com}
62011284Sandreas.hansson@arm.com
62111051Sandreas.hansson@arm.cominline
62211284Sandreas.hansson@arm.comvoid CacheMemory::setMemoryValue(const Address& addr, char* value,
62311284Sandreas.hansson@arm.com                                 unsigned int size_in_bytes ){
62411284Sandreas.hansson@arm.com  AbstractCacheEntry& entry = lookup(line_address(addr));
62511284Sandreas.hansson@arm.com  unsigned int startByte = addr.getAddress() - line_address(addr).getAddress();
62611051Sandreas.hansson@arm.com  assert(size_in_bytes > 0);
62711051Sandreas.hansson@arm.com  for(unsigned int i=0; i<size_in_bytes; ++i){
62811284Sandreas.hansson@arm.com    entry.getDataBlk().setByte(i + startByte, value[i]);
62911284Sandreas.hansson@arm.com  }
63011284Sandreas.hansson@arm.com
63111284Sandreas.hansson@arm.com  //  entry = lookup(line_address(addr));
63211284Sandreas.hansson@arm.com}
63311284Sandreas.hansson@arm.com
63411284Sandreas.hansson@arm.com#endif //CACHEMEMORY_H
63511284Sandreas.hansson@arm.com
63611284Sandreas.hansson@arm.com