diff --git a/CMakeLists.txt b/CMakeLists.txt
index a2a5618..0eec9cd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,7 +12,7 @@ set(CMAKE_C_COMPILER "clang")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
cmake_minimum_required(VERSION 3.18)
project(${PROJ_NAME} LANGUAGES C CXX)
-set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD 23)
file(STRINGS "./other/build.nr" BUILD_NUMBER)
#-----------------------------------------------------------------------------------------
diff --git a/other/build.nr b/other/build.nr
index da66d92..8f8453a 100644
--- a/other/build.nr
+++ b/other/build.nr
@@ -1 +1 @@
-1646
+1648
diff --git a/src/hardware/BUS.cpp b/src/hardware/BUS.cpp
new file mode 100644
index 0000000..6b3eb40
--- /dev/null
+++ b/src/hardware/BUS.cpp
@@ -0,0 +1,143 @@
+/*
+ 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)
+ {
+ data::ErrorHandler::pushError(data::ErrorCodes::MM_AtomicNotSupported, "MemoryDevice::guest_cas_u32: atomic not supported: ");
+ fault(addr, data::ExceptionCause::AtomicNotSupported, "MemoryDevice::guest_cas_u32");
+ return false;
+ }
+
+
+
+
+
+ namespace hw
+ {
+ bool BUS::guest_cas_u32(AddressType 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(AddressType 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(AddressType 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(AddressType 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(AddressType 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(AddressType 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(AddressType 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(AddressType 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(AddressType 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, AddressType startAddr, AddressType endAddr, bool remap, ostd::String name)
+ {
+ m_regions.push_back({ &device, startAddr, endAddr, remap, name });
+ }
+
+ ostd::String BUS::getMemoryRegionName(AddressType address)
+ {
+ tMemoryRegion* region = findRegion(address);
+ if (region == nullptr) return "Invalid";
+ return region->name;
+ }
+ }
+}
diff --git a/src/hardware/BUS.hpp b/src/hardware/BUS.hpp
new file mode 100644
index 0000000..b28b4f2
--- /dev/null
+++ b/src/hardware/BUS.hpp
@@ -0,0 +1,142 @@
+/*
+ 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
+#include "../tools/GlobalData.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(AddressType addr) const = 0;
+ virtual u8 load_u8 (AddressType 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, data::ExceptionCause cause, const String& msg = "") const { throw data::GuestException{ cause, addr, msg }; }; // 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 };
+ AddressType startAddress { 0x0000'0000 };
+ AddressType endAddress { 0x0000'0000 };
+ bool remap { false };
+ ostd::String name { "" };
+ };
+
+ public:
+ BUS(void) = default;
+
+ bool guest_cas_u32(AddressType addr, u32 expected, u32& actual, u32 desired) override;
+
+ // ---- Aligned loads ----
+ u64 load_u64(AddressType addr) const override;
+ u32 load_u32(AddressType addr) const override;
+ u16 load_u16(AddressType addr) const override;
+ u8 load_u8 (AddressType addr) const override;
+
+ // ---- Aligned stores ----
+ bool store_u64(AddressType addr, u64 value) override;
+ bool store_u32(AddressType addr, u32 value) override;
+ bool store_u16(AddressType addr, u16 value) override;
+ bool store_u8 (AddressType addr, u8 value) override;
+
+ void mapDevice(MemoryDevice& device, AddressType startAddr, AddressType endAddr, bool remap = false, ostd::String name = "");
+ ostd::String getMemoryRegionName(AddressType address);
+
+ private:
+ template
+ auto findRegion(this Self&& self, AddressType address)
+ {
+ for (auto& region : self.m_regions)
+ { // works whether self is const or not
+ if (address >= region.startAddress && address <= region.endAddress)
+ return ®ion;
+ }
+ data::ErrorHandler::pushError(data::ErrorCodes::MM_RegionNotFound, "Memory device not found");
+ return decltype(&self.m_regions[0]){nullptr};
+ }
+
+ private:
+ std::vector m_regions;
+
+ private:
+ };
+ }
+}
diff --git a/src/hardware/RAM.cpp b/src/hardware/RAM.cpp
new file mode 100644
index 0000000..055acca
--- /dev/null
+++ b/src/hardware/RAM.cpp
@@ -0,0 +1,172 @@
+/*
+ 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 "RAM.hpp"
+#include
+
+#define DRAGON_TEST_FOR_MISALIGNED_OR_BOUNDS_FAULT_R(size, msg) \
+ if (addr + size > m_size) \
+ { \
+ fault(addr, data::ExceptionCause::LoadBounds, msg); \
+ return 0; \
+ } \
+ if (addr & (size - 1)) \
+ { \
+ fault(addr, data::ExceptionCause::MisalignedLoad, msg); \
+ return 0; \
+ } \
+
+#define DRAGON_TEST_FOR_MISALIGNED_OR_BOUNDS_FAULT_W(size, msg) \
+ if (addr + size > m_size) \
+ { \
+ fault(addr, data::ExceptionCause::StoreBounds, msg); \
+ return false; \
+ } \
+ if (addr & (size - 1)) \
+ { \
+ fault(addr, data::ExceptionCause::MisalignedStore, msg); \
+ return false; \
+ } \
+
+namespace dragon
+{
+ namespace hw
+ {
+ bool RAM::guest_cas_u32(AddressType addr, u32 expected, u32& actual, u32 desired)
+ {
+ DRAGON_TEST_FOR_MISALIGNED_OR_BOUNDS_FAULT_R(4, "RAM::guest_cas_u32");
+
+ 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.
+ }
+ }
+
+ u64 RAM::load_u64(AddressType addr) const
+ {
+ DRAGON_TEST_FOR_MISALIGNED_OR_BOUNDS_FAULT_R(8, "RAM::load_u64");
+ return m_words[addr >> 3].load(std::memory_order_seq_cst);
+ }
+
+ u32 RAM::load_u32(AddressType addr) const
+ {
+ DRAGON_TEST_FOR_MISALIGNED_OR_BOUNDS_FAULT_R(4, "RAM::load_u32");
+ u64 word = m_words[addr >> 3].load(std::memory_order_seq_cst);
+ u32 shift = (addr & 4) * 8; // 0 or 32
+ return static_cast(word >> shift);
+ }
+
+ u16 RAM::load_u16(AddressType addr) const
+ {
+ DRAGON_TEST_FOR_MISALIGNED_OR_BOUNDS_FAULT_R(2, "RAM::load_u16");
+ u64 word = m_words[addr >> 3].load(std::memory_order_seq_cst);
+ u32 shift = (addr & 6) * 8; // 0, 16, 32, or 48
+ return static_cast(word >> shift);
+ }
+
+ u8 RAM::load_u8(AddressType addr) const
+ {
+ if (addr >= m_size)
+ {
+ fault(addr, data::ExceptionCause::LoadBounds, "RAM::load_u8");
+ return 0;
+ }
+ u64 word = m_words[addr >> 3].load(std::memory_order_seq_cst);
+ u32 shift = (addr & 7) * 8;
+ return static_cast(word >> shift);
+ }
+
+ bool RAM::store_u64(AddressType addr, u64 value)
+ {
+ DRAGON_TEST_FOR_MISALIGNED_OR_BOUNDS_FAULT_W(8, "RAM::store_u64");
+ m_words[addr >> 3].store(value, std::memory_order_seq_cst);
+ return true;
+ }
+
+ bool RAM::store_u32(AddressType addr, u32 value)
+ {
+ DRAGON_TEST_FOR_MISALIGNED_OR_BOUNDS_FAULT_W(4, "RAM::store_u32");
+ u32 shift = (addr & 4) * 8;
+ u64 mask = u64(0xFFFFFFFFu) << shift;
+ std::atomic& word = m_words[addr >> 3];
+ u64 expected = word.load(std::memory_order_relaxed);
+ u64 desired;
+ do
+ {
+ desired = (expected & ~mask) | (u64(value) << shift);
+ } while (!word.compare_exchange_weak(expected, desired, std::memory_order_seq_cst, std::memory_order_relaxed));
+ return true;
+ }
+
+ bool RAM::store_u16(AddressType addr, u16 value)
+ {
+ DRAGON_TEST_FOR_MISALIGNED_OR_BOUNDS_FAULT_W(2, "RAM::store_u16");
+ u32 shift = (addr & 6) * 8;
+ u64 mask = u64(0xFFFFu) << shift;
+ std::atomic& word = m_words[addr >> 3];
+ u64 expected = word.load(std::memory_order_relaxed);
+ u64 desired;
+ do
+ {
+ desired = (expected & ~mask) | (u64(value) << shift);
+ } while (!word.compare_exchange_weak(expected, desired, std::memory_order_seq_cst, std::memory_order_relaxed));
+ return true;
+ }
+
+ bool RAM::store_u8(AddressType addr, u8 value)
+ {
+ if (addr >= m_size)
+ {
+ fault(addr, data::ExceptionCause::StoreBounds, "RAM::store_u8");
+ return false;
+ }
+ u32 shift = (addr & 7) * 8;
+ u64 mask = u64(0xFFu) << shift;
+ std::atomic& word = m_words[addr >> 3];
+ u64 expected = word.load(std::memory_order_relaxed);
+ u64 desired;
+ do
+ {
+ desired = (expected & ~mask) | (u64(value) << shift);
+ } while (!word.compare_exchange_weak(expected, desired, std::memory_order_seq_cst, std::memory_order_relaxed));
+ return true;
+ }
+ }
+}
diff --git a/src/hardware/RAM.hpp b/src/hardware/RAM.hpp
new file mode 100644
index 0000000..de4ff22
--- /dev/null
+++ b/src/hardware/RAM.hpp
@@ -0,0 +1,51 @@
+/*
+ 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 "BUS.hpp"
+
+namespace dragon
+{
+ namespace hw
+ {
+ class RAM : public AtomicStorageMemoryDevice
+ {
+ public:
+ explicit RAM(u64 size) : AtomicStorageMemoryDevice(size) { }
+
+ bool guest_cas_u32(AddressType addr, u32 expected, u32& actual, u32 desired) override;
+
+ // ---- Aligned loads ----
+ u64 load_u64(AddressType addr) const override;
+ u32 load_u32(AddressType addr) const override;
+ u16 load_u16(AddressType addr) const override;
+ u8 load_u8 (AddressType addr) const override;
+
+ // ---- Aligned stores ----
+ bool store_u64(AddressType addr, u64 value) override;
+ bool store_u32(AddressType addr, u32 value) override;
+ bool store_u16(AddressType addr, u16 value) override;
+ bool store_u8 (AddressType addr, u8 value) override;
+ };
+ }
+}
diff --git a/src/tools/GlobalData.hpp b/src/tools/GlobalData.hpp
index 15e3d36..fe673b7 100644
--- a/src/tools/GlobalData.hpp
+++ b/src/tools/GlobalData.hpp
@@ -5,6 +5,7 @@
namespace dragon
{
+ using AddressType = u16;
namespace hw { class VirtualCPU; }
namespace data
{
@@ -13,51 +14,109 @@ namespace dragon
class ErrorCodes
{
public:
- inline static constexpr uint64_t NoError = 0x0000000000000000;
- inline static constexpr uint64_t AccessViolation_BiosModeRequired = 0x0000000000000001;
+ inline static constexpr uint64_t NoError = 0x0000000000000000;
+ inline static constexpr uint64_t AccessViolation_BiosModeRequired = 0x0000000000000001;
- inline static constexpr uint64_t MM_RegionNotFound = 0x1000000000000000;
+ inline static constexpr uint64_t MM_RegionNotFound = 0x1000000000000000;
+ inline static constexpr uint64_t MM_AtomicNotSupported = 0x1000000000000001;
- inline static constexpr uint64_t CPU_UnknownInstruction = 0x2000000000000000;
- inline static constexpr uint64_t CPU_UnsupportedExtension = 0x2000000000000001;
- inline static constexpr uint64_t CPU_StackOverflow = 0x2000000000000002;
+ inline static constexpr uint64_t CPU_UnknownInstruction = 0x2000000000000000;
+ inline static constexpr uint64_t CPU_UnsupportedExtension = 0x2000000000000001;
+ inline static constexpr uint64_t CPU_StackOverflow = 0x2000000000000002;
- inline static constexpr uint64_t BIOS_FailedToLoad = 0x3000000000000000;
- inline static constexpr uint64_t BIOS_InvalidSize = 0x3000000000000001;
- inline static constexpr uint64_t BIOS_WriteAttempt = 0x3000000000000002;
- inline static constexpr uint64_t BIOS_InvalidAddress = 0x3000000000000003;
+ inline static constexpr uint64_t BIOS_FailedToLoad = 0x3000000000000000;
+ inline static constexpr uint64_t BIOS_InvalidSize = 0x3000000000000001;
+ inline static constexpr uint64_t BIOS_WriteAttempt = 0x3000000000000002;
+ inline static constexpr uint64_t BIOS_InvalidAddress = 0x3000000000000003;
- inline static constexpr uint64_t HardDrive_UnableToMount = 0x4000000000000000;
- inline static constexpr uint64_t HardDrive_Uninitialized = 0x4000000000000001;
- inline static constexpr uint64_t HardDrive_ReadOverflow = 0x4000000000000002;
- inline static constexpr uint64_t HardDrive_WriteOverflow = 0x4000000000000003;
- inline static constexpr uint64_t HardDrive_BuffWriteOverflow = 0x4000000000000004;
- inline static constexpr uint64_t HardDrive_EmptyBuffer = 0x4000000000000005;
- inline static constexpr uint64_t HardDrive_InvalidConfiguration = 0x4000000000000006;
- inline static constexpr uint64_t HardDrive_ReadFailed = 0x4000000000000007;
- inline static constexpr uint64_t HardDrive_WriteFailed = 0x4000000000000008;
- inline static constexpr uint64_t HardDrive_MemoryOverflow = 0x4000000000000009;
- inline static constexpr uint64_t HardDrive_InvalidDiskSelected = 0x400000000000000A;
- inline static constexpr uint64_t HardDrive_EndOfDisk = 0x400000000000000B;
- inline static constexpr uint64_t HardDrive_ControllerReadFailed = 0x400000000000000C;
- inline static constexpr uint64_t HardDrive_ControllerWriteFailed = 0x400000000000000D;
- inline static constexpr uint64_t HardDrive_DisconnectInvalid = 0x400000000000000E;
- inline static constexpr uint64_t HardDrive_DiskAlreadyConnected = 0x400000000000000F;
+ inline static constexpr uint64_t HardDrive_UnableToMount = 0x4000000000000000;
+ inline static constexpr uint64_t HardDrive_Uninitialized = 0x4000000000000001;
+ inline static constexpr uint64_t HardDrive_ReadOverflow = 0x4000000000000002;
+ inline static constexpr uint64_t HardDrive_WriteOverflow = 0x4000000000000003;
+ inline static constexpr uint64_t HardDrive_BuffWriteOverflow = 0x4000000000000004;
+ inline static constexpr uint64_t HardDrive_EmptyBuffer = 0x4000000000000005;
+ inline static constexpr uint64_t HardDrive_InvalidConfiguration = 0x4000000000000006;
+ inline static constexpr uint64_t HardDrive_ReadFailed = 0x4000000000000007;
+ inline static constexpr uint64_t HardDrive_WriteFailed = 0x4000000000000008;
+ inline static constexpr uint64_t HardDrive_MemoryOverflow = 0x4000000000000009;
+ inline static constexpr uint64_t HardDrive_InvalidDiskSelected = 0x400000000000000A;
+ inline static constexpr uint64_t HardDrive_EndOfDisk = 0x400000000000000B;
+ inline static constexpr uint64_t HardDrive_ControllerReadFailed = 0x400000000000000C;
+ inline static constexpr uint64_t HardDrive_ControllerWriteFailed = 0x400000000000000D;
+ inline static constexpr uint64_t HardDrive_DisconnectInvalid = 0x400000000000000E;
+ inline static constexpr uint64_t HardDrive_DiskAlreadyConnected = 0x400000000000000F;
- inline static constexpr uint64_t CMOS_InvalidAddress = 0x5000000000000000;
- inline static constexpr uint64_t CMOS_UnableToMount = 0x5000000000000001;
- inline static constexpr uint64_t CMOS_InvalidSize = 0x5000000000000002;
- inline static constexpr uint64_t CMOS_Uninitialized = 0x5000000000000003;
+ inline static constexpr uint64_t CMOS_InvalidAddress = 0x5000000000000000;
+ inline static constexpr uint64_t CMOS_UnableToMount = 0x5000000000000001;
+ inline static constexpr uint64_t CMOS_InvalidSize = 0x5000000000000002;
+ inline static constexpr uint64_t CMOS_Uninitialized = 0x5000000000000003;
- inline static constexpr uint64_t BIOSVideo_InvalidAddress = 0x6000000000000000;
+ inline static constexpr uint64_t BIOSVideo_InvalidAddress = 0x6000000000000000;
- inline static constexpr uint64_t IntVector_InvalidAddress = 0x7000000000000000;
+ inline static constexpr uint64_t IntVector_InvalidAddress = 0x7000000000000000;
- inline static constexpr uint64_t Graphics_MemoryReadFailed = 0x8000000000000000;
- inline static constexpr uint64_t Graphics_MemoryWriteFailed = 0x8000000000000001;
+ inline static constexpr uint64_t Graphics_MemoryReadFailed = 0x8000000000000000;
+ inline static constexpr uint64_t Graphics_MemoryWriteFailed = 0x8000000000000001;
};
+ enum class ExceptionCause : u32
+ {
+ // === Instruction fetch faults ===
+ MisalignedFetch = 0x0000'0000, // PC not aligned to instruction boundary
+ InstructionBounds = 0x0000'0001, // PC outside any mapped region
+ InstructionPageFault = 0x0000'0002, // virt page not mapped (MMU on) or no X permission
+ InstructionPrivPageFault = 0x0000'0003, // privileged virt page not mapped (MMU on) or no X permission
+ UnknownInstruction = 0x0000'0004, // decoded opcode is not valid
+
+ // === Privilege ===
+ PrivilegeViolation = 0x0000'1000, // user mode executed a [PRIV] instruction
+
+ // === Memory access faults (loads) ===
+ MisalignedLoad = 0x0000'2000, // load address not naturally aligned
+ LoadBounds = 0x0000'2001, // load address outside mapped region
+ LoadPageFault = 0x0000'2002, // virt page not mapped or no R permission
+ LoadPrivPageFault = 0x0000'2003, // virt page not mapped or no R permission
+
+ // === Memory access faults (stores) ===
+ MisalignedStore = 0x0000'3000,
+ StoreBounds = 0x0000'3001,
+ StorePageFault = 0x0000'3002, // virt page not mapped or no W permission
+ StorePrivPageFault = 0x0000'3003, // virt page not mapped or no W permission
+
+ // === Atomic op faults ===
+ AtomicNotSupported = 0x0000'4000, // CAS/XADD/XCHG on a device that can't (ROM, MMIO)
+
+ // === Arithmetic ===
+ DivideByZero = 0x0000'5000,
+
+ // === MMIO ===
+ BusUnmapped = 0x0000'6000,
+ ReadOnlyViolation = 0x0000'6001,
+
+ // === Deliberate guest-initiated traps ===
+ Syscall = 0x0000'7000, // syscall instruction
+ SoftwareInt = 0x0000'7001, // int N instruction
+ TrapInstruction = 0x0000'7002, // explicit trap instr
+ Breakpoint = 0x0000'7003, // brk for debugger
+
+ // === Asynchronous (external) ===
+ HardwareInterrupt = 0x0000'F000, // generic external IRQ; details in INT controller
+
+ // === Catastrophic ===
+ DoubleFault = 0x000F'FFFF, // exception while handling exception
+
+ // Just in case
+ NoFault = 0xFFFF'FFFF,
+ };
+
+ struct GuestException
+ {
+ ExceptionCause cause;
+ AddressType fault_addr; // VA for translation faults, PA for bus faults, 0 otherwise
+ String msg; // For debug
+ };
+
class ErrorHandler
{
public: struct tError
@@ -127,22 +186,22 @@ namespace dragon
public:
inline BiosVideoDefaultPalette(void)
{
- m_colors.push_back({ 0, 0, 0 }); // Black
- m_colors.push_back({ 157, 157, 157 }); // Gray
- m_colors.push_back({ 255, 255, 255 }); // White
- m_colors.push_back({ 190, 38, 51 }); // Red
- m_colors.push_back({ 224, 111, 139 }); // Pink
- m_colors.push_back({ 73, 60, 43 }); // Brown
- m_colors.push_back({ 164, 100, 34 }); // Dark Orange
- m_colors.push_back({ 235, 137, 49 }); // Orange
- m_colors.push_back({ 247, 226, 107 }); // Yellow
- m_colors.push_back({ 47, 80, 42 }); // Dark Green
- m_colors.push_back({ 68, 137, 26 }); // Green
- m_colors.push_back({ 163, 206, 39 }); // Lime
- m_colors.push_back({ 27, 38, 50 }); // Dark Blue
- m_colors.push_back({ 0, 87, 132 }); // Blue
- m_colors.push_back({ 49, 162, 242 }); // Light Blue
- m_colors.push_back({ 178, 220, 239 }); // Sky
+ m_colors.push_back({ 0, 0, 0 }); // Black
+ m_colors.push_back({ 157, 157, 157 }); // Gray
+ m_colors.push_back({ 255, 255, 255 }); // White
+ m_colors.push_back({ 190, 38, 51 }); // Red
+ m_colors.push_back({ 224, 111, 139 }); // Pink
+ m_colors.push_back({ 73, 60, 43 }); // Brown
+ m_colors.push_back({ 164, 100, 34 }); // Dark Orange
+ m_colors.push_back({ 235, 137, 49 }); // Orange
+ m_colors.push_back({ 247, 226, 107 }); // Yellow
+ m_colors.push_back({ 47, 80, 42 }); // Dark Green
+ m_colors.push_back({ 68, 137, 26 }); // Green
+ m_colors.push_back({ 163, 206, 39 }); // Lime
+ m_colors.push_back({ 27, 38, 50 }); // Dark Blue
+ m_colors.push_back({ 0, 87, 132 }); // Blue
+ m_colors.push_back({ 49, 162, 242 }); // Light Blue
+ m_colors.push_back({ 178, 220, 239 }); // Sky
}
inline ostd::Color getColor(uint8_t col) override
@@ -203,12 +262,12 @@ namespace dragon
{
switch (code)
{
- case DiskInterfaceFFinished: return "Disk_Interface_Finished";
- case KeyPressed: return "Key_Pressed";
- case KeyReleased: return "Key_Released";
- case TextEntered: return "Text_Entered";
- case Text16ModeScreenRefreshed: return "Text16_Mode_Screen_Refreshed";
- default: return "UNKNOWN";
+ case DiskInterfaceFFinished: return "Disk_Interface_Finished";
+ case KeyPressed: return "Key_Pressed";
+ case KeyReleased: return "Key_Released";
+ case TextEntered: return "Text_Entered";
+ case Text16ModeScreenRefreshed: return "Text16_Mode_Screen_Refreshed";
+ default: return "UNKNOWN";
}
return "UNKNOWN";
}
@@ -217,59 +276,59 @@ namespace dragon
class CMOSRegisters
{
public:
- inline static constexpr uint8_t MemoryStart = 0x00;
- inline static constexpr uint8_t MemorySize = 0x02;
- inline static constexpr uint8_t ClockSpeed = 0x04;
- inline static constexpr uint8_t ScreenRedrawRate = 0x06;
- inline static constexpr uint8_t ScreenWidth = 0x07;
- inline static constexpr uint8_t ScreenHeight = 0x09;
- inline static constexpr uint8_t BootDisk = 0x10;
- inline static constexpr uint8_t StackSize = 0x11;
+ inline static constexpr uint8_t MemoryStart = 0x00;
+ inline static constexpr uint8_t MemorySize = 0x02;
+ inline static constexpr uint8_t ClockSpeed = 0x04;
+ inline static constexpr uint8_t ScreenRedrawRate = 0x06;
+ inline static constexpr uint8_t ScreenWidth = 0x07;
+ inline static constexpr uint8_t ScreenHeight = 0x09;
+ inline static constexpr uint8_t BootDisk = 0x10;
+ inline static constexpr uint8_t StackSize = 0x11;
- inline static constexpr uint8_t DiskList = 0x7E;
+ inline static constexpr uint8_t DiskList = 0x7E;
};
class DPTStructure
{
public: struct tFlags {
- inline static constexpr uint8_t Boot = 0;
+ inline static constexpr uint8_t Boot = 0;
};
public:
- inline static constexpr uint16_t DPTID = 0x000;
- inline static constexpr uint16_t DPTVersionMaj = 0x002;
- inline static constexpr uint16_t DPTVersionMin = 0x003;
- inline static constexpr uint16_t PartitionCount = 0x004;
+ inline static constexpr uint16_t DPTID = 0x000;
+ inline static constexpr uint16_t DPTVersionMaj = 0x002;
+ inline static constexpr uint16_t DPTVersionMin = 0x003;
+ inline static constexpr uint16_t PartitionCount = 0x004;
- inline static constexpr uint16_t EntriesStart = 0x00C;
+ inline static constexpr uint16_t EntriesStart = 0x00C;
- inline static constexpr uint16_t EntryStartAddress = 0x000;
- inline static constexpr uint16_t EntryPartitionSize = 0x004;
- inline static constexpr uint16_t EntryFlags = 0x008;
- inline static constexpr uint16_t EntryPartitionLabel = 0x024;
+ inline static constexpr uint16_t EntryStartAddress = 0x000;
+ inline static constexpr uint16_t EntryPartitionSize = 0x004;
+ inline static constexpr uint16_t EntryFlags = 0x008;
+ inline static constexpr uint16_t EntryPartitionLabel = 0x024;
- inline static constexpr uint16_t HeaderReservedSizeBytes = 7;
- inline static constexpr uint16_t DiskAddress = 0x200;
- inline static constexpr uint16_t DPT_ID_CODE = 0xF1CA;
- inline static constexpr uint16_t EntrySizeBytes = 100;
- inline static constexpr uint16_t EntryLabelSizeBytes = 64;
- inline static constexpr uint16_t EntryReservedSizeBytes = 26;
- inline static constexpr uint16_t HeaderSizeBytes = 12;
- inline static constexpr uint16_t DPTBlockSizeBytes = 512;
- inline static constexpr uint8_t CurrentDPTVersionMaj = 0x00;
- inline static constexpr uint8_t CurrentDPTVersionMin = 0x02;
- inline static constexpr uint32_t DiskStartAddr = 0x00000400;
- inline static constexpr uint8_t MaxPartCount = 5;
+ inline static constexpr uint16_t HeaderReservedSizeBytes = 7;
+ inline static constexpr uint16_t DiskAddress = 0x200;
+ inline static constexpr uint16_t DPT_ID_CODE = 0xF1CA;
+ inline static constexpr uint16_t EntrySizeBytes = 100;
+ inline static constexpr uint16_t EntryLabelSizeBytes = 64;
+ inline static constexpr uint16_t EntryReservedSizeBytes = 26;
+ inline static constexpr uint16_t HeaderSizeBytes = 12;
+ inline static constexpr uint16_t DPTBlockSizeBytes = 512;
+ inline static constexpr uint8_t CurrentDPTVersionMaj = 0x00;
+ inline static constexpr uint8_t CurrentDPTVersionMin = 0x02;
+ inline static constexpr uint32_t DiskStartAddr = 0x00000400;
+ inline static constexpr uint8_t MaxPartCount = 5;
- inline static constexpr uint16_t BootPart_IDAddr = 0x0000;
- inline static constexpr uint16_t BootPart_CodeStart = 0x0020;
- inline static constexpr uint16_t BootPart_ID_CODE = 0xF1C4;
- inline static constexpr uint16_t BootPart_CodeSizeBytes = 1024;
- inline static constexpr uint8_t BootPart_HeaderSizeBytes = 32;
+ inline static constexpr uint16_t BootPart_IDAddr = 0x0000;
+ inline static constexpr uint16_t BootPart_CodeStart = 0x0020;
+ inline static constexpr uint16_t BootPart_ID_CODE = 0xF1C4;
+ inline static constexpr uint16_t BootPart_CodeSizeBytes = 1024;
+ inline static constexpr uint8_t BootPart_HeaderSizeBytes = 32;
};
class CPUExtension