diff options
author | Jerry Zhao <jerryz123@berkeley.edu> | 2023-06-20 13:03:56 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-20 13:03:56 -0700 |
commit | d8b6fc534fb5f3b668410489e2d9cf4c48c9e1da (patch) | |
tree | 63b330ca79cb41df6c958e12054b33f6482381bd | |
parent | d2cfddd1141ba95adcfc9617e7767513f0f47146 (diff) | |
parent | b87c6e64d0dba9edf7dc070f9e4a29016641c3a1 (diff) | |
download | riscv-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.c | 2 | ||||
-rw-r--r-- | fdt/fdt.mk.in | 5 | ||||
-rw-r--r-- | riscv/abstract_device.h | 32 | ||||
-rw-r--r-- | riscv/clint.cc | 43 | ||||
-rw-r--r-- | riscv/debug_module.cc | 4 | ||||
-rw-r--r-- | riscv/debug_module.h | 2 | ||||
-rw-r--r-- | riscv/devices.cc | 46 | ||||
-rw-r--r-- | riscv/devices.h | 53 | ||||
-rw-r--r-- | riscv/dts.cc | 80 | ||||
-rw-r--r-- | riscv/dts.h | 26 | ||||
-rw-r--r-- | riscv/mmio_plugin.h | 91 | ||||
-rw-r--r-- | riscv/ns16550.cc | 44 | ||||
-rw-r--r-- | riscv/plic.cc | 39 | ||||
-rw-r--r-- | riscv/riscv.mk.in | 2 | ||||
-rw-r--r-- | riscv/sim.cc | 147 | ||||
-rw-r--r-- | riscv/sim.h | 19 | ||||
-rw-r--r-- | spike_main/spike.cc | 61 |
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; } |