mirror of
https://github.com/pound-emu/pound.git
synced 2025-12-12 10:37:00 +00:00
The core of the machine-type support is the new operations table, kvm_ops_t. This acts as a standard C-style virtual table decoupling the generic KVM core logic from target specific hardware emualtion. The kvm_t VM instance now points to an ops table, which defines the "personality" of the guest. A kvm_probe() factory function has been added to initialize a kvm_t instance with the correct ops table for a given machine type (eg, Switch 1). The ops table's .mmio_read and .mmio_write function pointers are the link between the armv8 CPU core and this new MMIO dispatcher. When a physical memory access is determined to be MMIO, the VM will call the appropriate function pointer, which in turn will use the MMIO dispatcher to find and execute the correct device handler. The initial implementation for the Switch 1 target (targets/switch1/hardware/probe.cpp) is a stub. The bootstrapping logic will be added in subsequent patches. Signed-off-by: Ronald Caesar <github43132@proton.me>
121 lines
5.1 KiB
C++
121 lines
5.1 KiB
C++
// Copyright 2025 Xenon Emulator Project. All rights reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "Logging/Log.h"
|
|
|
|
// Sometimes we want to try to continue even after hitting an assert.
|
|
// However touching this file yields a global recompilation as this header is included almost
|
|
// everywhere. So let's just move the handling of the failed assert to a single cpp file.
|
|
|
|
void assert_fail_impl();
|
|
void throw_fail_impl();
|
|
[[noreturn]] void unreachable_impl();
|
|
void assert_fail_debug_msg(const std::string& msg);
|
|
void throw_fail_debug_msg(const std::string& msg);
|
|
|
|
#ifdef _MSC_VER
|
|
#define POUND_NO_INLINE __declspec(noinline)
|
|
#else
|
|
#define POUND_NO_INLINE __attribute__((noinline))
|
|
#endif
|
|
|
|
#define THROW(_a_) \
|
|
( \
|
|
[&]() POUND_NO_INLINE \
|
|
{ \
|
|
if (!(_a_)) [[unlikely]] \
|
|
{ \
|
|
LOG_CRITICAL(Debug, "Assertion Failed!"); \
|
|
throw_fail_impl(); \
|
|
} \
|
|
})
|
|
|
|
#define ASSERT(_a_) \
|
|
( \
|
|
[&]() POUND_NO_INLINE \
|
|
{ \
|
|
if (!(_a_)) [[unlikely]] \
|
|
{ \
|
|
LOG_CRITICAL(Debug, "Assertion Failed!"); \
|
|
assert_fail_impl(); \
|
|
} \
|
|
})
|
|
|
|
#define THROW_MSG(_a_, ...) \
|
|
( \
|
|
[&]() POUND_NO_INLINE \
|
|
{ \
|
|
if (!(_a_)) [[unlikely]] \
|
|
{ \
|
|
LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \
|
|
throw_fail_impl(); \
|
|
} \
|
|
})
|
|
|
|
#define ASSERT_MSG(_a_, ...) \
|
|
( \
|
|
[&]() POUND_NO_INLINE \
|
|
{ \
|
|
if (!(_a_)) [[unlikely]] \
|
|
{ \
|
|
LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \
|
|
assert_fail_impl(); \
|
|
} \
|
|
})
|
|
|
|
#define UNREACHABLE() \
|
|
do \
|
|
{ \
|
|
LOG_CRITICAL(Debug, "Unreachable code!"); \
|
|
unreachable_impl(); \
|
|
} while (0)
|
|
|
|
#define UNREACHABLE_MSG(...) \
|
|
do \
|
|
{ \
|
|
LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); \
|
|
unreachable_impl(); \
|
|
} while (0)
|
|
|
|
#ifdef _DEBUG
|
|
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
|
|
#define DEBUG_ASSERT_MSG(_a_, ...) ASSERT_MSG(_a_, __VA_ARGS__)
|
|
#else // not debug
|
|
#define DEBUG_ASSERT(_a_) \
|
|
do \
|
|
{ \
|
|
} while (0)
|
|
#define DEBUG_ASSERT_MSG(_a_, _desc_, ...) \
|
|
do \
|
|
{ \
|
|
} while (0)
|
|
#endif
|
|
|
|
#define UNIMPLEMENTED() THROW_MSG(false, "Unimplemented code!")
|
|
#define UNIMPLEMENTED_MSG(...) THROW_MSG(false, __VA_ARGS__)
|
|
|
|
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
|
|
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
|
|
|
|
// If the assert is ignored, execute _b_
|
|
#define ASSERT_OR_EXECUTE(_a_, _b_) \
|
|
do \
|
|
{ \
|
|
ASSERT(_a_); \
|
|
if (!(_a_)) [[unlikely]] \
|
|
{ \
|
|
_b_ \
|
|
} \
|
|
} while (0)
|
|
|
|
// If the assert is ignored, execute _b_
|
|
#define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \
|
|
do \
|
|
{ \
|
|
ASSERT_MSG(_a_, __VA_ARGS__); \
|
|
if (!(_a_)) [[unlikely]] \
|
|
{ \
|
|
_b_ \
|
|
} \
|
|
} while (0)
|