mirror of
https://git.suyu.dev/suyu/dynarmic.git
synced 2026-01-04 13:44:31 +01:00
A32/thumb16: Implement IT instruction
This commit is contained in:
parent
97d8b50c25
commit
f77b0e2fbe
6 changed files with 155 additions and 29 deletions
|
|
@ -18,6 +18,7 @@
|
|||
#include "common/fp/fpsr.h"
|
||||
#include "common/llvm_disassemble.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "frontend/A32/ITState.h"
|
||||
#include "frontend/A32/location_descriptor.h"
|
||||
#include "frontend/A32/translate/translate.h"
|
||||
#include "frontend/A32/types.h"
|
||||
|
|
@ -36,8 +37,8 @@
|
|||
namespace {
|
||||
using namespace Dynarmic;
|
||||
|
||||
bool ShouldTestInst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst) {
|
||||
const A32::LocationDescriptor location = A32::LocationDescriptor{pc, {}, {}}.SetTFlag(is_thumb);
|
||||
bool ShouldTestInst(u32 instruction, u32 pc, bool is_thumb, bool is_last_inst, A32::ITState it_state = {}) {
|
||||
const A32::LocationDescriptor location = A32::LocationDescriptor{pc, {}, {}}.SetTFlag(is_thumb).SetIT(it_state);
|
||||
IR::Block block{location};
|
||||
const bool should_continue = A32::TranslateSingleInstruction(block, location, instruction);
|
||||
|
||||
|
|
@ -145,7 +146,7 @@ u32 GenRandomArmInst(u32 pc, bool is_last_inst) {
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<u16> GenRandomThumbInst(u32 pc, bool is_last_inst) {
|
||||
std::vector<u16> GenRandomThumbInst(u32 pc, bool is_last_inst, A32::ITState it_state = {}) {
|
||||
static const struct InstructionGeneratorInfo {
|
||||
std::vector<InstructionGenerator> generators;
|
||||
std::vector<InstructionGenerator> invalid;
|
||||
|
|
@ -162,8 +163,9 @@ std::vector<u16> GenRandomThumbInst(u32 pc, bool is_last_inst) {
|
|||
|
||||
// List of instructions not to test
|
||||
static constexpr std::array do_not_test {
|
||||
"thumb16_SETEND",
|
||||
"thumb16_BKPT",
|
||||
"thumb16_IT",
|
||||
"thumb16_SETEND",
|
||||
};
|
||||
|
||||
for (const auto& [fn, bitstring] : list) {
|
||||
|
|
@ -181,7 +183,7 @@ std::vector<u16> GenRandomThumbInst(u32 pc, bool is_last_inst) {
|
|||
const u32 inst = instructions.generators[index].Generate();
|
||||
const bool is_four_bytes = (inst >> 16) != 0;
|
||||
|
||||
if (ShouldTestInst(is_four_bytes ? Common::SwapHalves32(inst) : inst, pc, true, is_last_inst)) {
|
||||
if (ShouldTestInst(is_four_bytes ? Common::SwapHalves32(inst) : inst, pc, true, is_last_inst, it_state)) {
|
||||
if (is_four_bytes)
|
||||
return { static_cast<u16>(inst >> 16), static_cast<u16>(inst) };
|
||||
return { static_cast<u16>(inst) };
|
||||
|
|
@ -480,3 +482,55 @@ TEST_CASE("A32: Small random thumb block", "[thumb]") {
|
|||
RunTestInstance(jit, uni, jit_env, uni_env, regs, ext_reg, instructions, cpsr, fpcr, 5);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("A32: Test thumb IT instruction", "[thumb]") {
|
||||
ThumbTestEnv jit_env{};
|
||||
ThumbTestEnv uni_env{};
|
||||
|
||||
Dynarmic::A32::Jit jit{GetUserConfig(jit_env)};
|
||||
A32Unicorn<ThumbTestEnv> uni{uni_env};
|
||||
|
||||
A32Unicorn<ThumbTestEnv>::RegisterArray regs;
|
||||
A32Unicorn<ThumbTestEnv>::ExtRegArray ext_reg;
|
||||
std::vector<u16> instructions;
|
||||
|
||||
for (size_t iteration = 0; iteration < 100000; ++iteration) {
|
||||
std::generate(regs.begin(), regs.end(), [] { return RandInt<u32>(0, ~u32(0)); });
|
||||
std::generate(ext_reg.begin(), ext_reg.end(), [] { return RandInt<u32>(0, ~u32(0)); });
|
||||
|
||||
const size_t pre_instructions = RandInt<size_t>(0, 3);
|
||||
const size_t post_instructions = RandInt<size_t>(5, 8);
|
||||
|
||||
instructions.clear();
|
||||
|
||||
for (size_t i = 0; i < pre_instructions; i++) {
|
||||
const std::vector<u16> inst = GenRandomThumbInst(instructions.size() * 2, false);
|
||||
instructions.insert(instructions.end(), inst.begin(), inst.end());
|
||||
}
|
||||
|
||||
// Emit IT instruction
|
||||
A32::ITState it_state = [&]{
|
||||
while (true) {
|
||||
const u16 imm8 = RandInt<u16>(0, 0xFF);
|
||||
if (Common::Bits<0, 3>(imm8) == 0b0000 || Common::Bits<4, 7>(imm8) == 0b1111 || (Common::Bits<4, 7>(imm8) == 0b1110 && Common::BitCount(Common::Bits<0, 3>(imm8)) != 1)) {
|
||||
continue;
|
||||
}
|
||||
instructions.push_back(0b1011111100000000 | imm8);
|
||||
return A32::ITState{static_cast<u8>(imm8)};
|
||||
}
|
||||
}();
|
||||
|
||||
for (size_t i = 0; i < post_instructions; i++) {
|
||||
const std::vector<u16> inst = GenRandomThumbInst(instructions.size() * 2, i == post_instructions - 1, it_state);
|
||||
instructions.insert(instructions.end(), inst.begin(), inst.end());
|
||||
it_state = it_state.Advance();
|
||||
}
|
||||
|
||||
const u32 start_address = 100;
|
||||
const u32 cpsr = (RandInt<u32>(0, 0xF) << 28) | 0x1F0;
|
||||
const u32 fpcr = RandomFpcr();
|
||||
|
||||
regs[15] = start_address;
|
||||
RunTestInstance(jit, uni, jit_env, uni_env, regs, ext_reg, instructions, cpsr, fpcr, pre_instructions + 1 + post_instructions);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue