aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJerry Zhao <jerryz123@berkeley.edu>2023-06-20 13:03:56 -0700
committerGitHub <noreply@github.com>2023-06-20 13:03:56 -0700
commitd8b6fc534fb5f3b668410489e2d9cf4c48c9e1da (patch)
tree63b330ca79cb41df6c958e12054b33f6482381bd
parentd2cfddd1141ba95adcfc9617e7767513f0f47146 (diff)
parentb87c6e64d0dba9edf7dc070f9e4a29016641c3a1 (diff)
downloadriscv-isa-sim-d8b6fc534fb5f3b668410489e2d9cf4c48c9e1da.zip
riscv-isa-sim-d8b6fc534fb5f3b668410489e2d9cf4c48c9e1da.tar.gz
riscv-isa-sim-d8b6fc534fb5f3b668410489e2d9cf4c48c9e1da.tar.bz2
Merge pull request #1374 from riscv-software-src/devices
Use device factories to control dts-construction/dts-parsing/device-instantiation
-rw-r--r--ci-tests/testlib.c2
-rw-r--r--fdt/fdt.mk.in5
-rw-r--r--riscv/abstract_device.h32
-rw-r--r--riscv/clint.cc43
-rw-r--r--riscv/debug_module.cc4
-rw-r--r--riscv/debug_module.h2
-rw-r--r--riscv/devices.cc46
-rw-r--r--riscv/devices.h53
-rw-r--r--riscv/dts.cc80
-rw-r--r--riscv/dts.h26
-rw-r--r--riscv/mmio_plugin.h91
-rw-r--r--riscv/ns16550.cc44
-rw-r--r--riscv/plic.cc39
-rw-r--r--riscv/riscv.mk.in2
-rw-r--r--riscv/sim.cc147
-rw-r--r--riscv/sim.h19
-rw-r--r--spike_main/spike.cc61
17 files changed, 309 insertions, 387 deletions
diff --git a/ci-tests/testlib.c b/ci-tests/testlib.c
index 3d5438b..6342f9d 100644
--- a/ci-tests/testlib.c
+++ b/ci-tests/testlib.c
@@ -28,7 +28,7 @@ int main()
hartids,
false,
4);
- std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices;
+ std::vector<const device_factory_t*> plugin_devices;
std::vector<std::string> htif_args {"pk", "hello"};
debug_module_config_t dm_config = {
.progbufsize = 2,
diff --git a/fdt/fdt.mk.in b/fdt/fdt.mk.in
index 8c8dbe5..32c6d49 100644
--- a/fdt/fdt.mk.in
+++ b/fdt/fdt.mk.in
@@ -1,5 +1,10 @@
fdt_subproject_deps = \
+fdt_install_shared_lib = yes
+
+fdt_install_hdrs = \
+ libfdt.h \
+
fdt_c_srcs = \
fdt.c \
fdt_ro.c \
diff --git a/riscv/abstract_device.h b/riscv/abstract_device.h
index 559c64f..c5c6415 100644
--- a/riscv/abstract_device.h
+++ b/riscv/abstract_device.h
@@ -2,14 +2,46 @@
#define _RISCV_ABSTRACT_DEVICE_H
#include "decode.h"
+#include "common.h"
#include <cstdint>
#include <cstddef>
+#include <string>
+#include <map>
+#include <stdexcept>
+
+class sim_t;
class abstract_device_t {
public:
virtual bool load(reg_t addr, size_t len, uint8_t* bytes) = 0;
virtual bool store(reg_t addr, size_t len, const uint8_t* bytes) = 0;
virtual ~abstract_device_t() {}
+ virtual void tick(reg_t UNUSED rtc_ticks) {}
+};
+
+// factory for devices which should show up in the DTS, and can be
+// parameterized by parsing the DTS
+class device_factory_t {
+public:
+ virtual abstract_device_t* parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base) const = 0;
+ virtual std::string generate_dts(const sim_t* sim) const = 0;
+ virtual ~device_factory_t() {}
};
+// Type for holding all registered MMIO plugins by name.
+using mmio_device_map_t = std::map<std::string, const device_factory_t*>;
+
+mmio_device_map_t& mmio_device_map();
+
+#define REGISTER_DEVICE(name, parse, generate) \
+ class name##_factory_t : public device_factory_t { \
+ public: \
+ name##_factory_t() { \
+ std::string str(#name); \
+ if (!mmio_device_map().emplace(str, this).second) throw std::runtime_error("Plugin \"" + str + "\" already registered"); \
+ }; \
+ name##_t* parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base) const override { return parse(fdt, sim, base); } \
+ std::string generate_dts(const sim_t* sim) const override { return generate(sim); } \
+ }; const device_factory_t *name##_factory = new name##_factory_t();
+
#endif
diff --git a/riscv/clint.cc b/riscv/clint.cc
index f27f02c..908ccb6 100644
--- a/riscv/clint.cc
+++ b/riscv/clint.cc
@@ -1,9 +1,12 @@
#include <sys/time.h>
+#include <sstream>
#include "devices.h"
#include "processor.h"
#include "simif.h"
+#include "sim.h"
+#include "dts.h"
-clint_t::clint_t(simif_t* sim, uint64_t freq_hz, bool real_time)
+clint_t::clint_t(const simif_t* sim, uint64_t freq_hz, bool real_time)
: sim(sim), freq_hz(freq_hz), real_time(real_time), mtime(0)
{
struct timeval base;
@@ -12,7 +15,7 @@ clint_t::clint_t(simif_t* sim, uint64_t freq_hz, bool real_time)
real_time_ref_secs = base.tv_sec;
real_time_ref_usecs = base.tv_usec;
- increment(0);
+ tick(0);
}
/* 0000 msip hart 0
@@ -34,7 +37,7 @@ bool clint_t::load(reg_t addr, size_t len, uint8_t* bytes)
if (len > 8)
return false;
- increment(0);
+ tick(0);
if (addr >= MSIP_BASE && addr < MTIMECMP_BASE) {
if (len == 8) {
@@ -90,11 +93,11 @@ bool clint_t::store(reg_t addr, size_t len, const uint8_t* bytes)
} else {
return false;
}
- increment(0);
+ tick(0);
return true;
}
-void clint_t::increment(reg_t inc)
+void clint_t::tick(reg_t rtc_ticks)
{
if (real_time) {
struct timeval now;
@@ -104,7 +107,7 @@ void clint_t::increment(reg_t inc)
diff_usecs = ((now.tv_sec - real_time_ref_secs) * 1000000) + (now.tv_usec - real_time_ref_usecs);
mtime = diff_usecs * freq_hz / 1000000;
} else {
- mtime += inc;
+ mtime += rtc_ticks;
}
for (const auto& [hart_id, hart] : sim->get_harts()) {
@@ -112,3 +115,31 @@ void clint_t::increment(reg_t inc)
hart->state.mip->backdoor_write_with_mask(MIP_MTIP, mtime >= mtimecmp[hart_id] ? MIP_MTIP : 0);
}
}
+
+clint_t* clint_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base) {
+ if (fdt_parse_clint(fdt, base, "riscv,clint0") == 0)
+ return new clint_t(sim,
+ sim->CPU_HZ / sim->INSNS_PER_RTC_TICK,
+ sim->get_cfg().real_time_clint());
+ else
+ return nullptr;
+}
+
+std::string clint_generate_dts(const sim_t* sim) {
+ std::stringstream s;
+ s << std::hex
+ << " clint@" << CLINT_BASE << " {\n"
+ " compatible = \"riscv,clint0\";\n"
+ " interrupts-extended = <" << std::dec;
+ for (size_t i = 0; i < sim->get_cfg().nprocs(); i++)
+ s << "&CPU" << i << "_intc 3 &CPU" << i << "_intc 7 ";
+ reg_t clintbs = CLINT_BASE;
+ reg_t clintsz = CLINT_SIZE;
+ s << std::hex << ">;\n"
+ " reg = <0x" << (clintbs >> 32) << " 0x" << (clintbs & (uint32_t)-1) <<
+ " 0x" << (clintsz >> 32) << " 0x" << (clintsz & (uint32_t)-1) << ">;\n"
+ " };\n";
+ return s.str();
+}
+
+REGISTER_DEVICE(clint, clint_parse_from_fdt, clint_generate_dts)
diff --git a/riscv/debug_module.cc b/riscv/debug_module.cc
index 27dbe66..0f75c5e 100644
--- a/riscv/debug_module.cc
+++ b/riscv/debug_module.cc
@@ -118,10 +118,6 @@ void debug_module_t::reset()
challenge = random();
}
-void debug_module_t::add_device(bus_t *bus) {
- bus->add_device(DEBUG_START, this);
-}
-
bool debug_module_t::load(reg_t addr, size_t len, uint8_t* bytes)
{
addr = DEBUG_START + addr;
diff --git a/riscv/debug_module.h b/riscv/debug_module.h
index 0a62d77..518f119 100644
--- a/riscv/debug_module.h
+++ b/riscv/debug_module.h
@@ -113,8 +113,6 @@ class debug_module_t : public abstract_device_t
debug_module_t(simif_t *sim, const debug_module_config_t &config);
~debug_module_t();
- void add_device(bus_t *bus);
-
bool load(reg_t addr, size_t len, uint8_t* bytes);
bool store(reg_t addr, size_t len, const uint8_t* bytes);
diff --git a/riscv/devices.cc b/riscv/devices.cc
index 81b232d..2c06f78 100644
--- a/riscv/devices.cc
+++ b/riscv/devices.cc
@@ -2,6 +2,12 @@
#include "mmu.h"
#include <stdexcept>
+mmio_device_map_t& mmio_device_map()
+{
+ static mmio_device_map_t device_map;
+ return device_map;
+}
+
void bus_t::add_device(reg_t addr, abstract_device_t* dev)
{
// Searching devices via lower_bound/upper_bound
@@ -51,46 +57,6 @@ std::pair<reg_t, abstract_device_t*> bus_t::find_device(reg_t addr)
return std::make_pair(it->first, it->second);
}
-// Type for holding all registered MMIO plugins by name.
-using mmio_plugin_map_t = std::map<std::string, mmio_plugin_t>;
-
-// Simple singleton instance of an mmio_plugin_map_t.
-static mmio_plugin_map_t& mmio_plugin_map()
-{
- static mmio_plugin_map_t instance;
- return instance;
-}
-
-void register_mmio_plugin(const char* name_cstr,
- const mmio_plugin_t* mmio_plugin)
-{
- std::string name(name_cstr);
- if (!mmio_plugin_map().emplace(name, *mmio_plugin).second) {
- throw std::runtime_error("Plugin \"" + name + "\" already registered!");
- }
-}
-
-mmio_plugin_device_t::mmio_plugin_device_t(const std::string& name,
- const std::string& args)
- : plugin(mmio_plugin_map().at(name)), user_data((*plugin.alloc)(args.c_str()))
-{
-}
-
-mmio_plugin_device_t::~mmio_plugin_device_t()
-{
- (*plugin.dealloc)(user_data);
-}
-
-bool mmio_plugin_device_t::load(reg_t addr, size_t len, uint8_t* bytes)
-{
- return (*plugin.load)(user_data, addr, len, bytes);
-}
-
-bool mmio_plugin_device_t::store(reg_t addr, size_t len, const uint8_t* bytes)
-{
- return (*plugin.store)(user_data, addr, len, bytes);
-}
-
mem_t::mem_t(reg_t size)
: sz(size)
{
diff --git a/riscv/devices.h b/riscv/devices.h
index 02d9e98..b752a21 100644
--- a/riscv/devices.h
+++ b/riscv/devices.h
@@ -2,7 +2,6 @@
#define _RISCV_DEVICES_H
#include "decode.h"
-#include "mmio_plugin.h"
#include "abstract_device.h"
#include "abstract_interrupt_controller.h"
#include "platform.h"
@@ -17,8 +16,8 @@ class simif_t;
class bus_t : public abstract_device_t {
public:
- bool load(reg_t addr, size_t len, uint8_t* bytes);
- bool store(reg_t addr, size_t len, const uint8_t* bytes);
+ bool load(reg_t addr, size_t len, uint8_t* bytes) override;
+ bool store(reg_t addr, size_t len, const uint8_t* bytes) override;
void add_device(reg_t addr, abstract_device_t* dev);
std::pair<reg_t, abstract_device_t*> find_device(reg_t addr);
@@ -30,8 +29,8 @@ class bus_t : public abstract_device_t {
class rom_device_t : public abstract_device_t {
public:
rom_device_t(std::vector<char> data);
- bool load(reg_t addr, size_t len, uint8_t* bytes);
- bool store(reg_t addr, size_t len, const uint8_t* bytes);
+ bool load(reg_t addr, size_t len, uint8_t* bytes) override;
+ bool store(reg_t addr, size_t len, const uint8_t* bytes) override;
const std::vector<char>& contents() { return data; }
private:
std::vector<char> data;
@@ -43,8 +42,8 @@ class mem_t : public abstract_device_t {
mem_t(const mem_t& that) = delete;
~mem_t();
- bool load(reg_t addr, size_t len, uint8_t* bytes) { return load_store(addr, len, bytes, false); }
- bool store(reg_t addr, size_t len, const uint8_t* bytes) { return load_store(addr, len, const_cast<uint8_t*>(bytes), true); }
+ bool load(reg_t addr, size_t len, uint8_t* bytes) override { return load_store(addr, len, bytes, false); }
+ bool store(reg_t addr, size_t len, const uint8_t* bytes) override { return load_store(addr, len, const_cast<uint8_t*>(bytes), true); }
char* contents(reg_t addr);
reg_t size() { return sz; }
void dump(std::ostream& o);
@@ -58,18 +57,18 @@ class mem_t : public abstract_device_t {
class clint_t : public abstract_device_t {
public:
- clint_t(simif_t*, uint64_t freq_hz, bool real_time);
- bool load(reg_t addr, size_t len, uint8_t* bytes);
- bool store(reg_t addr, size_t len, const uint8_t* bytes);
+ clint_t(const simif_t*, uint64_t freq_hz, bool real_time);
+ bool load(reg_t addr, size_t len, uint8_t* bytes) override;
+ bool store(reg_t addr, size_t len, const uint8_t* bytes) override;
size_t size() { return CLINT_SIZE; }
- void increment(reg_t inc);
+ void tick(reg_t rtc_ticks) override;
uint64_t get_mtimecmp(reg_t hartid) { return mtimecmp[hartid]; }
uint64_t get_mtime() { return mtime; }
private:
typedef uint64_t mtime_t;
typedef uint64_t mtimecmp_t;
typedef uint32_t msip_t;
- simif_t* sim;
+ const simif_t* sim;
uint64_t freq_hz;
bool real_time;
uint64_t real_time_ref_secs;
@@ -97,10 +96,10 @@ struct plic_context_t {
class plic_t : public abstract_device_t, public abstract_interrupt_controller_t {
public:
- plic_t(simif_t*, uint32_t ndev);
- bool load(reg_t addr, size_t len, uint8_t* bytes);
- bool store(reg_t addr, size_t len, const uint8_t* bytes);
- void set_interrupt_level(uint32_t id, int lvl);
+ plic_t(const simif_t*, uint32_t ndev);
+ bool load(reg_t addr, size_t len, uint8_t* bytes) override;
+ bool store(reg_t addr, size_t len, const uint8_t* bytes) override;
+ void set_interrupt_level(uint32_t id, int lvl) override;
size_t size() { return PLIC_SIZE; }
private:
std::vector<plic_context_t> contexts;
@@ -127,14 +126,13 @@ class plic_t : public abstract_device_t, public abstract_interrupt_controller_t
class ns16550_t : public abstract_device_t {
public:
- ns16550_t(class bus_t *bus, abstract_interrupt_controller_t *intctrl,
+ ns16550_t(abstract_interrupt_controller_t *intctrl,
uint32_t interrupt_id, uint32_t reg_shift, uint32_t reg_io_width);
- bool load(reg_t addr, size_t len, uint8_t* bytes);
- bool store(reg_t addr, size_t len, const uint8_t* bytes);
- void tick(void);
+ bool load(reg_t addr, size_t len, uint8_t* bytes) override;
+ bool store(reg_t addr, size_t len, const uint8_t* bytes) override;
+ void tick(reg_t rtc_ticks) override;
size_t size() { return NS16550_SIZE; }
private:
- class bus_t *bus;
abstract_interrupt_controller_t *intctrl;
uint32_t interrupt_id;
uint32_t reg_shift;
@@ -158,19 +156,6 @@ class ns16550_t : public abstract_device_t {
static const int MAX_BACKOFF = 16;
};
-class mmio_plugin_device_t : public abstract_device_t {
- public:
- mmio_plugin_device_t(const std::string& name, const std::string& args);
- virtual ~mmio_plugin_device_t() override;
-
- virtual bool load(reg_t addr, size_t len, uint8_t* bytes) override;
- virtual bool store(reg_t addr, size_t len, const uint8_t* bytes) override;
-
- private:
- mmio_plugin_t plugin;
- void* user_data;
-};
-
template<typename T>
void write_little_endian_reg(T* word, reg_t addr, size_t len, const uint8_t* bytes)
{
diff --git a/riscv/dts.cc b/riscv/dts.cc
index 200288e..cc65e3c 100644
--- a/riscv/dts.cc
+++ b/riscv/dts.cc
@@ -17,7 +17,8 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz,
const char* bootargs,
size_t pmpregions,
std::vector<processor_t*> procs,
- std::vector<std::pair<reg_t, mem_t*>> mems)
+ std::vector<std::pair<reg_t, mem_t*>> mems,
+ std::string device_nodes)
{
std::stringstream s;
s << std::dec <<
@@ -85,47 +86,8 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz,
" #size-cells = <2>;\n"
" compatible = \"ucbbar,spike-bare-soc\", \"simple-bus\";\n"
" ranges;\n"
- " clint@" << CLINT_BASE << " {\n"
- " compatible = \"riscv,clint0\";\n"
- " interrupts-extended = <" << std::dec;
- for (size_t i = 0; i < procs.size(); i++)
- s << "&CPU" << i << "_intc 3 &CPU" << i << "_intc 7 ";
- reg_t clintbs = CLINT_BASE;
- reg_t clintsz = CLINT_SIZE;
- s << std::hex << ">;\n"
- " reg = <0x" << (clintbs >> 32) << " 0x" << (clintbs & (uint32_t)-1) <<
- " 0x" << (clintsz >> 32) << " 0x" << (clintsz & (uint32_t)-1) << ">;\n"
- " };\n"
- " PLIC: plic@" << PLIC_BASE << " {\n"
- " compatible = \"riscv,plic0\";\n"
- " #address-cells = <2>;\n"
- " interrupts-extended = <" << std::dec;
- for (size_t i = 0; i < procs.size(); i++)
- s << "&CPU" << i << "_intc 11 &CPU" << i << "_intc 9 ";
- reg_t plicbs = PLIC_BASE;
- reg_t plicsz = PLIC_SIZE;
- s << std::hex << ">;\n"
- " reg = <0x" << (plicbs >> 32) << " 0x" << (plicbs & (uint32_t)-1) <<
- " 0x" << (plicsz >> 32) << " 0x" << (plicsz & (uint32_t)-1) << ">;\n"
- " riscv,ndev = <0x" << PLIC_NDEV << ">;\n"
- " riscv,max-priority = <0x" << ((1U << PLIC_PRIO_BITS) - 1) << ">;\n"
- " #interrupt-cells = <1>;\n"
- " interrupt-controller;\n"
- " };\n"
- " SERIAL0: ns16550@" << NS16550_BASE << " {\n"
- " compatible = \"ns16550a\";\n"
- " clock-frequency = <" << std::dec << (cpu_hz/insns_per_rtc_tick) << ">;\n"
- " interrupt-parent = <&PLIC>;\n"
- " interrupts = <" << std::dec << NS16550_INTERRUPT_ID;
- reg_t ns16550bs = NS16550_BASE;
- reg_t ns16550sz = NS16550_SIZE;
- s << std::hex << ">;\n"
- " reg = <0x" << (ns16550bs >> 32) << " 0x" << (ns16550bs & (uint32_t)-1) <<
- " 0x" << (ns16550sz >> 32) << " 0x" << (ns16550sz & (uint32_t)-1) << ">;\n"
- " reg-shift = <0x" << NS16550_REG_SHIFT << ">;\n"
- " reg-io-width = <0x" << NS16550_REG_IO_WIDTH << ">;\n"
- " };\n"
- " };\n"
+ << device_nodes
+ << " };\n"
" htif {\n"
" compatible = \"ucb,htif0\";\n"
" };\n"
@@ -215,8 +177,8 @@ std::string dts_compile(const std::string& dts)
return dtb.str();
}
-static int fdt_get_node_addr_size(void *fdt, int node, reg_t *addr,
- unsigned long *size, const char *field)
+int fdt_get_node_addr_size(const void *fdt, int node, reg_t *addr,
+ unsigned long *size, const char *field)
{
int parent, len, i;
int cell_addr, cell_size;
@@ -259,7 +221,7 @@ static int fdt_get_node_addr_size(void *fdt, int node, reg_t *addr,
return 0;
}
-static int check_cpu_node(void *fdt, int cpu_offset)
+static int check_cpu_node(const void *fdt, int cpu_offset)
{
int len;
const void *prop;
@@ -276,22 +238,22 @@ static int check_cpu_node(void *fdt, int cpu_offset)
return 0;
}
-int fdt_get_offset(void *fdt, const char *field)
+int fdt_get_offset(const void *fdt, const char *field)
{
return fdt_path_offset(fdt, field);
}
-int fdt_get_first_subnode(void *fdt, int node)
+int fdt_get_first_subnode(const void *fdt, int node)
{
return fdt_first_subnode(fdt, node);
}
-int fdt_get_next_subnode(void *fdt, int node)
+int fdt_get_next_subnode(const void *fdt, int node)
{
return fdt_next_subnode(fdt, node);
}
-int fdt_parse_clint(void *fdt, reg_t *clint_addr,
+int fdt_parse_clint(const void *fdt, reg_t *clint_addr,
const char *compatible)
{
int nodeoffset, rc;
@@ -307,7 +269,7 @@ int fdt_parse_clint(void *fdt, reg_t *clint_addr,
return 0;
}
-int fdt_parse_plic(void *fdt, reg_t *plic_addr, uint32_t *ndev,
+int fdt_parse_plic(const void *fdt, reg_t *plic_addr, uint32_t *ndev,
const char *compatible)
{
int nodeoffset, len, rc;
@@ -329,8 +291,9 @@ int fdt_parse_plic(void *fdt, reg_t *plic_addr, uint32_t *ndev,
return 0;
}
-int fdt_parse_ns16550(void *fdt, reg_t *ns16550_addr,
+int fdt_parse_ns16550(const void *fdt, reg_t *ns16550_addr,
uint32_t *reg_shift, uint32_t *reg_io_width,
+ uint32_t* reg_int_id,
const char *compatible)
{
int nodeoffset, len, rc;
@@ -362,10 +325,19 @@ int fdt_parse_ns16550(void *fdt, reg_t *ns16550_addr,
}
}
+ reg_p = (fdt32_t *)fdt_getprop(fdt, nodeoffset, "interrupts", &len);
+ if (reg_int_id) {
+ if (reg_p) {
+ *reg_int_id = fdt32_to_cpu(*reg_p);
+ } else {
+ *reg_int_id = NS16550_INTERRUPT_ID;
+ }
+ }
+
return 0;
}
-int fdt_parse_pmp_num(void *fdt, int cpu_offset, reg_t *pmp_num)
+int fdt_parse_pmp_num(const void *fdt, int cpu_offset, reg_t *pmp_num)
{
int rc;
@@ -380,7 +352,7 @@ int fdt_parse_pmp_num(void *fdt, int cpu_offset, reg_t *pmp_num)
return 0;
}
-int fdt_parse_pmp_alignment(void *fdt, int cpu_offset, reg_t *pmp_align)
+int fdt_parse_pmp_alignment(const void *fdt, int cpu_offset, reg_t *pmp_align)
{
int rc;
@@ -395,7 +367,7 @@ int fdt_parse_pmp_alignment(void *fdt, int cpu_offset, reg_t *pmp_align)
return 0;
}
-int fdt_parse_mmu_type(void *fdt, int cpu_offset, const char **mmu_type)
+int fdt_parse_mmu_type(const void *fdt, int cpu_offset, const char **mmu_type)
{
assert(mmu_type);
diff --git a/riscv/dts.h b/riscv/dts.h
index 7a64d7b..7ec1ceb 100644
--- a/riscv/dts.h
+++ b/riscv/dts.h
@@ -4,7 +4,6 @@
#include "devices.h"
#include "processor.h"
-#include "mmu.h"
#include <string>
std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz,
@@ -12,22 +11,25 @@ std::string make_dts(size_t insns_per_rtc_tick, size_t cpu_hz,
const char* bootargs,
size_t pmpregions,
std::vector<processor_t*> procs,
- std::vector<std::pair<reg_t, mem_t*>> mems);
+ std::vector<std::pair<reg_t, mem_t*>> mems,
+ std::string device_nodes);
std::string dts_compile(const std::string& dts);
-int fdt_get_offset(void *fdt, const char *field);
-int fdt_get_first_subnode(void *fdt, int node);
-int fdt_get_next_subnode(void *fdt, int node);
+int fdt_get_node_addr_size(const void *fdt, int node, reg_t *addr,
+ unsigned long *size, const char *field);
+int fdt_get_offset(const void *fdt, const char *field);
+int fdt_get_first_subnode(const void *fdt, int node);
+int fdt_get_next_subnode(const void *fdt, int node);
-int fdt_parse_clint(void *fdt, reg_t *clint_addr,
+int fdt_parse_clint(const void *fdt, reg_t *clint_addr,
const char *compatible);
-int fdt_parse_plic(void *fdt, reg_t *plic_addr, uint32_t *ndev,
+int fdt_parse_plic(const void *fdt, reg_t *plic_addr, uint32_t *ndev,
const char *compatible);
-int fdt_parse_ns16550(void *fdt, reg_t *ns16550_addr,
- uint32_t *reg_shift, uint32_t *reg_io_width,
+int fdt_parse_ns16550(const void *fdt, reg_t *ns16550_addr,
+ uint32_t *reg_shift, uint32_t *reg_io_width, uint32_t* reg_int_id,
const char *compatible);
-int fdt_parse_pmp_num(void *fdt, int cpu_offset, reg_t *pmp_num);
-int fdt_parse_pmp_alignment(void *fdt, int cpu_offset, reg_t *pmp_align);
-int fdt_parse_mmu_type(void *fdt, int cpu_offset, const char **mmu_type);
+int fdt_parse_pmp_num(const void *fdt, int cpu_offset, reg_t *pmp_num);
+int fdt_parse_pmp_alignment(const void *fdt, int cpu_offset, reg_t *pmp_align);
+int fdt_parse_mmu_type(const void *fdt, int cpu_offset, const char **mmu_type);
#endif
diff --git a/riscv/mmio_plugin.h b/riscv/mmio_plugin.h
deleted file mode 100644
index f14470b..0000000
--- a/riscv/mmio_plugin.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef _RISCV_MMIO_PLUGIN_H
-#define _RISCV_MMIO_PLUGIN_H
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-typedef uint64_t reg_t;
-
-typedef struct {
- // Allocate user data for an instance of the plugin. The parameter is a simple
- // c-string containing arguments used to construct the plugin. It returns a
- // void* to the allocated data.
- void* (*alloc)(const char*);
-
- // Load a memory address of the MMIO plugin. The parameters are the user_data
- // (void*), memory offset (reg_t), number of bytes to load (size_t), and the
- // buffer into which the loaded data should be written (uint8_t*). Return true
- // if the load is successful and false otherwise.
- bool (*load)(void*, reg_t, size_t, uint8_t*);
-
- // Store some bytes to a memory address of the MMIO plugin. The parameters are
- // the user_data (void*), memory offset (reg_t), number of bytes to store
- // (size_t), and the buffer containing the data to be stored (const uint8_t*).
- // Return true if the store is successful and false otherwise.
- bool (*store)(void*, reg_t, size_t, const uint8_t*);
-
- // Deallocate the data allocated during the call to alloc. The parameter is a
- // pointer to the user data allocated during the call to alloc.
- void (*dealloc)(void*);
-} mmio_plugin_t;
-
-// Register an mmio plugin with the application. This should be called by
-// plugins as part of their loading process.
-extern void register_mmio_plugin(const char* name_cstr,
- const mmio_plugin_t* mmio_plugin);
-
-#ifdef __cplusplus
-}
-
-#include <string>
-
-// Wrapper around the C plugin API that makes registering a C++ class with
-// correctly formed constructor, load, and store functions easier. The template
-// type should be the type that implements the MMIO plugin interface. Simply
-// make a global mmio_plugin_registration_t and your plugin should register
-// itself with the application when it is loaded because the
-// mmio_plugin_registration_t constructor will be called.
-template <typename T>
-struct mmio_plugin_registration_t
-{
- static void* alloc(const char* args)
- {
- return reinterpret_cast<void*>(new T(std::string(args)));
- }
-
- static bool load(void* self, reg_t addr, size_t len, uint8_t* bytes)
- {
- return reinterpret_cast<T*>(self)->load(addr, len, bytes);
- }
-
- static bool store(void* self, reg_t addr, size_t len, const uint8_t* bytes)
- {
- return reinterpret_cast<T*>(self)->store(addr, len, bytes);
- }
-
- static void dealloc(void* self)
- {
- delete reinterpret_cast<T*>(self);
- }
-
- mmio_plugin_registration_t(const std::string& name)
- {
- mmio_plugin_t plugin = {
- mmio_plugin_registration_t<T>::alloc,
- mmio_plugin_registration_t<T>::load,
- mmio_plugin_registration_t<T>::store,
- mmio_plugin_registration_t<T>::dealloc,
- };
-
- register_mmio_plugin(name.c_str(), &plugin);
- }
-};
-#endif // __cplusplus
-
-#endif
diff --git a/riscv/ns16550.cc b/riscv/ns16550.cc
index 8d7e4de..dabe3a9 100644
--- a/riscv/ns16550.cc
+++ b/riscv/ns16550.cc
@@ -1,7 +1,10 @@
#include <sys/time.h>
+#include <sstream>
#include "devices.h"
#include "processor.h"
#include "term.h"
+#include "sim.h"
+#include "dts.h"
#define UART_QUEUE_SIZE 64
@@ -69,9 +72,9 @@
#define UART_SCR 7 /* I/O: Scratch Register */
-ns16550_t::ns16550_t(class bus_t *bus, abstract_interrupt_controller_t *intctrl,
+ns16550_t::ns16550_t(abstract_interrupt_controller_t *intctrl,
uint32_t interrupt_id, uint32_t reg_shift, uint32_t reg_io_width)
- : bus(bus), intctrl(intctrl), interrupt_id(interrupt_id), reg_shift(reg_shift), reg_io_width(reg_io_width), backoff_counter(0)
+ : intctrl(intctrl), interrupt_id(interrupt_id), reg_shift(reg_shift), reg_io_width(reg_io_width), backoff_counter(0)
{
ier = 0;
iir = UART_IIR_NO_INT;
@@ -292,7 +295,7 @@ bool ns16550_t::store(reg_t addr, size_t len, const uint8_t* bytes)
return ret;
}
-void ns16550_t::tick(void)
+void ns16550_t::tick(reg_t UNUSED rtc_ticks)
{
if (!(fcr & UART_FCR_ENABLE_FIFO) ||
(mcr & UART_MCR_LOOP) ||
@@ -317,3 +320,38 @@ void ns16550_t::tick(void)
lsr |= UART_LSR_DR;
update_interrupt();
}
+
+std::string ns16550_generate_dts(const sim_t* sim)
+{
+ std::stringstream s;
+ s << std::hex
+ << " SERIAL0: ns16550@" << NS16550_BASE << " {\n"
+ " compatible = \"ns16550a\";\n"
+ " clock-frequency = <" << std::dec << (sim->CPU_HZ/sim->INSNS_PER_RTC_TICK) << ">;\n"
+ " interrupt-parent = <&PLIC>;\n"
+ " interrupts = <" << std::dec << NS16550_INTERRUPT_ID;
+ reg_t ns16550bs = NS16550_BASE;
+ reg_t ns16550sz = NS16550_SIZE;
+ s << std::hex << ">;\n"
+ " reg = <0x" << (ns16550bs >> 32) << " 0x" << (ns16550bs & (uint32_t)-1) <<
+ " 0x" << (ns16550sz >> 32) << " 0x" << (ns16550sz & (uint32_t)-1) << ">;\n"
+ " reg-shift = <0x" << NS16550_REG_SHIFT << ">;\n"
+ " reg-io-width = <0x" << NS16550_REG_IO_WIDTH << ">;\n"
+ " };\n";
+ return s.str();
+}
+
+ns16550_t* ns16550_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base)
+{
+ uint32_t ns16550_shift, ns16550_io_width, ns16550_int_id;
+ if (fdt_parse_ns16550(fdt, base,
+ &ns16550_shift, &ns16550_io_width, &ns16550_int_id,
+ "ns16550a") == 0) {
+ abstract_interrupt_controller_t* intctrl = sim->get_intctrl();
+ return new ns16550_t(intctrl, ns16550_int_id, ns16550_shift, ns16550_io_width);
+ } else {
+ return nullptr;
+ }
+}
+
+REGISTER_DEVICE(ns16550, ns16550_parse_from_fdt, ns16550_generate_dts)
diff --git a/riscv/plic.cc b/riscv/plic.cc
index 37a5f53..1aa5852 100644
--- a/riscv/plic.cc
+++ b/riscv/plic.cc
@@ -1,7 +1,10 @@
#include <sys/time.h>
+#include <sstream>
#include "devices.h"
#include "processor.h"
#include "simif.h"
+#include "sim.h"
+#include "dts.h"
#define PLIC_MAX_CONTEXTS 15872
@@ -70,7 +73,7 @@
#define REG_SIZE 0x1000000
-plic_t::plic_t(simif_t* sim, uint32_t ndev)
+plic_t::plic_t(const simif_t* sim, uint32_t ndev)
: num_ids(ndev + 1), num_ids_word(((ndev + 1) + (32 - 1)) / 32),
max_prio((1UL << PLIC_PRIO_BITS) - 1), priority{}, level{}
{
@@ -388,3 +391,37 @@ bool plic_t::store(reg_t addr, size_t len, const uint8_t* bytes)
return ret;
}
+
+std::string plic_generate_dts(const sim_t* sim)
+{
+ std::stringstream s;
+ s << std::hex
+ << " PLIC: plic@" << PLIC_BASE << " {\n"
+ " compatible = \"riscv,plic0\";\n"
+ " #address-cells = <2>;\n"
+ " interrupts-extended = <" << std::dec;
+ for (size_t i = 0; i < sim->get_cfg().nprocs(); i++)
+ s << "&CPU" << i << "_intc 11 &CPU" << i << "_intc 9 ";
+ reg_t plicbs = PLIC_BASE;
+ reg_t plicsz = PLIC_SIZE;
+ s << std::hex << ">;\n"
+ " reg = <0x" << (plicbs >> 32) << " 0x" << (plicbs & (uint32_t)-1) <<
+ " 0x" << (plicsz >> 32) << " 0x" << (plicsz & (uint32_t)-1) << ">;\n"
+ " riscv,ndev = <0x" << PLIC_NDEV << ">;\n"
+ " riscv,max-priority = <0x" << ((1U << PLIC_PRIO_BITS) - 1) << ">;\n"
+ " #interrupt-cells = <1>;\n"
+ " interrupt-controller;\n"
+ " };\n";
+ return s.str();
+}
+
+plic_t* plic_parse_from_fdt(const void* fdt, const sim_t* sim, reg_t* base)
+{
+ uint32_t plic_ndev;
+ if (fdt_parse_plic(fdt, base, &plic_ndev, "riscv,plic0") == 0)
+ return new plic_t(sim, plic_ndev);
+ else
+ return nullptr;
+}
+
+REGISTER_DEVICE(plic, plic_parse_from_fdt, plic_generate_dts)
diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in
index a3e125f..1ad8b23 100644
--- a/riscv/riscv.mk.in
+++ b/riscv/riscv.mk.in
@@ -28,13 +28,13 @@ riscv_install_hdrs = \
decode.h \
devices.h \
disasm.h \
+ dts.h \
encoding.h \
entropy_source.h \
extension.h \
isa_parser.h \
log_file.h \
memtracer.h \
- mmio_plugin.h \
mmu.h \
platform.h \
processor.h \
diff --git a/riscv/sim.cc b/riscv/sim.cc
index dcbd469..0779b95 100644
--- a/riscv/sim.cc
+++ b/riscv/sim.cc
@@ -32,9 +32,13 @@ static void handle_signal(int sig)
const size_t sim_t::INTERLEAVE;
+extern device_factory_t* clint_factory;
+extern device_factory_t* plic_factory;
+extern device_factory_t* ns16550_factory;
+
sim_t::sim_t(const cfg_t *cfg, bool halted,
std::vector<std::pair<reg_t, mem_t*>> mems,
- std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices,
+ std::vector<const device_factory_t*> plugin_device_factories,
const std::vector<std::string>& args,
const debug_module_config_t &dm_config,
const char *log_path,
@@ -45,7 +49,6 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
isa(cfg->isa(), cfg->priv()),
cfg(cfg),
mems(mems),
- plugin_devices(plugin_devices),
procs(std::max(cfg->nprocs(), size_t(1))),
dtb_enabled(dtb_enabled),
log_file(log_path),
@@ -66,10 +69,7 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
for (auto& x : mems)
bus.add_device(x.first, x.second);
- for (auto& x : plugin_devices)
- bus.add_device(x.first, x.second);
-
- debug_module.add_device(&bus);
+ bus.add_device(DEBUG_START, &debug_module);
socketif = NULL;
#ifdef HAVE_BOOST_ASIO
@@ -89,9 +89,9 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
#ifndef RISCV_ENABLE_DUAL_ENDIAN
if (cfg->endianness != endianness_little) {
fputs("Big-endian support has not been prroperly enabled; "
- "please rebuild the riscv-isa-sim project using "
- "\"configure --enable-dual-endian\".\n",
- stderr);
+ "please rebuild the riscv-isa-sim project using "
+ "\"configure --enable-dual-endian\".\n",
+ stderr);
abort();
}
#endif
@@ -107,45 +107,73 @@ sim_t::sim_t(const cfg_t *cfg, bool halted,
// When running without using a dtb, skip the fdt-based configuration steps
if (!dtb_enabled) return;
- // Load dtb_file if provided, otherwise self-generate a dts/dtb
- make_dtb(dtb_file);
-
- void *fdt = (void *)dtb.c_str();
-
- // Only make a CLINT (Core-Local INTerrupt controller) if one is specified in
- // the device tree configuration.
+ // Only make a CLINT (Core-Local INTerrupt controller) and PLIC (Platform-
+ // Level-Interrupt-Controller) if they are specified in the device tree
+ // configuration.
//
// This isn't *quite* as general as we could get (because you might have one
// that's not bus-accessible), but it should handle the normal use cases. In
// particular, the default device tree configuration that you get without
// setting the dtb_file argument has one.
- reg_t clint_base;
- if (fdt_parse_clint(fdt, &clint_base, "riscv,clint0") == 0) {
- clint.reset(new clint_t(this, CPU_HZ / INSNS_PER_RTC_TICK, cfg->real_time_clint()));
- bus.add_device(clint_base, clint.get());
- }
+ std::vector<const device_factory_t*> device_factories = {
+ clint_factory, // clint must be element 0
+ plic_factory, // plic must be element 1
+ ns16550_factory};
+ device_factories.insert(device_factories.end(),
+ plugin_device_factories.begin(),
+ plugin_device_factories.end());
- // pointer to wired interrupt controller
- abstract_interrupt_controller_t *intctrl = NULL;
+ // Load dtb_file if provided, otherwise self-generate a dts/dtb
+ if (dtb_file) {
+ std::ifstream fin(dtb_file, std::ios::binary);
+ if (!fin.good()) {
+ std::cerr << "can't find dtb file: " << dtb_file << std::endl;
+ exit(-1);
+ }
+ std::stringstream strstream;
+ strstream << fin.rdbuf();
+ dtb = strstream.str();
+ } else {
+ std::pair<reg_t, reg_t> initrd_bounds = cfg->initrd_bounds();
+ std::string device_nodes;
+ for (const device_factory_t *factory : device_factories)
+ device_nodes.append(factory->generate_dts(this));
+ dts = make_dts(INSNS_PER_RTC_TICK, CPU_HZ,
+ initrd_bounds.first, initrd_bounds.second,
+ cfg->bootargs(), cfg->pmpregions, procs, mems,
+ device_nodes);
+ dtb = dts_compile(dts);
+ }
- // create plic
- reg_t plic_base;
- uint32_t plic_ndev;
- if (fdt_parse_plic(fdt, &plic_base, &plic_ndev, "riscv,plic0") == 0) {
- plic.reset(new plic_t(this, plic_ndev));
- bus.add_device(plic_base, plic.get());
- intctrl = plic.get();
+ int fdt_code = fdt_check_header(dtb.c_str());
+ if (fdt_code) {
+ std::cerr << "Failed to read DTB from ";
+ if (!dtb_file) {
+ std::cerr << "auto-generated DTS string";
+ } else {
+ std::cerr << "`" << dtb_file << "'";
+ }
+ std::cerr << ": " << fdt_strerror(fdt_code) << ".\n";
+ exit(-1);
}
- // create ns16550
- reg_t ns16550_base;
- uint32_t ns16550_shift, ns16550_io_width;
- if (fdt_parse_ns16550(fdt, &ns16550_base,
- &ns16550_shift, &ns16550_io_width, "ns16550a") == 0) {
- assert(intctrl);
- ns16550.reset(new ns16550_t(&bus, intctrl, NS16550_INTERRUPT_ID,
- ns16550_shift, ns16550_io_width));
- bus.add_device(ns16550_base, ns16550.get());
+ void *fdt = (void *)dtb.c_str();
+
+ for (size_t i = 0; i < device_factories.size(); i++) {
+ const device_factory_t *factory = device_factories[i];
+ reg_t device_base = 0;
+ abstract_device_t* device = factory->parse_from_fdt(fdt, this, &device_base);
+ if (device) {
+ assert(device_base);
+ bus.add_device(device_base, device);
+ std::shared_ptr<abstract_device_t> dev_ptr(device);
+ devices.push_back(dev_ptr);
+
+ if (i == 0) // clint_factory
+ clint = std::static_pointer_cast<clint_t>(dev_ptr);
+ else if (i == 1) // plic_factory
+ plic = std::static_pointer_cast<plic_t>(dev_ptr);
+ }
}
//per core attribute
@@ -242,8 +270,8 @@ void sim_t::step(size_t n)
procs[current_proc]->get_mmu()->yield_load_reservation();
if (++current_proc == procs.size()) {
current_proc = 0;
- if (clint) clint->increment(INTERLEAVE / INSNS_PER_RTC_TICK);
- if (ns16550) ns16550->tick();
+ reg_t rtc_ticks = INTERLEAVE / INSNS_PER_RTC_TICK;
+ for (auto &dev : devices) dev->tick(rtc_ticks);
}
}
}
@@ -299,40 +327,6 @@ bool sim_t::mmio_store(reg_t paddr, size_t len, const uint8_t* bytes)
return bus.store(paddr, len, bytes);
}
-void sim_t::make_dtb(const char* dtb_file)
-{
- if (dtb_file) {
- std::ifstream fin(dtb_file, std::ios::binary);
- if (!fin.good()) {
- std::cerr << "can't find dtb file: " << dtb_file << std::endl;
- exit(-1);
- }
-
- std::stringstream strstream;
- strstream << fin.rdbuf();
-
- dtb = strstream.str();
- } else {
- std::pair<reg_t, reg_t> initrd_bounds = cfg->initrd_bounds();
- dts = make_dts(INSNS_PER_RTC_TICK, CPU_HZ,
- initrd_bounds.first, initrd_bounds.second,
- cfg->bootargs(), cfg->pmpregions, procs, mems);
- dtb = dts_compile(dts);
- }
-
- int fdt_code = fdt_check_header(dtb.c_str());
- if (fdt_code) {
- std::cerr << "Failed to read DTB from ";
- if (!dtb_file) {
- std::cerr << "auto-generated DTS string";
- } else {
- std::cerr << "`" << dtb_file << "'";
- }
- std::cerr << ": " << fdt_strerror(fdt_code) << ".\n";
- exit(-1);
- }
-}
-
void sim_t::set_rom()
{
const int reset_vec_size = 8;
@@ -374,8 +368,9 @@ void sim_t::set_rom()
const int align = 0x1000;
rom.resize((rom.size() + align - 1) / align * align);
- boot_rom.reset(new rom_device_t(rom));
+ std::shared_ptr<rom_device_t> boot_rom(new rom_device_t(rom));
bus.add_device(DEFAULT_RSTVEC, boot_rom.get());
+ devices.push_back(boot_rom);
}
char* sim_t::addr_to_mem(reg_t paddr) {
diff --git a/riscv/sim.h b/riscv/sim.h
index 3109173..a3445db 100644
--- a/riscv/sim.h
+++ b/riscv/sim.h
@@ -27,7 +27,7 @@ class sim_t : public htif_t, public simif_t
public:
sim_t(const cfg_t *cfg, bool halted,
std::vector<std::pair<reg_t, mem_t*>> mems,
- std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices,
+ std::vector<const device_factory_t*> plugin_device_factories,
const std::vector<std::string>& args,
const debug_module_config_t &dm_config, const char *log_path,
bool dtb_enabled, const char *dtb_file,
@@ -52,6 +52,7 @@ public:
}
const char* get_dts() { return dts.c_str(); }
processor_t* get_core(size_t i) { return procs.at(i); }
+ abstract_interrupt_controller_t* get_intctrl() const { assert(plic.get()); return plic.get(); }
virtual const cfg_t &get_cfg() const override { return *cfg; }
virtual const std::map<size_t, processor_t*>& get_harts() const override { return harts; }
@@ -59,21 +60,23 @@ public:
// Callback for processors to let the simulation know they were reset.
virtual void proc_reset(unsigned id) override;
+ static const size_t INTERLEAVE = 5000;
+ static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core
+ static const size_t CPU_HZ = 1000000000; // 1GHz CPU
+
private:
isa_parser_t isa;
const cfg_t * const cfg;
std::vector<std::pair<reg_t, mem_t*>> mems;
- std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices;
std::vector<processor_t*> procs;
std::map<size_t, processor_t*> harts;
std::pair<reg_t, reg_t> initrd_range;
std::string dts;
std::string dtb;
bool dtb_enabled;
- std::unique_ptr<rom_device_t> boot_rom;
- std::unique_ptr<clint_t> clint;
- std::unique_ptr<plic_t> plic;
- std::unique_ptr<ns16550_t> ns16550;
+ std::vector<std::shared_ptr<abstract_device_t>> devices;
+ std::shared_ptr<clint_t> clint;
+ std::shared_ptr<plic_t> plic;
bus_t bus;
log_file_t log_file;
@@ -84,9 +87,6 @@ private:
processor_t* get_core(const std::string& i);
void step(size_t n); // step through simulation
- static const size_t INTERLEAVE = 5000;
- static const size_t INSNS_PER_RTC_TICK = 100; // 10 MHz clock for 1 BIPS core
- static const size_t CPU_HZ = 1000000000; // 1GHz CPU
size_t current_step;
size_t current_proc;
bool debug;
@@ -99,7 +99,6 @@ private:
virtual char* addr_to_mem(reg_t paddr) override;
virtual bool mmio_load(reg_t paddr, size_t len, uint8_t* bytes) override;
virtual bool mmio_store(reg_t paddr, size_t len, const uint8_t* bytes) override;
- void make_dtb(const char* dtb_file);
void set_rom();
virtual const char* get_symbol(uint64_t paddr) override;
diff --git a/spike_main/spike.cc b/spike_main/spike.cc
index 7290f38..4766f6d 100644
--- a/spike_main/spike.cc
+++ b/spike_main/spike.cc
@@ -50,12 +50,7 @@ static void help(int exit_code = 1)
fprintf(stderr, " --l2=<S>:<W>:<B> B both powers of 2).\n");
fprintf(stderr, " --big-endian Use a big-endian memory system.\n");
fprintf(stderr, " --misaligned Support misaligned memory accesses\n");
- fprintf(stderr, " --device=<P,B,A> Attach MMIO plugin device from an --extlib library\n");
- fprintf(stderr, " P -- Name of the MMIO plugin\n");
- fprintf(stderr, " B -- Base memory address of the device\n");
- fprintf(stderr, " A -- String arguments to pass to the plugin\n");
- fprintf(stderr, " This flag can be used multiple times.\n");
- fprintf(stderr, " The extlib flag for the library must come first.\n");
+ fprintf(stderr, " --device=<name> Attach MMIO plugin device from an --extlib library\n");
fprintf(stderr, " --log-cache-miss Generate a log of cache miss\n");
fprintf(stderr, " --log-commits Generate a log of commits info\n");
fprintf(stderr, " --extension=<name> Specify RoCC Extension\n");
@@ -336,7 +331,7 @@ int main(int argc, char** argv)
bool dtb_enabled = true;
const char* kernel = NULL;
reg_t kernel_offset, kernel_size;
- std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices;
+ std::vector<const device_factory_t*> plugin_device_factories;
std::unique_ptr<icache_sim_t> ic;
std::unique_ptr<dcache_sim_t> dc;
std::unique_ptr<cache_sim_t> l2;
@@ -376,47 +371,12 @@ int main(int argc, char** argv)
/*default_real_time_clint=*/false,
/*default_trigger_count=*/4);
- auto const device_parser = [&plugin_devices](const char *s) {
- const std::string str(s);
- std::istringstream stream(str);
-
- // We are parsing a string like name,base,args.
-
- // Parse the name, which is simply all of the characters leading up to the
- // first comma. The validity of the plugin name will be checked later.
- std::string name;
- std::getline(stream, name, ',');
- if (name.empty()) {
- throw std::runtime_error("Plugin name is empty.");
- }
-
- // Parse the base address. First, get all of the characters up to the next
- // comma (or up to the end of the string if there is no comma). Then try to
- // parse that string as an integer according to the rules of strtoull. It
- // could be in decimal, hex, or octal. Fail if we were able to parse a
- // number but there were garbage characters after the valid number. We must
- // consume the entire string between the commas.
- std::string base_str;
- std::getline(stream, base_str, ',');
- if (base_str.empty()) {
- throw std::runtime_error("Device base address is empty.");
- }
- char* end;
- reg_t base = static_cast<reg_t>(strtoull(base_str.c_str(), &end, 0));
- if (end != &*base_str.cend()) {
- throw std::runtime_error("Error parsing device base address.");
- }
-
- // The remainder of the string is the arguments. We could use getline, but
- // that could ignore newline characters in the arguments. That should be
- // rare and discouraged, but handle it here anyway with this weird in_avail
- // technique. The arguments are optional, so if there were no arguments
- // specified we could end up with an empty string here. That's okay.
- auto avail = stream.rdbuf()->in_avail();
- std::string args(avail, '\0');
- stream.readsome(&args[0], avail);
-
- plugin_devices.emplace_back(base, new mmio_plugin_device_t(name, args));
+ auto const device_parser = [&plugin_device_factories](const char *s) {
+ const std::string name(s);
+ if (name.empty()) throw std::runtime_error("Plugin name is empty.");
+ auto it = mmio_device_map().find(name);
+ if (it == mmio_device_map().end()) throw std::runtime_error("Plugin \"" + name + "\" not found in loaded extlibs.");
+ plugin_device_factories.push_back(it->second);
};
option_parser_t parser;
@@ -564,7 +524,7 @@ int main(int argc, char** argv)
}
sim_t s(&cfg, halted,
- mems, plugin_devices, htif_args, dm_config, log_path, dtb_enabled, dtb_file,
+ mems, plugin_device_factories, htif_args, dm_config, log_path, dtb_enabled, dtb_file,
socket,
cmd_file);
std::unique_ptr<remote_bitbang_t> remote_bitbang((remote_bitbang_t *) NULL);
@@ -602,8 +562,5 @@ int main(int argc, char** argv)
for (auto& mem : mems)
delete mem.second;
- for (auto& plugin_device : plugin_devices)
- delete plugin_device.second;
-
return return_code;
}