lucore now has its own assertion system
ripped off of how ive done it in like 10 different projects by now™️
This commit is contained in:
parent
a8fb72804c
commit
c20c852554
|
@ -5,9 +5,11 @@ project(lucore
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(lucore INTERFACE)
|
add_library(lucore
|
||||||
|
src/Assert.cpp
|
||||||
|
)
|
||||||
|
|
||||||
target_compile_features(lucore INTERFACE cxx_std_20)
|
target_compile_features(lucore PUBLIC cxx_std_20)
|
||||||
target_include_directories(lucore INTERFACE ${PROJECT_SOURCE_DIR}/include)
|
target_include_directories(lucore PUBLIC ${PROJECT_SOURCE_DIR}/include)
|
||||||
|
|
||||||
add_library(lucore::lucore ALIAS lucore)
|
add_library(lucore::lucore ALIAS lucore)
|
||||||
|
|
|
@ -1,16 +1,35 @@
|
||||||
//! Lucore Assert Wrappers
|
//! Lucore Assert Wrappers
|
||||||
|
|
||||||
// this just plumbs everything to libc by default
|
#pragma once
|
||||||
// your project can choose to configure its own assertion handler by
|
|
||||||
// defining LUCORE_ASSERT()
|
|
||||||
// TODO: LUCORE_VERIFY/plumbing this into our own assertion code?
|
|
||||||
#ifndef LUCORE_ASSERT
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#include <cstdio>
|
||||||
#define LUCORE_ASSERT(...) assert(__VA_ARGS__)
|
|
||||||
|
namespace lucore {
|
||||||
|
|
||||||
|
// TODO: wrapper which uses source_location (we don't need no macros anymore!)
|
||||||
|
[[noreturn]] void ExitMsg(const char* fileName, int fileLine, const char* message);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
#define LUCORE_ASSERT(expr, format, ...) \
|
||||||
|
if(!(expr)) [[unlikely]] { \
|
||||||
|
char buffer[256]; \
|
||||||
|
std::snprintf(&buffer[0], sizeof(buffer), \
|
||||||
|
"[Lucore] Assertion \"%s\" failed with message: " format "\n", #expr, \
|
||||||
|
##__VA_ARGS__); \
|
||||||
|
::lucore::ExitMsg(__FILE__, __LINE__, &buffer[0]); \
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define LUCORE_ASSERT(...)
|
#define LUCORE_ASSERT(expr, format, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
// CHECK() is always active, even in release builds
|
||||||
|
#define LUCORE_CHECK(expr, format, ...) \
|
||||||
|
if(!(expr)) [[unlikely]] { \
|
||||||
|
char buffer[256]; \
|
||||||
|
std::snprintf(&buffer[0], sizeof(buffer), \
|
||||||
|
"[Lucore] Check \"%s\" failed with message: " format "\n", #expr, \
|
||||||
|
##__VA_ARGS__); \
|
||||||
|
::lucore::ExitMsg(__FILE__, __LINE__, &buffer[0]); \
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ namespace lucore::detail {
|
||||||
|
|
||||||
struct Nullref_t {};
|
struct Nullref_t {};
|
||||||
|
|
||||||
|
/// Sentinel value to explicitly not populate an OptionalRef.
|
||||||
|
inline static Nullref_t NullRef {};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct OptionalRef; // sfinae on non-reference types
|
struct OptionalRef; // sfinae on non-reference types
|
||||||
|
|
||||||
|
@ -35,7 +38,9 @@ namespace lucore::detail {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr T& Value() const {
|
constexpr T& Value() const {
|
||||||
LUCORE_ASSERT(HasValue() && "Attempt to access OptionalRef without stored value!");
|
// this is a CHECK() since allowing unchecked access in release builds is probably a
|
||||||
|
// very very bad idea
|
||||||
|
LUCORE_CHECK(HasValue(), "Attempt to access OptionalRef without stored value!");
|
||||||
return *ptr;
|
return *ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,8 +65,6 @@ namespace lucore::detail {
|
||||||
T* ptr {};
|
T* ptr {};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Sentinel value to explicitly not populate an OptionalRef.
|
|
||||||
inline static Nullref_t NullRef {};
|
|
||||||
} // namespace lucore::detail
|
} // namespace lucore::detail
|
||||||
|
|
||||||
namespace lucore {
|
namespace lucore {
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
//! Implementation of lucore assertion facilities
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
|
namespace lucore {
|
||||||
|
|
||||||
|
[[noreturn]] void ExitMsg(const char* fileName, int fileLine, const char* message) {
|
||||||
|
// TODO: move this to logger functionality of lucore (gmsv_lcpu will end up containing a
|
||||||
|
// Sink impl..)
|
||||||
|
std::puts(message);
|
||||||
|
std::quick_exit(0xAF);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lucore
|
|
@ -7,6 +7,7 @@ project(riscv_emu
|
||||||
|
|
||||||
add_library(riscv
|
add_library(riscv
|
||||||
src/Bus.cpp
|
src/Bus.cpp
|
||||||
|
src/MemoryDevice.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_features(riscv PUBLIC cxx_std_20)
|
target_compile_features(riscv PUBLIC cxx_std_20)
|
||||||
|
|
|
@ -1,21 +1,17 @@
|
||||||
#include <riscv/Bus.hpp>
|
#include <riscv/Bus.hpp>
|
||||||
#include "riscv/Types.hpp"
|
|
||||||
|
|
||||||
#include <span>
|
#include <span>
|
||||||
|
|
||||||
|
#include "riscv/Types.hpp"
|
||||||
|
|
||||||
namespace riscv {
|
namespace riscv {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
template <bool Rom>
|
||||||
template<bool Rom>
|
|
||||||
struct BasicMemoryDevice : public Bus::Device {
|
struct BasicMemoryDevice : public Bus::Device {
|
||||||
BasicMemoryDevice(usize size)
|
BasicMemoryDevice(usize size) : memorySize(size) {
|
||||||
: memorySize(size) {
|
|
||||||
memory = new u8[size];
|
memory = new u8[size];
|
||||||
// TODO(feat): we should have a global panic system which is hooked in
|
LUCORE_CHECK(memory, "Could not allocate buffer for memory device.");
|
||||||
// so that we don't just blindly crash everything
|
|
||||||
assert(memory && "Out of host memory");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~BasicMemoryDevice() {
|
virtual ~BasicMemoryDevice() {
|
||||||
|
@ -43,7 +39,7 @@ namespace riscv {
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 PeekWord(AddressT offset) override {
|
u32 PeekWord(AddressT offset) override {
|
||||||
return std::bit_cast<u32*>(memory)[OffsetToIndex<u32>(offset)];
|
return std::bit_cast<u32*>(memory)[OffsetToIndex<u32>(offset)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void PokeByte(AddressT offset, u8 value) override {
|
void PokeByte(AddressT offset, u8 value) override {
|
||||||
|
@ -70,29 +66,26 @@ namespace riscv {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
/// helper used for implementing stuff
|
/// helper used for implementing stuff
|
||||||
template<class T>
|
template <class T>
|
||||||
constexpr usize OffsetToIndex(AddressT offset) {
|
constexpr usize OffsetToIndex(AddressT offset) {
|
||||||
return (offset % memorySize) / sizeof(T);
|
return (offset % memorySize) / sizeof(T);
|
||||||
}
|
}
|
||||||
|
|
||||||
// remember what we were attached to via "signal"
|
// remember what we were attached to via "signal"
|
||||||
Bus* attachedBus{};
|
Bus* attachedBus {};
|
||||||
AddressT baseAddress{};
|
AddressT baseAddress {};
|
||||||
|
|
||||||
u8* memory{};
|
u8* memory {};
|
||||||
usize memorySize{};
|
usize memorySize {};
|
||||||
};
|
};
|
||||||
|
|
||||||
using RamDevice = BasicMemoryDevice<false>;
|
using RamDevice = BasicMemoryDevice<false>;
|
||||||
using RomDevice = BasicMemoryDevice<true>;
|
using RomDevice = BasicMemoryDevice<true>;
|
||||||
|
|
||||||
}
|
} // namespace
|
||||||
|
|
||||||
|
// Bus::Device* NewRam()
|
||||||
|
|
||||||
//Bus::Device* NewRam()
|
} // namespace riscv
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue