aboutsummaryrefslogtreecommitdiff
path: root/riscv/devices.h
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/devices.h')
-rw-r--r--riscv/devices.h77
1 files changed, 77 insertions, 0 deletions
diff --git a/riscv/devices.h b/riscv/devices.h
index 08e9c45..bccda34 100644
--- a/riscv/devices.h
+++ b/riscv/devices.h
@@ -4,8 +4,10 @@
#include "decode.h"
#include "mmio_plugin.h"
#include "abstract_device.h"
+#include "abstract_interrupt_controller.h"
#include "platform.h"
#include <map>
+#include <queue>
#include <vector>
#include <utility>
@@ -74,6 +76,81 @@ class clint_t : public abstract_device_t {
std::vector<mtimecmp_t> mtimecmp;
};
+#define PLIC_MAX_DEVICES 1024
+
+struct plic_context {
+ uint32_t num;
+ processor_t *proc;
+ bool mmode;
+
+ uint8_t priority_threshold;
+ uint32_t enable[PLIC_MAX_DEVICES/32];
+ uint32_t pending[PLIC_MAX_DEVICES/32];
+ uint8_t pending_priority[PLIC_MAX_DEVICES];
+ uint32_t claimed[PLIC_MAX_DEVICES/32];
+};
+typedef struct plic_context plic_context_t;
+
+class plic_t : public abstract_device_t, public abstract_interrupt_controller_t {
+ public:
+ plic_t(std::vector<processor_t*>&, bool smode, 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);
+ size_t size() { return PLIC_SIZE; }
+ private:
+ std::vector<processor_t*>& procs;
+ std::vector<plic_context_t> contexts;
+ uint32_t num_ids;
+ uint32_t num_ids_word;
+ uint32_t max_prio;
+ uint8_t priority[PLIC_MAX_DEVICES];
+ uint32_t level[PLIC_MAX_DEVICES/32];
+ uint32_t context_best_pending(plic_context_t *c);
+ void context_update(plic_context_t *context);
+ uint32_t context_claim(plic_context_t *c);
+ bool priority_read(reg_t offset, uint32_t *val);
+ bool priority_write(reg_t offset, uint32_t val);
+ bool context_enable_read(plic_context_t *context,
+ reg_t offset, uint32_t *val);
+ bool context_enable_write(plic_context_t *context,
+ reg_t offset, uint32_t val);
+ bool context_read(plic_context_t *context,
+ reg_t offset, uint32_t *val);
+ bool context_write(plic_context_t *context,
+ reg_t offset, uint32_t val);
+};
+
+class ns16550_t : public abstract_device_t {
+ public:
+ ns16550_t(class bus_t *bus, 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);
+ size_t size() { return NS16550_SIZE; }
+ private:
+ class bus_t *bus;
+ abstract_interrupt_controller_t *intctrl;
+ uint32_t interrupt_id;
+ uint32_t reg_shift;
+ uint32_t reg_io_width;
+ std::queue<uint8_t> rx_queue;
+ uint8_t dll;
+ uint8_t dlm;
+ uint8_t iir;
+ uint8_t ier;
+ uint8_t fcr;
+ uint8_t lcr;
+ uint8_t mcr;
+ uint8_t lsr;
+ uint8_t msr;
+ uint8_t scr;
+ void update_interrupt(void);
+ uint8_t rx_byte(void);
+ void tx_byte(uint8_t val);
+};
+
class mmio_plugin_device_t : public abstract_device_t {
public:
mmio_plugin_device_t(const std::string& name, const std::string& args);