aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2017-04-30 22:03:15 -0700
committerAndrew Waterman <andrew@sifive.com>2017-04-30 22:03:15 -0700
commitabb7dddfdfd6ec5070c26c1824e4f5801e6bb12d (patch)
treec20479a56197fe8bcc6b886a0454af028444ac4c
parent1d2892407fed141d20607ae9c49e50673e2c5c11 (diff)
downloadspike-abb7dddfdfd6ec5070c26c1824e4f5801e6bb12d.zip
spike-abb7dddfdfd6ec5070c26c1824e4f5801e6bb12d.tar.gz
spike-abb7dddfdfd6ec5070c26c1824e4f5801e6bb12d.tar.bz2
Support more flexible main memory allocation
-rw-r--r--riscv/devices.cc11
-rw-r--r--riscv/devices.h23
-rw-r--r--riscv/sim.cc45
-rw-r--r--riscv/sim.h11
-rw-r--r--spike_main/spike.cc58
5 files changed, 113 insertions, 35 deletions
diff --git a/riscv/devices.cc b/riscv/devices.cc
index c7a63b0..af4dc7d 100644
--- a/riscv/devices.cc
+++ b/riscv/devices.cc
@@ -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;
+}
diff --git a/riscv/devices.h b/riscv/devices.h
index f3ecb67..ba344db 100644
--- a/riscv/devices.h
+++ b/riscv/devices.h
@@ -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*>&);
diff --git a/riscv/sim.cc b/riscv/sim.cc
index 7a10c9b..40be110 100644
--- a/riscv/sim.cc
+++ b/riscv/sim.cc
@@ -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()
diff --git a/riscv/sim.h b/riscv/sim.h
index edf15db..ea49e18 100644
--- a/riscv/sim.h
+++ b/riscv/sim.h
@@ -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();
diff --git a/spike_main/spike.cc b/spike_main/spike.cc
index dde6f5a..80c5fa6 100644
--- a/spike_main/spike.cc
+++ b/spike_main/spike.cc
@@ -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));