Proper implementation of Arm::Translate

This commit is contained in:
MerryMage 2016-07-04 21:37:50 +08:00
parent d743adf518
commit 14388ea690
29 changed files with 276 additions and 90 deletions

View file

@ -14,6 +14,7 @@ set(SRCS
frontend/disassembler_arm.cpp frontend/disassembler_arm.cpp
frontend/ir/ir.cpp frontend/ir/ir.cpp
frontend/ir_emitter.cpp frontend/ir_emitter.cpp
frontend/translate.cpp
) )
set(HEADERS set(HEADERS
@ -43,7 +44,9 @@ set(HEADERS
frontend/ir/ir.h frontend/ir/ir.h
frontend/ir/opcodes.h frontend/ir/opcodes.h
frontend/ir_emitter.h frontend/ir_emitter.h
frontend/translate_thumb.h frontend/translate.h
frontend/translate_arm.cpp
frontend/translate_thumb.cpp
interface/interface.h interface/interface.h
) )

View file

@ -9,6 +9,7 @@
#include "backend_x64/emit_x64.h" #include "backend_x64/emit_x64.h"
#include "common/x64/emitter.h" #include "common/x64/emitter.h"
#include "frontend/arm_types.h"
// TODO: More optimal use of immediates. // TODO: More optimal use of immediates.
// TODO: Have ARM flags in host flags and not have them use up GPR registers unless necessary. // TODO: Have ARM flags in host flags and not have them use up GPR registers unless necessary.
@ -34,6 +35,9 @@ static IR::Inst* FindUseWithOpcode(IR::Inst* inst, IR::Opcode opcode) {
} }
CodePtr EmitX64::Emit(Arm::LocationDescriptor descriptor, Dynarmic::IR::Block block) { CodePtr EmitX64::Emit(Arm::LocationDescriptor descriptor, Dynarmic::IR::Block block) {
inhibit_emission.clear();
reg_alloc.Reset();
code->INT3(); code->INT3();
CodePtr code_ptr = code->GetCodePtr(); CodePtr code_ptr = code->GetCodePtr();
@ -46,6 +50,7 @@ CodePtr EmitX64::Emit(Arm::LocationDescriptor descriptor, Dynarmic::IR::Block bl
reg_alloc.EndOfAllocScope(); reg_alloc.EndOfAllocScope();
} }
EmitAddCycles(block.cycle_count);
EmitReturnToDispatch(); EmitReturnToDispatch();
return code_ptr; return code_ptr;
@ -378,6 +383,11 @@ void EmitX64::EmitArithmeticShiftRight(IR::Value* value_) {
} }
} }
void EmitX64::EmitAddCycles(size_t cycles) {
ASSERT(cycles < std::numeric_limits<u32>::max());
code->SUB(64, MDisp(R15, offsetof(JitState, cycles_remaining)), Imm32(cycles));
}
void EmitX64::EmitReturnToDispatch() { void EmitX64::EmitReturnToDispatch() {
// TODO: Update cycle counts // TODO: Update cycle counts

View file

@ -7,6 +7,7 @@
#pragma once #pragma once
#include <set> #include <set>
#include <unordered_map>
#include "backend_x64/reg_alloc.h" #include "backend_x64/reg_alloc.h"
#include "backend_x64/routines.h" #include "backend_x64/routines.h"
@ -19,10 +20,15 @@ namespace BackendX64 {
class EmitX64 final { class EmitX64 final {
public: public:
EmitX64(Gen::XEmitter* code, Routines* routines, UserCallbacks cb) : code(code), reg_alloc(code), routines(routines), cb(cb) {} EmitX64(Gen::XEmitter* code, Routines* routines, UserCallbacks cb)
: reg_alloc(code), code(code), routines(routines), cb(cb) {}
CodePtr Emit(Arm::LocationDescriptor descriptor, IR::Block ir); CodePtr Emit(Arm::LocationDescriptor descriptor, IR::Block ir);
CodePtr GetBasicBlock(Arm::LocationDescriptor descriptor);
CodePtr GetBasicBlock(Arm::LocationDescriptor descriptor) {
auto iter = basic_blocks.find(descriptor);
return iter != basic_blocks.end() ? iter->second : nullptr;
}
void EmitImmU1(IR::Value* value); void EmitImmU1(IR::Value* value);
void EmitImmU8(IR::Value* value); void EmitImmU8(IR::Value* value);
@ -46,14 +52,17 @@ public:
void EmitLogicalShiftRight(IR::Value* value); void EmitLogicalShiftRight(IR::Value* value);
void EmitArithmeticShiftRight(IR::Value* value); void EmitArithmeticShiftRight(IR::Value* value);
void EmitAddCycles(size_t cycles);
void EmitReturnToDispatch(); void EmitReturnToDispatch();
private: private:
std::set<IR::Value*> inhibit_emission; std::set<IR::Value*> inhibit_emission;
Gen::XEmitter* code;
RegAlloc reg_alloc; RegAlloc reg_alloc;
Gen::XEmitter* code;
Routines* routines; Routines* routines;
UserCallbacks cb; UserCallbacks cb;
std::unordered_map<Arm::LocationDescriptor, CodePtr, Arm::LocationDescriptorHash> basic_blocks;
}; };
} // namespace BackendX64 } // namespace BackendX64

View file

@ -14,6 +14,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "frontend/arm_types.h" #include "frontend/arm_types.h"
#include "frontend/translate.h"
#include "interface/interface.h" #include "interface/interface.h"
namespace Dynarmic { namespace Dynarmic {
@ -27,12 +28,13 @@ struct BlockOfCode : Gen::XCodeBlock {
}; };
struct Jit::Impl { struct Jit::Impl {
Impl(UserCallbacks callbacks) : emitter(&block_of_code, &routines, callbacks) {} Impl(UserCallbacks callbacks) : emitter(&block_of_code, &routines, callbacks), callbacks(callbacks) {}
JitState jit_state{}; JitState jit_state{};
Routines routines{}; Routines routines{};
BlockOfCode block_of_code{}; BlockOfCode block_of_code{};
EmitX64 emitter; EmitX64 emitter;
const UserCallbacks callbacks;
size_t Execute(size_t cycle_count) { size_t Execute(size_t cycle_count) {
u32 pc = jit_state.Reg[15]; u32 pc = jit_state.Reg[15];
@ -50,7 +52,7 @@ private:
if (code_ptr) if (code_ptr)
return code_ptr; return code_ptr;
IR::Block ir_block = IR::Block({0, false, false}); // TODO: Do this. IR::Block ir_block = Arm::Translate(descriptor, callbacks.MemoryRead32);
return emitter.Emit(descriptor, ir_block); return emitter.Emit(descriptor, ir_block);
} }
}; };

View file

@ -201,5 +201,12 @@ void RegAlloc::EndOfAllocScope() {
iter.second = nullptr; iter.second = nullptr;
} }
void RegAlloc::Reset() {
hostloc_to_value.clear();
hostloc_state.clear();
remaining_uses.clear();
}
} // namespace BackendX64 } // namespace BackendX64
} // namespace Dynarmic } // namespace Dynarmic

View file

@ -78,6 +78,8 @@ public:
void EndOfAllocScope(); void EndOfAllocScope();
void Reset();
private: private:
HostLoc SelectARegister(std::initializer_list<HostLoc> desired_locations) const; HostLoc SelectARegister(std::initializer_list<HostLoc> desired_locations) const;
std::vector<HostLoc> ValueLocations(IR::Value* value) const; std::vector<HostLoc> ValueLocations(IR::Value* value) const;

View file

@ -72,5 +72,13 @@ struct LocationDescriptor {
} }
}; };
struct LocationDescriptorHash {
size_t operator()(const LocationDescriptor& x) const {
return std::hash<u64>()(static_cast<u64>(x.arm_pc)
^ (static_cast<u64>(x.TFlag) << 32)
^ (static_cast<u64>(x.EFlag) << 33));
}
};
} // namespace Arm } // namespace Arm
} // namespace Dynarmic } // namespace Dynarmic

View file

@ -43,6 +43,9 @@ private:
expect |= 1 << bit_position; expect |= 1 << bit_position;
mask |= 1 << bit_position; mask |= 1 << bit_position;
break; break;
default:
// Ignore
break;
} }
} }
return std::make_tuple(mask, expect); return std::make_tuple(mask, expect);

View file

@ -56,7 +56,7 @@ private:
}; };
template <typename V> template <typename V>
static const std::array<Thumb1Matcher<V>, 6> g_thumb1_instruction_table {{ static const std::array<Thumb1Matcher<V>, 7> g_thumb1_instruction_table {{
#define INST(fn, name, bitstring) detail::detail<Thumb1Matcher, u16, 16>::GetMatcher<decltype(fn), fn>(name, bitstring) #define INST(fn, name, bitstring) detail::detail<Thumb1Matcher, u16, 16>::GetMatcher<decltype(fn), fn>(name, bitstring)
@ -138,7 +138,7 @@ static const std::array<Thumb1Matcher<V>, 6> g_thumb1_instruction_table {{
// Branch instructions // Branch instructions
//{ INST(&V::thumb1_BX, "BX (reg)", "010001110mmmm000") }, // v4T //{ INST(&V::thumb1_BX, "BX (reg)", "010001110mmmm000") }, // v4T
//{ INST(&V::thumb1_BLX, "BLX (reg)", "010001111mmmm000") }, // v5T //{ INST(&V::thumb1_BLX, "BLX (reg)", "010001111mmmm000") }, // v5T
//{ INST(&V::thumb1_UDF, "UDF", "11011110--------") }, { INST(&V::thumb1_UDF, "UDF", "11011110--------") },
//{ INST(&V::thumb1_SWI, "SWI", "11011111xxxxxxxx") }, //{ INST(&V::thumb1_SWI, "SWI", "11011111xxxxxxxx") },
//{ INST(&V::thumb1_B_cond, "B (cond)", "1101ccccxxxxxxxx") }, //{ INST(&V::thumb1_B_cond, "B (cond)", "1101ccccxxxxxxxx") },
//{ INST(&V::thumb1_B_imm, "B (imm)", "11100xxxxxxxxxxx") }, //{ INST(&V::thumb1_B_imm, "B (imm)", "11100xxxxxxxxxxx") },

View file

@ -161,6 +161,7 @@ public:
Arm::LocationDescriptor location; Arm::LocationDescriptor location;
std::list<ValuePtr> instructions; std::list<ValuePtr> instructions;
size_t cycle_count = 0;
}; };

View file

@ -15,7 +15,10 @@ namespace Arm {
class IREmitter { class IREmitter {
public: public:
IR::Block block = Dynarmic::IR::Block({0, false, false}); explicit IREmitter(LocationDescriptor descriptor) : block(descriptor), current_location(descriptor) {}
IR::Block block;
LocationDescriptor current_location;
struct ResultAndCarry { struct ResultAndCarry {
IR::ValuePtr result; IR::ValuePtr result;

View file

@ -0,0 +1,22 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* This software may be used and distributed according to the terms of the GNU
* General Public License version 2 or any later version.
*/
#include "frontend/arm_types.h"
#include "frontend/ir/ir.h"
#include "frontend/translate.h"
namespace Dynarmic {
namespace Arm {
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
return (descriptor.TFlag ? TranslateThumb : TranslateArm)(descriptor, memory_read_32);
}
} // namespace Arm
} // namespace Dynarmic

19
src/frontend/translate.h Normal file
View file

@ -0,0 +1,19 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* This software may be used and distributed according to the terms of the GNU
* General Public License version 2 or any later version.
*/
#pragma once
#include "frontend/arm_types.h"
#include "frontend/ir/ir.h"
namespace Dynarmic {
namespace Arm {
using MemoryRead32FuncType = u32 (*)(u32 vaddr);
IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32);
} // namespace Arm
} // namespace Dynarmic

View file

@ -0,0 +1,21 @@
/* This file is part of the dynarmic project.
* Copyright (c) 2016 MerryMage
* This software may be used and distributed according to the terms of the GNU
* General Public License version 2 or any later version.
*/
#include "common/assert.h"
#include "frontend/arm_types.h"
#include "frontend/ir/ir.h"
#include "frontend/translate.h"
namespace Dynarmic {
namespace Arm {
IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
ASSERT_MSG(0, "Unimplemented");
return IR::Block(descriptor);
}
} // namespace Arm
} // namespace Dynarmic

View file

@ -4,19 +4,25 @@
* General Public License version 2 or any later version. * General Public License version 2 or any later version.
*/ */
#pragma once #include <tuple>
#include "common/assert.h"
#include "frontend/arm_types.h" #include "frontend/arm_types.h"
#include "frontend/decoder/thumb1.h"
#include "frontend/ir_emitter.h" #include "frontend/ir_emitter.h"
#include "frontend/translate.h"
namespace Dynarmic { namespace Dynarmic {
namespace Arm { namespace Arm {
class TranslatorVisitor { struct TranslatorVisitor final {
public: explicit TranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) {
ASSERT_MSG(descriptor.TFlag, "The processor must be in Thumb mode");
}
IREmitter ir; IREmitter ir;
void thumb1_LSL_imm(Imm5 imm5, Reg m, Reg d) { bool thumb1_LSL_imm(Imm5 imm5, Reg m, Reg d) {
u8 shift_n = imm5; u8 shift_n = imm5;
// LSLS <Rd>, <Rm>, #<imm5> // LSLS <Rd>, <Rm>, #<imm5>
auto cpsr_c = ir.GetCFlag(); auto cpsr_c = ir.GetCFlag();
@ -25,8 +31,9 @@ public:
ir.SetNFlag(ir.MostSignificantBit(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result)); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry); ir.SetCFlag(result.carry);
return true;
} }
void thumb1_LSR_imm(Imm5 imm5, Reg m, Reg d) { bool thumb1_LSR_imm(Imm5 imm5, Reg m, Reg d) {
u8 shift_n = imm5 != 0 ? imm5 : 32; u8 shift_n = imm5 != 0 ? imm5 : 32;
// LSRS <Rd>, <Rm>, #<imm5> // LSRS <Rd>, <Rm>, #<imm5>
auto cpsr_c = ir.GetCFlag(); auto cpsr_c = ir.GetCFlag();
@ -35,8 +42,9 @@ public:
ir.SetNFlag(ir.MostSignificantBit(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result)); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry); ir.SetCFlag(result.carry);
return true;
} }
void thumb1_ASR_imm(Imm5 imm5, Reg m, Reg d) { bool thumb1_ASR_imm(Imm5 imm5, Reg m, Reg d) {
u8 shift_n = imm5 != 0 ? imm5 : 32; u8 shift_n = imm5 != 0 ? imm5 : 32;
// ASRS <Rd>, <Rm>, #<imm5> // ASRS <Rd>, <Rm>, #<imm5>
auto cpsr_c = ir.GetCFlag(); auto cpsr_c = ir.GetCFlag();
@ -45,8 +53,10 @@ public:
ir.SetNFlag(ir.MostSignificantBit(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result)); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry); ir.SetCFlag(result.carry);
return true;
} }
void thumb1_LSL_reg(Reg m, Reg d_n) {
bool thumb1_LSL_reg(Reg m, Reg d_n) {
const Reg d = d_n, n = d_n; const Reg d = d_n, n = d_n;
// LSLS <Rdn>, <Rm> // LSLS <Rdn>, <Rm>
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m)); auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m));
@ -56,8 +66,9 @@ public:
ir.SetNFlag(ir.MostSignificantBit(result_carry.result)); ir.SetNFlag(ir.MostSignificantBit(result_carry.result));
ir.SetZFlag(ir.IsZero(result_carry.result)); ir.SetZFlag(ir.IsZero(result_carry.result));
ir.SetCFlag(result_carry.carry); ir.SetCFlag(result_carry.carry);
return true;
} }
void thumb1_LSR_reg(Reg m, Reg d_n) { bool thumb1_LSR_reg(Reg m, Reg d_n) {
const Reg d = d_n, n = d_n; const Reg d = d_n, n = d_n;
// LSRS <Rdn>, <Rm> // LSRS <Rdn>, <Rm>
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m)); auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m));
@ -67,8 +78,9 @@ public:
ir.SetNFlag(ir.MostSignificantBit(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result)); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry); ir.SetCFlag(result.carry);
return true;
} }
void thumb1_ASR_reg(Reg m, Reg d_n) { bool thumb1_ASR_reg(Reg m, Reg d_n) {
const Reg d = d_n, n = d_n; const Reg d = d_n, n = d_n;
// ASRS <Rdn>, <Rm> // ASRS <Rdn>, <Rm>
auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m)); auto shift_n = ir.LeastSignificantByte(ir.GetRegister(m));
@ -78,11 +90,73 @@ public:
ir.SetNFlag(ir.MostSignificantBit(result.result)); ir.SetNFlag(ir.MostSignificantBit(result.result));
ir.SetZFlag(ir.IsZero(result.result)); ir.SetZFlag(ir.IsZero(result.result));
ir.SetCFlag(result.carry); ir.SetCFlag(result.carry);
return true;
} }
bool thumb1_UDF() {
void thumb1_UDF() {} return false;
}
}; };
enum class ThumbInstSize {
Thumb16, Thumb32
};
static std::tuple<u32, ThumbInstSize> ReadThumbInstruction(u32 arm_pc, MemoryRead32FuncType memory_read_32) {
u32 first_part = (*memory_read_32)(arm_pc & 0xFFFFFFFC);
if ((arm_pc & 0x2) != 0)
first_part >>= 16;
first_part &= 0xFFFF;
if ((first_part & 0xF800) != 0xE800 && (first_part & 0xF000) != 0xF000) {
// 16-bit thumb instruction
return std::make_tuple(first_part, ThumbInstSize::Thumb16);
}
// 32-bit thumb instruction
u32 second_part = (*memory_read_32)((arm_pc+2) & 0xFFFFFFFC);
if (((arm_pc+2) & 0x2) != 0)
second_part >>= 16;
second_part &= 0xFFFF;
return std::make_tuple(static_cast<u32>((first_part << 16) | second_part), ThumbInstSize::Thumb32);
}
IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) {
TranslatorVisitor visitor{descriptor};
bool should_continue = true;
while (should_continue) {
const u32 arm_pc = visitor.ir.current_location.arm_pc;
u32 thumb_instruction;
ThumbInstSize inst_size;
std::tie(thumb_instruction, inst_size) = ReadThumbInstruction(arm_pc, memory_read_32);
if (inst_size == ThumbInstSize::Thumb16) {
auto decoder = DecodeThumb1<TranslatorVisitor>(static_cast<u16>(thumb_instruction));
if (decoder) {
should_continue = decoder->call(visitor, static_cast<u16>(thumb_instruction));
} else {
should_continue = visitor.thumb1_UDF();
}
} else {
/*auto decoder = DecodeThumb2<TranslatorVisitor>(thumb_instruction);
if (decoder) {
should_continue = decoder->call(visitor, thumb_instruction);
} else {
should_continue = visitor.thumb2_UDF();
}*/
ASSERT_MSG(0, "Unimplemented");
}
visitor.ir.current_location.arm_pc += inst_size == ThumbInstSize::Thumb16 ? 2 : 4;
visitor.ir.block.cycle_count++;
}
return visitor.ir.block;
}
} // namespace Arm } // namespace Arm
} // namepsace Dynarmic } // namepsace Dynarmic

View file

@ -1,4 +1,4 @@
include_directories(.) include_directories(. ../src)
set(SRCS set(SRCS
arm/fuzz_thumb.cpp arm/fuzz_thumb.cpp

View file

@ -6,54 +6,56 @@
#include <catch.hpp> #include <catch.hpp>
#include "backend_x64/emit_x64.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "frontend/decoder/thumb1.h" #include "interface/interface.h"
#include "frontend/translate_thumb.h"
struct TinyBlockOfCode : Gen::XCodeBlock { std::array<u32, 1024> code_mem{};
TinyBlockOfCode() {
AllocCodeSpace(256); u32 MemoryRead32(u32 vaddr) {
if (vaddr < code_mem.size() * sizeof(u32)) {
return code_mem[vaddr / sizeof(u32)];
} }
}; return vaddr;
}
void RunSingleThumbInstruction(u16 thumb_instruction, Dynarmic::BackendX64::JitState* jit_state_ptr) { Dynarmic::UserCallbacks GetUserCallbacks() {
Dynarmic::Arm::TranslatorVisitor visitor; Dynarmic::UserCallbacks user_callbacks{};
auto decoder = Dynarmic::Arm::DecodeThumb1<Dynarmic::Arm::TranslatorVisitor>(thumb_instruction); user_callbacks.MemoryRead32 = &MemoryRead32;
REQUIRE(!!decoder); return user_callbacks;
decoder->call(visitor, thumb_instruction);
TinyBlockOfCode block_of_code;
Dynarmic::BackendX64::Routines routines;
Dynarmic::UserCallbacks callbacks{};
Dynarmic::BackendX64::EmitX64 emitter(&block_of_code, &routines, callbacks);
Dynarmic::BackendX64::CodePtr code = emitter.Emit({0, true, false}, visitor.ir.block);
routines.RunCode(jit_state_ptr, code, 1);
} }
TEST_CASE( "thumb: lsls r0, r1, #2", "[thumb]" ) { TEST_CASE( "thumb: lsls r0, r1, #2", "[thumb]" ) {
Dynarmic::BackendX64::JitState jit_state; Dynarmic::Jit jit{GetUserCallbacks()};
jit_state.Reg[0] = 1; code_mem.fill({});
jit_state.Reg[1] = 2; code_mem[0] = 0x0088; // lsls r0, r1, #2
jit_state.Cpsr = 0; code_mem[1] = 0xDE00; // udf #0
RunSingleThumbInstruction(0x0088, &jit_state); jit.Regs()[0] = 1;
jit.Regs()[1] = 2;
jit.Regs()[15] = 0; // PC = 0
jit.Cpsr() = 0x00000030; // Thumb, User-mode
REQUIRE( jit_state.Reg[0] == 8 ); jit.Run(1);
REQUIRE( jit_state.Reg[1] == 2 );
REQUIRE( jit_state.Cpsr == 0 ); REQUIRE( jit.Regs()[0] == 8 );
REQUIRE( jit.Regs()[1] == 2 );
REQUIRE( jit.Cpsr() == 0x00000030 );
} }
TEST_CASE( "thumb: lsls r0, r1, #31", "[thumb]" ) { TEST_CASE( "thumb: lsls r0, r1, #31", "[thumb]" ) {
Dynarmic::BackendX64::JitState jit_state; Dynarmic::Jit jit{GetUserCallbacks()};
jit_state.Reg[0] = 1; code_mem.fill({});
jit_state.Reg[1] = 0xFFFFFFFF; code_mem[0] = 0x07C8; // lsls r0, r1, #31
jit_state.Cpsr = 0; code_mem[1] = 0xDE00; // udf #0
RunSingleThumbInstruction(0x07C8, &jit_state); jit.Regs()[0] = 1;
jit.Regs()[1] = 0xFFFFFFFF;
jit.Regs()[15] = 0; // PC = 0
jit.Cpsr() = 0x00000030; // Thumb, User-mode
REQUIRE( jit_state.Reg[0] == 0x80000000 ); jit.Run(1);
REQUIRE( jit_state.Reg[1] == 0xffffffff );
REQUIRE( jit_state.Cpsr == 0x20000000 ); REQUIRE( jit.Regs()[0] == 0x80000000 );
REQUIRE( jit.Regs()[1] == 0xffffffff );
REQUIRE( jit.Cpsr() == 0x20000030 ); // C flag, Thumb, User-mode
} }

View file

@ -2,8 +2,8 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "tests/skyeye_interpreter/dyncom/arm_dyncom_dec.h" #include "skyeye_interpreter/dyncom/arm_dyncom_dec.h"
#include "tests/skyeye_interpreter/skyeye_common/armsupp.h" #include "skyeye_interpreter/skyeye_common/armsupp.h"
const InstructionSetEncodingItem arm_instruction[] = { const InstructionSetEncodingItem arm_instruction[] = {
{ "vmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, { "vmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }},

View file

@ -10,13 +10,13 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "tests/skyeye_interpreter/dyncom/arm_dyncom_dec.h" #include "skyeye_interpreter/dyncom/arm_dyncom_dec.h"
#include "tests/skyeye_interpreter/dyncom/arm_dyncom_interpreter.h" #include "skyeye_interpreter/dyncom/arm_dyncom_interpreter.h"
#include "tests/skyeye_interpreter/dyncom/arm_dyncom_thumb.h" #include "skyeye_interpreter/dyncom/arm_dyncom_thumb.h"
#include "tests/skyeye_interpreter/dyncom/arm_dyncom_run.h" #include "skyeye_interpreter/dyncom/arm_dyncom_run.h"
#include "tests/skyeye_interpreter/skyeye_common/armstate.h" #include "skyeye_interpreter/skyeye_common/armstate.h"
#include "tests/skyeye_interpreter/skyeye_common/armsupp.h" #include "skyeye_interpreter/skyeye_common/armsupp.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfp.h" #include "skyeye_interpreter/skyeye_common/vfp/vfp.h"
enum { enum {
COND = (1 << 0), COND = (1 << 0),
@ -3184,11 +3184,11 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index)
// Floating point VFPv3 structures and instructions // Floating point VFPv3 structures and instructions
#define VFP_INTERPRETER_STRUCT #define VFP_INTERPRETER_STRUCT
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp" #include "skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp"
#undef VFP_INTERPRETER_STRUCT #undef VFP_INTERPRETER_STRUCT
#define VFP_INTERPRETER_TRANS #define VFP_INTERPRETER_TRANS
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp" #include "skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp"
#undef VFP_INTERPRETER_TRANS #undef VFP_INTERPRETER_TRANS
typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int);
@ -6859,7 +6859,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
} }
#define VFP_INTERPRETER_IMPL #define VFP_INTERPRETER_IMPL
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp" #include "skyeye_interpreter/skyeye_common/vfp/vfpinstr.cpp"
#undef VFP_INTERPRETER_IMPL #undef VFP_INTERPRETER_IMPL
END: END:

View file

@ -18,7 +18,7 @@
#pragma once #pragma once
#include "tests/skyeye_interpreter/skyeye_common/armstate.h" #include "skyeye_interpreter/skyeye_common/armstate.h"
/** /**
* Checks if the PC is being read, and if so, word-aligns it. * Checks if the PC is being read, and if so, word-aligns it.

View file

@ -5,8 +5,8 @@
// We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding // We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding
// ARM instruction, and using the existing ARM simulator. // ARM instruction, and using the existing ARM simulator.
#include "tests/skyeye_interpreter/dyncom/arm_dyncom_thumb.h" #include "skyeye_interpreter/dyncom/arm_dyncom_thumb.h"
#include "tests/skyeye_interpreter/skyeye_common/armsupp.h" #include "skyeye_interpreter/skyeye_common/armsupp.h"
// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field, // Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field,
// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions // with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions

View file

@ -4,8 +4,8 @@
#include <algorithm> #include <algorithm>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "tests/skyeye_interpreter/skyeye_common/armstate.h" #include "skyeye_interpreter/skyeye_common/armstate.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfp.h" #include "skyeye_interpreter/skyeye_common/vfp/vfp.h"
namespace Common { namespace Common {
inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);} inline u16 swap16(u16 data) {return (data >> 8) | (data << 8);}

View file

@ -22,7 +22,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "interface/interface.h" #include "interface/interface.h"
#include "tests/skyeye_interpreter/skyeye_common/arm_regformat.h" #include "skyeye_interpreter/skyeye_common/arm_regformat.h"
// Signal levels // Signal levels
enum { enum {

View file

@ -17,9 +17,9 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "tests/skyeye_interpreter/skyeye_common/arm_regformat.h" #include "skyeye_interpreter/skyeye_common/arm_regformat.h"
#include "tests/skyeye_interpreter/skyeye_common/armstate.h" #include "skyeye_interpreter/skyeye_common/armstate.h"
#include "tests/skyeye_interpreter/skyeye_common/armsupp.h" #include "skyeye_interpreter/skyeye_common/armsupp.h"
// Unsigned sum of absolute difference // Unsigned sum of absolute difference
u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right) u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)

View file

@ -23,9 +23,9 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "tests/skyeye_interpreter/skyeye_common/armstate.h" #include "skyeye_interpreter/skyeye_common/armstate.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/asm_vfp.h" #include "skyeye_interpreter/skyeye_common/vfp/asm_vfp.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfp.h" #include "skyeye_interpreter/skyeye_common/vfp/vfp.h"
void VFPInit(ARMul_State* state) void VFPInit(ARMul_State* state)
{ {

View file

@ -20,7 +20,7 @@
#pragma once #pragma once
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ #include "skyeye_interpreter/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */
#define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested", __FUNCTION__); #define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested", __FUNCTION__);
#define CHECK_VFP_ENABLED #define CHECK_VFP_ENABLED

View file

@ -34,8 +34,8 @@
#include <cstdio> #include <cstdio>
#include "common/common_types.h" #include "common/common_types.h"
#include "tests/skyeye_interpreter/skyeye_common/armstate.h" #include "skyeye_interpreter/skyeye_common/armstate.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/asm_vfp.h" #include "skyeye_interpreter/skyeye_common/vfp/asm_vfp.h"
#define do_div(n, base) {n/=base;} #define do_div(n, base) {n/=base;}

View file

@ -53,9 +53,9 @@
#include <algorithm> #include <algorithm>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfp.h" #include "skyeye_interpreter/skyeye_common/vfp/vfp.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfp_helper.h" #include "skyeye_interpreter/skyeye_common/vfp/vfp_helper.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/asm_vfp.h" #include "skyeye_interpreter/skyeye_common/vfp/asm_vfp.h"
static struct vfp_double vfp_double_default_qnan = { static struct vfp_double vfp_double_default_qnan = {
2047, 2047,

View file

@ -57,9 +57,9 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfp_helper.h" #include "skyeye_interpreter/skyeye_common/vfp/vfp_helper.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/asm_vfp.h" #include "skyeye_interpreter/skyeye_common/vfp/asm_vfp.h"
#include "tests/skyeye_interpreter/skyeye_common/vfp/vfp.h" #include "skyeye_interpreter/skyeye_common/vfp/vfp.h"
static struct vfp_single vfp_single_default_qnan = { static struct vfp_single vfp_single_default_qnan = {
255, 255,