diff options
author | Aaron Jones <aaron@vexing.codes> | 2019-07-21 16:08:37 -0600 |
---|---|---|
committer | Aaron Jones <aaron@vexing.codes> | 2019-07-22 11:34:33 -0600 |
commit | d184cd4dbfb1c863ae9f1e7c4c263ac626706351 (patch) | |
tree | d919b85827e8e3dfd957ff817286177ad7f59555 /riscv | |
parent | 88a852836acb4c7166b1aa4102e11354bfd99234 (diff) | |
download | spike-d184cd4dbfb1c863ae9f1e7c4c263ac626706351.zip spike-d184cd4dbfb1c863ae9f1e7c4c263ac626706351.tar.gz spike-d184cd4dbfb1c863ae9f1e7c4c263ac626706351.tar.bz2 |
Implement MMIO device plugins.
Diffstat (limited to 'riscv')
-rw-r--r-- | riscv/devices.cc | 40 | ||||
-rw-r--r-- | riscv/devices.h | 14 | ||||
-rw-r--r-- | riscv/mmio_plugin.h | 91 | ||||
-rw-r--r-- | riscv/riscv.mk.in | 3 | ||||
-rw-r--r-- | riscv/sim.cc | 12 | ||||
-rw-r--r-- | riscv/sim.h | 2 |
6 files changed, 158 insertions, 4 deletions
diff --git a/riscv/devices.cc b/riscv/devices.cc index bcdd3a1..4b768b6 100644 --- a/riscv/devices.cc +++ b/riscv/devices.cc @@ -48,3 +48,43 @@ std::pair<reg_t, abstract_device_t*> bus_t::find_device(reg_t addr) it--; 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); +} diff --git a/riscv/devices.h b/riscv/devices.h index 4e4d27f..aa4c050 100644 --- a/riscv/devices.h +++ b/riscv/devices.h @@ -2,6 +2,7 @@ #define _RISCV_DEVICES_H #include "decode.h" +#include "mmio_plugin.h" #include <cstdlib> #include <string> #include <map> @@ -76,4 +77,17 @@ class clint_t : public abstract_device_t { std::vector<mtimecmp_t> mtimecmp; }; +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; +}; + #endif diff --git a/riscv/mmio_plugin.h b/riscv/mmio_plugin.h new file mode 100644 index 0000000..f14470b --- /dev/null +++ b/riscv/mmio_plugin.h @@ -0,0 +1,91 @@ +#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/riscv.mk.in b/riscv/riscv.mk.in index 3057c7d..af5bbdc 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -20,6 +20,7 @@ riscv_hdrs = \ encoding.h \ cachesim.h \ memtracer.h \ + mmio_plugin.h \ tracer.h \ extension.h \ rocc.h \ @@ -29,6 +30,8 @@ riscv_hdrs = \ remote_bitbang.h \ jtag_dtm.h \ +riscv_install_hdrs = mmio_plugin.h + riscv_precompiled_hdrs = \ insn_template.h \ diff --git a/riscv/sim.cc b/riscv/sim.cc index 2eb623a..ffed440 100644 --- a/riscv/sim.cc +++ b/riscv/sim.cc @@ -26,19 +26,23 @@ static void handle_signal(int sig) sim_t::sim_t(const char* isa, const char* varch, size_t nprocs, bool halted, reg_t start_pc, std::vector<std::pair<reg_t, mem_t*>> mems, + std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices, const std::vector<std::string>& args, std::vector<int> const hartids, const debug_module_config_t &dm_config) - : htif_t(args), mems(mems), procs(std::max(nprocs, size_t(1))), - start_pc(start_pc), current_step(0), current_proc(0), debug(false), - histogram_enabled(false), dtb_enabled(true), remote_bitbang(NULL), - debug_module(this, dm_config) + : htif_t(args), mems(mems), plugin_devices(plugin_devices), + procs(std::max(nprocs, size_t(1))), start_pc(start_pc), current_step(0), + current_proc(0), debug(false), histogram_enabled(false), dtb_enabled(true), + remote_bitbang(NULL), debug_module(this, dm_config) { signal(SIGINT, &handle_signal); 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); debug_mmu = new mmu_t(this, NULL); diff --git a/riscv/sim.h b/riscv/sim.h index a2bdd1c..57d1148 100644 --- a/riscv/sim.h +++ b/riscv/sim.h @@ -23,6 +23,7 @@ class sim_t : public htif_t, public simif_t public: sim_t(const char* isa, const char* varch, size_t _nprocs, bool halted, reg_t start_pc, std::vector<std::pair<reg_t, mem_t*>> mems, + std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices, const std::vector<std::string>& args, const std::vector<int> hartids, const debug_module_config_t &dm_config); ~sim_t(); @@ -48,6 +49,7 @@ public: private: std::vector<std::pair<reg_t, mem_t*>> mems; + std::vector<std::pair<reg_t, abstract_device_t*>> plugin_devices; mmu_t* debug_mmu; // debug port into main memory std::vector<processor_t*> procs; reg_t start_pc; |