diff --git a/src/xenia/cpu/ppc/disasm_alu.cc b/src/xenia/cpu/ppc/disasm_alu.cc index 9d0eb489f..87e53b35e 100644 --- a/src/xenia/cpu/ppc/disasm_alu.cc +++ b/src/xenia/cpu/ppc/disasm_alu.cc @@ -474,75 +474,76 @@ XEDISASMR(xoris, 0x6C000000, D )(InstrData& i, InstrDisasm& d) { // Integer rotate (A-6) -XEDISASMR(rldclx, 0x78000010, MDS)(InstrData& i, InstrDisasm& d) { - d.Init("rldcl", "Rotate Left Doubleword then Clear Left", - i.MDS.Rc ? InstrDisasm::kRc : 0); - d.AddRegOperand(InstrRegister::kGPR, i.MDS.RA, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kGPR, i.MDS.RT, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kGPR, i.MDS.RB, InstrRegister::kRead); - d.AddUImmOperand((i.MDS.MB5 << 5) | i.MDS.MB, 1); - return d.Finish(); -} - -XEDISASMR(rldcrx, 0x78000012, MDS)(InstrData& i, InstrDisasm& d) { - d.Init("rldcr", "Rotate Left Doubleword then Clear Right", - i.MDS.Rc ? InstrDisasm::kRc : 0); - d.AddRegOperand(InstrRegister::kGPR, i.MDS.RA, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kGPR, i.MDS.RT, InstrRegister::kRead); - d.AddRegOperand(InstrRegister::kGPR, i.MDS.RB, InstrRegister::kRead); - d.AddUImmOperand((i.MDS.MB5 << 5) | i.MDS.MB, 1); - return d.Finish(); -} - -XEDISASMR(rldicx, 0x78000008, MD )(InstrData& i, InstrDisasm& d) { - const char* name; - const char* desc; - uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; - uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; - if (mb == 0x3E) { - name = "sldi"; - desc = "Shift Left Immediate"; +XEDISASMR(rld, 0x78000000, MDS)(InstrData& i, InstrDisasm& d) { + if (i.MD.idx == 0) { + // XEDISASMR(rldiclx, 0x78000000, MD ) + d.Init("rldicl", "Rotate Left Doubleword Immediate then Clear Left", + i.MD.Rc ? InstrDisasm::kRc : 0); + d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead); + d.AddUImmOperand((i.MD.SH5 << 5) | i.MD.SH, 1); + d.AddUImmOperand((i.MD.MB5 << 5) | i.MD.MB, 1); + return d.Finish(); + } else if (i.MD.idx == 1) { + // XEDISASMR(rldicrx, 0x78000004, MD ) + d.Init("rldicr", "Rotate Left Doubleword Immediate then Clear Right", + i.MD.Rc ? InstrDisasm::kRc : 0); + d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead); + d.AddUImmOperand((i.MD.SH5 << 5) | i.MD.SH, 1); + d.AddUImmOperand((i.MD.MB5 << 5) | i.MD.MB, 1); + return d.Finish(); + } else if (i.MD.idx == 2) { + // XEDISASMR(rldicx, 0x78000008, MD ) + const char* name; + const char* desc; + uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; + uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; + if (mb == 0x3E) { + name = "sldi"; + desc = "Shift Left Immediate"; + } else { + name = "rldic"; + desc = "Rotate Left Doubleword Immediate then Clear"; + } + d.Init(name, desc, + i.MD.Rc ? InstrDisasm::kRc : 0); + d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead); + d.AddUImmOperand(sh, 1); + d.AddUImmOperand(mb, 1); + return d.Finish(); + } else if (i.MDS.idx == 8) { + // XEDISASMR(rldclx, 0x78000010, MDS) + d.Init("rldcl", "Rotate Left Doubleword then Clear Left", + i.MDS.Rc ? InstrDisasm::kRc : 0); + d.AddRegOperand(InstrRegister::kGPR, i.MDS.RA, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kGPR, i.MDS.RT, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kGPR, i.MDS.RB, InstrRegister::kRead); + d.AddUImmOperand((i.MDS.MB5 << 5) | i.MDS.MB, 1); + return d.Finish(); + } else if (i.MDS.idx == 9) { + // XEDISASMR(rldcrx, 0x78000012, MDS) + d.Init("rldcr", "Rotate Left Doubleword then Clear Right", + i.MDS.Rc ? InstrDisasm::kRc : 0); + d.AddRegOperand(InstrRegister::kGPR, i.MDS.RA, InstrRegister::kWrite); + d.AddRegOperand(InstrRegister::kGPR, i.MDS.RT, InstrRegister::kRead); + d.AddRegOperand(InstrRegister::kGPR, i.MDS.RB, InstrRegister::kRead); + d.AddUImmOperand((i.MDS.MB5 << 5) | i.MDS.MB, 1); + return d.Finish(); + } else if (i.MD.idx == 3) { + // XEDISASMR(rldimix, 0x7800000C, MD ) + d.Init("rldimi", "Rotate Left Doubleword Immediate then Mask Insert", + i.MD.Rc ? InstrDisasm::kRc : 0); + d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kReadWrite); + d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead); + d.AddUImmOperand((i.MD.SH5 << 5) | i.MD.SH, 1); + d.AddUImmOperand((i.MD.MB5 << 5) | i.MD.MB, 1); + return d.Finish(); } else { - name = "rldic"; - desc = "Rotate Left Doubleword Immediate then Clear"; + XEASSERTALWAYS(); + return 1; } - d.Init(name, desc, - i.MD.Rc ? InstrDisasm::kRc : 0); - d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead); - d.AddUImmOperand(sh, 1); - d.AddUImmOperand(mb, 1); - return d.Finish(); -} - -XEDISASMR(rldiclx, 0x78000000, MD )(InstrData& i, InstrDisasm& d) { - d.Init("rldicl", "Rotate Left Doubleword Immediate then Clear Left", - i.MD.Rc ? InstrDisasm::kRc : 0); - d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead); - d.AddUImmOperand((i.MD.SH5 << 5) | i.MD.SH, 1); - d.AddUImmOperand((i.MD.MB5 << 5) | i.MD.MB, 1); - return d.Finish(); -} - -XEDISASMR(rldicrx, 0x78000004, MD )(InstrData& i, InstrDisasm& d) { - d.Init("rldicr", "Rotate Left Doubleword Immediate then Clear Right", - i.MD.Rc ? InstrDisasm::kRc : 0); - d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kWrite); - d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead); - d.AddUImmOperand((i.MD.SH5 << 5) | i.MD.SH, 1); - d.AddUImmOperand((i.MD.MB5 << 5) | i.MD.MB, 1); - return d.Finish(); -} - -XEDISASMR(rldimix, 0x7800000C, MD )(InstrData& i, InstrDisasm& d) { - d.Init("rldimi", "Rotate Left Doubleword Immediate then Mask Insert", - i.MD.Rc ? InstrDisasm::kRc : 0); - d.AddRegOperand(InstrRegister::kGPR, i.MD.RA, InstrRegister::kReadWrite); - d.AddRegOperand(InstrRegister::kGPR, i.MD.RT, InstrRegister::kRead); - d.AddUImmOperand((i.MD.SH5 << 5) | i.MD.SH, 1); - d.AddUImmOperand((i.MD.MB5 << 5) | i.MD.MB, 1); - return d.Finish(); } XEDISASMR(rlwimix, 0x50000000, M )(InstrData& i, InstrDisasm& d) { @@ -701,12 +702,13 @@ void RegisterDisasmCategoryALU() { XEREGISTERINSTR(xorx, 0x7C000278); XEREGISTERINSTR(xori, 0x68000000); XEREGISTERINSTR(xoris, 0x6C000000); - XEREGISTERINSTR(rldclx, 0x78000010); - XEREGISTERINSTR(rldcrx, 0x78000012); - XEREGISTERINSTR(rldicx, 0x78000008); - XEREGISTERINSTR(rldiclx, 0x78000000); - XEREGISTERINSTR(rldicrx, 0x78000004); - XEREGISTERINSTR(rldimix, 0x7800000C); + XEREGISTERINSTR(rld, 0x78000000); + // XEREGISTERINSTR(rldclx, 0x78000010); + // XEREGISTERINSTR(rldcrx, 0x78000012); + // XEREGISTERINSTR(rldicx, 0x78000008); + // XEREGISTERINSTR(rldiclx, 0x78000000); + // XEREGISTERINSTR(rldicrx, 0x78000004); + // XEREGISTERINSTR(rldimix, 0x7800000C); XEREGISTERINSTR(rlwimix, 0x50000000); XEREGISTERINSTR(rlwinmx, 0x54000000); XEREGISTERINSTR(rlwnmx, 0x5C000000); diff --git a/src/xenia/cpu/ppc/instr.cc b/src/xenia/cpu/ppc/instr.cc index 36b125d7d..fb9aa53bd 100644 --- a/src/xenia/cpu/ppc/instr.cc +++ b/src/xenia/cpu/ppc/instr.cc @@ -362,7 +362,9 @@ InstrType* xe::cpu::ppc::GetInstrType(uint32_t code) { break; case 30: // Opcode = 30, index = bits 4-1 (4) - slot = &xe::cpu::ppc::tables::instr_table_30[XESELECTBITS(code, 1, 4)]; + // Special cased to an uber instruction. + slot = &xe::cpu::ppc::tables::instr_table_30[XESELECTBITS(code, 0, 0)]; + // slot = &xe::cpu::ppc::tables::instr_table_30[XESELECTBITS(code, 1, 4)]; break; case 31: // Opcode = 31, index = bits 10-1 (10) diff --git a/src/xenia/cpu/ppc/instr.h b/src/xenia/cpu/ppc/instr.h index 4a97149da..d25e77cda 100644 --- a/src/xenia/cpu/ppc/instr.h +++ b/src/xenia/cpu/ppc/instr.h @@ -193,7 +193,7 @@ typedef struct { struct { uint32_t Rc : 1; uint32_t SH5 : 1; - uint32_t : 3; + uint32_t idx : 3; uint32_t MB5 : 1; uint32_t MB : 5; uint32_t SH : 5; @@ -204,7 +204,7 @@ typedef struct { // kXEPPCInstrFormatMDS struct { uint32_t Rc : 1; - uint32_t : 4; + uint32_t idx : 4; uint32_t MB5 : 1; uint32_t MB : 5; uint32_t RB : 5; diff --git a/src/xenia/cpu/ppc/instr_tables.h b/src/xenia/cpu/ppc/instr_tables.h index 871c05965..20199cec4 100644 --- a/src/xenia/cpu/ppc/instr_tables.h +++ b/src/xenia/cpu/ppc/instr_tables.h @@ -93,15 +93,19 @@ static InstrType* instr_table_19 = instr_table_prep( // Opcode = 30, index = bits 4-1 (4) static InstrType instr_table_30_unprep[] = { - INSTRUCTION(rldiclx, 0x78000000, MD , General , 0), - INSTRUCTION(rldicrx, 0x78000004, MD , General , 0), - INSTRUCTION(rldicx, 0x78000008, MD , General , 0), - INSTRUCTION(rldimix, 0x7800000C, MD , General , 0), - INSTRUCTION(rldclx, 0x78000010, MDS, General , 0), - INSTRUCTION(rldcrx, 0x78000012, MDS, General , 0), + // Decoding these instrunctions in this table is difficult because the + // index bits are kind of random. This is special cased by an uber + // instruction handler. + INSTRUCTION(rld, 0x78000000, MD , General , 0), + // INSTRUCTION(rldiclx, 0x78000000, MD , General , 0), + // INSTRUCTION(rldicrx, 0x78000004, MD , General , 0), + // INSTRUCTION(rldicx, 0x78000008, MD , General , 0), + // INSTRUCTION(rldimix, 0x7800000C, MD , General , 0), + // INSTRUCTION(rldclx, 0x78000010, MDS, General , 0), + // INSTRUCTION(rldcrx, 0x78000012, MDS, General , 0), }; static InstrType* instr_table_30 = instr_table_prep( - instr_table_30_unprep, XECOUNT(instr_table_30_unprep), 1, 4); + instr_table_30_unprep, XECOUNT(instr_table_30_unprep), 0, 0); // Opcode = 31, index = bits 10-1 (10) static InstrType instr_table_31_unprep[] = { diff --git a/src/xenia/cpu/x64/x64_emit_alu.cc b/src/xenia/cpu/x64/x64_emit_alu.cc index 03a93b5cf..c94d9f9a5 100644 --- a/src/xenia/cpu/x64/x64_emit_alu.cc +++ b/src/xenia/cpu/x64/x64_emit_alu.cc @@ -1023,90 +1023,91 @@ XEEMITTER(xoris, 0x6C000000, D )(X64Emitter& e, X86Compiler& c, InstrDat // Integer rotate (A-6) -XEEMITTER(rldclx, 0x78000010, MDS)(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} +XEEMITTER(rld, 0x78000000, MDS)(X64Emitter& e, X86Compiler& c, InstrData& i) { + if (i.MD.idx == 0) { + // XEEMITTER(rldiclx, 0x78000000, MD ) + // n <- sh[5] || sh[0:4] + // r <- ROTL64((RS), n) + // b <- mb[5] || mb[0:4] + // m <- MASK(b, 63) + // RA <- r & m -XEEMITTER(rldcrx, 0x78000012, MDS)(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} + uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; + uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; + uint64_t m = XEMASK(mb, 63); -XEEMITTER(rldicx, 0x78000008, MD )(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; -} + GpVar v(c.newGpVar()); + c.mov(v, e.gpr_value(i.MD.RT)); + if (sh) { + c.rol(v, imm(sh)); + } + if (m != 0xFFFFFFFFFFFFFFFF) { + GpVar mask(c.newGpVar()); + c.mov(mask, imm(m)); + c.and_(v, mask); + } + e.update_gpr_value(i.MD.RA, v); -XEEMITTER(rldiclx, 0x78000000, MD )(X64Emitter& e, X86Compiler& c, InstrData& i) { - // n <- sh[5] || sh[0:4] - // r <- ROTL64((RS), n) - // b <- mb[5] || mb[0:4] - // m <- MASK(b, 63) - // RA <- r & m + if (i.MD.Rc) { + // With cr0 update. + e.update_cr_with_cond(0, v); + } - uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; - uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; - uint64_t m = XEMASK(mb, 63); + e.clear_constant_gpr_value(i.MD.RA); - GpVar v(c.newGpVar()); - c.mov(v, e.gpr_value(i.MD.RT)); - if (sh) { - c.rol(v, imm(sh)); + return 0; + } else if (i.MD.idx == 1) { + // XEEMITTER(rldicrx, 0x78000004, MD ) + // n <- sh[5] || sh[0:4] + // r <- ROTL64((RS), n) + // e <- me[5] || me[0:4] + // m <- MASK(0, e) + // RA <- r & m + + uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; + uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; + uint64_t m = XEMASK(0, mb); + + GpVar v(c.newGpVar()); + c.mov(v, e.gpr_value(i.MD.RT)); + if (sh) { + c.rol(v, imm(sh)); + } + if (m != 0xFFFFFFFFFFFFFFFF) { + GpVar mask(c.newGpVar()); + c.mov(mask, imm(m)); + c.and_(v, mask); + } + e.update_gpr_value(i.MD.RA, v); + + if (i.MD.Rc) { + // With cr0 update. + e.update_cr_with_cond(0, v); + } + + e.clear_constant_gpr_value(i.MD.RA); + + return 0; + } else if (i.MD.idx == 2) { + // XEEMITTER(rldicx, 0x78000008, MD ) + XEINSTRNOTIMPLEMENTED(); + return 1; + } else if (i.MDS.idx == 8) { + // XEEMITTER(rldclx, 0x78000010, MDS) + XEINSTRNOTIMPLEMENTED(); + return 1; + } else if (i.MDS.idx == 9) { + // XEEMITTER(rldcrx, 0x78000012, MDS) + XEINSTRNOTIMPLEMENTED(); + return 1; + } else if (i.MD.idx == 3) { + // XEEMITTER(rldimix, 0x7800000C, MD ) + XEINSTRNOTIMPLEMENTED(); + return 1; + } else { + XEINSTRNOTIMPLEMENTED(); + return 1; } - if (m != 0xFFFFFFFFFFFFFFFF) { - GpVar mask(c.newGpVar()); - c.mov(mask, imm(m)); - c.and_(v, mask); - } - e.update_gpr_value(i.MD.RA, v); - - if (i.MD.Rc) { - // With cr0 update. - e.update_cr_with_cond(0, v); - } - - e.clear_constant_gpr_value(i.MD.RA); - - return 0; -} - -XEEMITTER(rldicrx, 0x78000004, MD )(X64Emitter& e, X86Compiler& c, InstrData& i) { - // n <- sh[5] || sh[0:4] - // r <- ROTL64((RS), n) - // e <- me[5] || me[0:4] - // m <- MASK(0, e) - // RA <- r & m - - uint32_t sh = (i.MD.SH5 << 5) | i.MD.SH; - uint32_t mb = (i.MD.MB5 << 5) | i.MD.MB; - uint64_t m = XEMASK(0, mb); - - GpVar v(c.newGpVar()); - c.mov(v, e.gpr_value(i.MD.RT)); - if (sh) { - c.rol(v, imm(sh)); - } - if (m != 0xFFFFFFFFFFFFFFFF) { - GpVar mask(c.newGpVar()); - c.mov(mask, imm(m)); - c.and_(v, mask); - } - e.update_gpr_value(i.MD.RA, v); - - if (i.MD.Rc) { - // With cr0 update. - e.update_cr_with_cond(0, v); - } - - e.clear_constant_gpr_value(i.MD.RA); - - return 0; -} - -XEEMITTER(rldimix, 0x7800000C, MD )(X64Emitter& e, X86Compiler& c, InstrData& i) { - XEINSTRNOTIMPLEMENTED(); - return 1; } XEEMITTER(rlwimix, 0x50000000, M )(X64Emitter& e, X86Compiler& c, InstrData& i) { @@ -1404,12 +1405,13 @@ void X64RegisterEmitCategoryALU() { XEREGISTERINSTR(xorx, 0x7C000278); XEREGISTERINSTR(xori, 0x68000000); XEREGISTERINSTR(xoris, 0x6C000000); - XEREGISTERINSTR(rldclx, 0x78000010); - XEREGISTERINSTR(rldcrx, 0x78000012); - XEREGISTERINSTR(rldicx, 0x78000008); - XEREGISTERINSTR(rldiclx, 0x78000000); - XEREGISTERINSTR(rldicrx, 0x78000004); - XEREGISTERINSTR(rldimix, 0x7800000C); + XEREGISTERINSTR(rld, 0x78000000); + // XEREGISTERINSTR(rldclx, 0x78000010); + // XEREGISTERINSTR(rldcrx, 0x78000012); + // XEREGISTERINSTR(rldicx, 0x78000008); + // XEREGISTERINSTR(rldiclx, 0x78000000); + // XEREGISTERINSTR(rldicrx, 0x78000004); + // XEREGISTERINSTR(rldimix, 0x7800000C); XEREGISTERINSTR(rlwimix, 0x50000000); XEREGISTERINSTR(rlwinmx, 0x54000000); XEREGISTERINSTR(rlwnmx, 0x5C000000);