diff --git a/CMakeLists.txt b/CMakeLists.txt
index 68e338c..eb89f72 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,12 +33,14 @@ list(APPEND RUNTIME_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/hardware/CPU.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/RAM.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/hardware/BUS.cpp
)
list(APPEND DEBUGGER_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/debugger/debugger_main.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/CPU.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/RAM.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/hardware/BUS.cpp
)
list(APPEND ASSEMBLER_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/assembler/assembler_main.cpp
@@ -49,6 +51,7 @@ list(APPEND TOOLS_SOURCE_FILES
list(APPEND TEST_SOURCE_FILES
${CMAKE_CURRENT_LIST_DIR}/src/RAM_test.cpp
${CMAKE_CURRENT_LIST_DIR}/src/hardware/RAM.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/src/hardware/BUS.cpp
)
#-----------------------------------------------------------------------------------------
diff --git a/other/build.nr b/other/build.nr
index ec63514..f599e28 100644
--- a/other/build.nr
+++ b/other/build.nr
@@ -1 +1 @@
-9
+10
diff --git a/src/common/Data.hpp b/src/common/Data.hpp
new file mode 100644
index 0000000..adf90ae
--- /dev/null
+++ b/src/common/Data.hpp
@@ -0,0 +1,35 @@
+/*
+ DragonV2 - A collection of useful functionality
+ Copyright (C) 2026 OmniaX-Dev
+
+ This file is part of DragonV2.
+
+ DragonV2 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DragonV2 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DragonV2. If not, see .
+*/
+
+#pragma once
+
+#include
+#include
+
+namespace dragon
+{
+ // ------ Contextual Aliases ------
+ using AddressType = u32;
+ using VirtualAddress = AddressType;
+ using PhysycalAddress = AddressType;
+ // --------------------------------
+
+ enum class MMUAccessType { Read, Write, Execute };
+}
diff --git a/src/hardware/BUS.cpp b/src/hardware/BUS.cpp
new file mode 100644
index 0000000..39c9eba
--- /dev/null
+++ b/src/hardware/BUS.cpp
@@ -0,0 +1,148 @@
+/*
+ DragonV2 - A collection of useful functionality
+ Copyright (C) 2026 OmniaX-Dev
+
+ This file is part of DragonV2.
+
+ DragonV2 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DragonV2 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DragonV2. If not, see .
+*/
+
+#include "BUS.hpp"
+
+namespace dragon
+{
+ AtomicStorageMemoryDevice::AtomicStorageMemoryDevice(u64 size)
+ {
+ if (size == 0) // Special case, for classes like BUS, that are MemoryDevices but don't own any data
+ {
+ m_wordCount = 0;
+ m_size = 0;
+ m_words = nullptr;
+ return;
+ }
+ m_wordCount = (size + 7) / 8; // Round up to multiple of 8 bytes for the word-granular backing
+ m_size = size;
+ m_words = new std::atomic[m_wordCount];
+ for (u64 i = 0; i < m_wordCount; ++i)
+ m_words[i].store(0, std::memory_order_relaxed);
+ }
+
+ AtomicStorageMemoryDevice::~AtomicStorageMemoryDevice(void)
+ {
+ delete[] m_words;
+ }
+
+ bool MemoryDevice::guest_cas_u32(AddressType addr, u32 expected, u32& actual, u32 desired)
+ {
+ fault(addr, 4, "CAS not supported on this device");
+ return false;
+ }
+
+
+
+
+
+ namespace hw
+ {
+ bool BUS::guest_cas_u32(PhysycalAddress addr, u32 expected, u32& actual, u32 desired)
+ {
+ auto region = findRegion(addr);
+ if (!region) { /* fault */ return false; }
+ AddressType finalAddr = (region->remap ? addr - region->startAddress : addr);
+ return region->device->guest_cas_u32(finalAddr, expected, actual, desired);
+ }
+
+ u8 BUS::load_u8(PhysycalAddress addr) const
+ {
+ auto region = findRegion(addr);
+ if (region == nullptr) return 0x00; //TODO: Error
+ AddressType finalAddr = (region->remap ? addr - region->startAddress : addr);
+ return region->device->load_u8(finalAddr);
+ }
+
+ u16 BUS::load_u16(PhysycalAddress addr) const
+ {
+ auto region = findRegion(addr);
+ if (region == nullptr) return 0x0000; //TODO: Error
+ AddressType finalAddr = (region->remap ? addr - region->startAddress : addr);
+ return region->device->load_u16(finalAddr);
+ }
+
+ u32 BUS::load_u32(PhysycalAddress addr) const
+ {
+ auto region = findRegion(addr);
+ if (region == nullptr) return 0x0000'0000; //TODO: Error
+ AddressType finalAddr = (region->remap ? addr - region->startAddress : addr);
+ return region->device->load_u32(finalAddr);
+ }
+
+ u64 BUS::load_u64(PhysycalAddress addr) const
+ {
+ auto region = findRegion(addr);
+ if (region == nullptr) return 0x0000'0000'0000'0000; //TODO: Error
+ AddressType finalAddr = (region->remap ? addr - region->startAddress : addr);
+ return region->device->load_u64(finalAddr);
+ }
+
+ bool BUS::store_u8(PhysycalAddress addr, u8 value)
+ {
+ auto region = findRegion(addr);
+ if (region == nullptr) return false;
+ AddressType finalAddr = (region->remap ? addr - region->startAddress : addr);
+ return region->device->store_u8(finalAddr, value);
+ }
+
+ bool BUS::store_u16(PhysycalAddress addr, u16 value)
+ {
+ auto region = findRegion(addr);
+ if (region == nullptr) return false;
+ AddressType finalAddr = (region->remap ? addr - region->startAddress : addr);
+ return region->device->store_u16(finalAddr, value);
+ }
+
+ bool BUS::store_u32(PhysycalAddress addr, u32 value)
+ {
+ auto region = findRegion(addr);
+ if (region == nullptr) return false;
+ AddressType finalAddr = (region->remap ? addr - region->startAddress : addr);
+ return region->device->store_u32(finalAddr, value);
+ }
+
+ bool BUS::store_u64(PhysycalAddress addr, u64 value)
+ {
+ auto region = findRegion(addr);
+ if (region == nullptr) return false;
+ AddressType finalAddr = (region->remap ? addr - region->startAddress : addr);
+ return region->device->store_u64(finalAddr, value);
+ }
+
+ void BUS::mapDevice(MemoryDevice& device, PhysycalAddress startAddr, PhysycalAddress endAddr, bool remap, ostd::String name)
+ {
+ m_regions.push_back({ &device, startAddr, endAddr, remap, name });
+ }
+
+ ostd::String BUS::getMemoryRegionName(PhysycalAddress address)
+ {
+ tMemoryRegion* region = findRegion(address);
+ if (region == nullptr) return "Invalid";
+ return region->name;
+ }
+
+ void BUS::fault(PhysycalAddress addr, u32 size, const String& msg) const
+ {
+ std::cout << msg << ostd::String::getHexStr(addr, true, 4) << "\n";
+ /* TODO: This function basically only has to deal with the "region not mapped" problem. */
+ }
+ }
+}
diff --git a/src/hardware/BUS.hpp b/src/hardware/BUS.hpp
new file mode 100644
index 0000000..c01b8ad
--- /dev/null
+++ b/src/hardware/BUS.hpp
@@ -0,0 +1,144 @@
+/*
+ DragonV2 - A collection of useful functionality
+ Copyright (C) 2026 OmniaX-Dev
+
+ This file is part of DragonV2.
+
+ DragonV2 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DragonV2 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DragonV2. If not, see .
+*/
+
+#include
+#include
+#include "../common/Data.hpp"
+
+#pragma once
+
+namespace dragon
+{
+ class MemoryDevice : public ostd::BaseObject
+ {
+ public:
+ MemoryDevice(void) = default;
+ MemoryDevice(const MemoryDevice&) = delete;
+ MemoryDevice& operator=(const MemoryDevice&) = delete;
+ MemoryDevice(MemoryDevice&&) = delete;
+ MemoryDevice& operator=(MemoryDevice&&) = delete;
+ virtual ~MemoryDevice() = default;
+
+ virtual bool guest_cas_u32(AddressType addr, u32 expected, u32& actual, u32 desired);
+
+ // ---- Aligned loads ----
+ virtual u64 load_u64(AddressType addr) const = 0;
+ virtual u32 load_u32(AddressType addr) const = 0;
+ virtual u16 load_u16(u32 addr) const = 0;
+ virtual u8 load_u8 (u32 addr) const = 0;
+
+ inline i64 load_i64(AddressType addr) const { return cast(load_u64(addr)); }
+ inline i32 load_i32(AddressType addr) const { return cast(load_u32(addr)); }
+ inline i16 load_i16(AddressType addr) const { return cast(load_u16(addr)); }
+ inline i8 load_i8 (AddressType addr) const { return cast(load_u8 (addr)); }
+
+ // ---- Aligned stores ----
+ virtual bool store_u64(AddressType addr, u64 value) = 0;
+ virtual bool store_u32(AddressType addr, u32 value) = 0;
+ virtual bool store_u16(AddressType addr, u16 value) = 0;
+ virtual bool store_u8 (AddressType addr, u8 value) = 0;
+
+ inline bool store_i64(AddressType addr, u64 value) { return store_u64(addr, cast(value)); }
+ inline bool store_i32(AddressType addr, u32 value) { return store_u32(addr, cast(value)); }
+ inline bool store_i16(AddressType addr, u16 value) { return store_u16(addr, cast(value)); }
+ inline bool store_i8 (AddressType addr, u8 value) { return store_u8 (addr, cast(value)); }
+
+ [[noreturn]] virtual void fault(AddressType addr, u32 size, const String& msg = "") const = 0; // Message can be useful for debugging
+
+ };
+
+ class AtomicStorageMemoryDevice : public MemoryDevice
+ {
+ public:
+ explicit AtomicStorageMemoryDevice(u64 size);
+ virtual ~AtomicStorageMemoryDevice(void);
+ AtomicStorageMemoryDevice(const AtomicStorageMemoryDevice&) = delete;
+ AtomicStorageMemoryDevice& operator=(const AtomicStorageMemoryDevice&) = delete;
+ AtomicStorageMemoryDevice(AtomicStorageMemoryDevice&&) = delete;
+ AtomicStorageMemoryDevice& operator=(AtomicStorageMemoryDevice&&) = delete;
+
+ // ---- Helpers ----
+ inline u64 getWordCount(void) const { return m_wordCount; }
+ inline u64 getSize(void) const { return m_size; }
+ inline virtual std::span> getRawData(void) { return { m_words, m_size }; }
+ inline virtual std::span> getRawData(void) const { return { m_words, m_size }; }
+ // Both getRawData() can be overridden to return empty spans for devices where internal memory shouldn't be exposed
+
+ protected:
+ std::atomic* m_words;
+ u64 m_wordCount;
+ u64 m_size;
+ };
+ namespace hw
+ {
+ class BUS : public MemoryDevice
+ {
+ public:
+ private: struct tMemoryRegion
+ {
+ MemoryDevice* device { nullptr };
+ PhysycalAddress startAddress { 0x0000'0000 };
+ PhysycalAddress endAddress { 0x0000'0000 };
+ bool remap { false };
+ ostd::String name { "" };
+ };
+
+ public:
+ BUS(void) = default;
+
+ bool guest_cas_u32(PhysycalAddress addr, u32 expected, u32& actual, u32 desired) override;
+
+ // ---- Aligned loads ----
+ u64 load_u64(PhysycalAddress addr) const override;
+ u32 load_u32(PhysycalAddress addr) const override;
+ u16 load_u16(PhysycalAddress addr) const override;
+ u8 load_u8 (PhysycalAddress addr) const override;
+
+ // ---- Aligned stores ----
+ bool store_u64(PhysycalAddress addr, u64 value) override;
+ bool store_u32(PhysycalAddress addr, u32 value) override;
+ bool store_u16(PhysycalAddress addr, u16 value) override;
+ bool store_u8 (PhysycalAddress addr, u8 value) override;
+
+ void mapDevice(MemoryDevice& device, PhysycalAddress startAddr, PhysycalAddress endAddr, bool remap = false, ostd::String name = "");
+ ostd::String getMemoryRegionName(PhysycalAddress address);
+
+ [[noreturn]] void fault(PhysycalAddress addr, u32 size, const String& msg) const override;
+
+ private:
+ template
+ auto findRegion(this Self&& self, PhysycalAddress address)
+ {
+ for (auto& region : self.m_regions)
+ { // works whether self is const or not
+ if (address >= region.startAddress && address <= region.endAddress)
+ return ®ion;
+ }
+ self.fault(address, 0, "Memory device not found: ");
+ return decltype(&self.m_regions[0]){nullptr};
+ }
+
+ private:
+ std::vector m_regions;
+
+ private:
+ };
+ }
+}
diff --git a/src/hardware/CPU.hpp b/src/hardware/CPU.hpp
index a0a9fa5..4ddf05b 100644
--- a/src/hardware/CPU.hpp
+++ b/src/hardware/CPU.hpp
@@ -20,10 +20,16 @@
#pragma once
-#include
+#include "../common/Data.hpp"
namespace dragon
{
+ struct GuestException
+ {
+ // ExceptionCause cause;
+ VirtualAddress fault_addr; // VA for translation faults, PA for bus faults, 0 otherwise
+ u32 faulting_pc; // set by the CPU before fault propagation, not by the throwsite
+ };
namespace hw
{
class CPU
diff --git a/src/hardware/MMU.cpp b/src/hardware/MMU.cpp
new file mode 100644
index 0000000..a4a810a
--- /dev/null
+++ b/src/hardware/MMU.cpp
@@ -0,0 +1,68 @@
+/*
+ DragonV2 - A collection of useful functionality
+ Copyright (C) 2026 OmniaX-Dev
+
+ This file is part of DragonV2.
+
+ DragonV2 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DragonV2 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DragonV2. If not, see .
+*/
+
+#include "MMU.hpp"
+
+namespace dragon
+{
+ namespace hw
+ {
+ }
+}
+
+
+
+// PhysycalAddress MMU::translate(VirtualAddress va, AccessType type, Mode mode)
+// {
+// if (!m_enabled) return va; // identity map when disabled
+
+// u32 l1_idx = (va >> 22) & 0x3FF;
+// u32 l2_idx = (va >> 12) & 0x3FF;
+// u32 offset = va & 0xFFF;
+
+// // Walk level 1
+// u32 l1_pte_addr = m_ptb + l1_idx * 4;
+// u32 l1_pte = ram.load_u32(l1_pte_addr);
+// if (!(l1_pte & PTE_PRESENT))
+// throw GuestException{cause_for(type, PageFault), va};
+
+// // Walk level 2
+// u32 l2_table_phys = (l1_pte >> 12) << 12; // physical address of L2 table
+// u32 l2_pte_addr = l2_table_phys + l2_idx * 4;
+// u32 l2_pte = ram.load_u32(l2_pte_addr);
+// if (!(l2_pte & PTE_PRESENT))
+// throw GuestException{cause_for(type, PageFault), va};
+
+// // Permission check
+// if (mode == Mode::User && !(l2_pte & PTE_USER))
+// throw GuestException{cause_for(type, PrivPageFault), va};
+// if (type == AccessType::Read && !(l2_pte & PTE_READ)) throw GuestException{...};
+// if (type == AccessType::Write && !(l2_pte & PTE_WRITE)) throw GuestException{...};
+// if (type == AccessType::Execute && !(l2_pte & PTE_EXEC)) throw GuestException{...};
+
+// // Set accessed bit (atomic so we don't race with other cores walking the same PTE)
+// if (!(l2_pte & PTE_ACCESSED)) {
+// // CAS to set the bit; ignore failure (means someone else set it)
+// ram.guest_cas_u32(l2_pte_addr, l2_pte, l2_pte | PTE_ACCESSED);
+// }
+
+// u32 phys_page = (l2_pte >> 12) << 12;
+// return phys_page | offset;
+// }
diff --git a/src/hardware/MMU.hpp b/src/hardware/MMU.hpp
new file mode 100644
index 0000000..3c78471
--- /dev/null
+++ b/src/hardware/MMU.hpp
@@ -0,0 +1,37 @@
+/*
+ DragonV2 - A collection of useful functionality
+ Copyright (C) 2026 OmniaX-Dev
+
+ This file is part of DragonV2.
+
+ DragonV2 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DragonV2 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DragonV2. If not, see .
+*/
+
+#pragma once
+
+#include "BUS.hpp"
+
+namespace dragon
+{
+ namespace hw
+ {
+ class MMU : public MemoryDevice
+ {
+ public:
+ explicit MMU(void);
+
+
+ };
+ }
+}
diff --git a/src/hardware/RAM.cpp b/src/hardware/RAM.cpp
index e35bda1..1be41bf 100644
--- a/src/hardware/RAM.cpp
+++ b/src/hardware/RAM.cpp
@@ -26,35 +26,55 @@ namespace dragon
{
namespace hw
{
- RAM::RAM(u64 size)
+ bool RAM::guest_cas_u32(PhysycalAddress addr, u32 expected, u32& actual, u32 desired)
{
- m_wordCount = (size + 7) / 8; // Round up to multiple of 8 bytes for the word-granular backing
- m_size = size;
- m_words = new std::atomic[m_wordCount];
- for (u64 i = 0; i < m_wordCount; ++i)
- m_words[i].store(0, std::memory_order_relaxed);
+ if (addr + 4 > m_size || (addr & 3))
+ {
+ fault(addr, 4, "Misaligned/OOB CAS");
+ return false;
+ }
+
+ u32 shift = (addr & 4) * 8;
+ u64 mask = u64(0xFFFFFFFFu) << shift;
+ std::atomic& word = m_words[addr >> 3];
+
+ u64 word_expected = word.load(std::memory_order_seq_cst);
+ while (true)
+ {
+ u32 current_in_slot = static_cast(word_expected >> shift);
+ if (current_in_slot != expected)
+ {
+ // CAS fails: report what we saw, don't modify
+ actual = current_in_slot;
+ return false;
+ }
+ // CAS could succeed: try to update
+ u64 word_desired = (word_expected & ~mask) | (u64(desired) << shift);
+ if (word.compare_exchange_weak(word_expected, word_desired, std::memory_order_seq_cst, std::memory_order_seq_cst))
+ {
+ actual = expected; // tell caller we succeeded
+ return true;
+ }
+ // CAS spuriously failed or someone else changed the word; word_expected
+ // is updated. Loop and re-check.
+ }
}
- RAM::~RAM(void)
- {
- delete[] m_words;
- }
-
- u64 RAM::load_u64(u32 addr) const
+ u64 RAM::load_u64(PhysycalAddress addr) const
{
if (addr + 8 > m_size || (addr & 7))
{
- fault(addr, 8);
+ fault(addr, 8, "Memory Fault: ");
return 0;
}
return m_words[addr >> 3].load(std::memory_order_seq_cst);
}
- u32 RAM::load_u32(u32 addr) const
+ u32 RAM::load_u32(PhysycalAddress addr) const
{
if (addr + 4 > m_size || (addr & 3))
{
- fault(addr, 4);
+ fault(addr, 4, "Memory Fault: ");
return 0;
}
u64 word = m_words[addr >> 3].load(std::memory_order_seq_cst);
@@ -62,11 +82,11 @@ namespace dragon
return static_cast(word >> shift);
}
- u16 RAM::load_u16(u32 addr) const
+ u16 RAM::load_u16(PhysycalAddress addr) const
{
if (addr + 2 > m_size || (addr & 1))
{
- fault(addr, 2);
+ fault(addr, 2, "Memory Fault: ");
return 0;
}
u64 word = m_words[addr >> 3].load(std::memory_order_seq_cst);
@@ -74,11 +94,11 @@ namespace dragon
return static_cast(word >> shift);
}
- u8 RAM::load_u8(u32 addr) const
+ u8 RAM::load_u8(PhysycalAddress addr) const
{
if (addr >= m_size)
{
- fault(addr, 1);
+ fault(addr, 1, "Memory Fault: ");
return 0;
}
u64 word = m_words[addr >> 3].load(std::memory_order_seq_cst);
@@ -86,22 +106,23 @@ namespace dragon
return static_cast(word >> shift);
}
- void RAM::store_u64(u32 addr, u64 value)
+ bool RAM::store_u64(PhysycalAddress addr, u64 value)
{
if (addr + 8 > m_size || (addr & 7))
{
- fault(addr, 8);
- return;
+ fault(addr, 8, "Memory Fault: ");
+ return false;
}
m_words[addr >> 3].store(value, std::memory_order_seq_cst);
+ return true;
}
- void RAM::store_u32(u32 addr, u32 value)
+ bool RAM::store_u32(PhysycalAddress addr, u32 value)
{
if (addr + 4 > m_size || (addr & 3))
{
- fault(addr, 4);
- return;
+ fault(addr, 4, "Memory Fault: ");
+ return false;
}
u32 shift = (addr & 4) * 8;
u64 mask = u64(0xFFFFFFFFu) << shift;
@@ -112,14 +133,15 @@ namespace dragon
{
desired = (expected & ~mask) | (u64(value) << shift);
} while (!word.compare_exchange_weak(expected, desired, std::memory_order_seq_cst, std::memory_order_relaxed));
+ return true;
}
- void RAM::store_u16(u32 addr, u16 value)
+ bool RAM::store_u16(PhysycalAddress addr, u16 value)
{
if (addr + 2 > m_size || (addr & 1))
{
- fault(addr, 2);
- return;
+ fault(addr, 2, "Memory Fault: ");
+ return false;
}
u32 shift = (addr & 6) * 8;
u64 mask = u64(0xFFFFu) << shift;
@@ -130,14 +152,15 @@ namespace dragon
{
desired = (expected & ~mask) | (u64(value) << shift);
} while (!word.compare_exchange_weak(expected, desired, std::memory_order_seq_cst, std::memory_order_relaxed));
+ return true;
}
- void RAM::store_u8(u32 addr, u8 value)
+ bool RAM::store_u8(PhysycalAddress addr, u8 value)
{
if (addr >= m_size)
{
- fault(addr, 1);
- return;
+ fault(addr, 1, "Memory Fault: ");
+ return false;
}
u32 shift = (addr & 7) * 8;
u64 mask = u64(0xFFu) << shift;
@@ -148,11 +171,12 @@ namespace dragon
{
desired = (expected & ~mask) | (u64(value) << shift);
} while (!word.compare_exchange_weak(expected, desired, std::memory_order_seq_cst, std::memory_order_relaxed));
+ return true;
}
- void RAM::fault(u32 addr, u32 size) const
+ void RAM::fault(PhysycalAddress addr, u32 size, const String& msg) const
{
- std::cout << "Memory Fault: " << ostd::String::getHexStr(addr, true, 4) << "\n";
+ std::cout << msg << ostd::String::getHexStr(addr, true, 4) << "\n";
/* TODO: raise guest trap */
}
}
diff --git a/src/hardware/RAM.hpp b/src/hardware/RAM.hpp
index d31a27e..54c24f4 100644
--- a/src/hardware/RAM.hpp
+++ b/src/hardware/RAM.hpp
@@ -21,46 +21,33 @@
#pragma once
#include
-#include
+
+#include "BUS.hpp"
namespace dragon
{
namespace hw
{
- class RAM
+ class RAM : public AtomicStorageMemoryDevice
{
public:
- explicit RAM(u64 size);
- ~RAM(void);
- RAM(const RAM&) = delete;
- RAM& operator=(const RAM&) = delete;
+ explicit RAM(u64 size) : AtomicStorageMemoryDevice(size) { }
+
+ bool guest_cas_u32(PhysycalAddress addr, u32 expected, u32& actual, u32 desired) override;
// ---- Aligned loads ----
- u64 load_u64(u32 addr) const;
- u32 load_u32(u32 addr) const;
- u16 load_u16(u32 addr) const;
- u8 load_u8 (u32 addr) const;
- inline i64 load_i64(u32 addr) const { return cast(load_u64(addr)); }
- inline i32 load_i32(u32 addr) const { return cast(load_u32(addr)); }
- inline i16 load_i16(u32 addr) const { return cast(load_u16(addr)); }
- inline i8 load_i8 (u32 addr) const { return cast(load_u8 (addr)); }
+ u64 load_u64(PhysycalAddress addr) const override;
+ u32 load_u32(PhysycalAddress addr) const override;
+ u16 load_u16(PhysycalAddress addr) const override;
+ u8 load_u8 (PhysycalAddress addr) const override;
// ---- Aligned stores ----
- void store_u64(u32 addr, u64 value);
- void store_u32(u32 addr, u32 value);
- void store_u16(u32 addr, u16 value);
- void store_u8 (u32 addr, u8 value);
- inline void store_i64(u32 addr, u64 value) { store_u64(addr, cast(value)); }
- inline void store_i32(u32 addr, u32 value) { store_u32(addr, cast(value)); }
- inline void store_i16(u32 addr, u16 value) { store_u16(addr, cast(value)); }
- inline void store_i8 (u32 addr, u8 value) { store_u8 (addr, cast(value)); }
+ bool store_u64(PhysycalAddress addr, u64 value) override;
+ bool store_u32(PhysycalAddress addr, u32 value) override;
+ bool store_u16(PhysycalAddress addr, u16 value) override;
+ bool store_u8 (PhysycalAddress addr, u8 value) override;
- void fault(u32 addr, u32 size) const;
-
- private:
- std::atomic* m_words;
- u64 m_wordCount;
- u64 m_size;
+ [[noreturn]] void fault(PhysycalAddress addr, u32 size, const String& msg = "") const override;
};
}
}
diff --git a/src/tools/tools_main.cpp b/src/tools/tools_main.cpp
index 1369646..891c37d 100644
--- a/src/tools/tools_main.cpp
+++ b/src/tools/tools_main.cpp
@@ -1,3 +1,23 @@
+/*
+ DragonV2 - A collection of useful functionality
+ Copyright (C) 2026 OmniaX-Dev
+
+ This file is part of DragonV2.
+
+ DragonV2 is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ DragonV2 is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with DragonV2. If not, see .
+*/
+
#include
int main(int argc, char** argv)