rexglue-skate3/resources/templates/codegen/init_h.inja

329 lines
16 KiB
Text

// Generated by rexglue
// DO NOT EDIT - this file is auto-generated
#pragma once
//=============================================================================
// Project Configuration
//=============================================================================
#define REX_CONFIG_H_INCLUDED
{% if config_flags.skip_lr %}#define REX_CONFIG_SKIP_LR
{% endif %}{% if config_flags.ctr_as_local %}#define REX_CONFIG_CTR_AS_LOCAL
{% endif %}{% if config_flags.xer_as_local %}#define REX_CONFIG_XER_AS_LOCAL
{% endif %}{% if config_flags.reserved_as_local %}#define REX_CONFIG_RESERVED_AS_LOCAL
{% endif %}{% if config_flags.skip_msr %}#define REX_CONFIG_SKIP_MSR
{% endif %}{% if config_flags.cr_as_local %}#define REX_CONFIG_CR_AS_LOCAL
{% endif %}{% if config_flags.non_argument_as_local %}#define REX_CONFIG_NON_ARGUMENT_AS_LOCAL
{% endif %}{% if config_flags.non_volatile_as_local %}#define REX_CONFIG_NON_VOLATILE_AS_LOCAL
{% endif %}
#define REX_IMAGE_BASE {{ image_base }}ull
#define REX_IMAGE_SIZE {{ image_size }}ull
#define REX_CODE_BASE {{ code_base }}ull
#define REX_CODE_SIZE {{ code_size }}ull
#define REX_THUNK_RESERVE_SIZE {{ thunk_reserve_size }}ull
#define REXCRT_HEAP {% if rexcrt_heap %}1{% else %}0{% endif %}
//=============================================================================
// SDK Headers
//=============================================================================
#include <rex/ppc.h>
#include <rex/image_info.h>
#include <rex/logging.h>
#include <rex/chrono/clock.h>
#include <rex/perf/counter.h>
#include <rex/thread/mutex.h>
#include <rex/system/mmio_handler.h>
#include <atomic>
#include <cassert>
#include <csetjmp>
#include <cstdlib>
#include <stdexcept>
#include <string_view>
#include <unordered_map>
//=============================================================================
// Image Info
//=============================================================================
extern const rex::PPCImageInfo {{ project }}_PPCImageConfig;
extern PPCFuncMapping {{ project }}_PPCFuncMappings[];
//=============================================================================
// Function Definition Macros
//=============================================================================
#define DECLARE_REX_FUNC(name) \
REX_EXTERN(name); \
REX_EXTERN(__imp__##name)
#if defined(__APPLE__)
#define DEFINE_REX_FUNC(name) \
REX_EXTERN(__imp__##name); \
REX_WEAK_FUNC(name) { \
__imp__##name(ctx, base); \
} \
REX_EXTERN(__imp__##name)
#else
#define DEFINE_REX_FUNC(name) \
__attribute__((alias("__imp__" #name))) REX_WEAK_FUNC(name); \
REX_EXTERN(__imp__##name)
#endif
//=============================================================================
// Function Prologue
//=============================================================================
#if defined(REXGLUE_PROFILE_GUEST_FUNCTIONS) && defined(REXGLUE_ENABLE_PROFILING)
#include <tracy/Tracy.hpp>
#if defined(__clang__)
#define REX_FUNC_PROLOGUE() \
__builtin_assume(((size_t)base & 0x1F) == 0); \
ZoneNamedN(___tracy_guest_zone, __func__, true)
#elif defined(__GNUC__)
#define REX_FUNC_PROLOGUE() \
do { \
if (((size_t)base & 0x1F) != 0) \
__builtin_unreachable(); \
} while (0); \
ZoneNamedN(___tracy_guest_zone, __func__, true)
#else
#define REX_FUNC_PROLOGUE() ZoneNamedN(___tracy_guest_zone, __func__, true)
#endif
#else
#if defined(__clang__)
#define REX_FUNC_PROLOGUE() __builtin_assume(((size_t)base & 0x1F) == 0)
#elif defined(__GNUC__)
#define REX_FUNC_PROLOGUE() \
do { \
if (((size_t)base & 0x1F) != 0) \
__builtin_unreachable(); \
} while (0)
#else
#define REX_FUNC_PROLOGUE() ((void)0)
#endif
#endif
//=============================================================================
// Memory Access
//=============================================================================
#if REX_PLATFORM_WIN32 || (REX_PLATFORM_MAC && REX_ARCH_ARM64)
#define REX_PHYS_HOST_OFFSET(addr) (((u32)(addr) >= 0xE0000000u) ? 0x1000u : 0u)
#else
#define REX_PHYS_HOST_OFFSET(addr) 0u
#endif
#define REX_RAW_ADDR(x) (base + (u32)(x) + REX_PHYS_HOST_OFFSET(x))
#define REX_LOAD_U8(x) (*(volatile u8*)(base + (u32)(x) + REX_PHYS_HOST_OFFSET(x)))
#define REX_LOAD_U16(x) __builtin_bswap16(*(volatile u16*)(base + (u32)(x) + REX_PHYS_HOST_OFFSET(x)))
#define REX_LOAD_U32(x) __builtin_bswap32(*(volatile u32*)(base + (u32)(x) + REX_PHYS_HOST_OFFSET(x)))
#define REX_LOAD_U64(x) __builtin_bswap64(*(volatile u64*)(base + (u32)(x) + REX_PHYS_HOST_OFFSET(x)))
#define REX_LOAD_STRING(x, len) \
std::string_view(reinterpret_cast<const char*>(base + (u32)(x) + REX_PHYS_HOST_OFFSET(x)), (len))
#define REX_STORE_U8(x, y) (*(volatile u8*)(base + (u32)(x) + REX_PHYS_HOST_OFFSET(x)) = (y))
#define REX_STORE_U16(x, y) (*(volatile u16*)(base + (u32)(x) + REX_PHYS_HOST_OFFSET(x)) = __builtin_bswap16(y))
#define REX_STORE_U32(x, y) (*(volatile u32*)(base + (u32)(x) + REX_PHYS_HOST_OFFSET(x)) = __builtin_bswap32(y))
#define REX_STORE_U64(x, y) (*(volatile u64*)(base + (u32)(x) + REX_PHYS_HOST_OFFSET(x)) = __builtin_bswap64(y))
#define REX_MEMORY_SIZE 0x100000000ull
//=============================================================================
// MMIO
//=============================================================================
#define REX_IS_MMIO_ADDR(addr) ((addr) >= 0x7F000000u && (addr) < 0x80000000u)
#define REX_MM_STORE_U8(addr, val) \
do { \
u32 _mmio_addr = (addr); \
if (REX_IS_MMIO_ADDR(_mmio_addr)) { \
rex::runtime::MMIOHandler::global_handler()->CheckStore(_mmio_addr, \
static_cast<u32>(val)); \
} else { \
*(volatile u8*)(base + _mmio_addr + REX_PHYS_HOST_OFFSET(_mmio_addr)) = (val); \
} \
} while (0)
#define REX_MM_STORE_U16(addr, val) \
do { \
u32 _mmio_addr = (addr); \
if (REX_IS_MMIO_ADDR(_mmio_addr)) { \
rex::runtime::MMIOHandler::global_handler()->CheckStore(_mmio_addr, \
static_cast<u32>(val)); \
} else { \
*(volatile u16*)(base + _mmio_addr + REX_PHYS_HOST_OFFSET(_mmio_addr)) = \
__builtin_bswap16(val); \
} \
} while (0)
#define REX_MM_STORE_U32(addr, val) \
do { \
u32 _mmio_addr = (addr); \
if (REX_IS_MMIO_ADDR(_mmio_addr)) { \
rex::runtime::MMIOHandler::global_handler()->CheckStore(_mmio_addr, \
static_cast<u32>(val)); \
} else { \
*(volatile u32*)(base + _mmio_addr + REX_PHYS_HOST_OFFSET(_mmio_addr)) = \
__builtin_bswap32(val); \
} \
} while (0)
#define REX_MM_STORE_U64(addr, val) \
do { \
u32 _mmio_addr = (addr); \
if (REX_IS_MMIO_ADDR(_mmio_addr)) { \
u64 _v64 = static_cast<u64>(val); \
rex::runtime::MMIOHandler::global_handler()->CheckStore(_mmio_addr, \
static_cast<u32>(_v64 >> 32)); \
rex::runtime::MMIOHandler::global_handler()->CheckStore(_mmio_addr + 4, \
static_cast<u32>(_v64)); \
} else { \
*(volatile u64*)(base + _mmio_addr + REX_PHYS_HOST_OFFSET(_mmio_addr)) = \
__builtin_bswap64(val); \
} \
} while (0)
#define REX_MM_LOAD_U8(addr) \
(REX_IS_MMIO_ADDR(addr) ? ({ \
u32 _v; \
rex::runtime::MMIOHandler::global_handler()->CheckLoad(addr, &_v); \
static_cast<u8>(_v); \
}) \
: *(volatile u8*)(base + (addr) + REX_PHYS_HOST_OFFSET(addr)))
#define REX_MM_LOAD_U16(addr) \
(REX_IS_MMIO_ADDR(addr) \
? ({ \
u32 _v; \
rex::runtime::MMIOHandler::global_handler()->CheckLoad(addr, &_v); \
static_cast<u16>(_v); \
}) \
: __builtin_bswap16(*(volatile u16*)(base + (addr) + REX_PHYS_HOST_OFFSET(addr))))
#define REX_MM_LOAD_U32(addr) \
(REX_IS_MMIO_ADDR(addr) \
? ({ \
u32 _v; \
rex::runtime::MMIOHandler::global_handler()->CheckLoad(addr, &_v); \
_v; \
}) \
: __builtin_bswap32(*(volatile u32*)(base + (addr) + REX_PHYS_HOST_OFFSET(addr))))
#define REX_MM_LOAD_U64(addr) \
(REX_IS_MMIO_ADDR(addr) \
? ({ \
u32 _hi, _lo; \
rex::runtime::MMIOHandler::global_handler()->CheckLoad(addr, &_hi); \
rex::runtime::MMIOHandler::global_handler()->CheckLoad((addr) + 4, &_lo); \
(static_cast<u64>(_hi) << 32) | _lo; \
}) \
: __builtin_bswap64(*(volatile u64*)(base + (addr) + REX_PHYS_HOST_OFFSET(addr))))
//=============================================================================
// Function Dispatch
//=============================================================================
#define REX_CALL_FUNC(x) x(ctx, base)
{% include "codegen/_indirect_call.inja" %}
//=============================================================================
// Flush Mode
//=============================================================================
#define REX_SET_FLUSH_MODE(enable) \
do { if (enable) ctx.fpscr.enableFlushMode(); else ctx.fpscr.disableFlushMode(); } while (0)
//=============================================================================
// Misc
//=============================================================================
#define REX_UNIMPLEMENTED(addr, opcode) \
throw std::runtime_error("Unimplemented PPC instruction: " opcode)
#define REX_QUERY_TIMEBASE() rex::chrono::Clock::QueryGuestTickCount()
//=============================================================================
// Setjmp/Longjmp
//=============================================================================
inline std::unordered_map<u32, jmp_buf>& get_jmp_buf_map() {
static thread_local std::unordered_map<u32, jmp_buf> map;
return map;
}
#define ppc_setjmp(guest_buf_addr) (setjmp(::get_jmp_buf_map()[(guest_buf_addr)]))
[[noreturn]] inline void ppc_longjmp(u32 guest_buf_addr, int val) {
auto& map = get_jmp_buf_map();
auto it = map.find(guest_buf_addr);
if (it != map.end()) {
longjmp(it->second, val);
}
std::abort();
}
//=============================================================================
// Trap Handling
//=============================================================================
inline void ppc_trap(PPCContext& ctx, u8* base, u16 trap_type) {
switch (trap_type) {
case 20:
case 26: {
auto str = REX_LOAD_STRING(ctx.r3.u32, ctx.r4.u16);
REXCPU_DEBUG("(service trap) {}", str);
break;
}
case 0:
case 22:
REXCPU_WARN("tw/td trap hit (type {})", trap_type);
break;
case 25:
break;
default:
REXCPU_WARN("Unknown trap type {}", trap_type);
break;
}
}
//=============================================================================
// Interrupt Locks
//=============================================================================
inline std::atomic<i32>& ppc_global_lock_count_() {
static std::atomic<i32> count{0};
return count;
}
#define REX_CHECK_GLOBAL_LOCK() \
([&]() -> u64 { \
auto lock_ = rex::thread::global_critical_region::AcquireDirect(); \
return ppc_global_lock_count_().load() ? 0 : 0x8000; \
}())
#define REX_ENTER_GLOBAL_LOCK() \
do { \
rex::thread::global_critical_region::mutex().lock(); \
ppc_global_lock_count_().fetch_add(1); \
} while (0)
#define REX_LEAVE_GLOBAL_LOCK() \
do { \
auto old_count_ = ppc_global_lock_count_().fetch_sub(1); \
assert(old_count_ >= 1 && "LeaveGlobalLock called without matching EnterGlobalLock"); \
rex::thread::global_critical_region::mutex().unlock(); \
} while (0)
//=============================================================================
// Function Declarations
//=============================================================================
{% for fn in functions %}DECLARE_REX_FUNC({{ fn.name }});
{% endfor %}