Support more flexible main memory allocation
authorAndrew Waterman <andrew@sifive.com>
Mon, 1 May 2017 05:03:15 +0000 (22:03 -0700)
committerAndrew Waterman <andrew@sifive.com>
Mon, 1 May 2017 05:03:15 +0000 (22:03 -0700)
riscv/devices.cc
riscv/devices.h
riscv/sim.cc
riscv/sim.h
spike_main/spike.cc

index c7a63b0044b87e5a9a5dbd3df2958abd95699cd5..af4dc7d127bc52684866e3be3ac5134e531e61f8 100644 (file)
@@ -20,3 +20,14 @@ bool bus_t::store(reg_t addr, size_t len, const uint8_t* bytes)
     return false;
   return it->second->store(addr - -it->first, len, bytes);
 }
+
+bus_t::descriptor bus_t::find_device(reg_t addr)
+{
+  auto it = devices.lower_bound(-addr);
+  if (it == devices.end()) {
+    bus_t::descriptor desc = {0, 0};
+    return desc;
+  }
+  bus_t::descriptor desc = {-it->first, it->second};
+  return desc;
+}
index f3ecb67a3c7f3ac46c5385aee18bb175ea93395c..ba344dbdb8dc821269eff074a5ab9720eb8118dd 100644 (file)
@@ -20,6 +20,9 @@ class bus_t : public abstract_device_t {
   bool store(reg_t addr, size_t len, const uint8_t* bytes);
   void add_device(reg_t addr, abstract_device_t* dev);
 
+  struct descriptor { reg_t base; abstract_device_t* device; };
+  descriptor find_device(reg_t addr);
+
  private:
   std::map<reg_t, abstract_device_t*> devices;
 };
@@ -34,6 +37,26 @@ class rom_device_t : public abstract_device_t {
   std::vector<char> data;
 };
 
+class mem_t : public abstract_device_t {
+ public:
+  mem_t(size_t size) : len(size) {
+    data = (char*)calloc(1, size);
+    if (!data)
+      throw std::runtime_error("couldn't allocate " + std::to_string(size) + " bytes of target memory");
+  }
+  mem_t(const mem_t& that) = delete;
+  ~mem_t() { free(data); }
+
+  bool load(reg_t addr, size_t len, uint8_t* bytes) { return false; }
+  bool store(reg_t addr, size_t len, const uint8_t* bytes) { return false; }
+  char* contents() { return data; }
+  size_t size() { return len; }
+
+ private:
+  char* data;
+  size_t len;
+};
+
 class clint_t : public abstract_device_t {
  public:
   clint_t(std::vector<processor_t*>&);
index 7a10c9b4d2c9a4705cf726c0bd638e242950f7b4..40be110cf3190a5123e58a6fbc15d52e7394eb63 100644 (file)
@@ -23,26 +23,16 @@ static void handle_signal(int sig)
   signal(sig, &handle_signal);
 }
 
-sim_t::sim_t(const char* isa, size_t nprocs, size_t mem_mb, bool halted,
+sim_t::sim_t(const char* isa, size_t nprocs, bool halted,
+             std::vector<std::pair<reg_t, mem_t*>> mems,
              const std::vector<std::string>& args)
-  : htif_t(args), procs(std::max(nprocs, size_t(1))),
+  : htif_t(args), mems(mems), procs(std::max(nprocs, size_t(1))),
     current_step(0), current_proc(0), debug(false), gdbserver(NULL)
 {
   signal(SIGINT, &handle_signal);
-  // allocate target machine's memory, shrinking it as necessary
-  // until the allocation succeeds
-  size_t memsz0 = (size_t)mem_mb << 20;
-  size_t quantum = 1L << 20;
-  if (memsz0 == 0)
-    memsz0 = (size_t)2048 << 20;
 
-  memsz = memsz0;
-  while ((mem = (char*)calloc(1, memsz)) == NULL)
-    memsz = (size_t)(memsz*0.9)/quantum*quantum;
-
-  if (memsz != memsz0)
-    fprintf(stderr, "warning: only got %zu bytes of target mem (wanted %zu)\n",
-            memsz, memsz0);
+  for (auto& x : mems)
+    bus.add_device(x.first, x.second);
 
   bus.add_device(DEBUG_START, &debug_module);
 
@@ -63,7 +53,6 @@ sim_t::~sim_t()
   for (size_t i = 0; i < procs.size(); i++)
     delete procs[i];
   delete debug_mmu;
-  free(mem);
 }
 
 void sim_thread_main(void* arg)
@@ -278,15 +267,16 @@ void sim_t::make_dtb()
          "      };\n"
          "    };\n";
   }
-  reg_t membs = DRAM_BASE;
-  s << std::hex <<
-         "  };\n"
-         "  memory@" << DRAM_BASE << " {\n"
+  s <<   "  };\n";
+  for (auto& m : mems) {
+    s << std::hex <<
+         "  memory@" << m.first << " {\n"
          "    device_type = \"memory\";\n"
-         "    reg = <0x" << (membs >> 32) << " 0x" << (membs & (uint32_t)-1) <<
-                   " 0x" << (memsz >> 32) << " 0x" << (memsz & (uint32_t)-1) << ">;\n"
-         "  };\n"
-         "  soc {\n"
+         "    reg = <0x" << (m.first >> 32) << " 0x" << (m.first & (uint32_t)-1) <<
+                   " 0x" << (m.second->size() >> 32) << " 0x" << (m.second->size() & (uint32_t)-1) << ">;\n"
+         "  };\n";
+  }
+  s <<   "  soc {\n"
          "    #address-cells = <2>;\n"
          "    #size-cells = <2>;\n"
          "    compatible = \"ucbbar,spike-bare-soc\", \"simple-bus\";\n"
@@ -316,6 +306,13 @@ void sim_t::make_dtb()
   bus.add_device(DEFAULT_RSTVEC, boot_rom.get());
 }
 
+char* sim_t::addr_to_mem(reg_t addr) {
+  auto desc = bus.find_device(addr);
+  if (auto mem = dynamic_cast<mem_t*>(desc.device))
+    return mem->contents() + (addr - desc.base);
+  return NULL;
+}
+
 // htif
 
 void sim_t::idle()
index edf15dbf2e926a950cd528b74d09ecdd6d637dd2..ea49e1852cbbcc08ed9fe00c5ad0d047f050b11c 100644 (file)
@@ -19,7 +19,8 @@ class gdbserver_t;
 class sim_t : public htif_t
 {
 public:
-  sim_t(const char* isa, size_t _nprocs, size_t mem_mb, bool halted,
+  sim_t(const char* isa, size_t _nprocs,  bool halted,
+        std::vector<std::pair<reg_t, mem_t*>> mems,
         const std::vector<std::string>& args);
   ~sim_t();
 
@@ -34,8 +35,7 @@ public:
   processor_t* get_core(size_t i) { return procs.at(i); }
 
 private:
-  char* mem; // main memory
-  size_t memsz; // memory size in bytes
+  std::vector<std::pair<reg_t, mem_t*>> mems;
   mmu_t* debug_mmu;  // debug port into main memory
   std::vector<processor_t*> procs;
   std::string dts;
@@ -57,10 +57,7 @@ private:
   gdbserver_t* gdbserver;
 
   // memory-mapped I/O routines
-  bool addr_is_mem(reg_t addr) {
-    return addr >= DRAM_BASE && addr < DRAM_BASE + memsz;
-  }
-  char* addr_to_mem(reg_t addr) { return addr_is_mem(addr) ? mem + addr - DRAM_BASE : 0; }
+  char* addr_to_mem(reg_t addr);
   bool mmio_load(reg_t addr, size_t len, uint8_t* bytes);
   bool mmio_store(reg_t addr, size_t len, const uint8_t* bytes);
   void make_dtb();
index dde6f5a5b902e458c9b3b7f9a0ffd7aefc188590..80c5fa6a12b51727f8f5e5ff3b5bd740ae2b044f 100644 (file)
@@ -18,7 +18,9 @@ static void help()
   fprintf(stderr, "usage: spike [host options] <target program> [target options]\n");
   fprintf(stderr, "Host Options:\n");
   fprintf(stderr, "  -p<n>                 Simulate <n> processors [default 1]\n");
-  fprintf(stderr, "  -m<n>                 Provide <n> MiB of target memory [default 4096]\n");
+  fprintf(stderr, "  -m<n>                 Provide <n> MiB of target memory [default 2048]\n");
+  fprintf(stderr, "  -m<a:m,b:n,...>       Provide memory regions of size m and n bytes\n");
+  fprintf(stderr, "                          at base addresses a and b (with 4 KiB alignment)\n");
   fprintf(stderr, "  -d                    Interactive debug mode\n");
   fprintf(stderr, "  -g                    Track histogram of PCs\n");
   fprintf(stderr, "  -l                    Generate a log of execution\n");
@@ -35,6 +37,51 @@ static void help()
   exit(1);
 }
 
+static std::vector<std::pair<reg_t, mem_t*>> make_mems(const char* arg)
+{
+  // handle legacy mem argument
+  char* p;
+  auto mb = strtoull(arg, &p, 0);
+  if (*p == 0) {
+    reg_t size = reg_t(mb) << 20;
+    return std::vector<std::pair<reg_t, mem_t*>>(1, std::make_pair(reg_t(DRAM_BASE), new mem_t(size)));
+  }
+
+  // handle base/size tuples
+  std::vector<std::pair<reg_t, mem_t*>> res;
+  while (true) {
+    auto base = strtoull(arg, &p, 0);
+    if (!*p || *p != ':')
+      help();
+    auto size = strtoull(p + 1, &p, 0);
+    if ((size | base) % PGSIZE != 0)
+      help();
+    res.push_back(std::make_pair(reg_t(base), new mem_t(size)));
+    if (!*p)
+      break;
+    if (*p != ',')
+      help();
+    arg = p + 1;
+  }
+  return res;
+#if 0
+  // allocate target machine's memory, shrinking it as necessary
+  // until the allocation succeeds
+  size_t memsz0 = (size_t)mem_mb << 20;
+  size_t quantum = 1L << 20;
+  if (memsz0 == 0)
+    memsz0 = (size_t)2048 << 20;
+
+  memsz = memsz0;
+  while ((mem = (char*)calloc(1, memsz)) == NULL)
+    memsz = (size_t)(memsz*0.9)/quantum*quantum;
+
+  if (memsz != memsz0)
+    fprintf(stderr, "warning: only got %zu bytes of target mem (wanted %zu)\n",
+            memsz, memsz0);
+#endif
+}
+
 int main(int argc, char** argv)
 {
   bool debug = false;
@@ -43,7 +90,7 @@ int main(int argc, char** argv)
   bool log = false;
   bool dump_dts = false;
   size_t nprocs = 1;
-  size_t mem_mb = 0;
+  std::vector<std::pair<reg_t, mem_t*>> mems;
   std::unique_ptr<icache_sim_t> ic;
   std::unique_ptr<dcache_sim_t> dc;
   std::unique_ptr<cache_sim_t> l2;
@@ -58,7 +105,7 @@ int main(int argc, char** argv)
   parser.option('g', 0, 0, [&](const char* s){histogram = true;});
   parser.option('l', 0, 0, [&](const char* s){log = 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('m', 0, 1, [&](const char* s){mems = make_mems(s);});
   // I wanted to use --halted, but for some reason that doesn't work.
   parser.option('H', 0, 0, [&](const char* s){halted = true;});
   parser.option(0, "gdb-port", 1, [&](const char* s){gdb_port = atoi(s);});
@@ -78,7 +125,10 @@ int main(int argc, char** argv)
 
   auto argv1 = parser.parse(argv);
   std::vector<std::string> htif_args(argv1, (const char*const*)argv + argc);
-  sim_t s(isa, nprocs, mem_mb, halted, htif_args);
+  if (mems.empty())
+    mems = make_mems("2048");
+
+  sim_t s(isa, nprocs, halted, mems, htif_args);
   std::unique_ptr<gdbserver_t> gdbserver;
   if (gdb_port) {
     gdbserver = std::unique_ptr<gdbserver_t>(new gdbserver_t(gdb_port, &s));