// 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 #include #include #include #include #include #include #include #include #include #include #include #include #include //============================================================================= // 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) #define DEFINE_REX_FUNC(name) \ __attribute__((alias("__imp__" #name))) REX_WEAK_FUNC(name); \ REX_EXTERN(__imp__##name) //============================================================================= // Function Prologue //============================================================================= #if defined(REXGLUE_PROFILE_GUEST_FUNCTIONS) && defined(REXGLUE_ENABLE_PROFILING) #include #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 #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(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(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(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(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(val); \ rex::runtime::MMIOHandler::global_handler()->CheckStore(_mmio_addr, \ static_cast(_v64 >> 32)); \ rex::runtime::MMIOHandler::global_handler()->CheckStore(_mmio_addr + 4, \ static_cast(_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(_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(_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(_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& get_jmp_buf_map() { static thread_local std::unordered_map 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& ppc_global_lock_count_() { static std::atomic 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 %}