aboutsummaryrefslogtreecommitdiff
path: root/riscv/devices.cc
diff options
context:
space:
mode:
Diffstat (limited to 'riscv/devices.cc')
-rw-r--r--riscv/devices.cc53
1 files changed, 43 insertions, 10 deletions
diff --git a/riscv/devices.cc b/riscv/devices.cc
index 6c78456..fb476ec 100644
--- a/riscv/devices.cc
+++ b/riscv/devices.cc
@@ -1,5 +1,6 @@
#include "devices.h"
#include "mmu.h"
+#include <stdexcept>
void bus_t::add_device(reg_t addr, abstract_device_t* dev)
{
@@ -90,17 +91,49 @@ bool mmio_plugin_device_t::store(reg_t addr, size_t len, const uint8_t* bytes)
return (*plugin.store)(user_data, addr, len, bytes);
}
-char* mem_t::contents() {
- return data;
+mem_t::mem_t(reg_t size)
+ : sz(size)
+{
+ if (size == 0 || size % PGSIZE != 0)
+ throw std::runtime_error("memory size must be a positive multiple of 4 KiB");
+}
+
+mem_t::~mem_t()
+{
+ for (auto& entry : sparse_memory_map)
+ free(entry.second);
+}
+
+bool mem_t::load_store(reg_t addr, size_t len, uint8_t* bytes, bool store)
+{
+ if (addr + len < addr || addr + len > sz)
+ return false;
+
+ while (len > 0) {
+ auto n = std::min(PGSIZE - (addr % PGSIZE), len);
+
+ if (store)
+ memcpy(this->contents(addr), bytes, n);
+ else
+ memcpy(bytes, this->contents(addr), n);
+
+ addr += n;
+ bytes += n;
+ len -= n;
+ }
+
+ return true;
}
char* mem_t::contents(reg_t addr) {
- reg_t pg_idx = addr & ~reg_t(PGSIZE - 1);
- auto search = acc_tbl.find(pg_idx);
- if (search == acc_tbl.end() || !search->second.second) {
- char* mem_ptr = (char*)calloc(PGSIZE, sizeof(char));
- acc_tbl[pg_idx] = std::make_pair(mem_ptr, true);
- }
- auto offset = addr & (PGSIZE - 1);
- return acc_tbl[pg_idx].first + offset;
+ reg_t ppn = addr >> PGSHIFT, pgoff = addr % PGSIZE;
+ auto search = sparse_memory_map.find(ppn);
+ if (search == sparse_memory_map.end()) {
+ auto res = (char*)calloc(PGSIZE, 1);
+ if (res == nullptr)
+ throw std::bad_alloc();
+ sparse_memory_map[ppn] = res;
+ return res + pgoff;
+ }
+ return search->second + pgoff;
}