mirror of
https://github.com/citra-emu/citra.git
synced 2024-11-24 11:51:04 +00:00
Added mov immediate
This commit is contained in:
parent
3151d6a99b
commit
0aec1529d3
@ -165,4 +165,13 @@ ARMFuncs::ResultCarry ARMFuncs::RRX_C(InstructionBlock* instruction, llvm::Value
|
|||||||
result = ir_builder->CreateOr(result, ir_builder->CreateShl(ir_builder->CreateZExt(carry_in, ir_builder->getInt32Ty()), 31));
|
result = ir_builder->CreateOr(result, ir_builder->CreateShl(ir_builder->CreateZExt(carry_in, ir_builder->getInt32Ty()), 31));
|
||||||
auto carry = ir_builder->CreateTrunc(x, ir_builder->getInt1Ty());
|
auto carry = ir_builder->CreateTrunc(x, ir_builder->getInt1Ty());
|
||||||
return{ result, carry };
|
return{ result, carry };
|
||||||
|
}
|
||||||
|
|
||||||
|
ARMFuncs::ResultCarry ARMFuncs::ARMExpandImm_C(InstructionBlock *instruction, u32 imm12, llvm::Value* carry)
|
||||||
|
{
|
||||||
|
auto ir_builder = instruction->IrBuilder();
|
||||||
|
|
||||||
|
auto value = ir_builder->getInt32(imm12 & 0xFF);
|
||||||
|
auto shift = ir_builder->getInt32(2 * (imm12 >> 8));
|
||||||
|
return Shift_C(instruction, value, SRType::ROR, shift, carry);
|
||||||
}
|
}
|
@ -3,7 +3,8 @@
|
|||||||
/*
|
/*
|
||||||
* Functions from the manual,
|
* Functions from the manual,
|
||||||
* A8.4.3 Pseudocode details of instruction-specified shifts and rotates
|
* A8.4.3 Pseudocode details of instruction-specified shifts and rotates
|
||||||
* A2.2.1 Integer arithmetic
|
* A2.2.1 Integer arithmetic
|
||||||
|
* A5.2.4 Modified immediate constants in ARM instructions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class InstructionBlock;
|
class InstructionBlock;
|
||||||
@ -39,4 +40,6 @@ public:
|
|||||||
static ResultCarry ASR_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift);
|
static ResultCarry ASR_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift);
|
||||||
static ResultCarry ROR_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift);
|
static ResultCarry ROR_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift);
|
||||||
static ResultCarry RRX_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *carry_in);
|
static ResultCarry RRX_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *carry_in);
|
||||||
|
|
||||||
|
static ResultCarry ARMExpandImm_C(InstructionBlock *instruction, u32 imm12, llvm::Value *carry);
|
||||||
};
|
};
|
@ -3,12 +3,12 @@
|
|||||||
#include "InstructionBlock.h"
|
#include "InstructionBlock.h"
|
||||||
#include "ModuleGen.h"
|
#include "ModuleGen.h"
|
||||||
#include "ARMFuncs.h"
|
#include "ARMFuncs.h"
|
||||||
|
#include <binary_translation/BinarySearch.h>
|
||||||
|
|
||||||
static RegisterInstruction<MovShift> register_instruction;
|
static RegisterInstruction<MovShift> register_instruction;
|
||||||
|
|
||||||
bool MovShift::Decode()
|
bool MovShift::Decode()
|
||||||
{
|
{
|
||||||
// Mov and shifts must have zeroes at some operands of different data processing instructions
|
|
||||||
if (ReadFields({ CondDef(), FieldDef<3>(0), FieldDef<4>(13), FieldDef<1>(&s), FieldDef<4>(0),
|
if (ReadFields({ CondDef(), FieldDef<3>(0), FieldDef<4>(13), FieldDef<1>(&s), FieldDef<4>(0),
|
||||||
FieldDef<4>(&rd), FieldDef<5>(&imm5), FieldDef<2>(&op2), FieldDef<1>(0), FieldDef<4>(&rm) }))
|
FieldDef<4>(&rd), FieldDef<5>(&imm5), FieldDef<2>(&op2), FieldDef<1>(0), FieldDef<4>(&rm) }))
|
||||||
{
|
{
|
||||||
@ -17,6 +17,20 @@ bool MovShift::Decode()
|
|||||||
if (rd == Register::PC && s) return false; // SEE SUBS PC, LR and related instructions;
|
if (rd == Register::PC && s) return false; // SEE SUBS PC, LR and related instructions;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (ReadFields({ CondDef(), FieldDef<7>(0x1d), FieldDef<1>(&s), FieldDef<4>(0),
|
||||||
|
FieldDef<4>(&rd), FieldDef<12>(&imm12) }))
|
||||||
|
{
|
||||||
|
form = Form::ImmediateA1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (ReadFields({ CondDef(), FieldDef<8>(0x30), FieldDef<4>(&imm4),
|
||||||
|
FieldDef<4>(&rd), FieldDef<12>(&imm12) }))
|
||||||
|
{
|
||||||
|
s = false;
|
||||||
|
form = Form::ImmediateA2;
|
||||||
|
if (rd == Register::PC) return false; // UNPREDICTIBLE
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,39 +38,51 @@ void MovShift::GenerateInstructionCode(InstructionBlock* instruction_block)
|
|||||||
{
|
{
|
||||||
auto ir_builder = instruction_block->IrBuilder();
|
auto ir_builder = instruction_block->IrBuilder();
|
||||||
|
|
||||||
auto original_carry = instruction_block->Read(Register::C);
|
auto carry_in = instruction_block->Read(Register::C);
|
||||||
ARMFuncs::ResultCarry result = { instruction_block->Read(rm), original_carry };
|
ARMFuncs::ResultCarry result = {};
|
||||||
|
|
||||||
switch (op2)
|
switch (form)
|
||||||
{
|
{
|
||||||
case Op2Type::MoveAndLSL:
|
case Form::Register:
|
||||||
if (imm5 != 0)
|
result = { instruction_block->Read(rm), carry_in };
|
||||||
{
|
switch (op2)
|
||||||
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSL,
|
{
|
||||||
ARMFuncs::DecodeImmShift(instruction_block, 0, imm5).amount, result.carry);
|
case Op2Type::MoveAndLSL:
|
||||||
}
|
if (imm5 != 0)
|
||||||
break;
|
{
|
||||||
case Op2Type::LSR:
|
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSL,
|
||||||
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSR,
|
ARMFuncs::DecodeImmShift(instruction_block, 0, imm5).amount, result.carry);
|
||||||
ARMFuncs::DecodeImmShift(instruction_block, 1, imm5).amount, result.carry);
|
}
|
||||||
break;
|
break;
|
||||||
case Op2Type::ASR:
|
case Op2Type::LSR:
|
||||||
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ASR,
|
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSR,
|
||||||
ARMFuncs::DecodeImmShift(instruction_block, 2, imm5).amount, result.carry);
|
ARMFuncs::DecodeImmShift(instruction_block, 1, imm5).amount, result.carry);
|
||||||
break;
|
break;
|
||||||
case Op2Type::RRXAndROR:
|
case Op2Type::ASR:
|
||||||
if (imm5 == 0)
|
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ASR,
|
||||||
{
|
ARMFuncs::DecodeImmShift(instruction_block, 2, imm5).amount, result.carry);
|
||||||
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::RRX,
|
break;
|
||||||
ir_builder->getInt32(1), result.carry);
|
case Op2Type::RRXAndROR:
|
||||||
}
|
if (imm5 == 0)
|
||||||
else
|
{
|
||||||
{
|
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::RRX,
|
||||||
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ROR,
|
ir_builder->getInt32(1), result.carry);
|
||||||
ARMFuncs::DecodeImmShift(instruction_block, 3, imm5).amount, result.carry);
|
}
|
||||||
}
|
else
|
||||||
break;
|
{
|
||||||
}
|
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ROR,
|
||||||
|
ARMFuncs::DecodeImmShift(instruction_block, 3, imm5).amount, result.carry);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Form::ImmediateA1:
|
||||||
|
result = ARMFuncs::ARMExpandImm_C(instruction_block, imm12, carry_in);
|
||||||
|
break;
|
||||||
|
case Form::ImmediateA2:
|
||||||
|
result.result = ir_builder->getInt32((imm4 << 12) | imm12);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
instruction_block->Write(rd, result.result);
|
instruction_block->Write(rd, result.result);
|
||||||
|
|
||||||
@ -64,7 +90,7 @@ void MovShift::GenerateInstructionCode(InstructionBlock* instruction_block)
|
|||||||
{
|
{
|
||||||
instruction_block->Write(Register::N, ir_builder->CreateTrunc(ir_builder->CreateLShr(result.result, 31), ir_builder->getInt1Ty()));
|
instruction_block->Write(Register::N, ir_builder->CreateTrunc(ir_builder->CreateLShr(result.result, 31), ir_builder->getInt1Ty()));
|
||||||
instruction_block->Write(Register::Z, ir_builder->CreateICmpEQ(result.result, ir_builder->getInt32(0)));
|
instruction_block->Write(Register::Z, ir_builder->CreateICmpEQ(result.result, ir_builder->getInt32(0)));
|
||||||
if (result.carry != original_carry)
|
if (result.carry != carry_in)
|
||||||
instruction_block->Write(Register::C, result.carry);
|
instruction_block->Write(Register::C, result.carry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ public:
|
|||||||
};
|
};
|
||||||
enum class Form
|
enum class Form
|
||||||
{
|
{
|
||||||
Register, RegisterShiftedRegister, Immediate
|
Register, ImmediateA1, ImmediateA2
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -29,5 +29,6 @@ private:
|
|||||||
Register rm;
|
Register rm;
|
||||||
u32 imm12;
|
u32 imm12;
|
||||||
u32 imm5;
|
u32 imm5;
|
||||||
|
u32 imm4;
|
||||||
Op2Type op2;
|
Op2Type op2;
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user