[sim] hacked in a dcache simulator
[riscv-isa-sim.git] / riscv / icsim.cc
index 73d6e9c050aae0eb6350c8c91c71c8c8fe905c0b..308e7ed537e6cc4b1cba5b14d7e08eb74bd52665 100644 (file)
@@ -3,53 +3,98 @@
 #include <iostream>
 #include <iomanip>
 
-icsim_t::icsim_t(size_t _sets, size_t _ways, size_t _linesz)
+icsim_t::icsim_t(size_t _sets, size_t _ways, size_t _linesz, const char* _name)
+ : sets(_sets), ways(_ways), linesz(_linesz), idx_mask(_sets-1), name(_name)
 {
-  sets = _sets;
-  ways = _ways;
-  linesz = _linesz;
-
   if(sets == 0 || (sets & (sets-1)))
     throw std::logic_error("sets not a power of 2");
   if(linesz == 0 || (linesz & (linesz-1)))
     throw std::logic_error("linesz not a power of 2");
-  if(ways != 1)
-    throw std::logic_error("set associativity currently unsupported");
 
-  idx_mask = sets-1;
   idx_shift = 0;
   while(_linesz >>= 1)
     idx_shift++;
 
   tags = new uint64_t[sets*ways];
   memset(tags, 0, sets*ways*sizeof(uint64_t));
+
+  read_accesses = 0;
+  read_misses = 0;
+  bytes_read = 0;
+  write_accesses = 0;
+  write_misses = 0;
+  bytes_written = 0;
+  writebacks = 0;
+}
+
+icsim_t::icsim_t(const icsim_t& rhs)
+ : sets(rhs.sets), ways(rhs.ways), linesz(rhs.linesz),
+   idx_shift(rhs.idx_shift), idx_mask(rhs.idx_mask), name(rhs.name)
+{
+  tags = new uint64_t[sets*ways];
+  memcpy(tags, rhs.tags, sets*ways*sizeof(uint64_t));
 }
 
 icsim_t::~icsim_t()
 {
-  float mr = 100.0f*misses/accesses;
-  float cr = 100.0f*bytes_fetched/(4*accesses);
+  delete [] tags;
+}
 
-  std::cout << "Instruction cache statsistics" << std::endl;
-  std::cout << "Bytes fetched: " << bytes_fetched << std::endl;
-  std::cout << "Hits: " << (accesses-misses) << std::endl;
-  std::cout << "Misses: " << misses << std::endl;
-  std::cout << "Miss rate: " << std::setprecision(3) << mr << '%' << std::endl;
-  std::cout << "RVC compression ratio: " << cr << '%' << std::endl;
+void icsim_t::print_stats()
+{
+  if(read_accesses + write_accesses == 0)
+    return;
 
-  delete [] tags;
+  float mr = 100.0f*(read_misses+write_misses)/(read_accesses+write_accesses);
+
+  std::cout << std::setprecision(3) << std::fixed;
+  std::cout << name << " ";
+  std::cout << "Bytes Read:            " << bytes_read << std::endl;
+  std::cout << name << " ";
+  std::cout << "Bytes Written:         " << bytes_written << std::endl;
+  std::cout << name << " ";
+  std::cout << "Read Accesses:         " << read_accesses << std::endl;
+  std::cout << name << " ";
+  std::cout << "Write Accesses:        " << write_accesses << std::endl;
+  std::cout << name << " ";
+  std::cout << "Read Misses:           " << read_misses << std::endl;
+  std::cout << name << " ";
+  std::cout << "Write Misses:          " << write_misses << std::endl;
+  std::cout << name << " ";
+  std::cout << "Writebacks:            " << writebacks << std::endl;
+  std::cout << name << " ";
+  std::cout << "Miss Rate:             " << mr << '%' << std::endl;
+
+  float cr = read_accesses == 0 ? 0.0f : 100.0f*bytes_read/(4*read_accesses);
+  if(name == "I$")
+  {
+    std::cout << name << " ";
+    std::cout << "RVC compression ratio: " << cr << '%' << std::endl;
+  }
 }
 
-void icsim_t::tick(uint64_t pc, int insnlen)
+void icsim_t::tick(uint64_t pc, int insnlen, bool store)
 {
-  accesses++;
-  bytes_fetched += insnlen;
+  store ? write_accesses++ : read_accesses++;
+  (store ? bytes_written : bytes_read) += insnlen;
 
   size_t idx = (pc >> idx_shift) & idx_mask;
   size_t tag = (pc >> idx_shift) | VALID;
-  if(tag != tags[idx])
+
+  for(size_t i = 0; i < ways; i++)
   {
-    misses++;
-    tags[idx] = tag;
+    if(tag == (tags[idx + i*sets] & ~DIRTY)) // hit
+    {
+      if(store)
+        tags[idx + i*sets] |= DIRTY;
+      return;
+    }
   }
+
+  store ? write_misses++ : read_misses++;
+
+  size_t way = lfsr.next() % ways;
+  if((tags[idx + way*sets] & (VALID | DIRTY)) == (VALID | DIRTY))
+    writebacks++;
+  tags[idx + way*sets] = tag;
 }