Restored legacy ostd SerialIO class
This commit is contained in:
parent
4aa5e318f0
commit
c81d2dcfea
19 changed files with 608 additions and 622 deletions
|
|
@ -44,6 +44,7 @@ list(APPEND RUNTIME_SOURCE_FILES
|
|||
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/Utils.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/GlobalData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/LegacyOstdSerial.cpp
|
||||
)
|
||||
list(APPEND DEBUGGER_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/debugger/debugger_main.cpp
|
||||
|
|
@ -69,6 +70,7 @@ list(APPEND DEBUGGER_SOURCE_FILES
|
|||
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/Utils.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/GlobalData.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/LegacyOstdSerial.cpp
|
||||
)
|
||||
list(APPEND ASSEMBLER_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/assembler/assembler_main.cpp
|
||||
|
|
@ -79,11 +81,13 @@ list(APPEND ASSEMBLER_SOURCE_FILES
|
|||
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualHardDrive.cpp
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/Utils.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/LegacyOstdSerial.cpp
|
||||
)
|
||||
list(APPEND TOOLS_SOURCE_FILES
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/tools_main.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/Utils.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/Tools.cpp
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/tools/LegacyOstdSerial.cpp
|
||||
|
||||
${CMAKE_CURRENT_LIST_DIR}/src/hardware/VirtualHardDrive.cpp
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,5 +1,5 @@
|
|||
## --
|
||||
## -- This file is automatically generated by the DragonAssembler (version 0.4.1646)
|
||||
## -- This file is automatically generated by the DragonAssembler (version 0.4.1649)
|
||||
## -- Please do not modify this file in any way.
|
||||
## --
|
||||
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1648
|
||||
1650
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <ostd/io/FileSystem.hpp>
|
||||
#include <ostd/io/Serial.hpp>
|
||||
#include "../tools/LegacyOstdSerial.hpp"
|
||||
#include <ostd/io/IOHandlers.hpp>
|
||||
#include <ostd/io/Memory.hpp>
|
||||
#include <ostd/math/MathUtils.hpp>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <ostd/io/File.hpp>
|
||||
#include <ostd/io/FileSystem.hpp>
|
||||
#include <ostd/io/Memory.hpp>
|
||||
#include <ostd/io/Serial.hpp>
|
||||
#include "../tools/LegacyOstdSerial.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <ostd/string/String.hpp>
|
||||
|
|
|
|||
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<u64>[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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <ostd/data/BaseObject.hpp>
|
||||
#include <atomic>
|
||||
#include <span>
|
||||
#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<i64>(load_u64(addr)); }
|
||||
inline i32 load_i32(AddressType addr) const { return cast<i32>(load_u32(addr)); }
|
||||
inline i16 load_i16(AddressType addr) const { return cast<i16>(load_u16(addr)); }
|
||||
inline i8 load_i8 (AddressType addr) const { return cast<i8 >(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<i64>(value)); }
|
||||
inline bool store_i32(AddressType addr, u32 value) { return store_u32(addr, cast<i32>(value)); }
|
||||
inline bool store_i16(AddressType addr, u16 value) { return store_u16(addr, cast<i16>(value)); }
|
||||
inline bool store_i8 (AddressType addr, u8 value) { return store_u8 (addr, cast<i8 >(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<std::atomic<u64>> getRawData(void) { return { m_words, m_size }; }
|
||||
inline virtual std::span<const std::atomic<u64>> 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<u64>* 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 <typename Self>
|
||||
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<tMemoryRegion> m_regions;
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#include "MemoryMapper.hpp"
|
||||
#include <ostd/io/Serial.hpp>
|
||||
#include <ostd/data/Types.hpp>
|
||||
|
||||
#include "../tools/GlobalData.hpp"
|
||||
|
|
|
|||
|
|
@ -1,172 +0,0 @@
|
|||
/*
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "RAM.hpp"
|
||||
#include <ostd/string/String.hpp>
|
||||
|
||||
#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<u64>& word = m_words[addr >> 3];
|
||||
|
||||
u64 word_expected = word.load(std::memory_order_seq_cst);
|
||||
while (true)
|
||||
{
|
||||
u32 current_in_slot = static_cast<u32>(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<u32>(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<u16>(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<u8>(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<u64>& 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<u64>& 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<u64>& 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostd/data/Types.hpp>
|
||||
|
||||
#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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include "IMemoryDevice.hpp"
|
||||
#include "../tools/GlobalData.hpp"
|
||||
#include <ostd/io/Serial.hpp>
|
||||
#include "../tools/LegacyOstdSerial.hpp"
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <ostd/io/Serial.hpp>
|
||||
#include "../tools/LegacyOstdSerial.hpp"
|
||||
|
||||
namespace dragon
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <ostd/io/Serial.hpp>
|
||||
#include "../tools/LegacyOstdSerial.hpp"
|
||||
#include "IMemoryDevice.hpp"
|
||||
|
||||
namespace dragon
|
||||
|
|
|
|||
|
|
@ -60,63 +60,6 @@ namespace dragon
|
|||
|
||||
};
|
||||
|
||||
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
|
||||
|
|
|
|||
457
src/tools/LegacyOstdSerial.cpp
Normal file
457
src/tools/LegacyOstdSerial.cpp
Normal file
|
|
@ -0,0 +1,457 @@
|
|||
#include "LegacyOstdSerial.hpp"
|
||||
#include <ostd/io/Memory.hpp>
|
||||
|
||||
namespace ostd
|
||||
{
|
||||
namespace serial
|
||||
{
|
||||
bool SerialIO::init(u64 size, u8 endianness)
|
||||
{
|
||||
if (size < 1) return false;
|
||||
for (u64 i = 0; i < size; i++)
|
||||
m_data.push_back(0);
|
||||
m_endianness = endianness;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SerialIO::r_QWord(StreamIndex addr, QWord& outVal)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::QWORD)) return false;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
outVal = ( m_data[addr + 7] & 0x00000000000000FFU)
|
||||
| (( m_data[addr + 6] << 8) & 0x000000000000FF00U)
|
||||
| (( m_data[addr + 5] << 16) & 0x0000000000FF0000U)
|
||||
| (( m_data[addr + 4] << 24) & 0x00000000FF000000U)
|
||||
| (((QWord)m_data[addr + 3] << 32) & 0x000000FF00000000U)
|
||||
| (((QWord)m_data[addr + 2] << 40) & 0x0000FF0000000000U)
|
||||
| (((QWord)m_data[addr + 1] << 48) & 0x00FF000000000000U)
|
||||
| (((QWord)m_data[addr + 0] << 56) & 0xFF00000000000000U);
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
outVal = (((QWord)m_data[addr + 0] << 56) & 0xFF00000000000000U)
|
||||
| (((QWord)m_data[addr + 1] << 48) & 0x00FF000000000000U)
|
||||
| (((QWord)m_data[addr + 2] << 40) & 0x0000FF0000000000U)
|
||||
| (((QWord)m_data[addr + 3] << 32) & 0x000000FF00000000U)
|
||||
| (( m_data[addr + 4] << 24) & 0x00000000FF000000U)
|
||||
| (( m_data[addr + 5] << 16) & 0x0000000000FF0000U)
|
||||
| (( m_data[addr + 6] << 8) & 0x000000000000FF00U)
|
||||
| ( m_data[addr + 7] & 0x00000000000000FFU);
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_DWord(StreamIndex addr, DWord& outVal)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::DWORD)) return false;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
outVal = ((m_data[addr + 0] ) & 0x000000FF)
|
||||
| ((m_data[addr + 1] << 8) & 0x0000FF00)
|
||||
| ((m_data[addr + 2] << 16) & 0x00FF0000)
|
||||
| ((m_data[addr + 3] << 24) & 0xFF000000);
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
outVal = ((m_data[addr + 0] << 24) & 0xFF000000U)
|
||||
| ((m_data[addr + 1] << 16) & 0x00FF0000U)
|
||||
| ((m_data[addr + 2] << 8) & 0x0000FF00U)
|
||||
| ( m_data[addr + 3] & 0x000000FFU);
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_Word(StreamIndex addr, Word& outVal)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::WORD)) return false;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
outVal = ((m_data[addr + 0] ) & 0x00FFU)
|
||||
| ((m_data[addr + 1] << 8) & 0xFF00U);
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
outVal = ((m_data[addr + 0] << 8) & 0xFF00U)
|
||||
| ( m_data[addr + 1] & 0x00FFU);
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_Byte(StreamIndex addr, Byte& outVal)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::BYTE)) return false;
|
||||
outVal = m_data[addr];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_Addr(StreamIndex addr, StreamIndex& outVal)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::ADDR)) return false;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
outVal = ((m_data[addr + 0] ) & 0x000000FF)
|
||||
| ((m_data[addr + 1] << 8) & 0x0000FF00)
|
||||
| ((m_data[addr + 2] << 16) & 0x00FF0000)
|
||||
| ((m_data[addr + 3] << 24) & 0xFF000000);
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
outVal = ((m_data[addr + 0] << 24) & 0xFF000000U)
|
||||
| ((m_data[addr + 1] << 16) & 0x00FF0000U)
|
||||
| ((m_data[addr + 2] << 8) & 0x0000FF00U)
|
||||
| ( m_data[addr + 3] & 0x000000FFU);
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_Float(StreamIndex addr, f32& outVal)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::FLOAT)) return false;
|
||||
__float_parser fp;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
fp.data[3] = m_data[addr + 0];
|
||||
fp.data[2] = m_data[addr + 1];
|
||||
fp.data[1] = m_data[addr + 2];
|
||||
fp.data[0] = m_data[addr + 3];
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
fp.data[0] = m_data[addr + 0];
|
||||
fp.data[1] = m_data[addr + 1];
|
||||
fp.data[2] = m_data[addr + 2];
|
||||
fp.data[3] = m_data[addr + 3];
|
||||
}
|
||||
else return false;
|
||||
outVal = fp.val;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_Double(StreamIndex addr, f64& outVal)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::DOUBLE)) return false;
|
||||
__double_parser dp;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
dp.data[7] = m_data[addr++];
|
||||
dp.data[6] = m_data[addr++];
|
||||
dp.data[5] = m_data[addr++];
|
||||
dp.data[4] = m_data[addr++];
|
||||
dp.data[3] = m_data[addr++];
|
||||
dp.data[2] = m_data[addr++];
|
||||
dp.data[1] = m_data[addr++];
|
||||
dp.data[0] = m_data[addr ];
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
dp.data[0] = m_data[addr++];
|
||||
dp.data[1] = m_data[addr++];
|
||||
dp.data[2] = m_data[addr++];
|
||||
dp.data[3] = m_data[addr++];
|
||||
dp.data[4] = m_data[addr++];
|
||||
dp.data[5] = m_data[addr++];
|
||||
dp.data[6] = m_data[addr++];
|
||||
dp.data[7] = m_data[addr ];
|
||||
}
|
||||
else return false;
|
||||
outVal = dp.val;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_ByteStream(StreamIndex addr, ByteStream& outStream)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::ADDR)) return false;
|
||||
u32 stream_size;
|
||||
if (!r_Addr(addr, stream_size)) return false;
|
||||
addr += tTypeSize::ADDR;
|
||||
if (!is_validAddr(addr, stream_size)) return false;
|
||||
outStream.clear();
|
||||
outStream.reserve(stream_size);
|
||||
for (StreamIndex j = addr; j < addr + stream_size; j++)
|
||||
outStream.push_back(m_data[j]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_ByteStream(StreamIndex addr, ByteStream& outStream, u32 size)
|
||||
{
|
||||
if (!is_validAddr(addr, size)) return false;
|
||||
outStream.clear();
|
||||
outStream.reserve(size);
|
||||
for (StreamIndex j = addr; j < addr + size; j++)
|
||||
outStream.push_back(m_data[j]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_String(StreamIndex addr, String& outString)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::ADDR)) return false;
|
||||
u32 stream_size;
|
||||
if (!r_Addr(addr, stream_size)) return false;
|
||||
addr += tTypeSize::ADDR;
|
||||
if (!is_validAddr(addr, stream_size)) return false;
|
||||
outString = "";
|
||||
for (StreamIndex j = addr; j < addr + stream_size; j++)
|
||||
outString += (char)(m_data[j]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_String(StreamIndex addr, String& outString, u32 size)
|
||||
{
|
||||
if (!is_validAddr(addr, size)) return false;
|
||||
outString = "";
|
||||
for (StreamIndex j = addr; j < addr + size; j++)
|
||||
outString += (char)(m_data[j]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::r_NullTerminatedString(StreamIndex addr, String& outString)
|
||||
{
|
||||
outString = "";
|
||||
i8 c = 0;
|
||||
if (!r_Byte(addr, c)) return false;
|
||||
addr += tTypeSize::BYTE;
|
||||
while (c != 0)
|
||||
{
|
||||
outString += (char)c;
|
||||
if (!r_Byte(addr, c)) return false;
|
||||
addr += tTypeSize::BYTE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SerialIO::w_QWord(StreamIndex addr, QWord val)
|
||||
{
|
||||
m_statuWriting = true;
|
||||
if (!is_validAddr(addr, tTypeSize::QWORD)) return false;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
m_data[addr + 0] = val & 0xFF;
|
||||
m_data[addr + 1] = (val >> 8) & 0xFF;
|
||||
m_data[addr + 2] = (val >> 16) & 0xFF;
|
||||
m_data[addr + 3] = (val >> 24) & 0xFF;
|
||||
m_data[addr + 4] = (val >> 32) & 0xFF;
|
||||
m_data[addr + 5] = (val >> 40) & 0xFF;
|
||||
m_data[addr + 6] = (val >> 48) & 0xFF;
|
||||
m_data[addr + 7] = (val >> 56) & 0xFF;
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
m_data[addr + 0] = (val >> 56) & 0xFF;
|
||||
m_data[addr + 1] = (val >> 48) & 0xFF;
|
||||
m_data[addr + 2] = (val >> 40) & 0xFF;
|
||||
m_data[addr + 3] = (val >> 32) & 0xFF;
|
||||
m_data[addr + 4] = (val >> 24) & 0xFF;
|
||||
m_data[addr + 5] = (val >> 16) & 0xFF;
|
||||
m_data[addr + 6] = (val >> 8) & 0xFF;
|
||||
m_data[addr + 7] = val & 0xFF;
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::w_DWord(StreamIndex addr, DWord val)
|
||||
{
|
||||
m_statuWriting = true;
|
||||
if (!is_validAddr(addr, tTypeSize::DWORD)) return false;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
m_data[addr + 0] = val & 0xFF;
|
||||
m_data[addr + 1] = (val >> 8) & 0xFF;
|
||||
m_data[addr + 2] = (val >> 16) & 0xFF;
|
||||
m_data[addr + 3] = (val >> 24) & 0xFF;
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
m_data[addr + 0] = (val >> 24) & 0xFF;
|
||||
m_data[addr + 1] = (val >> 16) & 0xFF;
|
||||
m_data[addr + 2] = (val >> 8) & 0xFF;
|
||||
m_data[addr + 3] = val & 0xFF;
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::w_Word(StreamIndex addr, Word val)
|
||||
{
|
||||
m_statuWriting = true;
|
||||
if (!is_validAddr(addr, tTypeSize::WORD)) return false;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
m_data[addr + 0] = val & 0xFF;
|
||||
m_data[addr + 1] = (val >> 8) & 0xFF;
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
m_data[addr + 0] = (val >> 8) & 0xFF;
|
||||
m_data[addr + 1] = val & 0xFF;
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::w_Byte(StreamIndex addr, Byte val)
|
||||
{
|
||||
m_statuWriting = true;
|
||||
if (!is_validAddr(addr, tTypeSize::BYTE)) return false;
|
||||
m_data[addr] = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::w_Addr(StreamIndex addr, StreamIndex val)
|
||||
{
|
||||
m_statuWriting = true;
|
||||
if (!is_validAddr(addr, tTypeSize::ADDR)) return false;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
m_data[addr + 0] = val & 0xFF;
|
||||
m_data[addr + 1] = (val >> 8) & 0xFF;
|
||||
m_data[addr + 2] = (val >> 16) & 0xFF;
|
||||
m_data[addr + 3] = (val >> 24) & 0xFF;
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
m_data[addr + 0] = (val >> 24) & 0xFF;
|
||||
m_data[addr + 1] = (val >> 16) & 0xFF;
|
||||
m_data[addr + 2] = (val >> 8) & 0xFF;
|
||||
m_data[addr + 3] = val & 0xFF;
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::w_Float(StreamIndex addr, f32 val)
|
||||
{
|
||||
m_statuWriting = true;
|
||||
if (!is_validAddr(addr, tTypeSize::FLOAT)) return false;
|
||||
__float_parser fp;
|
||||
fp.val = val;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
m_data[addr + 0] = fp.data[3];
|
||||
m_data[addr + 1] = fp.data[2];
|
||||
m_data[addr + 2] = fp.data[1];
|
||||
m_data[addr + 3] = fp.data[0];
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
m_data[addr + 0] = fp.data[0];
|
||||
m_data[addr + 1] = fp.data[1];
|
||||
m_data[addr + 2] = fp.data[2];
|
||||
m_data[addr + 3] = fp.data[3];
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::w_Double(StreamIndex addr, f64 val)
|
||||
{
|
||||
m_statuWriting = true;
|
||||
if (!is_validAddr(addr, tTypeSize::DOUBLE)) return false;
|
||||
__double_parser dp;
|
||||
dp.val = val;
|
||||
if (isLittleEndian())
|
||||
{
|
||||
m_data[addr++] = dp.data[7];
|
||||
m_data[addr++] = dp.data[6];
|
||||
m_data[addr++] = dp.data[5];
|
||||
m_data[addr++] = dp.data[4];
|
||||
m_data[addr++] = dp.data[3];
|
||||
m_data[addr++] = dp.data[2];
|
||||
m_data[addr++] = dp.data[1];
|
||||
m_data[addr ] = dp.data[0];
|
||||
}
|
||||
else if (isBigEndian())
|
||||
{
|
||||
m_data[addr++] = dp.data[0];
|
||||
m_data[addr++] = dp.data[1];
|
||||
m_data[addr++] = dp.data[2];
|
||||
m_data[addr++] = dp.data[3];
|
||||
m_data[addr++] = dp.data[4];
|
||||
m_data[addr++] = dp.data[5];
|
||||
m_data[addr++] = dp.data[6];
|
||||
m_data[addr ] = dp.data[7];
|
||||
}
|
||||
else return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::w_ByteStream(StreamIndex addr, const ByteStream& stream, bool store_size)
|
||||
{
|
||||
m_statuWriting = true;
|
||||
u32 stream_size = stream.size();
|
||||
if (store_size)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::ADDR + stream_size)) return false;
|
||||
if (!w_Addr(addr, stream_size)) return false;
|
||||
addr += tTypeSize::ADDR;
|
||||
}
|
||||
else if (!is_validAddr(addr, stream_size)) return false;
|
||||
for (StreamIndex j = addr; j < addr + stream_size; j++)
|
||||
m_data[j] = stream[j - addr];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialIO::w_String(StreamIndex addr, const String& str, bool store_size, bool null_terminate)
|
||||
{
|
||||
m_statuWriting = true;
|
||||
auto stream = Memory::stringToByteStream(str);
|
||||
u32 stream_size = stream.size();
|
||||
if (store_size && !null_terminate)
|
||||
{
|
||||
if (!is_validAddr(addr, tTypeSize::ADDR + stream_size)) return false;
|
||||
if (!w_Addr(addr, stream_size)) return false;
|
||||
addr += tTypeSize::ADDR;
|
||||
}
|
||||
else if (!is_validAddr(addr, stream_size)) return false;
|
||||
for (StreamIndex j = addr; j < addr + stream_size; j++)
|
||||
m_data[j] = stream[j - addr];
|
||||
addr += str.len() * tTypeSize::BYTE;
|
||||
if (null_terminate)
|
||||
if (!w_Byte(addr, 0x00)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SerialIO::is_validAddr(StreamIndex addr, StreamIndex offset)
|
||||
{
|
||||
if ((addr + offset - 1) >= m_data.size())
|
||||
{
|
||||
if (isAutoResizeEnabled() && m_statuWriting)
|
||||
{
|
||||
for (u32 i = 0; i <= m_resizeAmount; i++)
|
||||
m_data.push_back(0);
|
||||
m_statuWriting = false;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_statuWriting = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
m_statuWriting = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SerialIO::print(StreamIndex start, OutputHandlerBase& out)
|
||||
{
|
||||
u32 line_len = 32;
|
||||
u64 power = 1;
|
||||
while(power < size())
|
||||
power *= 2;
|
||||
Memory::printByteStream(m_data, start, line_len, power / line_len, out);
|
||||
}
|
||||
|
||||
bool SerialIO::saveToFile(const String& filePath)
|
||||
{
|
||||
return Memory::saveByteStreamToFile(getData(), filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
92
src/tools/LegacyOstdSerial.hpp
Normal file
92
src/tools/LegacyOstdSerial.hpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
OmniaFramework - A collection of useful functionality
|
||||
Copyright (C) 2026 OmniaX-Dev
|
||||
|
||||
This file is part of OmniaFramework.
|
||||
|
||||
OmniaFramework 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.
|
||||
|
||||
OmniaFramework 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 OmniaFramework. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostd/data/Types.hpp>
|
||||
#include <ostd/data/Bitfields.hpp>
|
||||
#include <ostd/data/BaseObject.hpp>
|
||||
|
||||
namespace ostd
|
||||
{
|
||||
class OutputHandlerBase;
|
||||
|
||||
namespace serial
|
||||
{
|
||||
class SerialIO
|
||||
{
|
||||
public: struct tEndianness {
|
||||
inline static constexpr u8 LittleEndian = 0x00;
|
||||
inline static constexpr u8 BigEndian = 0x01;
|
||||
};
|
||||
|
||||
public:
|
||||
inline SerialIO(void) { init(); }
|
||||
inline SerialIO(u64 size, u8 endianness = tEndianness::BigEndian) { init(size, endianness); }
|
||||
inline SerialIO(ByteStream& data, u8 endianness = tEndianness::BigEndian) { m_data = data; m_endianness = endianness; }
|
||||
bool init(u64 size = SerialIO::DefaultMaxSize, u8 endianness = tEndianness::BigEndian);
|
||||
bool r_QWord(StreamIndex addr, QWord& outVal);
|
||||
bool r_DWord(StreamIndex addr, DWord& outVal);
|
||||
bool r_Word(StreamIndex addr, Word& outVal);
|
||||
bool r_Byte(StreamIndex addr, Byte& outVal);
|
||||
bool r_Addr(StreamIndex addr, StreamIndex& outVal);
|
||||
bool r_Float(StreamIndex addr, f32& outVal);
|
||||
bool r_Double(StreamIndex addr, f64& outVal);
|
||||
bool r_ByteStream(StreamIndex addr, ByteStream& outStream);
|
||||
bool r_ByteStream(StreamIndex addr, ByteStream& outStream, u32 size);
|
||||
bool r_String(StreamIndex addr, String& outString);
|
||||
bool r_String(StreamIndex addr, String& outString, u32 size);
|
||||
bool r_NullTerminatedString(StreamIndex addr, String& outString);
|
||||
|
||||
bool w_QWord(StreamIndex addr, QWord val);
|
||||
bool w_DWord(StreamIndex addr, DWord val);
|
||||
bool w_Word(StreamIndex addr, Word val);
|
||||
bool w_Byte(StreamIndex addr, Byte val);
|
||||
bool w_Addr(StreamIndex addr, StreamIndex val);
|
||||
bool w_Float(StreamIndex addr, f32 val);
|
||||
bool w_Double(StreamIndex addr, f64 val);
|
||||
bool w_ByteStream(StreamIndex addr, const ByteStream& stream, bool store_size = true);
|
||||
bool w_String(StreamIndex addr, const String& str, bool store_size = false, bool null_terminate = true);
|
||||
bool is_validAddr(StreamIndex addr, StreamIndex offset = 1);
|
||||
inline u64 size(void) { return m_data.size(); }
|
||||
inline ByteStream& getData(void) { return m_data; }
|
||||
|
||||
void print(StreamIndex start, OutputHandlerBase& out);
|
||||
bool saveToFile(const String& filePath);
|
||||
|
||||
inline u8 getEndianness(void) const { return m_endianness; }
|
||||
inline bool isLittleEndian(void) const { return m_endianness == tEndianness::LittleEndian; }
|
||||
inline bool isBigEndian(void) const { return m_endianness == tEndianness::BigEndian; }
|
||||
|
||||
inline bool isAutoResizeEnabled(void) const { return m_autoResize; }
|
||||
inline void enableAutoResize(bool val = true, i32 resizeAmount = 1024) { m_autoResize = val; if (!val) return; m_resizeAmount = resizeAmount; }
|
||||
|
||||
private:
|
||||
ByteStream m_data;
|
||||
u8 m_endianness { tEndianness::BigEndian };
|
||||
bool m_autoResize { true };
|
||||
i32 m_resizeAmount { 1024 };
|
||||
bool m_statuWriting { false };
|
||||
|
||||
public:
|
||||
inline static constexpr u64 DefaultMaxSize = 512;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
#include "GlobalData.hpp"
|
||||
#include "../debugger/DisassemblyLoader.hpp"
|
||||
#include <ostd/io/Memory.hpp>
|
||||
#include <ostd/io/Serial.hpp>
|
||||
#include "../tools/LegacyOstdSerial.hpp"
|
||||
|
||||
namespace dragon
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "Utils.hpp"
|
||||
#include <ostd/io/Serial.hpp>
|
||||
#include <ostd/math/Random.hpp>
|
||||
|
||||
namespace dragon
|
||||
|
|
|
|||
Loading…
Reference in a new issue