From f530ef749adb15f53d85b7ddd0e3b4d40c60a196 Mon Sep 17 00:00:00 2001 From: DrChat Date: Tue, 22 Nov 2016 20:05:33 -0600 Subject: [PATCH] JIT documentation! --- docs/cpu.md | 73 +++++++++++++++++++++++++++++++++++----- docs/images/CPU-JIT.png | Bin 0 -> 11476 bytes 2 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 docs/images/CPU-JIT.png diff --git a/docs/cpu.md b/docs/cpu.md index 04903647f..9bb0a3f49 100644 --- a/docs/cpu.md +++ b/docs/cpu.md @@ -1,15 +1,70 @@ # CPU Documentation -## Code +## The JIT -Xenia uses a dynamic recompiler to recompile PPC instructions to host -architecture instructions at runtime. Functions are converted as they -are called by the guest/host and stored in a code cache. Currently, the -only backend that exists is the x64 backend. +![JIT Diagram](images/CPU-JIT.png?raw=true) -Unfortunately, one problem with this approach is that code usually never -ends up in the same spot across reruns due to multithreading. Host code -may also morph depending on which spots of a function are called first. +The JIT is the core of Xenia. It translates Xenon PowerPC code into native +code runnable on the host computer. + +There are 3 phases to translation: +1. Translation to IR (intermediate representation) +2. IR compilation/optimization +3. Backend emission + +PowerPC instructions are translated to Xenia's intermediate representation +format in src/xenia/cpu/ppc/ppc_emit_*.cc (e.g. processor control is done in +[ppc_emit_control.cc](../src/xenia/cpu/ppc/ppc_emit_control.cc)). HIR opcodes +are relatively simple opcodes such that any host can define an implementation. + +After the HIR is generated, it is ran through a compiler to prep it for generation. +The compiler is ran in a series of passes, the order of which is defined in +[ppc_translator.cc](../src/xenia/cpu/ppc/ppc_translator.cc). Some passes are +essential to the successful generation, while others are merely for optimization +purposes. Compiler passes are defined in src/xenia/cpu/compiler/passes with +descriptive class names. + +Finally, the backend consumes the HIR and emits code that runs natively on the +host. Currently, the only backend that exists is the x64 backend, with all the +emission done in +[x64_sequences.cc](../src/xenia/cpu/backend/x64/x64_sequences.cc). + +## ABI + +Xenia guest functions are not directly callable, but rather must be called +through APIs provided by Xenia. Xenia will first execute a thunk to transition +the host context to a state dependent on the JIT backend, and that will call the +guest code. + +### x64 + +Transition thunks defined in [x64_backend.cc](../src/xenia/cpu/backend/x64/x64_backend.cc#L389). +Registers are stored on the stack as defined by [StackLayout::Thunk](../src/xenia/cpu/backend/x64/x64_stack_layout.h#L96) +for later transitioning back to the host. + +Some registers are reserved for usage by the JIT to store temporary variables. +See: [X64Emitter::gpr_reg_map_ and X64Emitter::xmm_reg_map_](../src/xenia/cpu/backend/x64/x64_backend.cc#L57). + +#### Integer Registers + +Register | Usage +--- | --- +RAX | Scratch +RBX | JIT temp +RCX | Scratch +RDX | Scratch +RSP | Stack Pointer +RBP | Unused +RSI | PowerPC Context +RDI | Virtual Memory Base +R8-R11 | Unused (parameters) +R12-R15 | JIT temp + +#### Floating Point Registers +Register | Usage +--- | --- +XMM0-XMM5 | Scratch +XMM6-XMM15 | JIT temp ## Memory @@ -55,7 +110,7 @@ Programs are still allowed to use 64-bit PowerPC instructions, and registers are 64-bit as well, but 32-bit instructions will run in 32-bit mode. The CPU is largely similar to the PPC part in the PS3, so Cell documents often line up for the core instructions. The 360 adds some additional AltiVec -instructions, though,which are only documented in a few places (like the gcc source code, etc). +instructions, though, which are only documented in a few places (like the gcc source code, etc). * [Free60 Info](http://www.free60.org/Xenon_\(CPU\)) * [Power ISA docs](https://www.power.org/wp-content/uploads/2012/07/PowerISA_V2.06B_V2_PUBLIC.pdf) (aka 'PowerISA') diff --git a/docs/images/CPU-JIT.png b/docs/images/CPU-JIT.png new file mode 100644 index 0000000000000000000000000000000000000000..27567f8e1cb9106c33ad39df9116d7af48f88841 GIT binary patch literal 11476 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 QS{b0BqN7};XchH805b%61^@s6 literal 0 HcmV?d00001