From b28c51271d645709ddaa96a2c35e7f02fcf905e8 Mon Sep 17 00:00:00 2001
From: Ben Vanik <ben.vanik@gmail.com>
Date: Sun, 13 Oct 2013 22:53:33 -0700
Subject: [PATCH] A bunch of disasm instructions used by some games.

---
 src/xenia/cpu/ppc/disasm_altivec.cc | 33 +++++++++++++++++++++++------
 src/xenia/cpu/ppc/disasm_fpu.cc     | 14 ++++++++----
 src/xenia/cpu/ppc/instr.cc          |  7 ++++++
 src/xenia/cpu/ppc/instr.h           | 10 +++++++++
 4 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/src/xenia/cpu/ppc/disasm_altivec.cc b/src/xenia/cpu/ppc/disasm_altivec.cc
index 1008a32fe..08b23b43c 100644
--- a/src/xenia/cpu/ppc/disasm_altivec.cc
+++ b/src/xenia/cpu/ppc/disasm_altivec.cc
@@ -1268,7 +1268,10 @@ XEDISASMR(vsl,            0x100001C4, VX  )(InstrData& i, InstrDisasm& d) {
 XEDISASMR(vslb,           0x10000104, VX  )(InstrData& i, InstrDisasm& d) {
   d.Init("vslb", "Vector Shift Left Integer Byte",
          InstrDisasm::kVMX);
-  return 1;
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite);
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VA, InstrRegister::kRead);
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead);
+  return d.Finish();
 }
 
 XEDISASMR(vsldoi,         0x1000002C, VXA )(InstrData& i, InstrDisasm& d) {
@@ -1324,31 +1327,49 @@ XEDISASMR(vslw128,        VX128(6, 208),    VX128  )(InstrData& i, InstrDisasm&
 XEDISASMR(vspltb,         0x1000020C, VX  )(InstrData& i, InstrDisasm& d) {
   d.Init("vspltb", "Vector Splat Byte",
          InstrDisasm::kVMX);
-  return 1;
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite);
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead);
+  d.AddUImmOperand(i.VX.VA & 0xF, 1);
+  return d.Finish();
 }
 
 XEDISASMR(vsplth,         0x1000024C, VX  )(InstrData& i, InstrDisasm& d) {
   d.Init("vsplth", "Vector Splat Half Word",
          InstrDisasm::kVMX);
-  return 1;
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite);
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VB, InstrRegister::kRead);
+  d.AddUImmOperand(i.VX.VA & 0x7, 1);
+  return d.Finish();
 }
 
 XEDISASMR(vspltisb,       0x1000030C, VX  )(InstrData& i, InstrDisasm& d) {
   d.Init("vspltisb", "Vector Splat Immediate Signed Byte",
          InstrDisasm::kVMX);
-  return 1;
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite);
+  // 5bit -> 8bit sign extend
+  uint64_t v = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFFFFFFFFFFFFFF0) : i.VX.VA;
+  d.AddSImmOperand(v, 1);
+  return d.Finish();
 }
 
 XEDISASMR(vspltish,       0x1000034C, VX  )(InstrData& i, InstrDisasm& d) {
   d.Init("vspltish", "Vector Splat Immediate Signed Half Word",
          InstrDisasm::kVMX);
-  return 1;
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite);
+  // 5bit -> 16bit sign extend
+  uint64_t v = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFFFFFFFFFFFFFF0) : i.VX.VA;
+  d.AddSImmOperand(v, 1);
+  return d.Finish();
 }
 
 XEDISASMR(vspltisw,       0x1000038C, VX  )(InstrData& i, InstrDisasm& d) {
   d.Init("vspltisw", "Vector Splat Immediate Signed Word",
          InstrDisasm::kVMX);
-  return 1;
+  d.AddRegOperand(InstrRegister::kVMX, i.VX.VD, InstrRegister::kWrite);
+  // 5bit -> 32bit sign extend
+  uint64_t v = (i.VX.VA & 0x10) ? (i.VX.VA | 0xFFFFFFFFFFFFFFF0) : i.VX.VA;
+  d.AddSImmOperand(v, 1);
+  return d.Finish();
 }
 
 XEDISASMR(vspltisw128,    VX128_3(6, 1904), VX128_3)(InstrData& i, InstrDisasm& d) {
diff --git a/src/xenia/cpu/ppc/disasm_fpu.cc b/src/xenia/cpu/ppc/disasm_fpu.cc
index 5c977524c..6b63d8290 100644
--- a/src/xenia/cpu/ppc/disasm_fpu.cc
+++ b/src/xenia/cpu/ppc/disasm_fpu.cc
@@ -299,8 +299,11 @@ XEDISASMR(mcrfs,        0xFC000080, X  )(InstrData& i, InstrDisasm& d) {
 }
 
 XEDISASMR(mffsx,        0xFC00048E, X  )(InstrData& i, InstrDisasm& d) {
-  XEINSTRNOTIMPLEMENTED();
-  return 1;
+  d.Init("mffs", "Move from FPSCR",
+         InstrDisasm::kFP | (i.X.Rc ? InstrDisasm::kRc : 0));
+  d.AddFPSCR(InstrRegister::kRead);
+  d.AddRegOperand(InstrRegister::kFPR, i.X.RT, InstrRegister::kWrite);
+  return d.Finish();
 }
 
 XEDISASMR(mtfsb0x,      0xFC00008C, X  )(InstrData& i, InstrDisasm& d) {
@@ -314,8 +317,11 @@ XEDISASMR(mtfsb1x,      0xFC00004C, X  )(InstrData& i, InstrDisasm& d) {
 }
 
 XEDISASMR(mtfsfx,       0xFC00058E, XFL)(InstrData& i, InstrDisasm& d) {
-  XEINSTRNOTIMPLEMENTED();
-  return 1;
+  d.Init("mtfsf", "Move to FPSCR Fields",
+         InstrDisasm::kFP | (i.XFL.Rc ? InstrDisasm::kRc : 0));
+  d.AddFPSCR(InstrRegister::kWrite);
+  d.AddRegOperand(InstrRegister::kFPR, i.XFL.RB, InstrRegister::kRead);
+  return d.Finish();
 }
 
 XEDISASMR(mtfsfix,      0xFC00010C, X  )(InstrData& i, InstrDisasm& d) {
diff --git a/src/xenia/cpu/ppc/instr.cc b/src/xenia/cpu/ppc/instr.cc
index c87c07f0c..b53c4bfe9 100644
--- a/src/xenia/cpu/ppc/instr.cc
+++ b/src/xenia/cpu/ppc/instr.cc
@@ -336,6 +336,13 @@ void InstrDisasm::AddCR(uint32_t bf, InstrRegister::Access access) {
   special_registers.push_back(i);
 }
 
+void InstrDisasm::AddFPSCR(InstrRegister::Access access) {
+  InstrRegister i = {
+    InstrRegister::kFPSCR, 0, access
+  };
+  special_registers.push_back(i);
+}
+
 void InstrDisasm::AddRegOperand(
     InstrRegister::RegisterSet set, uint32_t ordinal,
     InstrRegister::Access access, const char* display) {
diff --git a/src/xenia/cpu/ppc/instr.h b/src/xenia/cpu/ppc/instr.h
index b5ecac3a9..7fa0c5c97 100644
--- a/src/xenia/cpu/ppc/instr.h
+++ b/src/xenia/cpu/ppc/instr.h
@@ -171,6 +171,15 @@ typedef struct {
       uint32_t                : 6;
     } XFX;
     // kXEPPCInstrFormatXFL
+    struct {
+      uint32_t        Rc      : 1;
+      uint32_t                : 10;
+      uint32_t        RB      : 5;
+      uint32_t                : 1;
+      uint32_t        FM      : 8;
+      uint32_t                : 1;
+      uint32_t                : 6;
+    } XFL;
     // kXEPPCInstrFormatXS
     struct {
       uint32_t        Rc      : 1;
@@ -478,6 +487,7 @@ public:
   void AddLR(InstrRegister::Access access);
   void AddCTR(InstrRegister::Access access);
   void AddCR(uint32_t bf, InstrRegister::Access access);
+  void AddFPSCR(InstrRegister::Access access);
   void AddRegOperand(InstrRegister::RegisterSet set, uint32_t ordinal,
                      InstrRegister::Access access, const char* display = NULL);
   void AddSImmOperand(uint64_t value, size_t width, const char* display = NULL);