[sim] hacked in a dcache simulator
authorAndrew Waterman <waterman@s141.Millennium.Berkeley.EDU>
Sun, 1 May 2011 06:44:59 +0000 (23:44 -0700)
committerAndrew Waterman <waterman@s141.Millennium.Berkeley.EDU>
Sun, 1 May 2011 06:44:59 +0000 (23:44 -0700)
riscv/icsim.cc
riscv/icsim.h
riscv/mmu.h
riscv/processor.cc
riscv/processor.h
riscv/riscv-isa-run.cc
riscv/sim.cc
riscv/sim.h

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;
 }
index 122730cf5691a63b2457a0a9dbce4033824ec7fa..48931f585d33c5dfd0c317c36616f1884491b33b 100644 (file)
@@ -2,29 +2,51 @@
 #define _RISCV_ICSIM_H
 
 #include <cstring>
+#include <string>
 #include <stdint.h>
 
+class lfsr_t
+{
+public:
+  lfsr_t() : reg(1) {}
+  lfsr_t(const lfsr_t& lfsr) : reg(lfsr.reg) {}
+  uint32_t next() { return reg = (reg>>1)^(-(reg&1) & 0xd0000001); }
+private:
+  uint32_t reg;
+};
+
 class icsim_t
 {
 public:
-  icsim_t(size_t sets, size_t ways, size_t linesz);
+  icsim_t(size_t sets, size_t ways, size_t linesz, const char* name);
+  icsim_t(const icsim_t& rhs);
   ~icsim_t();
 
-  void tick(uint64_t pc, int insnlen);
+  void tick(uint64_t pc, int insnlen, bool store);
+  void print_stats();
 private:
+  lfsr_t lfsr;
+
   size_t sets;
   size_t ways;
   size_t linesz;
   size_t idx_shift;
   size_t idx_mask;
-  
-  uint64_t accesses;
-  uint64_t misses;
-  uint64_t bytes_fetched;
 
   uint64_t* tags;
+  
+  uint64_t read_accesses;
+  uint64_t read_misses;
+  uint64_t bytes_read;
+  uint64_t write_accesses;
+  uint64_t write_misses;
+  uint64_t bytes_written;
+  uint64_t writebacks;
+
+  std::string name;
 
   static const uint64_t VALID = 1ULL << 63;
+  static const uint64_t DIRTY = 1ULL << 62;
 };
 
 #endif
index 289c200d441586440cea2a18ff707a673765af56..f8ee597f5e62758b349d169e5ac5a9bbb71f8b49 100644 (file)
@@ -1,22 +1,42 @@
 #include "decode.h"
 #include "trap.h"
+#include "icsim.h"
 
 class processor_t;
 
 class mmu_t
 {
 public:
-  mmu_t(char* _mem, size_t _memsz) : mem(_mem), memsz(_memsz), badvaddr(0) {}
+  mmu_t(char* _mem, size_t _memsz)
+   : mem(_mem), memsz(_memsz), badvaddr(0),
+     icsim(NULL), dcsim(NULL), itlbsim(NULL), dtlbsim(NULL)
+  {
+  }
+
+  void set_icsim(icsim_t* _icsim) { icsim = _icsim; }
+  void set_dcsim(icsim_t* _dcsim) { dcsim = _dcsim; }
+  void set_itlbsim(icsim_t* _itlbsim) { itlbsim = _itlbsim; }
+  void set_dtlbsim(icsim_t* _dtlbsim) { dtlbsim = _dtlbsim; }
+
+  #ifdef RISCV_ENABLE_ICSIM
+  # define dcsim_tick(dcsim, dtlbsim, addr, size, st) \
+      do { if(dcsim) (dcsim)->tick(addr, size, st); \
+           if(dtlbsim) (dtlbsim)->tick(addr, sizeof(reg_t), false); } while(0)
+  #else
+  # define dcsim_tick(dcsim, addr, size)
+  #endif
 
   #define load_func(type) \
     type##_t load_##type(reg_t addr) { \
       check_align_and_bounds(addr, sizeof(type##_t), false, false); \
+      dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), false); \
       return *(type##_t*)(mem+addr); \
     }
 
   #define store_func(type) \
     void store_##type(reg_t addr, type##_t val) { \
       check_align_and_bounds(addr, sizeof(type##_t), true, false); \
+      dcsim_tick(dcsim, dtlbsim, addr, sizeof(type##_t), true); \
       *(type##_t*)(mem+addr) = val; \
     }
 
@@ -30,6 +50,13 @@ public:
     insn_t insn; 
     insn.bits = lo | ((uint32_t)hi << 16);
 
+    #ifdef RISCV_ENABLE_ICSIM
+    if(icsim)
+      icsim->tick(addr, insn_length(insn), false);
+    if(itlbsim)
+      itlbsim->tick(addr, sizeof(reg_t), false);
+    #endif
+
     return insn;
     #else
     check_align_and_bounds(addr, 4, false, true);
@@ -59,6 +86,11 @@ private:
   size_t memsz;
   reg_t badvaddr;
 
+  icsim_t* icsim;
+  icsim_t* dcsim;
+  icsim_t* itlbsim;
+  icsim_t* dtlbsim;
+
   void check_align(reg_t addr, int size, bool store, bool fetch)
   {
     if(addr & (size-1))
index 471afabecd559e6f0c7784bb0ac7cb6ace2a2572..4494c5953df8941a8abc42caea5747fd9af4216e 100644 (file)
@@ -53,14 +53,32 @@ processor_t::processor_t(sim_t* _sim, char* _mem, size_t _memsz)
   static_assert(sizeof(uint128_t) == 16 && sizeof(int128_t) == 16);
 
   icsim = NULL;
+  dcsim = NULL;
+  itlbsim = NULL;
+  dtlbsim = NULL;
 }
 
 processor_t::~processor_t()
 {
+  if(icsim)
+    icsim->print_stats();
   delete icsim;
+
+  if(itlbsim)
+    itlbsim->print_stats();
+  delete itlbsim;
+
+  if(dcsim)
+    dcsim->print_stats();
+  delete dcsim;
+
+  if(dtlbsim)
+    dtlbsim->print_stats();
+  delete dtlbsim;
 }
 
-void processor_t::init(uint32_t _id)
+void processor_t::init(uint32_t _id, icsim_t* default_icache,
+                       icsim_t* default_dcache)
 {
   id = _id;
 
@@ -74,7 +92,16 @@ void processor_t::init(uint32_t _id)
   }
 
   #ifdef RISCV_ENABLE_ICSIM
-  icsim = new icsim_t(1024, 1, 32);
+  icsim = new icsim_t(*default_icache);
+  mmu.set_icsim(icsim);
+  itlbsim = new icsim_t(1, 8, 4096, "ITLB");
+  mmu.set_itlbsim(itlbsim);
+  #endif
+  #ifdef RISCV_ENABLE_ICSIM
+  dcsim = new icsim_t(*default_dcache);
+  mmu.set_dcsim(dcsim);
+  dtlbsim = new icsim_t(1, 8, 4096, "DTLB");
+  mmu.set_dtlbsim(dtlbsim);
   #endif
 }
 
@@ -134,9 +161,6 @@ void processor_t::step(size_t n, bool noisy)
         take_trap(trap_interrupt,noisy);
 
       insn_t insn = mmu.load_insn(pc, sr & SR_EC);
-      #ifdef RISCV_ENABLE_ICSIM
-      icsim->tick(pc, insn_length(insn));
-      #endif
   
       reg_t npc = pc + insn_length(insn);
 
index 5c524c0fef183834c5b523f3c91ffc7d2f704a0f..e92d093fc1dea25b455ffbfab2ded75e49d49ca4 100644 (file)
@@ -16,7 +16,7 @@ class processor_t
 public:
   processor_t(sim_t* _sim, char* _mem, size_t _memsz);
   ~processor_t();
-  void init(uint32_t _id);
+  void init(uint32_t _id, icsim_t* defualt_icache, icsim_t* default_dcache);
   void step(size_t n, bool noisy);
 
 private:
@@ -73,8 +73,11 @@ private:
   int nfpr_use;
   processor_t* uts[MAX_UTS];
 
-  // icache sim
+  // cache sim
   icsim_t* icsim;
+  icsim_t* dcsim;
+  icsim_t* itlbsim;
+  icsim_t* dtlbsim;
 
   friend class sim_t;
 };
index 83bb28637922f0393eeae6b63f0f3009146b0a1d..c14cbbba834bef2558309216452758ebe3cfc78f 100644 (file)
@@ -9,8 +9,9 @@ int main(int argc, char** argv)
   bool debug = false;
   int nprocs = 1;
   int fromhost_fd = -1, tohost_fd = -1;
+  size_t icsim_sets = 1024, icsim_linesz = 32, icsim_ways = 1;
 
-  for(int c; (c = getopt(argc,argv,"dpf:t:")) != -1; )
+  for(int c; (c = getopt(argc,argv,"dp:f:t:i:")) != -1; )
   {
     switch(c)
     {
@@ -26,15 +27,32 @@ int main(int argc, char** argv)
       case 't':
         tohost_fd = atoi(optarg);
         break;
+      case 'i':
+        switch(optarg[0])
+        {
+          case 's':
+            icsim_sets = atoi(optarg+1);
+            break;
+          case 'l':
+            icsim_linesz = atoi(optarg+1);
+            break;
+          case 'a':
+            icsim_ways = atoi(optarg+1);
+            break;
+        }
+        break;
     }
   }
 
   demand(fcntl(fromhost_fd,F_GETFD) >= 0, "fromhost file not open");
   demand(fcntl(tohost_fd,F_GETFD) >= 0, "tohost file not open");
 
-  appserver_link_t applink(tohost_fd,fromhost_fd);
+  icsim_t icache(icsim_sets, icsim_ways, icsim_linesz, "I$");
+  icsim_t dcache(512, 2, 32, "D$");
+
+  appserver_link_t applink(tohost_fd, fromhost_fd);
 
-  sim_t s(nprocs,MEMSIZE,&applink);
+  sim_t s(nprocs, MEMSIZE, &applink, &icache, &dcache);
   try
   {
     s.run(debug);
index 7ac60c11b398b963d8b6eca186e263b4e793f052..c503ccbb922bf150f4c9f01da00193acef31c9b4 100644 (file)
@@ -6,7 +6,7 @@
 #include <iostream>
 #include <climits>
 
-sim_t::sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink)
+sim_t::sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink, icsim_t* default_icache, icsim_t* default_dcache)
   : applink(_applink),
     memsz(_memsz),
     mem((char*)mmap64(NULL, memsz, PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0)),
@@ -15,7 +15,7 @@ sim_t::sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink)
   demand(mem != MAP_FAILED, "couldn't allocate target machine's memory");
 
   for(int i = 0; i < (int)procs.size(); i++)
-    procs[i].init(i);
+    procs[i].init(i, default_icache, default_dcache);
 
   applink->init(this);
 }
index a471500973ee6e67eee17f125ae916c45920b7fb..c3f308e2e9421491c8ce2d3e06d659c42b5c4735 100644 (file)
@@ -12,7 +12,7 @@ class appserver_link_t;
 class sim_t
 {
 public:
-  sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink);
+  sim_t(int _nprocs, size_t _memsz, appserver_link_t* _applink, icsim_t* _default_icache, icsim_t* default_dcache);
   ~sim_t();
   void run(bool debug);