Implement thumb POP instruction
This commit is contained in:
parent
f7e3d7b8d2
commit
dfef65d98f
6 changed files with 45 additions and 6 deletions
|
@ -82,7 +82,7 @@ static CPUCaps Detect() {
|
||||||
caps.vendor = CPUVendor::OTHER;
|
caps.vendor = CPUVendor::OTHER;
|
||||||
|
|
||||||
// Set reasonable default brand string even if brand string not available
|
// Set reasonable default brand string even if brand string not available
|
||||||
strcpy_s(caps.cpu_string, caps.brand_string);
|
strcpy_s(caps.cpu_string, sizeof(caps.cpu_string), caps.brand_string);
|
||||||
|
|
||||||
// Detect family and other miscellaneous features
|
// Detect family and other miscellaneous features
|
||||||
if (max_std_fn >= 1) {
|
if (max_std_fn >= 1) {
|
||||||
|
|
|
@ -125,7 +125,7 @@ boost::optional<const Thumb16Matcher<V>&> DecodeThumb16(u16 instruction) {
|
||||||
INST(&V::thumb16_UXTH, "UXTH", "1011001010mmmddd"), // v6
|
INST(&V::thumb16_UXTH, "UXTH", "1011001010mmmddd"), // v6
|
||||||
INST(&V::thumb16_UXTB, "UXTB", "1011001011mmmddd"), // v6
|
INST(&V::thumb16_UXTB, "UXTB", "1011001011mmmddd"), // v6
|
||||||
INST(&V::thumb16_PUSH, "PUSH", "1011010Mxxxxxxxx"), // v4T
|
INST(&V::thumb16_PUSH, "PUSH", "1011010Mxxxxxxxx"), // v4T
|
||||||
//INST(&V::thumb16_POP, "POP", "1011110rxxxxxxxx"), // v4T
|
INST(&V::thumb16_POP, "POP", "1011110Pxxxxxxxx"), // v4T
|
||||||
//INST(&V::thumb16_SETEND, "SETEND", "101101100101x000"), // v6
|
//INST(&V::thumb16_SETEND, "SETEND", "101101100101x000"), // v6
|
||||||
//INST(&V::thumb16_CPS, "CPS", "10110110011m0aif"), // v6
|
//INST(&V::thumb16_CPS, "CPS", "10110110011m0aif"), // v6
|
||||||
INST(&V::thumb16_REV, "REV", "1011101000mmmddd"), // v6
|
INST(&V::thumb16_REV, "REV", "1011101000mmmddd"), // v6
|
||||||
|
|
|
@ -298,6 +298,24 @@ public:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string thumb16_POP(bool P, RegList reg_list) {
|
||||||
|
if (P)
|
||||||
|
reg_list |= 1 << 15;
|
||||||
|
|
||||||
|
std::string ret = "PUSH ";
|
||||||
|
bool first_reg = true;
|
||||||
|
for (size_t i = 0; i < 16; i++) {
|
||||||
|
if (Common::Bit(i, reg_list)) {
|
||||||
|
if (!first_reg)
|
||||||
|
ret += ", ";
|
||||||
|
ret += RegStr(static_cast<Reg>(i));
|
||||||
|
first_reg = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
std::string thumb16_REV(Reg m, Reg d) {
|
std::string thumb16_REV(Reg m, Reg d) {
|
||||||
return Common::StringFromFormat("rev %s, %s", RegStr(d), RegStr(m));
|
return Common::StringFromFormat("rev %s, %s", RegStr(d), RegStr(m));
|
||||||
}
|
}
|
||||||
|
|
|
@ -515,11 +515,12 @@ struct ThumbTranslatorVisitor final {
|
||||||
}
|
}
|
||||||
// PUSH <reg_list>
|
// PUSH <reg_list>
|
||||||
// reg_list cannot encode for R15.
|
// reg_list cannot encode for R15.
|
||||||
u32 num_bytes_to_push = static_cast<u32>(4 * Common::BitCount(reg_list));
|
const u32 num_bytes_to_push = static_cast<u32>(4 * Common::BitCount(reg_list));
|
||||||
const auto final_address = ir.Sub(ir.GetRegister(Reg::SP), ir.Imm32(num_bytes_to_push));
|
const auto final_address = ir.Sub(ir.GetRegister(Reg::SP), ir.Imm32(num_bytes_to_push));
|
||||||
auto address = final_address;
|
auto address = final_address;
|
||||||
for (size_t i = 0; i < 16; i++) {
|
for (size_t i = 0; i < 16; i++) {
|
||||||
if (Common::Bit(i, reg_list)) {
|
if (Common::Bit(i, reg_list)) {
|
||||||
|
// TODO: Deal with alignment
|
||||||
auto Ri = ir.GetRegister(static_cast<Reg>(i));
|
auto Ri = ir.GetRegister(static_cast<Reg>(i));
|
||||||
ir.WriteMemory32(address, Ri);
|
ir.WriteMemory32(address, Ri);
|
||||||
address = ir.Add(address, ir.Imm32(4));
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
|
@ -530,6 +531,26 @@ struct ThumbTranslatorVisitor final {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool thumb16_POP(bool P, RegList reg_list) {
|
||||||
|
if (P) reg_list |= 1 << 15;
|
||||||
|
if (Common::BitCount(reg_list) < 1) {
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
}
|
||||||
|
// POP <reg_list>
|
||||||
|
auto address = ir.GetRegister(Reg::SP);
|
||||||
|
for (size_t i = 0; i < 15; i++) {
|
||||||
|
if (Common::Bit(i, reg_list)) {
|
||||||
|
// TODO: Deal with alignment
|
||||||
|
auto data = ir.ReadMemory32(address);
|
||||||
|
ir.SetRegister(static_cast<Reg>(i), data);
|
||||||
|
address = ir.Add(address, ir.Imm32(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ir.SetRegister(Reg::SP, address);
|
||||||
|
// TODO(optimization): Possible location for an RSB push.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool thumb16_REV(Reg m, Reg d) {
|
bool thumb16_REV(Reg m, Reg d) {
|
||||||
// REV <Rd>, <Rm>
|
// REV <Rd>, <Rm>
|
||||||
// Rd cannot encode R15.
|
// Rd cannot encode R15.
|
||||||
|
|
|
@ -163,7 +163,6 @@ static bool DoesBehaviorMatch(const ARMul_State& interp, const Dynarmic::Jit& ji
|
||||||
&& interp_write_records == jit_write_records;
|
&& interp_write_records == jit_write_records;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_execute_count, const size_t run_count, const std::function<u16()> instruction_generator) {
|
void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_execute_count, const size_t run_count, const std::function<u16()> instruction_generator) {
|
||||||
// Prepare memory
|
// Prepare memory
|
||||||
code_mem.fill(0xE7FE); // b +#0
|
code_mem.fill(0xE7FE); // b +#0
|
||||||
|
@ -274,7 +273,8 @@ TEST_CASE("Fuzz Thumb instructions set 1", "[JitX64][Thumb]") {
|
||||||
ThumbInstGen("1001xxxxxxxxxxxx"), // LDR/STR Rd, [SP, #]
|
ThumbInstGen("1001xxxxxxxxxxxx"), // LDR/STR Rd, [SP, #]
|
||||||
ThumbInstGen("10110100xxxxxxxx", // PUSH (R = 0)
|
ThumbInstGen("10110100xxxxxxxx", // PUSH (R = 0)
|
||||||
[](u16 inst){ return Dynarmic::Common::Bits<0, 7>(inst) != 0; }), // Empty reg_list is UNPREDICTABLE
|
[](u16 inst){ return Dynarmic::Common::Bits<0, 7>(inst) != 0; }), // Empty reg_list is UNPREDICTABLE
|
||||||
ThumbInstGen("10111100xxxxxxxx"), // POP (R = 0)
|
ThumbInstGen("10111100xxxxxxxx", // POP (R = 0)
|
||||||
|
[](u16 inst){ return Dynarmic::Common::Bits<0, 7>(inst) != 0; }), // Empty reg_list is UNPREDICTABLE
|
||||||
ThumbInstGen("1100xxxxxxxxxxxx"), // STMIA/LDMIA
|
ThumbInstGen("1100xxxxxxxxxxxx"), // STMIA/LDMIA
|
||||||
//ThumbInstGen("101101100101x000"), // SETEND
|
//ThumbInstGen("101101100101x000"), // SETEND
|
||||||
}};
|
}};
|
||||||
|
|
Loading…
Reference in a new issue