aboutsummaryrefslogtreecommitdiff
path: root/riscv
diff options
context:
space:
mode:
authorAaron Jones <aaron@vexing.codes>2019-07-21 16:08:37 -0600
committerAaron Jones <aaron@vexing.codes>2019-07-22 11:34:33 -0600
commitd184cd4dbfb1c863ae9f1e7c4c263ac626706351 (patch)
treed919b85827e8e3dfd957ff817286177ad7f59555 /riscv
parent88a852836acb4c7166b1aa4102e11354bfd99234 (diff)
downloadspike-d184cd4dbfb1c863ae9f1e7c4c263ac626706351.zip
spike-d184cd4dbfb1c863ae9f1e7c4c263ac626706351.tar.gz
spike-d184cd4dbfb1c863ae9f1e7c4c263ac626706351.tar.bz2
Implement MMIO device plugins.
Diffstat (limited to 'riscv')
-rw-r--r--riscv/devices.cc40
-rw-r--r--riscv/devices.h14
-rw-r--r--riscv/mmio_plugin.h91
-rw-r--r--riscv/riscv.mk.in3
-rw-r--r--riscv/sim.cc12
-rw-r--r--riscv/sim.h2
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;