diff --git a/src/frontend/decoder/thumb1.h b/src/frontend/decoder/thumb1.h index 9276c95c..d9867699 100644 --- a/src/frontend/decoder/thumb1.h +++ b/src/frontend/decoder/thumb1.h @@ -56,7 +56,7 @@ private: }; template -static const std::array, 28> g_thumb1_instruction_table {{ +static const std::array, 29> g_thumb1_instruction_table {{ #define INST(fn, name, bitstring) detail::detail::GetMatcher(name, bitstring) @@ -84,7 +84,7 @@ static const std::array, 28> g_thumb1_instruction_table {{ { INST(&V::thumb1_ROR_reg, "ROR (reg)", "0100000111sssddd") }, { INST(&V::thumb1_TST_reg, "TST (reg)", "0100001000mmmnnn") }, { INST(&V::thumb1_RSB_imm, "RSB (imm)", "0100001001nnnddd") }, - { INST(&V::thumb1_CMP_reg, "CMP (reg)", "0100001010mmmnnn") }, + { INST(&V::thumb1_CMP_reg_t1, "CMP (reg, T1)", "0100001010mmmnnn") }, { INST(&V::thumb1_CMN_reg, "CMN (reg)", "0100001011mmmnnn") }, { INST(&V::thumb1_ORR_reg, "ORR (reg)", "0100001100mmmddd") }, //{ INST(&V::thumb1_MULS_rr, "MULS (rr)", "0100001101mmmddd") }, @@ -93,7 +93,7 @@ static const std::array, 28> g_thumb1_instruction_table {{ // Special data instructions { INST(&V::thumb1_ADD_reg_t2, "ADD (reg, T2)", "01000100Dmmmmddd") }, // v4T, Low regs: v6T2 - //{ INST(&V::thumb1_CMP_high, "CMP (high)", "01000101dmmmmddd") }, // v4T + { INST(&V::thumb1_CMP_reg_t2, "CMP (reg, T2)", "01000101Nmmmmnnn") }, // v4T //{ INST(&V::thumb1_MOV_high, "MOV (high)", "01000110dmmmmddd") }, // v4T, Low regs: v6 // Store/Load single data item instructions diff --git a/src/frontend/disassembler_thumb.cpp b/src/frontend/disassembler_thumb.cpp index 0ce5913b..4b079238 100644 --- a/src/frontend/disassembler_thumb.cpp +++ b/src/frontend/disassembler_thumb.cpp @@ -187,7 +187,7 @@ public: return Common::StringFromFormat("rsbs %s, %s, #0", RegStr(d), RegStr(n)); } - std::string thumb1_CMP_reg(Reg m, Reg n) { + std::string thumb1_CMP_reg_t1(Reg m, Reg n) { return Common::StringFromFormat("cmp %s, %s", RegStr(n), RegStr(m)); } @@ -212,6 +212,11 @@ public: return Common::StringFromFormat("add %s, %s", RegStr(d_n), RegStr(m)); } + std::string thumb1_CMP_reg_t2(bool n_hi, Reg m, Reg n_lo) { + Reg n = n_hi ? (n_lo + 8) : n_lo; + return Common::StringFromFormat("cmp %s, %s", RegStr(n), RegStr(m)); + } + std::string thumb1_UDF() { return Common::StringFromFormat("udf"); } diff --git a/src/frontend/translate_thumb.cpp b/src/frontend/translate_thumb.cpp index 024a0bc8..797777e9 100644 --- a/src/frontend/translate_thumb.cpp +++ b/src/frontend/translate_thumb.cpp @@ -269,7 +269,7 @@ struct TranslatorVisitor final { ir.SetVFlag(result.overflow); return true; } - bool thumb1_CMP_reg(Reg m, Reg n) { + bool thumb1_CMP_reg_t1(Reg m, Reg n) { // CMP , auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(1)); ir.SetNFlag(ir.MostSignificantBit(result.result)); @@ -336,6 +336,22 @@ struct TranslatorVisitor final { } } + bool thumb1_CMP_reg_t2(bool n_hi, Reg m, Reg n_lo) { + Reg n = n_hi ? (n_lo + 8) : n_lo; + if (n < Reg::R8 && m < Reg::R8) { + return UnpredictableInstruction(); + } else if (n == Reg::PC || m == Reg::PC) { + return UnpredictableInstruction(); + } + // CMP , + auto result = ir.SubWithCarry(ir.GetRegister(n), ir.GetRegister(m), ir.Imm1(1)); + ir.SetNFlag(ir.MostSignificantBit(result.result)); + ir.SetZFlag(ir.IsZero(result.result)); + ir.SetCFlag(result.carry); + ir.SetVFlag(result.overflow); + return true; + } + bool thumb1_UDF() { return TranslateThisInstruction(); } diff --git a/tests/arm/fuzz_thumb.cpp b/tests/arm/fuzz_thumb.cpp index bd7f8078..81d84d93 100644 --- a/tests/arm/fuzz_thumb.cpp +++ b/tests/arm/fuzz_thumb.cpp @@ -180,8 +180,10 @@ TEST_CASE("Fuzz Thumb instructions set 1", "[JitX64][Thumb]") { InstructionGenerator("001ooxxxxxxxxxxx"), // ADD/SUB/CMP/MOV_imm InstructionGenerator("010000ooooxxxxxx"), // Data Processing InstructionGenerator("010001000hxxxxxx"), // ADD (high registers) - InstructionGenerator("0100010101xxxxxx"), // CMP (high registers) - InstructionGenerator("0100010110xxxxxx"), // CMP (high registers) + InstructionGenerator("0100010101xxxxxx", // CMP (high registers) + [](u16 inst){ return Dynarmic::Common::Bits<3, 5>(inst) != 0b111; }), // R15 is UNPREDICTABLE + InstructionGenerator("0100010110xxxxxx", // CMP (high registers) + [](u16 inst){ return Dynarmic::Common::Bits<0, 2>(inst) != 0b111; }), // R15 is UNPREDICTABLE InstructionGenerator("010001100hxxxxxx"), // MOV (high registers) InstructionGenerator("10110000oxxxxxxx"), // Adjust stack pointer InstructionGenerator("10110010ooxxxxxx"), // SXT/UXT