citra/src/core/arm/decoder/decoder.h
2016-04-06 20:34:33 +01:00

323 lines
12 KiB
C++

// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <functional>
#include <memory>
#include <boost/optional.hpp>
#include "common/common_types.h"
#include "common/common_funcs.h"
namespace ArmDecoder {
// This is a generic ARMv6 decoder using double dispatch.
class Instruction;
class Visitor;
boost::optional<const Instruction&> DecodeArm(u32 instruction);
const Instruction& DecodeThumb(u16 instruction);
struct Matcher {
u32 bit_mask;
u32 expected;
FORCE_INLINE bool Match(u32 x) const {
return (x & bit_mask) == expected;
}
virtual void visit(Visitor* v, u32 inst) = 0;
};
class Instruction {
private:
const std::unique_ptr<Matcher> matcher;
public:
Instruction(const char* const name, std::unique_ptr<Matcher> matcher) : matcher(std::move(matcher)), name(name) {}
const char* const name;
FORCE_INLINE bool Match(u32 instruction) const {
return (instruction & matcher->bit_mask) == matcher->expected;
}
FORCE_INLINE void Visit(Visitor* v, u32 instruction) const {
matcher->visit(v, instruction);
}
};
using Cond = u8;
using Imm5 = u32;
using Imm8 = u32;
using Imm11 = u32;
using Imm24 = u32;
using Register = int;
using ShiftType = int;
class Visitor {
public:
virtual ~Visitor() = default;
// Branch instructions
virtual void B(Cond cond, Imm24 imm24) = 0;
virtual void BL(Cond cond, Imm24 imm24) = 0;
virtual void BLX_imm(bool H, Imm24 imm24) = 0;
virtual void BLX_reg(Cond cond, Register Rm) = 0;
virtual void BX(Cond cond, Register Rm) = 0;
virtual void BXJ(Cond cond, Register Rm) = 0;
// Coprocessor instructions
virtual void CDP() = 0;
virtual void LDC() = 0;
virtual void MCR() = 0;
virtual void MCRR() = 0;
virtual void MRC() = 0;
virtual void MRRC() = 0;
virtual void STC() = 0;
// Data processing instructions
virtual void ADC_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void ADC_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void ADC_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void ADD_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void ADD_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void ADD_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void AND_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void AND_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void AND_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void BIC_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void BIC_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void BIC_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void CMN_imm(Cond cond, Register Rn, int rotate, Imm8 imm8) = 0;
virtual void CMN_reg(Cond cond, Register Rn, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void CMN_rsr(Cond cond, Register Rn, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void CMP_imm(Cond cond, Register Rn, int rotate, Imm8 imm8) = 0;
virtual void CMP_reg(Cond cond, Register Rn, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void CMP_rsr(Cond cond, Register Rn, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void EOR_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void EOR_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void EOR_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void MOV_imm(Cond cond, bool S, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void MOV_reg(Cond cond, bool S, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void MOV_rsr(Cond cond, bool S, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void MVN_imm(Cond cond, bool S, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void MVN_reg(Cond cond, bool S, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void MVN_rsr(Cond cond, bool S, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void ORR_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void ORR_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void ORR_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void RSB_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void RSB_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void RSB_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void RSC_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void RSC_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void RSC_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void SBC_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void SBC_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void SBC_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void SUB_imm(Cond cond, bool S, Register Rn, Register Rd, int rotate, Imm8 imm8) = 0;
virtual void SUB_reg(Cond cond, bool S, Register Rn, Register Rd, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void SUB_rsr(Cond cond, bool S, Register Rn, Register Rd, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void TEQ_imm(Cond cond, Register Rn, int rotate, Imm8 imm8) = 0;
virtual void TEQ_reg(Cond cond, Register Rn, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void TEQ_rsr(Cond cond, Register Rn, Register Rs, ShiftType shift, Register Rm) = 0;
virtual void TST_imm(Cond cond, Register Rn, int rotate, Imm8 imm8) = 0;
virtual void TST_reg(Cond cond, Register Rn, Imm5 imm5, ShiftType shift, Register Rm) = 0;
virtual void TST_rsr(Cond cond, Register Rn, Register Rs, ShiftType shift, Register Rm) = 0;
// Exception generation instructions
virtual void BKPT() = 0;
virtual void SVC() = 0;
virtual void UDF() = 0;
// Extension functions
virtual void SXTAB() = 0;
virtual void SXTAB16() = 0;
virtual void SXTAH() = 0;
virtual void SXTB() = 0;
virtual void SXTB16() = 0;
virtual void SXTH() = 0;
virtual void UXTAB() = 0;
virtual void UXTAB16() = 0;
virtual void UXTAH() = 0;
virtual void UXTB() = 0;
virtual void UXTB16() = 0;
virtual void UXTH() = 0;
// Hint instructions
virtual void PLD() = 0;
virtual void SEV() = 0;
virtual void WFE() = 0;
virtual void WFI() = 0;
virtual void YIELD() = 0;
// Load/Store instructions
virtual void LDR_imm() = 0;
virtual void LDR_reg() = 0;
virtual void LDRB_imm() = 0;
virtual void LDRB_reg() = 0;
virtual void LDRBT() = 0;
virtual void LDRD_imm() = 0;
virtual void LDRD_reg() = 0;
virtual void LDRH_imm() = 0;
virtual void LDRH_reg() = 0;
virtual void LDRHT() = 0;
virtual void LDRSB_imm() = 0;
virtual void LDRSB_reg() = 0;
virtual void LDRSBT() = 0;
virtual void LDRSH_imm() = 0;
virtual void LDRSH_reg() = 0;
virtual void LDRSHT() = 0;
virtual void LDRT() = 0;
virtual void STR_imm() = 0;
virtual void STR_reg() = 0;
virtual void STRB_imm() = 0;
virtual void STRB_reg() = 0;
virtual void STRBT() = 0;
virtual void STRD_imm() = 0;
virtual void STRD_reg() = 0;
virtual void STRH_imm() = 0;
virtual void STRH_reg() = 0;
virtual void STRHT() = 0;
virtual void STRT() = 0;
// Load/Store multiple instructions
virtual void LDM() = 0;
virtual void STM() = 0;
// Miscellaneous instructions
virtual void CLZ() = 0;
virtual void NOP() = 0;
virtual void SEL() = 0;
// Unsigned sum of absolute difference functions
virtual void USAD8() = 0;
virtual void USADA8() = 0;
// Packing instructions
virtual void PKHBT(Cond cond, Register Rn, Register Rd, Imm5 imm5, Register Rm) = 0;
virtual void PKHTB(Cond cond, Register Rn, Register Rd, Imm5 imm5, Register Rm) = 0;
// Reversal instructions
virtual void REV() = 0;
virtual void REV16() = 0;
virtual void REVSH() = 0;
// Saturation instructions
virtual void SSAT() = 0;
virtual void SSAT16() = 0;
virtual void USAT() = 0;
virtual void USAT16() = 0;
// Multiply (Normal) instructions
virtual void MLA() = 0;
virtual void MUL() = 0;
// Multiply (Long) instructions
virtual void SMLAL() = 0;
virtual void SMULL() = 0;
virtual void UMAAL() = 0;
virtual void UMLAL() = 0;
virtual void UMULL() = 0;
// Multiply (Halfword) instructions
virtual void SMLALxy() = 0;
virtual void SMLAxy() = 0;
virtual void SMULxy() = 0;
// Multiply (word by halfword) instructions
virtual void SMLAWy() = 0;
virtual void SMULWy() = 0;
// Multiply (Most significant word) instructions
virtual void SMMLA() = 0;
virtual void SMMLS() = 0;
virtual void SMMUL() = 0;
// Multiply (Dual) instructions
virtual void SMLAD() = 0;
virtual void SMLALD() = 0;
virtual void SMLSD() = 0;
virtual void SMLSLD() = 0;
virtual void SMUAD() = 0;
virtual void SMUSD() = 0;
// Parallel Add/Subtract (Modulo arithmetic) instructions
virtual void SADD8() = 0;
virtual void SADD16() = 0;
virtual void SASX() = 0;
virtual void SSAX() = 0;
virtual void SSUB8() = 0;
virtual void SSUB16() = 0;
virtual void UADD8() = 0;
virtual void UADD16() = 0;
virtual void UASX() = 0;
virtual void USAX() = 0;
virtual void USUB8() = 0;
virtual void USUB16() = 0;
// Parallel Add/Subtract (Saturating) instructions
virtual void QADD8() = 0;
virtual void QADD16() = 0;
virtual void QASX() = 0;
virtual void QSAX() = 0;
virtual void QSUB8() = 0;
virtual void QSUB16() = 0;
virtual void UQADD8() = 0;
virtual void UQADD16() = 0;
virtual void UQASX() = 0;
virtual void UQSAX() = 0;
virtual void UQSUB8() = 0;
virtual void UQSUB16() = 0;
// Parallel Add/Subtract (Halving) instructions
virtual void SHADD8() = 0;
virtual void SHADD16() = 0;
virtual void SHASX() = 0;
virtual void SHSAX() = 0;
virtual void SHSUB8() = 0;
virtual void SHSUB16() = 0;
virtual void UHADD8() = 0;
virtual void UHADD16() = 0;
virtual void UHASX() = 0;
virtual void UHSAX() = 0;
virtual void UHSUB8() = 0;
virtual void UHSUB16() = 0;
// Saturated Add/Subtract instructions
virtual void QADD() = 0;
virtual void QSUB() = 0;
virtual void QDADD() = 0;
virtual void QDSUB() = 0;
// Synchronization Primitive instructions
virtual void CLREX() = 0;
virtual void LDREX() = 0;
virtual void LDREXB() = 0;
virtual void LDREXD() = 0;
virtual void LDREXH() = 0;
virtual void STREX() = 0;
virtual void STREXB() = 0;
virtual void STREXD() = 0;
virtual void STREXH() = 0;
virtual void SWP() = 0;
// Status register access instructions
virtual void CPS() = 0;
virtual void MRS() = 0;
virtual void MSR() = 0;
virtual void RFE() = 0;
virtual void SETEND(bool E) = 0;
virtual void SRS() = 0;
// Thumb specific instructions
virtual void thumb_BLX_prefix(Imm11 imm11) = 0;
virtual void thumb_BLX_suffix(bool L, Imm11 imm11) = 0;
};
};