early-access version 1536
This commit is contained in:
1
externals/dynarmic/src/CMakeLists.txt
vendored
1
externals/dynarmic/src/CMakeLists.txt
vendored
@@ -163,6 +163,7 @@ if ("A32" IN_LIST DYNARMIC_FRONTENDS)
|
||||
frontend/A32/translate/impl/thumb32_data_processing_shifted_register.cpp
|
||||
frontend/A32/translate/impl/thumb32_load_byte.cpp
|
||||
frontend/A32/translate/impl/thumb32_load_halfword.cpp
|
||||
frontend/A32/translate/impl/thumb32_load_store_multiple.cpp
|
||||
frontend/A32/translate/impl/thumb32_load_word.cpp
|
||||
frontend/A32/translate/impl/thumb32_long_multiply.cpp
|
||||
frontend/A32/translate/impl/thumb32_misc.cpp
|
||||
|
@@ -440,13 +440,13 @@ void EmitX64::EmitVectorAnd(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
static void ArithmeticShiftRightByte(EmitContext& ctx, BlockOfCode& code, const Xbyak::Xmm& result, u8 shift_amount) {
|
||||
if (code.HasAVX512_Icelake()) {
|
||||
// Do a logical shift right upon the 8x8 bit-matrix, but shift in
|
||||
// `0x80` bytes into the matrix to repeat the most significant bit.
|
||||
const u64 zero_extend = ~(0xFFFFFFFFFFFFFFFF << (shift_amount * 8)) & 0x8080808080808080;
|
||||
const u64 shift_matrix = (0x0102040810204080 >> (shift_amount * 8)) | zero_extend;
|
||||
const u64 shift_matrix = shift_amount < 8
|
||||
? (0x0102040810204080 << (shift_amount * 8)) | (0x8080808080808080 >> (64 - shift_amount * 8))
|
||||
: 0x8080808080808080;
|
||||
code.vgf2p8affineqb(result, result, code.MConst(xword_b, shift_matrix), 0);
|
||||
return;
|
||||
}
|
||||
|
||||
const Xbyak::Xmm tmp = ctx.reg_alloc.ScratchXmm();
|
||||
|
||||
code.punpckhbw(tmp, result);
|
||||
@@ -1465,20 +1465,21 @@ void EmitX64::EmitVectorLogicalShiftLeft8(EmitContext& ctx, IR::Inst* inst) {
|
||||
const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]);
|
||||
const u8 shift_amount = args[1].GetImmediateU8();
|
||||
|
||||
if (shift_amount == 1) {
|
||||
if (shift_amount == 0) {
|
||||
// do nothing
|
||||
} else if (shift_amount >= 8) {
|
||||
code.pxor(result, result);
|
||||
} else if (shift_amount == 1) {
|
||||
code.paddb(result, result);
|
||||
} else if (shift_amount > 0) {
|
||||
if (code.HasAVX512_Icelake()) {
|
||||
// Galois 8x8 identity matrix, bit-shifted by the shift-amount
|
||||
const u64 shift_matrix = 0x0102040810204080 >> (shift_amount * 8);
|
||||
code.vgf2p8affineqb(result, result, code.MConst(xword_b, shift_matrix), 0);
|
||||
} else {
|
||||
const u64 replicand = (0xFFULL << shift_amount) & 0xFF;
|
||||
const u64 mask = Common::Replicate(replicand, Common::BitSize<u8>());
|
||||
} else if (code.HasAVX512_Icelake()) {
|
||||
const u64 shift_matrix = 0x0102040810204080 >> (shift_amount * 8);
|
||||
code.vgf2p8affineqb(result, result, code.MConst(xword_b, shift_matrix), 0);
|
||||
} else {
|
||||
const u64 replicand = (0xFFULL << shift_amount) & 0xFF;
|
||||
const u64 mask = Common::Replicate(replicand, Common::BitSize<u8>());
|
||||
|
||||
code.psllw(result, shift_amount);
|
||||
code.pand(result, code.MConst(xword, mask, mask));
|
||||
}
|
||||
code.psllw(result, shift_amount);
|
||||
code.pand(result, code.MConst(xword, mask, mask));
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
@@ -1523,18 +1524,19 @@ void EmitX64::EmitVectorLogicalShiftRight8(EmitContext& ctx, IR::Inst* inst) {
|
||||
const Xbyak::Xmm result = ctx.reg_alloc.UseScratchXmm(args[0]);
|
||||
const u8 shift_amount = args[1].GetImmediateU8();
|
||||
|
||||
if (shift_amount > 0) {
|
||||
if (code.HasAVX512_Icelake()) {
|
||||
// Galois 8x8 identity matrix, bit-shifted by the shift-amount
|
||||
const u64 shift_matrix = 0x0102040810204080 << (shift_amount * 8);
|
||||
code.vgf2p8affineqb(result, result, code.MConst(xword_b, shift_matrix), 0);
|
||||
} else {
|
||||
const u64 replicand = 0xFEULL >> shift_amount;
|
||||
const u64 mask = Common::Replicate(replicand, Common::BitSize<u8>());
|
||||
if (shift_amount == 0) {
|
||||
// Do nothing
|
||||
} else if (shift_amount >= 8) {
|
||||
code.pxor(result, result);
|
||||
} else if (code.HasAVX512_Icelake()) {
|
||||
const u64 shift_matrix = 0x0102040810204080 << (shift_amount * 8);
|
||||
code.vgf2p8affineqb(result, result, code.MConst(xword_b, shift_matrix), 0);
|
||||
} else {
|
||||
const u64 replicand = 0xFEULL >> shift_amount;
|
||||
const u64 mask = Common::Replicate(replicand, Common::BitSize<u8>());
|
||||
|
||||
code.psrlw(result, shift_amount);
|
||||
code.pand(result, code.MConst(xword, mask, mask));
|
||||
}
|
||||
code.psrlw(result, shift_amount);
|
||||
code.pand(result, code.MConst(xword, mask, mask));
|
||||
}
|
||||
|
||||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
@@ -2768,12 +2770,8 @@ void EmitX64::EmitVectorReverseBits(EmitContext& ctx, IR::Inst* inst) {
|
||||
|
||||
const Xbyak::Xmm data = ctx.reg_alloc.UseScratchXmm(args[0]);
|
||||
|
||||
if (code.HasAVX512_Icelake() && code.HasSSSE3()) {
|
||||
// GFNI(vgf2p8affineqb) and SSSE3(pshuf)
|
||||
// Reverse bits within bytes
|
||||
if (code.HasAVX512_Icelake()) {
|
||||
code.vgf2p8affineqb(data, data, code.MConst(xword_b, 0x8040201008040201), 0);
|
||||
// Reverse bytes within vector
|
||||
code.pshufb(data, code.MConst(xword, 0x0001020304050607, 0x08090a0b0c0d0e0f));
|
||||
} else {
|
||||
const Xbyak::Xmm high_nibble_reg = ctx.reg_alloc.ScratchXmm();
|
||||
code.movdqa(high_nibble_reg, code.MConst(xword, 0xF0F0F0F0F0F0F0F0, 0xF0F0F0F0F0F0F0F0));
|
||||
|
@@ -1,12 +1,12 @@
|
||||
// Load/Store Multiple
|
||||
//INST(thumb32_SRS_1, "SRS", "1110100000-0--------------------")
|
||||
//INST(thumb32_RFE_2, "RFE", "1110100000-1--------------------")
|
||||
//INST(thumb32_STMIA, "STMIA/STMEA", "1110100010-0--------------------")
|
||||
//INST(thumb32_POP, "POP", "1110100010111101----------------")
|
||||
//INST(thumb32_LDMIA, "LDMIA/LDMFD", "1110100010-1--------------------")
|
||||
//INST(thumb32_PUSH, "PUSH", "1110100100101101----------------")
|
||||
//INST(thumb32_STMDB, "STMDB/STMFD", "1110100100-0--------------------")
|
||||
//INST(thumb32_LDMDB, "LDMDB/LDMEA", "1110100100-1--------------------")
|
||||
INST(thumb32_STMIA, "STMIA/STMEA", "1110100010W0nnnn0iiiiiiiiiiiiiii")
|
||||
INST(thumb32_POP, "POP", "1110100010111101iiiiiiiiiiiiiiii")
|
||||
INST(thumb32_LDMIA, "LDMIA/LDMFD", "1110100010W1nnnniiiiiiiiiiiiiiii")
|
||||
INST(thumb32_PUSH, "PUSH", "11101001001011010iiiiiiiiiiiiiii")
|
||||
INST(thumb32_STMDB, "STMDB/STMFD", "1110100100W0nnnn0iiiiiiiiiiiiiii")
|
||||
INST(thumb32_LDMDB, "LDMDB/LDMEA", "1110100100W1nnnniiiiiiiiiiiiiiii")
|
||||
//INST(thumb32_SRS_1, "SRS", "1110100110-0--------------------")
|
||||
//INST(thumb32_RFE_2, "RFE", "1110100110-1--------------------")
|
||||
|
||||
@@ -66,10 +66,10 @@ INST(thumb32_SUB_imm_1, "SUB (imm)", "11110v01101Snnnn0vvvdd
|
||||
INST(thumb32_RSB_imm, "RSB (imm)", "11110v01110Snnnn0vvvddddvvvvvvvv")
|
||||
|
||||
// Data Processing (Plain Binary Immediate)
|
||||
//INST(thumb32_ADR, "ADR", "11110-10000011110---------------")
|
||||
INST(thumb32_ADR_t3, "ADR", "11110i10000011110iiiddddiiiiiiii")
|
||||
INST(thumb32_ADD_imm_2, "ADD (imm)", "11110i10000011010iiiddddiiiiiiii")
|
||||
INST(thumb32_MOVW_imm, "MOVW (imm)", "11110i100100iiii0iiiddddiiiiiiii")
|
||||
//INST(thumb32_ADR, "ADR", "11110-10101011110---------------")
|
||||
INST(thumb32_ADR_t2, "ADR", "11110i10101011110iiiddddiiiiiiii")
|
||||
INST(thumb32_SUB_imm_2, "SUB (imm)", "11110i10101011010iiiddddiiiiiiii")
|
||||
INST(thumb32_MOVT, "MOVT", "11110i101100iiii0iiiddddiiiiiiii")
|
||||
INST(thumb32_UDF, "Invalid decoding", "11110011-010----0000----0001----")
|
||||
@@ -124,24 +124,25 @@ INST(thumb32_UDF, "Invalid decoding", "11110-111-------10-0--
|
||||
INST(thumb32_B_cond, "B (cond)", "11110Sccccvvvvvv10i0ivvvvvvvvvvv")
|
||||
|
||||
// Store Single Data Item
|
||||
//INST(thumb32_STRB_imm_1, "STRB (imm)", "111110000000--------1--1--------")
|
||||
//INST(thumb32_STRB_imm_2, "STRB (imm)", "111110000000--------1100--------")
|
||||
//INST(thumb32_STRB_imm_3, "STRB (imm)", "111110001000--------------------")
|
||||
//INST(thumb32_STRBT, "STRBT", "111110000000--------1110--------")
|
||||
INST(thumb32_STRB_imm_1, "STRB (imm)", "111110000000nnnntttt1PU1iiiiiiii")
|
||||
INST(thumb32_STRB_imm_2, "STRB (imm)", "111110000000nnnntttt1100iiiiiiii")
|
||||
INST(thumb32_STRB_imm_3, "STRB (imm)", "111110001000nnnnttttiiiiiiiiiiii")
|
||||
INST(thumb32_STRBT, "STRBT", "111110000000nnnntttt1110iiiiiiii")
|
||||
INST(thumb32_STRB, "STRB (reg)", "111110000000nnnntttt000000iimmmm")
|
||||
//INST(thumb32_STRH_imm_1, "STRH (imm)", "111110000010--------1--1--------")
|
||||
//INST(thumb32_STRH_imm_2, "STRH (imm)", "111110000010--------1100--------")
|
||||
//INST(thumb32_STRH_imm_3, "STRH (imm)", "111110001010--------------------")
|
||||
//INST(thumb32_STRHT, "STRHT", "111110000010--------1110--------")
|
||||
INST(thumb32_STRH_imm_1, "STRH (imm)", "111110000010nnnntttt1PU1iiiiiiii")
|
||||
INST(thumb32_STRH_imm_2, "STRH (imm)", "111110000010nnnntttt1100iiiiiiii")
|
||||
INST(thumb32_STRH_imm_3, "STRH (imm)", "111110001010nnnnttttiiiiiiiiiiii")
|
||||
INST(thumb32_STRHT, "STRHT", "111110000010nnnntttt1110iiiiiiii")
|
||||
INST(thumb32_STRH, "STRH (reg)", "111110000010nnnntttt000000iimmmm")
|
||||
//INST(thumb32_STR_imm_1, "STR (imm)", "111110000100--------1--1--------")
|
||||
//INST(thumb32_STR_imm_2, "STR (imm)", "111110000100--------1100--------")
|
||||
//INST(thumb32_STR_imm_3, "STR (imm)", "111110001100--------------------")
|
||||
//INST(thumb32_STRT, "STRT", "111110000100--------1110--------")
|
||||
INST(thumb32_STR_imm_1, "STR (imm)", "111110000100nnnntttt1PU1iiiiiiii")
|
||||
INST(thumb32_STR_imm_2, "STR (imm)", "111110000100nnnntttt1100iiiiiiii")
|
||||
INST(thumb32_STR_imm_3, "STR (imm)", "111110001100nnnnttttiiiiiiiiiiii")
|
||||
INST(thumb32_STRT, "STRT", "111110000100nnnntttt1110iiiiiiii")
|
||||
INST(thumb32_STR_reg, "STR (reg)", "111110000100nnnntttt000000iimmmm")
|
||||
|
||||
// Load Byte and Memory Hints
|
||||
INST(thumb32_PLD_lit, "PLD (lit)", "11111000U00111111111iiiiiiiiiiii")
|
||||
INST(thumb32_PLD_lit, "PLD (lit)", "11111000U01111111111iiiiiiiiiiii")
|
||||
INST(thumb32_PLD_reg, "PLD (reg)", "1111100000W1nnnn1111000000iimmmm")
|
||||
INST(thumb32_PLD_imm8, "PLD (imm8)", "1111100000W1nnnn11111100iiiiiiii")
|
||||
INST(thumb32_PLD_imm12, "PLD (imm12)", "1111100010W1nnnn1111iiiiiiiiiiii")
|
||||
@@ -161,27 +162,27 @@ INST(thumb32_LDRSB_imm8, "LDRSB (imm8)", "111110010001nnnntttt1P
|
||||
INST(thumb32_LDRSB_imm12, "LDRSB (imm12)", "111110011001nnnnttttiiiiiiiiiiii")
|
||||
|
||||
// Load Halfword and Memory Hints
|
||||
//INST(thumb32_LDRH_lit, "LDRH (lit)", "11111000-0111111----------------")
|
||||
//INST(thumb32_LDRH_reg, "LDRH (reg)", "111110000011--------000000------")
|
||||
//INST(thumb32_LDRHT, "LDRHT", "111110000011--------1110--------")
|
||||
//INST(thumb32_LDRH_imm8, "LDRH (imm8)", "111110000011--------1-----------")
|
||||
//INST(thumb32_LDRH_imm12, "LDRH (imm12)", "111110001011--------------------")
|
||||
//INST(thumb32_LDRSH_lit, "LDRSH (lit)", "11111001-0111111----------------")
|
||||
//INST(thumb32_LDRSH_reg, "LDRSH (reg)", "111110010011--------000000------")
|
||||
//INST(thumb32_LDRSHT, "LDRSHT", "111110010011--------1110--------")
|
||||
//INST(thumb32_LDRSH_imm8, "LDRSH (imm8)", "111110010011--------1-----------")
|
||||
//INST(thumb32_LDRSH_imm12, "LDRSH (imm12)", "111110011011--------------------")
|
||||
//INST(thumb32_NOP, "NOP", "111110010011----1111000000------")
|
||||
//INST(thumb32_NOP, "NOP", "111110010011----11111100--------")
|
||||
//INST(thumb32_NOP, "NOP", "11111001-01111111111------------")
|
||||
//INST(thumb32_NOP, "NOP", "111110011011----1111------------")
|
||||
INST(thumb32_LDRH_lit, "LDRH (lit)", "11111000U0111111ttttiiiiiiiiiiii")
|
||||
INST(thumb32_LDRH_reg, "LDRH (reg)", "111110000011nnnntttt000000iimmmm")
|
||||
INST(thumb32_LDRHT, "LDRHT", "111110000011nnnntttt1110iiiiiiii")
|
||||
INST(thumb32_LDRH_imm8, "LDRH (imm8)", "111110000011nnnntttt1PUWiiiiiiii")
|
||||
INST(thumb32_LDRH_imm12, "LDRH (imm12)", "111110001011nnnnttttiiiiiiiiiiii")
|
||||
INST(thumb32_NOP, "NOP", "11111001-01111111111------------")
|
||||
INST(thumb32_LDRSH_lit, "LDRSH (lit)", "11111001U0111111ttttiiiiiiiiiiii")
|
||||
INST(thumb32_NOP, "NOP", "111110010011----1111000000------")
|
||||
INST(thumb32_LDRSH_reg, "LDRSH (reg)", "111110010011nnnntttt000000iimmmm")
|
||||
INST(thumb32_LDRSHT, "LDRSHT", "111110010011nnnntttt1110iiiiiiii")
|
||||
INST(thumb32_NOP, "NOP", "111110010011----11111100--------")
|
||||
INST(thumb32_NOP, "NOP", "111110011011----1111------------")
|
||||
INST(thumb32_LDRSH_imm8, "LDRSH (imm8)", "111110010011nnnntttt1PUWiiiiiiii")
|
||||
INST(thumb32_LDRSH_imm12, "LDRSH (imm12)", "111110011011nnnnttttiiiiiiiiiiii")
|
||||
|
||||
// Load Word
|
||||
//INST(thumb32_LDR_lit, "LDR (lit)", "11111000-1011111----------------")
|
||||
//INST(thumb32_LDRT, "LDRT", "111110000101--------1110--------")
|
||||
//INST(thumb32_LDR_reg, "LDR (reg)", "111110000101--------000000------")
|
||||
//INST(thumb32_LDR_imm8, "LDR (imm8)", "111110000101--------1-----------")
|
||||
//INST(thumb32_LDR_imm12, "LDR (imm12)", "111110001101--------------------")
|
||||
INST(thumb32_LDR_lit, "LDR (lit)", "11111000U1011111ttttiiiiiiiiiiii")
|
||||
INST(thumb32_LDRT, "LDRT", "111110000101nnnntttt1110iiiiiiii")
|
||||
INST(thumb32_LDR_reg, "LDR (reg)", "111110000101nnnntttt000000iimmmm")
|
||||
INST(thumb32_LDR_imm8, "LDR (imm8)", "111110000101nnnntttt1PUWiiiiiiii")
|
||||
INST(thumb32_LDR_imm12, "LDR (imm12)", "111110001101nnnnttttiiiiiiiiiiii")
|
||||
|
||||
// Data Processing (register)
|
||||
INST(thumb32_LSL_reg, "LSL (reg)", "111110100000mmmm1111dddd0000ssss")
|
||||
|
@@ -52,6 +52,30 @@ static bool Saturation16(ThumbTranslatorVisitor& v, Reg n, Reg d, size_t saturat
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_ADR_t2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8) {
|
||||
if (d == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto imm32 = concatenate(imm1, imm3, imm8).ZeroExtend();
|
||||
const auto result = ir.AlignPC(4) - imm32;
|
||||
|
||||
ir.SetRegister(d, ir.Imm32(result));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_ADR_t3(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8) {
|
||||
if (d == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto imm32 = concatenate(imm1, imm3, imm8).ZeroExtend();
|
||||
const auto result = ir.AlignPC(4) + imm32;
|
||||
|
||||
ir.SetRegister(d, ir.Imm32(result));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_ADD_imm_2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8) {
|
||||
if (d == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
|
@@ -7,5 +7,135 @@
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
|
||||
using ExtensionFunction = IR::U32 (IREmitter::*)(const IR::U16&);
|
||||
|
||||
static bool LoadHalfLiteral(ThumbTranslatorVisitor& v, bool U, Reg t, Imm<12> imm12,
|
||||
ExtensionFunction ext_fn) {
|
||||
const auto imm32 = imm12.ZeroExtend();
|
||||
const auto base = v.ir.AlignPC(4);
|
||||
const auto address = U ? (base + imm32) : (base - imm32);
|
||||
const auto data = (v.ir.*ext_fn)(v.ir.ReadMemory16(v.ir.Imm32(address)));
|
||||
|
||||
v.ir.SetRegister(t, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadHalfRegister(ThumbTranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2, Reg m,
|
||||
ExtensionFunction ext_fn) {
|
||||
if (m == Reg::PC) {
|
||||
return v.UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const IR::U32 reg_m = v.ir.GetRegister(m);
|
||||
const IR::U32 reg_n = v.ir.GetRegister(n);
|
||||
const IR::U32 offset = v.ir.LogicalShiftLeft(reg_m, v.ir.Imm8(imm2.ZeroExtend<u8>()));
|
||||
const IR::U32 address = v.ir.Add(reg_n, offset);
|
||||
const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory16(address));
|
||||
|
||||
v.ir.SetRegister(t, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool LoadHalfImmediate(ThumbTranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W,
|
||||
Imm<12> imm12, ExtensionFunction ext_fn) {
|
||||
const u32 imm32 = imm12.ZeroExtend();
|
||||
const IR::U32 reg_n = v.ir.GetRegister(n);
|
||||
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32))
|
||||
: v.ir.Sub(reg_n, v.ir.Imm32(imm32));
|
||||
const IR::U32 address = P ? offset_address
|
||||
: reg_n;
|
||||
const IR::U32 data = (v.ir.*ext_fn)(v.ir.ReadMemory16(address));
|
||||
|
||||
if (W) {
|
||||
v.ir.SetRegister(n, offset_address);
|
||||
}
|
||||
|
||||
v.ir.SetRegister(t, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12) {
|
||||
return LoadHalfLiteral(*this, U, t, imm12, &IREmitter::ZeroExtendHalfToWord);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRH_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
|
||||
return LoadHalfRegister(*this, n, t, imm2, m, &IREmitter::ZeroExtendHalfToWord);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) {
|
||||
if (!P && !W) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC && W) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (W && n == t) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
return LoadHalfImmediate(*this, n, t, P, U, W, Imm<12>{imm8.ZeroExtend()},
|
||||
&IREmitter::ZeroExtendHalfToWord);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRH_imm12(Reg n, Reg t, Imm<12> imm12) {
|
||||
return LoadHalfImmediate(*this, n, t, true, true, false, imm12,
|
||||
&IREmitter::ZeroExtendHalfToWord);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRHT(Reg n, Reg t, Imm<8> imm8) {
|
||||
// TODO: Add an unpredictable instruction path if this
|
||||
// is executed in hypervisor mode if we ever support
|
||||
// privileged execution levels.
|
||||
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
// Treat it as a normal LDRH, given we don't support
|
||||
// execution levels other than EL0 currently.
|
||||
return thumb32_LDRH_imm8(n, t, true, true, false, imm8);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRSH_lit(bool U, Reg t, Imm<12> imm12) {
|
||||
return LoadHalfLiteral(*this, U, t, imm12, &IREmitter::SignExtendHalfToWord);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRSH_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
|
||||
return LoadHalfRegister(*this, n, t, imm2, m, &IREmitter::SignExtendHalfToWord);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRSH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) {
|
||||
if (!P && !W) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC && W) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (W && n == t) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
return LoadHalfImmediate(*this, n, t, P, U, W, Imm<12>{imm8.ZeroExtend()},
|
||||
&IREmitter::SignExtendHalfToWord);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRSH_imm12(Reg n, Reg t, Imm<12> imm12) {
|
||||
return LoadHalfImmediate(*this, n, t, true, true, false, imm12,
|
||||
&IREmitter::SignExtendHalfToWord);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRSHT(Reg n, Reg t, Imm<8> imm8) {
|
||||
// TODO: Add an unpredictable instruction path if this
|
||||
// is executed in hypervisor mode if we ever support
|
||||
// privileged execution levels.
|
||||
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
// Treat it as a normal LDRSH, given we don't support
|
||||
// execution levels other than EL0 currently.
|
||||
return thumb32_LDRSH_imm8(n, t, true, true, false, imm8);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
150
externals/dynarmic/src/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp
vendored
Executable file
150
externals/dynarmic/src/frontend/A32/translate/impl/thumb32_load_store_multiple.cpp
vendored
Executable file
@@ -0,0 +1,150 @@
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2021 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
*/
|
||||
|
||||
#include "common/bit_util.h"
|
||||
#include "frontend/A32/translate/impl/translate_thumb.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
static bool ITBlockCheck(const A32::IREmitter& ir) {
|
||||
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
|
||||
}
|
||||
|
||||
static bool LDMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list,
|
||||
const IR::U32& start_address, const IR::U32& writeback_address) {
|
||||
auto address = start_address;
|
||||
for (size_t i = 0; i <= 14; i++) {
|
||||
if (Common::Bit(i, list)) {
|
||||
ir.SetRegister(static_cast<Reg>(i), ir.ReadMemory32(address));
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
}
|
||||
}
|
||||
if (W && !Common::Bit(RegNumber(n), list)) {
|
||||
ir.SetRegister(n, writeback_address);
|
||||
}
|
||||
if (Common::Bit<15>(list)) {
|
||||
ir.UpdateUpperLocationDescriptor();
|
||||
ir.LoadWritePC(ir.ReadMemory32(address));
|
||||
if (n == Reg::R13) {
|
||||
ir.SetTerm(IR::Term::PopRSBHint{});
|
||||
} else {
|
||||
ir.SetTerm(IR::Term::FastDispatchHint{});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool STMHelper(A32::IREmitter& ir, bool W, Reg n, u32 list,
|
||||
const IR::U32& start_address, const IR::U32& writeback_address) {
|
||||
auto address = start_address;
|
||||
for (size_t i = 0; i <= 14; i++) {
|
||||
if (Common::Bit(i, list)) {
|
||||
ir.WriteMemory32(address, ir.GetRegister(static_cast<Reg>(i)));
|
||||
address = ir.Add(address, ir.Imm32(4));
|
||||
}
|
||||
}
|
||||
if (W) {
|
||||
ir.SetRegister(n, writeback_address);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list) {
|
||||
const auto regs_imm = reg_list.ZeroExtend();
|
||||
const auto num_regs = static_cast<u32>(Common::BitCount(regs_imm));
|
||||
|
||||
if (n == Reg::PC || num_regs < 2) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (reg_list.Bit<15>() && reg_list.Bit<14>()) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (W && Common::Bit(static_cast<size_t>(n), regs_imm)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (reg_list.Bit<13>()) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (reg_list.Bit<15>() && ITBlockCheck(ir)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
// Start address is the same as the writeback address.
|
||||
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs));
|
||||
return LDMHelper(ir, W, n, regs_imm, start_address, start_address);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list) {
|
||||
const auto regs_imm = reg_list.ZeroExtend();
|
||||
const auto num_regs = static_cast<u32>(Common::BitCount(regs_imm));
|
||||
|
||||
if (n == Reg::PC || num_regs < 2) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (reg_list.Bit<15>() && reg_list.Bit<14>()) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (W && Common::Bit(static_cast<size_t>(n), regs_imm)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (reg_list.Bit<13>()) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (reg_list.Bit<15>() && ITBlockCheck(ir)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto start_address = ir.GetRegister(n);
|
||||
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4));
|
||||
return LDMHelper(ir, W, n, regs_imm, start_address, writeback_address);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_POP(Imm<16> reg_list) {
|
||||
return thumb32_LDMIA(true, Reg::SP, reg_list);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_PUSH(Imm<15> reg_list) {
|
||||
return thumb32_STMDB(true, Reg::SP, reg_list);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STMIA(bool W, Reg n, Imm<15> reg_list) {
|
||||
const auto regs_imm = reg_list.ZeroExtend();
|
||||
const auto num_regs = static_cast<u32>(Common::BitCount(regs_imm));
|
||||
|
||||
if (n == Reg::PC || num_regs < 2) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (W && Common::Bit(static_cast<size_t>(n), regs_imm)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (reg_list.Bit<13>()) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto start_address = ir.GetRegister(n);
|
||||
const auto writeback_address = ir.Add(start_address, ir.Imm32(num_regs * 4));
|
||||
return STMHelper(ir, W, n, regs_imm, start_address, writeback_address);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STMDB(bool W, Reg n, Imm<15> reg_list) {
|
||||
const auto regs_imm = reg_list.ZeroExtend();
|
||||
const auto num_regs = static_cast<u32>(Common::BitCount(regs_imm));
|
||||
|
||||
if (n == Reg::PC || num_regs < 2) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (W && Common::Bit(static_cast<size_t>(n), regs_imm)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (reg_list.Bit<13>()) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
// Start address is the same as the writeback address.
|
||||
const IR::U32 start_address = ir.Sub(ir.GetRegister(n), ir.Imm32(4 * num_regs));
|
||||
return STMHelper(ir, W, n, regs_imm, start_address, start_address);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
@@ -6,6 +6,129 @@
|
||||
#include "frontend/A32/translate/impl/translate_thumb.h"
|
||||
|
||||
namespace Dynarmic::A32 {
|
||||
static bool ITBlockCheck(const A32::IREmitter& ir) {
|
||||
return ir.current_location.IT().IsInITBlock() && !ir.current_location.IT().IsLastInITBlock();
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12) {
|
||||
if (t == Reg::PC && ITBlockCheck(ir)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const u32 imm32 = imm12.ZeroExtend();
|
||||
const u32 base = ir.AlignPC(4);
|
||||
const u32 address = U ? base + imm32 : base - imm32;
|
||||
const auto data = ir.ReadMemory32(ir.Imm32(address));
|
||||
|
||||
if (t == Reg::PC) {
|
||||
ir.UpdateUpperLocationDescriptor();
|
||||
ir.LoadWritePC(data);
|
||||
ir.SetTerm(IR::Term::FastDispatchHint{});
|
||||
return false;
|
||||
}
|
||||
|
||||
ir.SetRegister(t, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8) {
|
||||
if (!P && !W) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (W && n == t) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (t == Reg::PC && ITBlockCheck(ir)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const u32 imm32 = imm8.ZeroExtend();
|
||||
const IR::U32 reg_n = ir.GetRegister(n);
|
||||
const IR::U32 offset_address = U ? ir.Add(reg_n, ir.Imm32(imm32))
|
||||
: ir.Sub(reg_n, ir.Imm32(imm32));
|
||||
const IR::U32 address = P ? offset_address
|
||||
: reg_n;
|
||||
const IR::U32 data = ir.ReadMemory32(address);
|
||||
|
||||
if (W) {
|
||||
ir.SetRegister(n, offset_address);
|
||||
}
|
||||
|
||||
if (t == Reg::PC) {
|
||||
ir.UpdateUpperLocationDescriptor();
|
||||
ir.LoadWritePC(data);
|
||||
|
||||
if (!P && W && n == Reg::R13) {
|
||||
ir.SetTerm(IR::Term::PopRSBHint{});
|
||||
} else {
|
||||
ir.SetTerm(IR::Term::FastDispatchHint{});
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ir.SetRegister(t, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDR_imm12(Reg n, Reg t, Imm<12> imm12) {
|
||||
if (t == Reg::PC && ITBlockCheck(ir)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto imm32 = imm12.ZeroExtend();
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto address = ir.Add(reg_n, ir.Imm32(imm32));
|
||||
const auto data = ir.ReadMemory32(address);
|
||||
|
||||
if (t == Reg::PC) {
|
||||
ir.UpdateUpperLocationDescriptor();
|
||||
ir.LoadWritePC(data);
|
||||
ir.SetTerm(IR::Term::FastDispatchHint{});
|
||||
return false;
|
||||
}
|
||||
|
||||
ir.SetRegister(t, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
|
||||
if (m == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
if (t == Reg::PC && ITBlockCheck(ir)) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
const auto reg_m = ir.GetRegister(m);
|
||||
const auto reg_n = ir.GetRegister(n);
|
||||
const auto offset = ir.LogicalShiftLeft(reg_m, ir.Imm8(imm2.ZeroExtend<u8>()));
|
||||
const auto address = ir.Add(reg_n, offset);
|
||||
const auto data = ir.ReadMemory32(address);
|
||||
|
||||
if (t == Reg::PC) {
|
||||
ir.UpdateUpperLocationDescriptor();
|
||||
ir.LoadWritePC(data);
|
||||
ir.SetTerm(IR::Term::FastDispatchHint{});
|
||||
return false;
|
||||
}
|
||||
|
||||
ir.SetRegister(t, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_LDRT(Reg n, Reg t, Imm<8> imm8) {
|
||||
// TODO: Add an unpredictable instruction path if this
|
||||
// is executed in hypervisor mode if we ever support
|
||||
// privileged execution levels.
|
||||
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
// Treat it as a normal LDR, given we don't support
|
||||
// execution levels other than EL0 currently.
|
||||
return thumb32_LDR_imm8(n, t, true, true, false, imm8);
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A32
|
||||
|
@@ -29,18 +29,192 @@ static bool StoreRegister(ThumbTranslatorVisitor& v, Reg n, Reg t, Imm<2> imm2,
|
||||
return true;
|
||||
}
|
||||
|
||||
using StoreImmFn = void (*)(ThumbTranslatorVisitor&, const IR::U32&, const IR::U32&);
|
||||
|
||||
static void StoreImmByteFn(ThumbTranslatorVisitor& v, const IR::U32& address, const IR::U32& data) {
|
||||
v.ir.WriteMemory8(address, v.ir.LeastSignificantByte(data));
|
||||
}
|
||||
|
||||
static void StoreImmHalfFn(ThumbTranslatorVisitor& v, const IR::U32& address, const IR::U32& data) {
|
||||
v.ir.WriteMemory16(address, v.ir.LeastSignificantHalf(data));
|
||||
}
|
||||
|
||||
static void StoreImmWordFn(ThumbTranslatorVisitor& v, const IR::U32& address, const IR::U32& data) {
|
||||
v.ir.WriteMemory32(address, data);
|
||||
}
|
||||
|
||||
static bool StoreImmediate(ThumbTranslatorVisitor& v, Reg n, Reg t, bool P, bool U, bool W, Imm<12> imm12,
|
||||
StoreImmFn store_fn) {
|
||||
const auto imm32 = imm12.ZeroExtend();
|
||||
const auto reg_n = v.ir.GetRegister(n);
|
||||
const auto reg_t = v.ir.GetRegister(t);
|
||||
|
||||
const IR::U32 offset_address = U ? v.ir.Add(reg_n, v.ir.Imm32(imm32))
|
||||
: v.ir.Sub(reg_n, v.ir.Imm32(imm32));
|
||||
const IR::U32 address = P ? offset_address
|
||||
: reg_n;
|
||||
|
||||
store_fn(v, address, reg_t);
|
||||
if (W) {
|
||||
v.ir.SetRegister(n, offset_address);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRB_imm_1(Reg n, Reg t, bool P, bool U, Imm<8> imm8) {
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC || n == t) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
return StoreImmediate(*this, n, t, P, U, true, Imm<12>{imm8.ZeroExtend()}, StoreImmByteFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRB_imm_2(Reg n, Reg t, Imm<8> imm8) {
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
return StoreImmediate(*this, n, t, true, false, false, Imm<12>{imm8.ZeroExtend()}, StoreImmByteFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRB_imm_3(Reg n, Reg t, Imm<12> imm12) {
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
return StoreImmediate(*this, n, t, true, true, false, imm12, StoreImmByteFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRBT(Reg n, Reg t, Imm<8> imm8) {
|
||||
// TODO: Add an unpredictable instruction path if this
|
||||
// is executed in hypervisor mode if we ever support
|
||||
// privileged execution levels.
|
||||
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
// Treat this as a normal STRB, given we don't support
|
||||
// execution levels other than EL0 currently.
|
||||
return StoreImmediate(*this, n, t, true, true, false, Imm<12>{imm8.ZeroExtend()}, StoreImmByteFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRB(Reg n, Reg t, Imm<2> imm2, Reg m) {
|
||||
return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) {
|
||||
ir.WriteMemory8(offset_address, ir.LeastSignificantByte(data));
|
||||
});
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRH_imm_1(Reg n, Reg t, bool P, bool U, Imm<8> imm8) {
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC || n == t) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
return StoreImmediate(*this, n, t, P, U, true, Imm<12>{imm8.ZeroExtend()}, StoreImmHalfFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRH_imm_2(Reg n, Reg t, Imm<8> imm8) {
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
return StoreImmediate(*this, n, t, true, false, false, Imm<12>{imm8.ZeroExtend()}, StoreImmHalfFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRH_imm_3(Reg n, Reg t, Imm<12> imm12) {
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
return StoreImmediate(*this, n, t, true, true, false, imm12, StoreImmHalfFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRHT(Reg n, Reg t, Imm<8> imm8) {
|
||||
// TODO: Add an unpredictable instruction path if this
|
||||
// is executed in hypervisor mode if we ever support
|
||||
// privileged execution levels.
|
||||
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
// Treat this as a normal STRH, given we don't support
|
||||
// execution levels other than EL0 currently.
|
||||
return StoreImmediate(*this, n, t, true, true, false, Imm<12>{imm8.ZeroExtend()}, StoreImmHalfFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRH(Reg n, Reg t, Imm<2> imm2, Reg m) {
|
||||
return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) {
|
||||
ir.WriteMemory16(offset_address, ir.LeastSignificantHalf(data));
|
||||
});
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STR_imm_1(Reg n, Reg t, bool P, bool U, Imm<8> imm8) {
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC || n == t) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
return StoreImmediate(*this, n, t, P, U, true, Imm<12>{imm8.ZeroExtend()}, StoreImmWordFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STR_imm_2(Reg n, Reg t, Imm<8> imm8) {
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
return StoreImmediate(*this, n, t, true, false, false, Imm<12>{imm8.ZeroExtend()}, StoreImmWordFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STR_imm_3(Reg n, Reg t, Imm<12> imm12) {
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
return StoreImmediate(*this, n, t, true, true, false, imm12, StoreImmWordFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STRT(Reg n, Reg t, Imm<8> imm8) {
|
||||
// TODO: Add an unpredictable instruction path if this
|
||||
// is executed in hypervisor mode if we ever support
|
||||
// privileged execution levels.
|
||||
|
||||
if (n == Reg::PC) {
|
||||
return UndefinedInstruction();
|
||||
}
|
||||
if (t == Reg::PC) {
|
||||
return UnpredictableInstruction();
|
||||
}
|
||||
|
||||
// Treat this as a normal STR, given we don't support
|
||||
// execution levels other than EL0 currently.
|
||||
return StoreImmediate(*this, n, t, true, true, false, Imm<12>{imm8.ZeroExtend()}, StoreImmWordFn);
|
||||
}
|
||||
|
||||
bool ThumbTranslatorVisitor::thumb32_STR_reg(Reg n, Reg t, Imm<2> imm2, Reg m) {
|
||||
return StoreRegister(*this, n, t, imm2, m, [this](const IR::U32& offset_address, const IR::U32& data) {
|
||||
ir.WriteMemory32(offset_address, data);
|
||||
|
@@ -171,6 +171,14 @@ struct ThumbTranslatorVisitor final {
|
||||
bool thumb16_B_t1(Cond cond, Imm<8> imm8);
|
||||
bool thumb16_B_t2(Imm<11> imm11);
|
||||
|
||||
// thumb32 load/store multiple instructions
|
||||
bool thumb32_LDMDB(bool W, Reg n, Imm<16> reg_list);
|
||||
bool thumb32_LDMIA(bool W, Reg n, Imm<16> reg_list);
|
||||
bool thumb32_POP(Imm<16> reg_list);
|
||||
bool thumb32_PUSH(Imm<15> reg_list);
|
||||
bool thumb32_STMIA(bool W, Reg n, Imm<15> reg_list);
|
||||
bool thumb32_STMDB(bool W, Reg n, Imm<15> reg_list);
|
||||
|
||||
// thumb32 data processing (shifted register) instructions
|
||||
bool thumb32_TST_reg(Reg n, Imm<3> imm3, Imm<2> imm2, ShiftType type, Reg m);
|
||||
bool thumb32_AND_reg(bool S, Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, ShiftType type, Reg m);
|
||||
@@ -209,6 +217,8 @@ struct ThumbTranslatorVisitor final {
|
||||
bool thumb32_RSB_imm(Imm<1> i, bool S, Reg n, Imm<3> imm3, Reg d, Imm<8> imm8);
|
||||
|
||||
// thumb32 data processing (plain binary immediate) instructions.
|
||||
bool thumb32_ADR_t2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8);
|
||||
bool thumb32_ADR_t3(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8);
|
||||
bool thumb32_ADD_imm_2(Imm<1> imm1, Imm<3> imm3, Reg d, Imm<8> imm8);
|
||||
bool thumb32_BFC(Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb);
|
||||
bool thumb32_BFI(Reg n, Imm<3> imm3, Reg d, Imm<2> imm2, Imm<5> msb);
|
||||
@@ -243,8 +253,20 @@ struct ThumbTranslatorVisitor final {
|
||||
bool thumb32_B_cond(Imm<1> S, Cond cond, Imm<6> hi, Imm<1> j1, Imm<1> j2, Imm<11> lo);
|
||||
|
||||
// thumb32 store single data item instructions
|
||||
bool thumb32_STRB_imm_1(Reg n, Reg t, bool P, bool U, Imm<8> imm8);
|
||||
bool thumb32_STRB_imm_2(Reg n, Reg t, Imm<8> imm8);
|
||||
bool thumb32_STRB_imm_3(Reg n, Reg t, Imm<12> imm12);
|
||||
bool thumb32_STRBT(Reg n, Reg t, Imm<8> imm8);
|
||||
bool thumb32_STRB(Reg n, Reg t, Imm<2> imm2, Reg m);
|
||||
bool thumb32_STRH_imm_1(Reg n, Reg t, bool P, bool U, Imm<8> imm8);
|
||||
bool thumb32_STRH_imm_2(Reg n, Reg t, Imm<8> imm8);
|
||||
bool thumb32_STRH_imm_3(Reg n, Reg t, Imm<12> imm12);
|
||||
bool thumb32_STRHT(Reg n, Reg t, Imm<8> imm8);
|
||||
bool thumb32_STRH(Reg n, Reg t, Imm<2> imm2, Reg m);
|
||||
bool thumb32_STR_imm_1(Reg n, Reg t, bool P, bool U, Imm<8> imm8);
|
||||
bool thumb32_STR_imm_2(Reg n, Reg t, Imm<8> imm8);
|
||||
bool thumb32_STR_imm_3(Reg n, Reg t, Imm<12> imm12);
|
||||
bool thumb32_STRT(Reg n, Reg t, Imm<8> imm8);
|
||||
bool thumb32_STR_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
|
||||
|
||||
// thumb32 load byte and memory hints
|
||||
@@ -267,6 +289,25 @@ struct ThumbTranslatorVisitor final {
|
||||
bool thumb32_LDRSB_imm12(Reg n, Reg t, Imm<12> imm12);
|
||||
bool thumb32_LDRSBT(Reg n, Reg t, Imm<8> imm8);
|
||||
|
||||
// thumb32 load halfword instructions
|
||||
bool thumb32_LDRH_lit(bool U, Reg t, Imm<12> imm12);
|
||||
bool thumb32_LDRH_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
|
||||
bool thumb32_LDRH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
|
||||
bool thumb32_LDRH_imm12(Reg n, Reg t, Imm<12> imm12);
|
||||
bool thumb32_LDRHT(Reg n, Reg t, Imm<8> imm8);
|
||||
bool thumb32_LDRSH_lit(bool U, Reg t, Imm<12> imm12);
|
||||
bool thumb32_LDRSH_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
|
||||
bool thumb32_LDRSH_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
|
||||
bool thumb32_LDRSH_imm12(Reg n, Reg t, Imm<12> imm12);
|
||||
bool thumb32_LDRSHT(Reg n, Reg t, Imm<8> imm8);
|
||||
|
||||
// thumb32 load word instructions
|
||||
bool thumb32_LDR_lit(bool U, Reg t, Imm<12> imm12);
|
||||
bool thumb32_LDR_reg(Reg n, Reg t, Imm<2> imm2, Reg m);
|
||||
bool thumb32_LDR_imm8(Reg n, Reg t, bool P, bool U, bool W, Imm<8> imm8);
|
||||
bool thumb32_LDR_imm12(Reg n, Reg t, Imm<12> imm12);
|
||||
bool thumb32_LDRT(Reg n, Reg t, Imm<8> imm8);
|
||||
|
||||
// thumb32 data processing (register) instructions
|
||||
bool thumb32_ASR_reg(Reg m, Reg d, Reg s);
|
||||
bool thumb32_LSL_reg(Reg m, Reg d, Reg s);
|
||||
|
@@ -61,6 +61,8 @@ INST(WFI, "WFI", "11010
|
||||
INST(SEV, "SEV", "11010101000000110010000010011111")
|
||||
INST(SEVL, "SEVL", "11010101000000110010000010111111")
|
||||
//INST(DGH, "DGH", "11010101000000110010000011011111") // v8.6
|
||||
//INST(WFET, "WFET", "110101010000001100010000000ddddd") // v8.7
|
||||
//INST(WFIT, "WFIT", "110101010000001100010000001ddddd") // v8.7
|
||||
//INST(XPAC_1, "XPACD, XPACI, XPACLRI", "110110101100000101000D11111ddddd")
|
||||
//INST(XPAC_2, "XPACD, XPACI, XPACLRI", "11010101000000110010000011111111")
|
||||
//INST(PACIA_1, "PACIA, PACIA1716, PACIASP, PACIAZ, PACIZA", "110110101100000100Z000nnnnnddddd")
|
||||
@@ -267,6 +269,10 @@ INST(LDTRSW, "LDTRSW", "10111
|
||||
//INST(LDUMIN, "LDUMIN, LDUMINA, LDUMINAL, LDUMINL", "1-111000AR1sssss011100nnnnnttttt")
|
||||
//INST(SWP, "SWP, SWPA, SWPAL, SWPL", "1-111000AR1sssss100000nnnnnttttt")
|
||||
//INST(LDAPR, "LDAPR", "1-11100010111111110000nnnnnttttt")
|
||||
//INST(LD64B, "LD64B", "1111100000111111110100nnnnnttttt") // v8.7
|
||||
//INST(ST64B, "ST64B", "1111100000111111100100nnnnnttttt") // v8.7
|
||||
//INST(ST64BV, "ST64BV", "11111000001sssss101100nnnnnttttt") // v8.7
|
||||
//INST(ST64BV0, "ST64BV0", "11111000001sssss101000nnnnnttttt") // v8.7
|
||||
|
||||
// Loads and stores - Load/Store register (register offset)
|
||||
INST(STRx_reg, "STRx (register)", "zz111000o01mmmmmxxxS10nnnnnttttt")
|
||||
|
Reference in New Issue
Block a user