aboutsummaryrefslogtreecommitdiff
path: root/qtmips_machine/memory.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'qtmips_machine/memory.cpp')
-rw-r--r--qtmips_machine/memory.cpp137
1 files changed, 137 insertions, 0 deletions
diff --git a/qtmips_machine/memory.cpp b/qtmips_machine/memory.cpp
new file mode 100644
index 0000000..25deab0
--- /dev/null
+++ b/qtmips_machine/memory.cpp
@@ -0,0 +1,137 @@
+#include "memory.h"
+
+void MemoryAccess::write_hword(std::uint32_t offset, std::uint16_t value) {
+ this->write_byte(offset++, (std::uint8_t)value);
+ this->write_byte(offset, (std::uint8_t)(value >> 8));
+}
+
+void MemoryAccess::write_word(std::uint32_t offset, std::uint32_t value) {
+ this->write_byte(offset++, (std::uint8_t)value);
+ this->write_byte(offset++, (std::uint8_t)(value >> 8));
+ this->write_byte(offset++, (std::uint8_t)(value >> 16));
+ this->write_byte(offset++, (std::uint8_t)(value >> 24));
+}
+
+std::uint16_t MemoryAccess::read_hword(std::uint32_t offset) {
+ std::uint16_t dt = 0;
+ dt |= this->read_byte(offset++);
+ dt |= (this->read_byte(offset) << 8);
+ return dt;
+}
+
+std::uint32_t MemoryAccess::read_word(std::uint32_t offset) {
+ std::uint32_t dt = 0;
+ dt |= this->read_byte(offset++);
+ dt |= (this->read_byte(offset++) << 8);
+ dt |= (this->read_byte(offset++) << 16);
+ dt |= (this->read_byte(offset) << 24);
+ return dt;
+}
+
+MemorySection::MemorySection(std::uint32_t length) {
+ this->length = length;
+ this->dt = new std::uint8_t[length];
+}
+
+MemorySection::~MemorySection() {
+ delete this->dt;
+}
+
+using namespace std;
+
+void MemorySection::write_byte(std::uint32_t offset, std::uint8_t value) {
+ if (offset >= this->length)
+ throw QTMIPS_EXCEPTION(OutOfMemoryAccess, "Trying to write outside of the memory section", std::string("Accessing using offset: ") + std::to_string(offset));
+ this->dt[offset] = value;
+}
+
+std::uint8_t MemorySection::read_byte(std::uint32_t offset) {
+ if (offset >= this->length)
+ throw QTMIPS_EXCEPTION(OutOfMemoryAccess, "Trying to read outside of the memory section", std::string("Accessing using offset: ") + std::to_string(offset));
+ return this->dt[offset];
+}
+
+// Number of bites per row on lookup tree
+#define MEMORY_TREE_ROW ((32 - MEMORY_SECTION_BITS) / MEMORY_TREE_H)
+// Size of row in memory lookup tree
+#define MEMORY_TREE_LEN (1 << MEMORY_TREE_ROW)
+// Just do some sanity checks
+#if (MEMORY_TREE_LEN == 0)
+#error Nonzero memory tree row size
+#endif
+#if (((32 - MEMORY_SECTION_BITS) % MEMORY_TREE_H) != 0)
+#error Memory tree is not fully divisible by memory tree height
+#endif
+#if (MEMORY_TREE_H < 2)
+#error Memory tree have to be higher or in limit equal to two
+#endif
+
+union MemoryTree {
+ union MemoryTree *mt;
+ MemorySection *sec;
+};
+
+Memory::Memory() {
+ this->mt_root = allocate_section_tree();
+}
+
+Memory::~Memory() {
+ // Free up memory tree
+ // TODO
+}
+
+union MemoryTree *Memory::allocate_section_tree() {
+ union MemoryTree *mt = new union MemoryTree[MEMORY_TREE_LEN];
+ for (size_t i = 0; i < MEMORY_TREE_LEN; i++)
+ // Note that this also nulls sec pointer as those are both pointers and so they have same size
+ mt[i].mt = nullptr;
+ return mt;
+}
+
+// Create address mask with section length
+#define ADDRESS_MASK(LEN) ((1 << LEN) - 1)
+
+// Get index in tree node from address, length of row and tree depth
+// ADDR is expected to be and address with lowest bites removed (MEMORY_SECTION_BITS)
+#define ADDRESS_TREE_INDEX(DEPTH, ADDR) ((ADDR >> (DEPTH * MEMORY_TREE_ROW)) & ADDRESS_MASK(MEMORY_TREE_ROW))
+
+
+MemorySection *Memory::get_section(std::uint32_t address, bool create) {
+ std::uint32_t addr = address >> MEMORY_SECTION_BITS; // drop all bits for addressing inside of the section
+ union MemoryTree *w = this->mt_root;
+ size_t ii;
+ for (int i = 0; i < (MEMORY_TREE_H - 1); i++) {
+ ii = ADDRESS_TREE_INDEX(i, addr);
+ if (w[ii].mt == nullptr) { // We don't have this tree so allocate it
+ if (!create) // If we shouldn't be creating it than just return null
+ return nullptr;
+ w[ii].mt = allocate_section_tree();
+ }
+ w = w[ii].mt;
+ }
+ // Now expand last level
+ ii = ADDRESS_TREE_INDEX((MEMORY_TREE_H - 1), addr);
+ if (w[ii].sec == nullptr) {
+ if (!create)
+ return nullptr;
+ w[ii].sec = new MemorySection(1 << MEMORY_SECTION_BITS);
+ }
+ return w[ii].sec;
+}
+
+// Note about this address magic: we want to mask upper bits in address as those were used
+// for section lookup. We do it using (2^BITS - 1).
+#define SECTION_ADDRESS(ADDR) (ADDR & ADDRESS_MASK(MEMORY_SECTION_BITS))
+
+void Memory::write_byte(std::uint32_t address, std::uint8_t value) {
+ MemorySection *section = this->get_section(address, true);
+ section->write_byte(SECTION_ADDRESS(address), value);
+}
+
+std::uint8_t Memory::read_byte(std::uint32_t address) {
+ MemorySection *section = this->get_section(address, true);
+ if (section == nullptr)
+ return 0;
+ else
+ return section->read_byte(SECTION_ADDRESS(address));
+}