164 lines
6.3 KiB
Markdown
164 lines
6.3 KiB
Markdown
## Xenia Xbox 360 Emulator: JIT vs Interpreter Architecture Analysis
|
|
Analysis of Xenia's architecture comparing JIT vs interpreter approaches for Rust porting. Key findings: JIT pipeline [1a-1d] uses Xbyak with no Rust equivalent, MMIO relies on hardware exceptions [2a-2d], while interpreter approach uses explicit MMIO checking [3a-3d]. The PPC context [4a-4d] and opcode infrastructure [5a-5d] support both approaches. Memory system [6a-6c] requires unsafe Rust regardless. Kernel HLE [7a-7c] and GPU shader translation [8a-8c] present additional challenges.
|
|
### 1. JIT Code Generation Pipeline
|
|
The current PPC-to-x64 JIT compilation pipeline using HIR and Xbyak
|
|
### 1a. JIT Pipeline Initialization (`ppc_translator.cc:44`)
|
|
Sets up scanner, HIR builder, compiler, and Xbyak assembler
|
|
```text
|
|
PPCTranslator::PPCTranslator(PPCFrontend* frontend) : frontend_(frontend) {
|
|
```
|
|
### 1b. HIR Optimization Passes (`ppc_translator.cc:57`)
|
|
Adds multiple optimization passes to the compiler pipeline
|
|
```text
|
|
compiler_->AddPass(std::make_unique<passes::ControlFlowAnalysisPass>());
|
|
```
|
|
### 1c. Xbyak-based Code Emitter (`x64_emitter.h:208`)
|
|
X64Emitter inherits from Xbyak for runtime x64 code generation
|
|
```text
|
|
class X64Emitter : public Xbyak::CodeGenerator {
|
|
```
|
|
### 1d. Host-to-Guest Thunk (`x64_backend.cc:656`)
|
|
Raw x64 assembly emitted for host↔guest ABI transitions
|
|
```text
|
|
mov(rdi, ptr[rsi + offsetof(ppc::PPCContext, virtual_membase)]); // membase
|
|
```
|
|
### 2. MMIO Exception Handling
|
|
Hardware exception-based MMIO interception used by the JIT
|
|
### 2a. Exception Handler Entry (`mmio_handler.cc:402`)
|
|
Catches access violations to handle MMIO operations
|
|
```text
|
|
bool MMIOHandler::ExceptionCallback(Exception* ex) {
|
|
```
|
|
### 2b. Filter Access Violations (`mmio_handler.cc:403`)
|
|
Only processes memory access violations
|
|
```text
|
|
if (ex->code() != Exception::Code::kAccessViolation) {
|
|
```
|
|
### 2c. Address Translation (`mmio_handler.cc:427`)
|
|
Translates host fault address back to guest virtual address
|
|
```text
|
|
fault_guest_virtual_address = host_to_guest_virtual_(
|
|
```
|
|
### 2d. Instruction Decoding (`mmio_handler.cc:449`)
|
|
Decodes the faulting x64 instruction to determine the operation
|
|
```text
|
|
if (!TryDecodeLoadStore(p, decoded_load_store)) {
|
|
```
|
|
### 3. Interpreter Alternative Approach
|
|
Explicit MMIO checking pattern that enables interpreter implementation
|
|
### 3a. Explicit MMIO Check Function (`x64_seq_memory.cc:1216`)
|
|
Pattern for checking MMIO ranges without exceptions
|
|
```text
|
|
static T MMIOAwareLoad(void* _ctx, unsigned int guestaddr) {
|
|
```
|
|
### 3b. Range Lookup (`x64_seq_memory.cc:1225`)
|
|
Explicitly checks if address is in mapped MMIO range
|
|
```text
|
|
auto gaddr = ctx->processor->memory()->LookupVirtualMappedRange(guestaddr);
|
|
```
|
|
### 3c. MMIO Callback Invocation (`x64_seq_memory.cc:1236`)
|
|
Calls MMIO read callback instead of accessing memory directly
|
|
```text
|
|
value = gaddr->read(nullptr, gaddr->callback_context, guestaddr);
|
|
```
|
|
### 3d. MMIO Handler Interface (`mmio_handler.h:73`)
|
|
Public API for explicit MMIO checking in interpreter mode
|
|
```text
|
|
bool CheckLoad(uint32_t virtual_address, uint32_t* out_value);
|
|
```
|
|
### 4. PPC Context and State Management
|
|
Register file and thread state structures that would need Rust porting
|
|
### 4a. PPC Register File (`ppc_context.h:378`)
|
|
32 GPRs, CTR, LR, MSR in the context structure
|
|
```text
|
|
uint64_t r[32]; // 0x20 General purpose registers
|
|
```
|
|
### 4b. Floating-Point and Vector Registers (`ppc_context.h:384`)
|
|
32 FPRs and 128 VMX128 vector registers
|
|
```text
|
|
double f[32]; // 0x120 Floating-point registers
|
|
```
|
|
### 4c. Thread State Context (`thread_state.h:49`)
|
|
Each guest thread owns a PPCContext pointer
|
|
```text
|
|
ppc::PPCContext* context_;
|
|
```
|
|
### 4d. Big-Endian Wrapper (`byte_order.h:134`)
|
|
Type that handles big-endian conversion for guest structures
|
|
```text
|
|
template <typename T>
|
|
using be = endian_store<T, std::endian::big>;
|
|
```
|
|
### 5. Opcode Dispatch Infrastructure
|
|
PPC opcode enumeration and lookup that enables interpreter implementation
|
|
### 5a. PPC Opcode Enumeration (`ppc_opcode.h:14`)
|
|
Complete enum of all PPC opcodes including VMX128 extensions
|
|
```text
|
|
enum class PPCOpcode : uint32_t {
|
|
```
|
|
### 5b. Opcode Dispatch Table (`ppc_opcode_lookup_gen.cc:262`)
|
|
Fast lookup table for opcode decoding
|
|
```text
|
|
case 0b000101: PPC_DECODER_HIT(vrlw128);
|
|
```
|
|
### 5c. VMX128 Instruction Encoding (`ppc_emit_altivec.cc:37`)
|
|
Macros for decoding Xbox 360-specific VMX128 instructions
|
|
```text
|
|
#define VX128(op, xop) (OP(op) | (((uint32_t)(xop)) & 0x3d0))
|
|
```
|
|
### 5d. Basic Block Discovery (`ppc_scanner.h:36`)
|
|
Finds basic block boundaries for potential interpreter caching
|
|
```text
|
|
std::vector<BlockInfo> FindBlocks(GuestFunction* function);
|
|
```
|
|
### 6. Memory System Architecture
|
|
4GB virtual address space management required for both approaches
|
|
### 6a. Virtual Memory Allocation (`memory.cc:142`)
|
|
Creates 4GB+ file-backed mapping for guest address space
|
|
```text
|
|
mapping_ = xe::memory::CreateFileMappingHandle(
|
|
```
|
|
### 6b. Virtual Memory Base (`memory.cc:167`)
|
|
Sets up virtual and physical memory base addresses
|
|
```text
|
|
virtual_membase_ = mapping_base_;
|
|
```
|
|
### 6c. Guest Address Translation (`ppc_context.h:433`)
|
|
Fast inline function for translating guest to host addresses
|
|
```text
|
|
inline T TranslateVirtual(uint32_t guest_address) const {
|
|
```
|
|
### 7. Kernel HLE System
|
|
Massive kernel export table that would need Rust porting
|
|
### 7a. Kernel Export Table (`xboxkrnl_table.inc:15`)
|
|
96KB+ table of all xboxkrnl exports
|
|
```text
|
|
XE_EXPORT(xboxkrnl, 0x00000001, DbgBreakPoint, kFunction),
|
|
```
|
|
### 7b. Guest Thread Structure (`xthread.h:256`)
|
|
Packed big-endian X_KTHREAD structure living in guest memory
|
|
```text
|
|
xe::be<uint32_t> stack_base; // 0x5C
|
|
```
|
|
### 7c. Kernel State Management (`emulator.h:349`)
|
|
Central kernel object tracking all guest kernel state
|
|
```text
|
|
std::unique_ptr<kernel::KernelState> kernel_state_;
|
|
```
|
|
### 8. GPU Shader Translation
|
|
Complex shader translation pipeline that poses challenges for Rust porting
|
|
### 8a. SPIR-V Builder Initialization (`spirv_shader_translator.cc:155`)
|
|
Uses glslang C++ API for SPIR-V generation
|
|
```text
|
|
builder_ = std::make_unique<SpirvBuilder>(
|
|
```
|
|
### 8b. Shader Interpreter (`shader_interpreter.h:51`)
|
|
Existing interpreter for simple shaders without texture fetches
|
|
```text
|
|
static bool CanInterpretShader(const Shader& shader) {
|
|
```
|
|
### 8c. C++ Dependency (`premake5.lua:31`)
|
|
glslang dependency with no direct Rust equivalent
|
|
```text
|
|
"glslang-spirv",
|
|
``` |