add I$/D$/L2$ simulators
authorAndrew Waterman <waterman@cs.berkeley.edu>
Wed, 13 Feb 2013 20:59:53 +0000 (12:59 -0800)
committerAndrew Waterman <waterman@cs.berkeley.edu>
Wed, 13 Feb 2013 20:59:53 +0000 (12:59 -0800)
riscv/cachesim.cc [new file with mode: 0644]
riscv/cachesim.h [new file with mode: 0644]
riscv/icsim.cc [deleted file]
riscv/icsim.h [deleted file]
riscv/memtracer.h [new file with mode: 0644]
riscv/mmu.cc
riscv/mmu.h
riscv/processor.h
riscv/riscv-isa-run.cc
riscv/riscv.mk.in
riscv/sim.h

diff --git a/riscv/cachesim.cc b/riscv/cachesim.cc
new file mode 100644 (file)
index 0000000..d029c29
--- /dev/null
@@ -0,0 +1,129 @@
+#include "cachesim.h"
+#include <cstdlib>
+#include <iostream>
+#include <iomanip>
+
+cache_sim_t::cache_sim_t(size_t _sets, size_t _ways, size_t _linesz, const char* _name)
+ : sets(_sets), ways(_ways), linesz(_linesz), name(_name)
+{
+  init();
+}
+
+static void help()
+{
+  std::cerr << "Cache configurations must be of the form" << std::endl;
+  std::cerr << "  sets:ways:blocksize" << std::endl;
+  std::cerr << "where sets, ways, and blocksize are positive integers, with" << std::endl;
+  std::cerr << "sets and blocksize both powers of two and blocksize at least 8." << std::endl;
+  exit(1);
+}
+
+cache_sim_t::cache_sim_t(const char* config, const char* _name)
+ : name(_name)
+{
+  const char* wp = strchr(config, ':');
+  if (!wp++) help();
+  const char* bp = strchr(wp, ':');
+  if (!bp++) help();
+
+  sets = atoi(std::string(config, wp).c_str());
+  ways = atoi(std::string(wp, bp).c_str());
+  linesz = atoi(bp);
+
+  init();
+}
+
+void cache_sim_t::init()
+{
+  if(sets == 0 || (sets & (sets-1)))
+    help();
+  if(linesz < 8 || (linesz & (linesz-1)))
+    help();
+
+  idx_shift = 0;
+  for (size_t x = linesz; x; x >>= 1)
+    idx_shift++;
+
+  tags = new uint64_t[sets*ways]();
+  read_accesses = 0;
+  read_misses = 0;
+  bytes_read = 0;
+  write_accesses = 0;
+  write_misses = 0;
+  bytes_written = 0;
+  writebacks = 0;
+
+  miss_handler = NULL;
+}
+
+cache_sim_t::cache_sim_t(const cache_sim_t& rhs)
+ : sets(rhs.sets), ways(rhs.ways), linesz(rhs.linesz),
+   idx_shift(rhs.idx_shift), name(rhs.name)
+{
+  tags = new uint64_t[sets*ways];
+  memcpy(tags, rhs.tags, sets*ways*sizeof(uint64_t));
+}
+
+cache_sim_t::~cache_sim_t()
+{
+  print_stats();
+  delete [] tags;
+}
+
+void cache_sim_t::print_stats()
+{
+  if(read_accesses + write_accesses == 0)
+    return;
+
+  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;
+}
+
+void cache_sim_t::access(uint64_t addr, size_t bytes, bool store)
+{
+  store ? write_accesses++ : read_accesses++;
+  (store ? bytes_written : bytes_read) += bytes;
+
+  size_t idx = (addr >> idx_shift) & (sets-1);
+  size_t tag = (addr >> idx_shift) | VALID;
+  size_t* set_tags = &tags[idx*ways];
+
+  for(size_t i = 0; i < ways; i++)
+  {
+    if(tag == (set_tags[i] & ~DIRTY)) // hit
+    {
+      if(store)
+        set_tags[i] |= DIRTY;
+      return;
+    }
+  }
+
+  store ? write_misses++ : read_misses++;
+
+  size_t way = lfsr.next() % ways;
+  if((set_tags[way] & (VALID | DIRTY)) == (VALID | DIRTY))
+  {
+    uint64_t dirty_addr = (set_tags[way] & ~(VALID | DIRTY)) << idx_shift;
+    if (miss_handler) miss_handler->access(dirty_addr, linesz, true);
+    writebacks++;
+  }
+  if (miss_handler) miss_handler->access(addr & ~(linesz-1), linesz, false);
+  set_tags[way] = tag | (store ? DIRTY : 0);
+}
diff --git a/riscv/cachesim.h b/riscv/cachesim.h
new file mode 100644 (file)
index 0000000..d4f4fb4
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef _RISCV_CACHE_SIM_H
+#define _RISCV_CACHE_SIM_H
+
+#include "memtracer.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 cache_sim_t
+{
+ public:
+  cache_sim_t(const char* config, const char* name);
+  cache_sim_t(size_t sets, size_t ways, size_t linesz, const char* name);
+  cache_sim_t(const cache_sim_t& rhs);
+  ~cache_sim_t();
+
+  void access(uint64_t addr, size_t bytes, bool store);
+  void print_stats();
+  void set_miss_handler(cache_sim_t* mh) { miss_handler = mh; }
+
+ private:
+  lfsr_t lfsr;
+  cache_sim_t* miss_handler;
+
+  size_t sets;
+  size_t ways;
+  size_t linesz;
+  size_t idx_shift;
+
+  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;
+
+  void init();
+};
+
+class unified_cache_sim_t : public memtracer_t
+{
+ public:
+  unified_cache_sim_t(const char* config) : cache(config, "U$") {}
+  bool interested_in_range(size_t begin, size_t end, bool store, bool fetch)
+  {
+    return true;
+  }
+  void trace(uint64_t addr, size_t bytes, bool store, bool fetch)
+  {
+    cache.access(addr, bytes, store);
+  }
+ private:
+  cache_sim_t cache;
+};
+
+class icache_sim_t : public memtracer_t, public cache_sim_t
+{
+ public:
+  icache_sim_t(const char* config) : cache_sim_t(config, "I$") {}
+  bool interested_in_range(size_t begin, size_t end, bool store, bool fetch)
+  {
+    return fetch;
+  }
+  void trace(uint64_t addr, size_t bytes, bool store, bool fetch)
+  {
+    if (fetch) access(addr, bytes, false);
+  }
+};
+
+class dcache_sim_t : public memtracer_t, public cache_sim_t
+{
+ public:
+  dcache_sim_t(const char* config) : cache_sim_t(config, "D$") {}
+  bool interested_in_range(size_t begin, size_t end, bool store, bool fetch)
+  {
+    return !fetch;
+  }
+  void trace(uint64_t addr, size_t bytes, bool store, bool fetch)
+  {
+    if (!fetch) access(addr, bytes, store);
+  }
+};
+
+#endif
diff --git a/riscv/icsim.cc b/riscv/icsim.cc
deleted file mode 100644 (file)
index 308e7ed..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-#include "icsim.h"
-#include <stdexcept>
-#include <iostream>
-#include <iomanip>
-
-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)
-{
-  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");
-
-  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()
-{
-  delete [] tags;
-}
-
-void icsim_t::print_stats()
-{
-  if(read_accesses + write_accesses == 0)
-    return;
-
-  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, bool store)
-{
-  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;
-
-  for(size_t i = 0; i < ways; i++)
-  {
-    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;
-}
diff --git a/riscv/icsim.h b/riscv/icsim.h
deleted file mode 100644 (file)
index ec6eae4..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _RISCV_ICSIM_H
-#define _RISCV_ICSIM_H
-
-// this file models a simple cache to estimate hit/miss rates.
-// it is currently unused.
-
-#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, const char* name);
-  icsim_t(const icsim_t& rhs);
-  ~icsim_t();
-
-  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* 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
diff --git a/riscv/memtracer.h b/riscv/memtracer.h
new file mode 100644 (file)
index 0000000..ed62be5
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef _MEMTRACER_H
+#define _MEMTRACER_H
+
+#include <stdint.h>
+#include <string.h>
+#include <vector>
+
+class memtracer_t
+{
+ public:
+  memtracer_t() : link(NULL) {}
+  virtual ~memtracer_t() {}
+
+  virtual bool interested_in_range(uint64_t begin, uint64_t end, bool store, bool fetch) = 0;
+  virtual void trace(uint64_t addr, size_t bytes, bool store, bool fetch) = 0;
+
+ protected:
+
+ private:
+  memtracer_t* link;
+};
+
+class memtracer_list_t : public memtracer_t
+{
+ public:
+  bool interested_in_range(uint64_t begin, uint64_t end, bool store, bool fetch)
+  {
+    for (std::vector<memtracer_t*>::iterator it = list.begin(); it != list.end(); ++it)
+      if ((*it)->interested_in_range(begin, end, store, fetch))
+        return true;
+    return false;
+  }
+  void trace(uint64_t addr, size_t bytes, bool store, bool fetch)
+  {
+    for (std::vector<memtracer_t*>::iterator it = list.begin(); it != list.end(); ++it)
+      (*it)->trace(addr, bytes, store, fetch);
+  }
+  void hook(memtracer_t* h)
+  {
+    list.push_back(h);
+  }
+ private:
+  std::vector<memtracer_t*> list;
+};
+
+#endif
index c8eec16a6f4156ce0c253f3b92d37e4a0f18354d..6782ae2f3fac214285d3171381e12d884d3d1457 100644 (file)
@@ -27,7 +27,7 @@ void mmu_t::flush_icache()
   memset(icache_tag, -1, sizeof(icache_tag));
 }
 
-void* mmu_t::refill(reg_t addr, bool store, bool fetch)
+void* mmu_t::refill(reg_t addr, reg_t bytes, bool store, bool fetch)
 {
   reg_t idx = (addr >> PGSHIFT) % TLB_ENTRIES;
   reg_t expected_tag = addr & ~(PGSIZE-1);
@@ -49,12 +49,21 @@ void* mmu_t::refill(reg_t addr, bool store, bool fetch)
     throw store ? trap_store_access_fault : trap_load_access_fault;
   }
 
-  tlb_load_tag[idx] = (pte_perm & PTE_UR) ? expected_tag : -1;
-  tlb_store_tag[idx] = (pte_perm & PTE_UW) ? expected_tag : -1;
-  tlb_insn_tag[idx] = (pte_perm & PTE_UX) ? expected_tag : -1;
-  tlb_data[idx] = (long)(pte >> PTE_PPN_SHIFT << PGSHIFT) + (long)mem;
+  reg_t pgoff = addr & (PGSIZE-1);
+  reg_t pgbase = pte >> PTE_PPN_SHIFT << PGSHIFT;
+  reg_t paddr = pgbase + pgoff;
 
-  return (void*)(((long)addr & (PGSIZE-1)) + tlb_data[idx]);
+  if (unlikely(tracer.interested_in_range(pgbase, pgbase + PGSIZE, store, fetch)))
+    tracer.trace(paddr, bytes, store, fetch);
+  else
+  {
+    tlb_load_tag[idx] = (pte_perm & PTE_UR) ? expected_tag : -1;
+    tlb_store_tag[idx] = (pte_perm & PTE_UW) ? expected_tag : -1;
+    tlb_insn_tag[idx] = (pte_perm & PTE_UX) ? expected_tag : -1;
+    tlb_data[idx] = (char*)mem + pgbase;
+  }
+
+  return (char*)mem + paddr;
 }
 
 pte_t mmu_t::walk(reg_t addr)
@@ -107,3 +116,9 @@ pte_t mmu_t::walk(reg_t addr)
 
   return pte;
 }
+
+void mmu_t::register_memtracer(memtracer_t* t)
+{
+  flush_tlb();
+  tracer.hook(t);
+}
index f6ca972a8cea38b71d59601d1850a208b9f5b65b..24208784c436db1dfa5c7e81e6e2cc7124c8d9c2 100644 (file)
@@ -6,6 +6,8 @@
 #include "common.h"
 #include "config.h"
 #include "processor.h"
+#include "memtracer.h"
+#include <vector>
 
 class processor_t;
 
@@ -49,7 +51,7 @@ public:
         badvaddr = addr; \
         throw trap_load_address_misaligned; \
       } \
-      void* paddr = translate(addr, false, false); \
+      void* paddr = translate(addr, sizeof(type##_t), false, false); \
       return *(type##_t*)paddr; \
     }
 
@@ -73,7 +75,7 @@ public:
         badvaddr = addr; \
         throw trap_store_address_misaligned; \
       } \
-      void* paddr = translate(addr, true, false); \
+      void* paddr = translate(addr, sizeof(type##_t), true, false); \
       *(type##_t*)paddr = val; \
     }
 
@@ -97,7 +99,7 @@ public:
     #ifdef RISCV_ENABLE_RVC
     if(addr % 4 == 2 && rvc) // fetch across word boundary
     {
-      void* addr_lo = translate(addr, false, true);
+      void* addr_lo = translate(addr, 2, false, true);
       insn.bits = *(uint16_t*)addr_lo;
 
       *func = processor_t::dispatch_table
@@ -105,7 +107,7 @@ public:
 
       if(!INSN_IS_RVC(insn.bits))
       {
-        void* addr_hi = translate(addr+2, false, true);
+        void* addr_hi = translate(addr+2, 2, false, true);
         insn.bits |= (uint32_t)*(uint16_t*)addr_hi << 16;
       }
     }
@@ -119,13 +121,17 @@ public:
         return data;
 
       // the processor guarantees alignment based upon rvc mode
-      void* paddr = translate(addr, false, true);
+      void* paddr = translate(addr, sizeof(insn_t), false, true);
       insn = *(insn_t*)paddr;
+      *func = processor_t::dispatch_table
+               [insn.bits % processor_t::DISPATCH_TABLE_SIZE];
 
-      icache_tag[idx] = addr;
-      icache_data[idx] = insn;
-      icache_func[idx] = *func = processor_t::dispatch_table
-                                 [insn.bits % processor_t::DISPATCH_TABLE_SIZE];
+      if (!tracer.interested_in_range(addr, addr + sizeof(insn_t), false, true))
+      {
+        icache_tag[idx] = addr;
+        icache_data[idx] = insn;
+        icache_func[idx] = *func;
+      }
     }
 
     return insn;
@@ -146,18 +152,20 @@ public:
   void flush_tlb();
   void flush_icache();
 
+  void register_memtracer(memtracer_t*);
+
 private:
   char* mem;
   size_t memsz;
   reg_t badvaddr;
-
   reg_t ptbr;
   bool supervisor;
   bool vm_enabled;
+  memtracer_list_t tracer;
 
   // implement a TLB for simulator performance
   static const reg_t TLB_ENTRIES = 256;
-  long tlb_data[TLB_ENTRIES];
+  char* tlb_data[TLB_ENTRIES];
   reg_t tlb_insn_tag[TLB_ENTRIES];
   reg_t tlb_load_tag[TLB_ENTRIES];
   reg_t tlb_store_tag[TLB_ENTRIES];
@@ -169,22 +177,22 @@ private:
   reg_t icache_tag[ICACHE_ENTRIES];
 
   // finish translation on a TLB miss and upate the TLB
-  void* refill(reg_t addr, bool store, bool fetch);
+  void* refill(reg_t addr, reg_t bytes, bool store, bool fetch);
 
   // perform a page table walk for a given virtual address
   pte_t walk(reg_t addr);
 
   // translate a virtual address to a physical address
-  void* translate(reg_t addr, bool store, bool fetch)
+  void* translate(reg_t addr, reg_t bytes, bool store, bool fetch)
   {
     reg_t idx = (addr >> PGSHIFT) % TLB_ENTRIES;
 
     reg_t* tlb_tag = fetch ? tlb_insn_tag : store ? tlb_store_tag :tlb_load_tag;
     reg_t expected_tag = addr & ~(PGSIZE-1);
     if(likely(tlb_tag[idx] == expected_tag))
-      return (void*)(((long)addr & (PGSIZE-1)) + tlb_data[idx]);
+      return ((uintptr_t)addr & (PGSIZE-1)) + tlb_data[idx];
 
-    return refill(addr, store, fetch);
+    return refill(addr, bytes, store, fetch);
   }
   
   friend class processor_t;
index 168f95ec0411f515d7e03a2154d0760d5d787e3d..d086760ee04b19f29523c4a76f5cdcf9afaf805d 100644 (file)
@@ -26,6 +26,7 @@ public:
   bool running() { return run; }
   void set_pcr(int which, reg_t val);
   reg_t get_pcr(int which);
+  mmu_t* get_mmu() { return &mmu; }
 
 private:
   sim_t& sim;
index 156ae829c3e566eee27bb1d4c7454e6e3d7cb4c1..7b79945abf36c2b67851dc8862cac5c08305e09d 100644 (file)
@@ -1,52 +1,60 @@
 #include "sim.h"
 #include "htif.h"
+#include "cachesim.h"
+#include <fesvr/option_parser.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <getopt.h>
 #include <vector>
 #include <string>
+#include <memory>
 
 static void help()
 {
   fprintf(stderr, "usage: riscv-isa-run [host options] <target program> [target options]\n");
   fprintf(stderr, "Host Options:\n");
-  fprintf(stderr, "  -p <n>     Simulate <n> processors\n");
-  fprintf(stderr, "  -m <n>     Provide <n> MB of target memory\n");
-  fprintf(stderr, "  -d         Interactive debug mode\n");
-  fprintf(stderr, "  -h         Print this help message\n");
+  fprintf(stderr, "  -p <n>             Simulate <n> processors\n");
+  fprintf(stderr, "  -m <n>             Provide <n> MB of target memory\n");
+  fprintf(stderr, "  -d                 Interactive debug mode\n");
+  fprintf(stderr, "  -h                 Print this help message\n");
+  fprintf(stderr, "  -h                 Print this help message\n");
+  fprintf(stderr, "  --ic=<S>:<W>:<B>   Instantiate a cache model with S sets,\n");
+  fprintf(stderr, "  --dc=<S>:<W>:<B>     W ways, and B-byte blocks (with S and\n");
+  fprintf(stderr, "  --l2=<S>:<W>:<B>     B both powers of 2).\n");
   exit(1);
 }
 
 int main(int argc, char** argv)
 {
   bool debug = false;
-  int nprocs = 1;
-  int mem_mb = 0;
+  size_t nprocs = 1;
+  size_t mem_mb = 0;
+  std::unique_ptr<icache_sim_t> ic;
+  std::unique_ptr<dcache_sim_t> dc;
+  std::unique_ptr<cache_sim_t> l2;
 
-  // parse command-line arguments
-  for(int c; (c = getopt(argc,argv,"hdp:m:")) != -1; )
-  {
-    switch(c)
-    {
-      case 'd':
-        debug = true;
-        break;
-      case 'p':
-        nprocs = atoi(optarg);
-        break;
-      case 'm':
-        mem_mb = atoi(optarg);
-        break;
-      default:
-        fprintf(stderr, "unknown option: -%c", optopt);
-      case 'h':
-        help();
-    }
-  }
+  option_parser_t parser;
+  parser.help(&help);
+  parser.option('d', 0, 0, [&](const char* s){debug = true;});
+  parser.option('p', 0, 1, [&](const char* s){nprocs = atoi(s);});
+  parser.option('m', 0, 1, [&](const char* s){mem_mb = atoi(s);});
+  parser.option(0, "ic", 1, [&](const char* s){ic.reset(new icache_sim_t(s));});
+  parser.option(0, "dc", 1, [&](const char* s){dc.reset(new dcache_sim_t(s));});
+  parser.option(0, "l2", 1, [&](const char* s){l2.reset(new cache_sim_t(s, "L2$"));});
 
-  if (optind == argc)
+  auto argv1 = parser.parse(argv);
+  if (!*argv1)
     help();
-
-  std::vector<std::string> htif_args(argv + optind, argv + argc);
+  std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc);
   sim_t s(nprocs, mem_mb, htif_args);
+
+  if (ic && l2) ic->set_miss_handler(&*l2);
+  if (dc && l2) dc->set_miss_handler(&*l2);
+  for (size_t i = 0; i < nprocs; i++)
+  {
+    if (ic) s.get_core(i)->get_mmu()->register_memtracer(&*ic);
+    if (dc) s.get_core(i)->get_mmu()->register_memtracer(&*dc);
+  }
+
   s.run(debug);
 }
index 1abbc46ae07c557a27f7bf3544e0e1b82ee96922..bf6e07ab6f637ba067a5e7bc84dfc690b222577c 100644 (file)
@@ -13,6 +13,8 @@ riscv_hdrs = \
        opcodes.h \
        insn_header.h \
        dispatch.h \
+       cachesim.h \
+       memtracer.h \
 
 NDISPATCH := 10
 DISPATCH_SRCS := \
@@ -40,7 +42,7 @@ riscv_srcs = \
        sim.cc \
        interactive.cc \
        trap.cc \
-       icsim.cc \
+       cachesim.cc \
        mmu.cc \
        disasm.cc \
        $(DISPATCH_SRCS) \
index 085eb68cf02169fe53b0f3c91741feb8c413241c..aed4e87f67dc39db4db8f5b70dfafc6727ba9d7e 100644 (file)
@@ -23,6 +23,7 @@ public:
 
   // returns the number of processors in this simulator
   size_t num_cores() { return procs.size(); }
+  processor_t* get_core(size_t i) { return procs[i]; }
 
   // read one of the system control registers
   reg_t get_scr(int which);