From abb7dddfdfd6ec5070c26c1824e4f5801e6bb12d Mon Sep 17 00:00:00 2001 From: Andrew Waterman Date: Sun, 30 Apr 2017 22:03:15 -0700 Subject: [PATCH] Support more flexible main memory allocation --- riscv/devices.cc | 11 +++++++++ riscv/devices.h | 23 ++++++++++++++++++ riscv/sim.cc | 45 ++++++++++++++++------------------- riscv/sim.h | 11 ++++----- spike_main/spike.cc | 58 +++++++++++++++++++++++++++++++++++++++++---- 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 devices; }; @@ -34,6 +37,26 @@ class rom_device_t : public abstract_device_t { std::vector 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&); 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> mems, const std::vector& 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(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> mems, const std::vector& 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> mems; mmu_t* debug_mmu; // debug port into main memory std::vector 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 options]\n"); fprintf(stderr, "Host Options:\n"); fprintf(stderr, " -p Simulate processors [default 1]\n"); - fprintf(stderr, " -m Provide MiB of target memory [default 4096]\n"); + fprintf(stderr, " -m Provide MiB of target memory [default 2048]\n"); + fprintf(stderr, " -m 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> 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>(1, std::make_pair(reg_t(DRAM_BASE), new mem_t(size))); + } + + // handle base/size tuples + std::vector> 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> mems; std::unique_ptr ic; std::unique_ptr dc; std::unique_ptr 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 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; if (gdb_port) { gdbserver = std::unique_ptr(new gdbserver_t(gdb_port, &s)); -- 2.30.2