Browse Source

Support more flexible main memory allocation

pull/100/head
Andrew Waterman 9 years ago
parent
commit
abb7dddfdf
  1. 11
      riscv/devices.cc
  2. 23
      riscv/devices.h
  3. 43
      riscv/sim.cc
  4. 11
      riscv/sim.h
  5. 58
      spike_main/spike.cc

11
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;
}

23
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*>&);

43
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 << " };\n";
for (auto& m : mems) {
s << std::hex <<
" };\n"
" memory@" << DRAM_BASE << " {\n"
" 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()

11
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();

58
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));

Loading…
Cancel
Save