Reorganisation, Import Skyeye, This is a mess

This commit is contained in:
MerryMage
2016-07-04 17:22:11 +08:00
parent be1c1de552
commit d743adf518
55 changed files with 14939 additions and 591 deletions

351
src/frontend/decoder/arm.h Normal file
View File

@@ -0,0 +1,351 @@
/* 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.
*
* Original version of table by Lioncash.
*/
#pragma once
#include <algorithm>
#include <array>
#include <functional>
#include <tuple>
#include <boost/optional.hpp>
#include "common/common_types.h"
#include "frontend/decoder/decoder_detail.h"
namespace Dynarmic {
namespace Arm {
template <typename Visitor>
struct ArmMatcher {
using CallRetT = typename mp::MemFnInfo<decltype(&Visitor::arm_UDF), &Visitor::arm_UDF>::return_type;
ArmMatcher(const char* const name, u32 mask, u32 expect, std::function<CallRetT(Visitor&, u32)> fn)
: name(name), mask(mask), expect(expect), fn(fn) {}
/// Gets the name of this type of instruction.
const char* GetName() const {
return name;
}
/**
* Tests to see if the instruction is this type of instruction.
* @param instruction The instruction to test
* @returns true if the instruction is
*/
bool Matches(u32 instruction) const {
return (instruction & mask) == expect;
}
/**
* Calls the corresponding instruction handler on visitor for this type of instruction.
* @param v The visitor to use
* @param instruction The instruction to decode.
*/
CallRetT call(Visitor& v, u32 instruction) const {
assert(Matches(instruction));
return fn(v, instruction);
}
private:
const char* name;
u32 mask, expect;
std::function<CallRetT(Visitor&, u32)> fn;
};
template <typename V>
static const std::array<ArmMatcher<V>, 221> g_arm_instruction_table = {{
#define INST(fn, name, bitstring) detail::detail<ArmMatcher, u32, 32>::GetMatcher<decltype(fn), fn>(name, bitstring)
// Branch instructions
{ INST(&V::arm_BLX_imm, "BLX (imm)", "1111101hvvvvvvvvvvvvvvvvvvvvvvvv") }, // v5
{ INST(&V::arm_BLX_reg, "BLX (reg)", "cccc000100101111111111110011mmmm") }, // v5
{ INST(&V::arm_B, "B", "cccc1010vvvvvvvvvvvvvvvvvvvvvvvv") }, // all
{ INST(&V::arm_BL, "BL", "cccc1011vvvvvvvvvvvvvvvvvvvvvvvv") }, // all
{ INST(&V::arm_BX, "BX", "cccc000100101111111111110001mmmm") }, // v4T
{ INST(&V::arm_BXJ, "BXJ", "cccc000100101111111111110010mmmm") }, // v5J
// Coprocessor instructions
{ INST(&V::arm_CDP, "CDP2", "11111110-------------------1----") }, // v5
{ INST(&V::arm_CDP, "CDP", "----1110-------------------0----") }, // v2
{ INST(&V::arm_LDC, "LDC2", "1111110----1--------------------") }, // v5
{ INST(&V::arm_LDC, "LDC", "----110----1--------------------") }, // v2
{ INST(&V::arm_MCR, "MCR2", "----1110---0---------------1----") }, // v5
{ INST(&V::arm_MCR, "MCR", "----1110---0---------------1----") }, // v2
{ INST(&V::arm_MCRR, "MCRR2", "111111000100--------------------") }, // v6
{ INST(&V::arm_MCRR, "MCRR", "----11000100--------------------") }, // v5E
{ INST(&V::arm_MRC, "MRC2", "11111110---1---------------1----") }, // v5
{ INST(&V::arm_MRC, "MRC", "----1110---1---------------1----") }, // v2
{ INST(&V::arm_MRRC, "MRRC2", "111111000101--------------------") }, // v6
{ INST(&V::arm_MRRC, "MRRC", "----11000101--------------------") }, // v5E
{ INST(&V::arm_STC, "STC2", "1111110----0--------------------") }, // v5
{ INST(&V::arm_STC, "STC", "----110----0--------------------") }, // v2
// Data Processing instructions
{ INST(&V::arm_ADC_imm, "ADC (imm)", "cccc0010101Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_ADC_reg, "ADC (reg)", "cccc0000101Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_ADC_rsr, "ADC (rsr)", "cccc0000101Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_ADD_imm, "ADD (imm)", "cccc0010100Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_ADD_reg, "ADD (reg)", "cccc0000100Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_ADD_rsr, "ADD (rsr)", "cccc0000100Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_AND_imm, "AND (imm)", "cccc0010000Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_AND_reg, "AND (reg)", "cccc0000000Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_AND_rsr, "AND (rsr)", "cccc0000000Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_BIC_imm, "BIC (imm)", "cccc0011110Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_BIC_reg, "BIC (reg)", "cccc0001110Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_BIC_rsr, "BIC (rsr)", "cccc0001110Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_CMN_imm, "CMN (imm)", "cccc00110111nnnn0000rrrrvvvvvvvv") }, // all
{ INST(&V::arm_CMN_reg, "CMN (reg)", "cccc00010111nnnn0000vvvvvrr0mmmm") }, // all
{ INST(&V::arm_CMN_rsr, "CMN (rsr)", "cccc00010111nnnn0000ssss0rr1mmmm") }, // all
{ INST(&V::arm_CMP_imm, "CMP (imm)", "cccc00110101nnnn0000rrrrvvvvvvvv") }, // all
{ INST(&V::arm_CMP_reg, "CMP (reg)", "cccc00010101nnnn0000vvvvvrr0mmmm") }, // all
{ INST(&V::arm_CMP_rsr, "CMP (rsr)", "cccc00010101nnnn0000ssss0rr1mmmm") }, // all
{ INST(&V::arm_EOR_imm, "EOR (imm)", "cccc0010001Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_EOR_reg, "EOR (reg)", "cccc0000001Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_EOR_rsr, "EOR (rsr)", "cccc0000001Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_MOV_imm, "MOV (imm)", "cccc0011101S0000ddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_MOV_reg, "MOV (reg)", "cccc0001101S0000ddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_MOV_rsr, "MOV (rsr)", "cccc0001101S0000ddddssss0rr1mmmm") }, // all
{ INST(&V::arm_MVN_imm, "MVN (imm)", "cccc0011111S0000ddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_MVN_reg, "MVN (reg)", "cccc0001111S0000ddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_MVN_rsr, "MVN (rsr)", "cccc0001111S0000ddddssss0rr1mmmm") }, // all
{ INST(&V::arm_ORR_imm, "ORR (imm)", "cccc0011100Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_ORR_reg, "ORR (reg)", "cccc0001100Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_ORR_rsr, "ORR (rsr)", "cccc0001100Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_RSB_imm, "RSB (imm)", "cccc0010011Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_RSB_reg, "RSB (reg)", "cccc0000011Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_RSB_rsr, "RSB (rsr)", "cccc0000011Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_RSC_imm, "RSC (imm)", "cccc0010111Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_RSC_reg, "RSC (reg)", "cccc0000111Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_RSC_rsr, "RSC (rsr)", "cccc0000111Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_SBC_imm, "SBC (imm)", "cccc0010110Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_SBC_reg, "SBC (reg)", "cccc0000110Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_SBC_rsr, "SBC (rsr)", "cccc0000110Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_SUB_imm, "SUB (imm)", "cccc0010010Snnnnddddrrrrvvvvvvvv") }, // all
{ INST(&V::arm_SUB_reg, "SUB (reg)", "cccc0000010Snnnnddddvvvvvrr0mmmm") }, // all
{ INST(&V::arm_SUB_rsr, "SUB (rsr)", "cccc0000010Snnnnddddssss0rr1mmmm") }, // all
{ INST(&V::arm_TEQ_imm, "TEQ (imm)", "cccc00110011nnnn0000rrrrvvvvvvvv") }, // all
{ INST(&V::arm_TEQ_reg, "TEQ (reg)", "cccc00010011nnnn0000vvvvvrr0mmmm") }, // all
{ INST(&V::arm_TEQ_rsr, "TEQ (rsr)", "cccc00010011nnnn0000ssss0rr1mmmm") }, // all
{ INST(&V::arm_TST_imm, "TST (imm)", "cccc00110001nnnn0000rrrrvvvvvvvv") }, // all
{ INST(&V::arm_TST_reg, "TST (reg)", "cccc00010001nnnn0000vvvvvrr0mmmm") }, // all
{ INST(&V::arm_TST_rsr, "TST (rsr)", "cccc00010001nnnn0000ssss0rr1mmmm") }, // all
// Exception Generating instructions
{ INST(&V::arm_BKPT, "BKPT", "cccc00010010vvvvvvvvvvvv0111vvvv") }, // v5
{ INST(&V::arm_SVC, "SVC", "cccc1111vvvvvvvvvvvvvvvvvvvvvvvv") }, // all
{ INST(&V::arm_UDF, "UDF", "111001111111------------1111----") }, // all
// Extension instructions
{ INST(&V::arm_SXTB, "SXTB", "cccc011010101111ddddrr000111mmmm") }, // v6
{ INST(&V::arm_SXTB16, "SXTB16", "cccc011010001111ddddrr000111mmmm") }, // v6
{ INST(&V::arm_SXTH, "SXTH", "cccc011010111111ddddrr000111mmmm") }, // v6
{ INST(&V::arm_SXTAB, "SXTAB", "cccc01101010nnnnddddrr000111mmmm") }, // v6
{ INST(&V::arm_SXTAB16, "SXTAB16", "cccc01101000nnnnddddrr000111mmmm") }, // v6
{ INST(&V::arm_SXTAH, "SXTAH", "cccc01101011nnnnddddrr000111mmmm") }, // v6
{ INST(&V::arm_UXTB, "UXTB", "cccc011011101111ddddrr000111mmmm") }, // v6
{ INST(&V::arm_UXTB16, "UXTB16", "cccc011011001111ddddrr000111mmmm") }, // v6
{ INST(&V::arm_UXTH, "UXTH", "cccc011011111111ddddrr000111mmmm") }, // v6
{ INST(&V::arm_UXTAB, "UXTAB", "cccc01101110nnnnddddrr000111mmmm") }, // v6
{ INST(&V::arm_UXTAB16, "UXTAB16", "cccc01101100nnnnddddrr000111mmmm") }, // v6
{ INST(&V::arm_UXTAH, "UXTAH", "cccc01101111nnnnddddrr000111mmmm") }, // v6
// Hint instructions
{ INST(&V::arm_PLD, "PLD", "111101---101----1111------------") }, // v5E
{ INST(&V::arm_SEV, "SEV", "----0011001000001111000000000100") }, // v6K
{ INST(&V::arm_WFE, "WFE", "----0011001000001111000000000010") }, // v6K
{ INST(&V::arm_WFI, "WFI", "----0011001000001111000000000011") }, // v6K
{ INST(&V::arm_YIELD, "YIELD", "----0011001000001111000000000001") }, // v6K
// Synchronization Primitive instructions
{ INST(&V::arm_CLREX, "CLREX", "11110101011111111111000000011111") }, // v6K
{ INST(&V::arm_LDREX, "LDREX", "cccc00011001nnnndddd111110011111") }, // v6
{ INST(&V::arm_LDREXB, "LDREXB", "cccc00011101nnnndddd111110011111") }, // v6K
{ INST(&V::arm_LDREXD, "LDREXD", "cccc00011011nnnndddd111110011111") }, // v6K
{ INST(&V::arm_LDREXH, "LDREXH", "cccc00011111nnnndddd111110011111") }, // v6K
{ INST(&V::arm_STREX, "STREX", "cccc00011000nnnndddd11111001mmmm") }, // v6
{ INST(&V::arm_STREXB, "STREXB", "cccc00011100nnnndddd11111001mmmm") }, // v6K
{ INST(&V::arm_STREXD, "STREXD", "cccc00011010nnnndddd11111001mmmm") }, // v6K
{ INST(&V::arm_STREXH, "STREXH", "cccc00011110nnnndddd11111001mmmm") }, // v6K
{ INST(&V::arm_SWP, "SWP", "cccc00010000nnnndddd00001001mmmm") }, // v2S (v6: Deprecated)
{ INST(&V::arm_SWPB, "SWPB", "cccc00010100nnnndddd00001001mmmm") }, // v2S (v6: Deprecated)
// Load/Store instructions
{ INST(&V::arm_LDR_imm, "LDR (imm)", "cccc010pu0w1nnnnddddvvvvvvvvvvvv") },
{ INST(&V::arm_LDR_reg, "LDR (reg)", "cccc011pu0w1nnnnddddvvvvvrr0mmmm") },
{ INST(&V::arm_LDRB_imm, "LDRB (imm)", "cccc010pu1w1nnnnddddvvvvvvvvvvvv") },
{ INST(&V::arm_LDRB_reg, "LDRB (reg)", "cccc011pu1w1nnnnddddvvvvvrr0mmmm") },
{ INST(&V::arm_LDRBT, "LDRBT (A1)", "----0100-111--------------------") },
{ INST(&V::arm_LDRBT, "LDRBT (A2)", "----0110-111---------------0----") },
{ INST(&V::arm_LDRD_imm, "LDRD (imm)", "cccc000pu1w0nnnnddddvvvv1101vvvv") }, // v5E
{ INST(&V::arm_LDRD_reg, "LDRD (reg)", "cccc000pu0w0nnnndddd00001101mmmm") }, // v5E
{ INST(&V::arm_LDRH_imm, "LDRH (imm)", "cccc000pu1w1nnnnddddvvvv1011vvvv") },
{ INST(&V::arm_LDRH_reg, "LDRH (reg)", "cccc000pu0w1nnnndddd00001011mmmm") },
{ INST(&V::arm_LDRHT, "LDRHT (A1)", "----0000-111------------1011----") },
{ INST(&V::arm_LDRHT, "LDRHT (A2)", "----0000-011--------00001011----") },
{ INST(&V::arm_LDRSB_imm, "LDRSB (imm)", "cccc000pu1w1nnnnddddvvvv1101vvvv") },
{ INST(&V::arm_LDRSB_reg, "LDRSB (reg)", "cccc000pu0w1nnnndddd00001101mmmm") },
{ INST(&V::arm_LDRSBT, "LDRSBT (A1)", "----0000-111------------1101----") },
{ INST(&V::arm_LDRSBT, "LDRSBT (A2)", "----0000-011--------00001101----") },
{ INST(&V::arm_LDRSH_imm, "LDRSH (imm)", "cccc000pu1w1nnnnddddvvvv1111vvvv") },
{ INST(&V::arm_LDRSH_reg, "LDRSH (reg)", "cccc000pu0w1nnnndddd00001111mmmm") },
{ INST(&V::arm_LDRSHT, "LDRSHT (A1)", "----0000-111------------1111----") },
{ INST(&V::arm_LDRSHT, "LDRSHT (A2)", "----0000-011--------00001111----") },
{ INST(&V::arm_LDRT, "LDRT (A1)", "----0100-011--------------------") },
{ INST(&V::arm_LDRT, "LDRT (A2)", "----0110-011---------------0----") },
{ INST(&V::arm_STR_imm, "STR (imm)", "cccc010pu0w0nnnnddddvvvvvvvvvvvv") },
{ INST(&V::arm_STR_reg, "STR (reg)", "cccc011pu0w0nnnnddddvvvvvrr0mmmm") },
{ INST(&V::arm_STRB_imm, "STRB (imm)", "cccc010pu1w0nnnnddddvvvvvvvvvvvv") },
{ INST(&V::arm_STRB_reg, "STRB (reg)", "cccc011pu1w0nnnnddddvvvvvrr0mmmm") },
{ INST(&V::arm_STRBT, "STRBT (A1)", "----0100-110--------------------") },
{ INST(&V::arm_STRBT, "STRBT (A2)", "----0110-110---------------0----") },
{ INST(&V::arm_STRD_imm, "STRD (imm)", "cccc000pu1w0nnnnddddvvvv1111vvvv") }, // v5E
{ INST(&V::arm_STRD_reg, "STRD (reg)", "cccc000pu0w0nnnndddd00001111mmmm") }, // v5E
{ INST(&V::arm_STRH_imm, "STRH (imm)", "cccc000pu1w0nnnnddddvvvv1011vvvv") },
{ INST(&V::arm_STRH_reg, "STRH (reg)", "cccc000pu0w0nnnndddd00001011mmmm") },
{ INST(&V::arm_STRHT, "STRHT (A1)", "----0000-110------------1011----") },
{ INST(&V::arm_STRHT, "STRHT (A2)", "----0000-010--------00001011----") },
{ INST(&V::arm_STRT, "STRT (A1)", "----0100-010--------------------") },
{ INST(&V::arm_STRT, "STRT (A2)", "----0110-010---------------0----") },
// Load/Store Multiple instructions
{ INST(&V::arm_LDM, "LDM", "cccc100pu0w1nnnnxxxxxxxxxxxxxxxx") }, // all
{ INST(&V::arm_LDM_usr, "LDM (usr reg)", "----100--101--------------------") }, // all
{ INST(&V::arm_LDM_eret, "LDM (exce ret)", "----100--1-1----1---------------") }, // all
{ INST(&V::arm_STM, "STM", "cccc100pu0w0nnnnxxxxxxxxxxxxxxxx") }, // all
{ INST(&V::arm_STM_usr, "STM (usr reg)", "----100--100--------------------") }, // all
// Miscellaneous instructions
{ INST(&V::arm_CLZ, "CLZ", "cccc000101101111dddd11110001mmmm") }, // v5
{ INST(&V::arm_NOP, "NOP", "----001100100000111100000000----") }, // v6K
{ INST(&V::arm_SEL, "SEL", "cccc01101000nnnndddd11111011mmmm") }, // v6
// Unsigned Sum of Absolute Differences instructions
{ INST(&V::arm_USAD8, "USAD8", "cccc01111000dddd1111mmmm0001nnnn") }, // v6
{ INST(&V::arm_USADA8, "USADA8", "cccc01111000ddddaaaammmm0001nnnn") }, // v6
// Packing instructions
{ INST(&V::arm_PKHBT, "PKHBT", "cccc01101000nnnnddddvvvvv001mmmm") }, // v6K
{ INST(&V::arm_PKHTB, "PKHTB", "cccc01101000nnnnddddvvvvv101mmmm") }, // v6K
// Reversal instructions
{ INST(&V::arm_REV, "REV", "cccc011010111111dddd11110011mmmm") }, // v6
{ INST(&V::arm_REV16, "REV16", "cccc011010111111dddd11111011mmmm") }, // v6
{ INST(&V::arm_REVSH, "REVSH", "cccc011011111111dddd11111011mmmm") }, // v6
// Saturation instructions
{ INST(&V::arm_SSAT, "SSAT", "cccc0110101vvvvvddddvvvvvr01nnnn") }, // v6
{ INST(&V::arm_SSAT16, "SSAT16", "cccc01101010vvvvdddd11110011nnnn") }, // v6
{ INST(&V::arm_USAT, "USAT", "cccc0110111vvvvvddddvvvvvr01nnnn") }, // v6
{ INST(&V::arm_USAT16, "USAT16", "cccc01101110vvvvdddd11110011nnnn") }, // v6
// Multiply (Normal) instructions
{ INST(&V::arm_MLA, "MLA", "cccc0000001Sddddaaaammmm1001nnnn") }, // v2
{ INST(&V::arm_MUL, "MUL", "cccc0000000Sdddd0000mmmm1001nnnn") }, // v2
// Multiply (Long) instructions
{ INST(&V::arm_SMLAL, "SMLAL", "cccc0000111Sddddaaaammmm1001nnnn") }, // v3M
{ INST(&V::arm_SMULL, "SMULL", "cccc0000110Sddddaaaammmm1001nnnn") }, // v3M
{ INST(&V::arm_UMAAL, "UMAAL", "cccc00000100ddddaaaammmm1001nnnn") }, // v6
{ INST(&V::arm_UMLAL, "UMLAL", "cccc0000101Sddddaaaammmm1001nnnn") }, // v3M
{ INST(&V::arm_UMULL, "UMULL", "cccc0000100Sddddaaaammmm1001nnnn") }, // v3M
// Multiply (Halfword) instructions
{ INST(&V::arm_SMLALxy, "SMLALXY", "cccc00010100ddddaaaammmm1xy0nnnn") }, // v5xP
{ INST(&V::arm_SMLAxy, "SMLAXY", "cccc00010000ddddaaaammmm1xy0nnnn") }, // v5xP
{ INST(&V::arm_SMULxy, "SMULXY", "cccc00010110dddd0000mmmm1xy0nnnn") }, // v5xP
// Multiply (Word by Halfword) instructions
{ INST(&V::arm_SMLAWy, "SMLAWY", "cccc00010010ddddaaaammmm1y00nnnn") }, // v5xP
{ INST(&V::arm_SMULWy, "SMULWY", "cccc00010010dddd0000mmmm1y10nnnn") }, // v5xP
// Multiply (Most Significant Word) instructions
{ INST(&V::arm_SMMUL, "SMMUL", "cccc01110101dddd1111mmmm00R1nnnn") }, // v6
{ INST(&V::arm_SMMLA, "SMMLA", "cccc01110101ddddaaaammmm00R1nnnn") }, // v6
{ INST(&V::arm_SMMLS, "SMMLS", "cccc01110101ddddaaaammmm11R1nnnn") }, // v6
// Multiply (Dual) instructions
{ INST(&V::arm_SMLAD, "SMLAD", "cccc01110000ddddaaaammmm00M1nnnn") }, // v6
{ INST(&V::arm_SMLALD, "SMLALD", "cccc01110100ddddaaaammmm00M1nnnn") }, // v6
{ INST(&V::arm_SMLSD, "SMLSD", "cccc01110000ddddaaaammmm01M1nnnn") }, // v6
{ INST(&V::arm_SMLSLD, "SMLSLD", "cccc01110100ddddaaaammmm01M1nnnn") }, // v6
{ INST(&V::arm_SMUAD, "SMUAD", "cccc01110000dddd1111mmmm00M1nnnn") }, // v6
{ INST(&V::arm_SMUSD, "SMUSD", "cccc01110000dddd1111mmmm01M1nnnn") }, // v6
// Parallel Add/Subtract (Modulo) instructions
{ INST(&V::arm_SADD8, "SADD8", "cccc01100001nnnndddd11111001mmmm") }, // v6
{ INST(&V::arm_SADD16, "SADD16", "cccc01100001nnnndddd11110001mmmm") }, // v6
{ INST(&V::arm_SASX, "SASX", "cccc01100001nnnndddd11110011mmmm") }, // v6
{ INST(&V::arm_SSAX, "SSAX", "cccc01100001nnnndddd11110101mmmm") }, // v6
{ INST(&V::arm_SSUB8, "SSUB8", "cccc01100001nnnndddd11111111mmmm") }, // v6
{ INST(&V::arm_SSUB16, "SSUB16", "cccc01100001nnnndddd11110111mmmm") }, // v6
{ INST(&V::arm_UADD8, "UADD8", "cccc01100101nnnndddd11111001mmmm") }, // v6
{ INST(&V::arm_UADD16, "UADD16", "cccc01100101nnnndddd11110001mmmm") }, // v6
{ INST(&V::arm_UASX, "UASX", "cccc01100101nnnndddd11110011mmmm") }, // v6
{ INST(&V::arm_USAX, "USAX", "cccc01100101nnnndddd11110101mmmm") }, // v6
{ INST(&V::arm_USUB8, "USUB8", "cccc01100101nnnndddd11111111mmmm") }, // v6
{ INST(&V::arm_USUB16, "USUB16", "cccc01100101nnnndddd11110111mmmm") }, // v6
// Parallel Add/Subtract (Saturating) instructions
{ INST(&V::arm_QADD8, "QADD8", "cccc01100010nnnndddd11111001mmmm") }, // v6
{ INST(&V::arm_QADD16, "QADD16", "cccc01100010nnnndddd11110001mmmm") }, // v6
{ INST(&V::arm_QASX, "QASX", "cccc01100010nnnndddd11110011mmmm") }, // v6
{ INST(&V::arm_QSAX, "QSAX", "cccc01100010nnnndddd11110101mmmm") }, // v6
{ INST(&V::arm_QSUB8, "QSUB8", "cccc01100010nnnndddd11111111mmmm") }, // v6
{ INST(&V::arm_QSUB16, "QSUB16", "cccc01100010nnnndddd11110111mmmm") }, // v6
{ INST(&V::arm_UQADD8, "UQADD8", "cccc01100110nnnndddd11111001mmmm") }, // v6
{ INST(&V::arm_UQADD16, "UQADD16", "cccc01100110nnnndddd11110001mmmm") }, // v6
{ INST(&V::arm_UQASX, "UQASX", "cccc01100110nnnndddd11110011mmmm") }, // v6
{ INST(&V::arm_UQSAX, "UQSAX", "cccc01100110nnnndddd11110101mmmm") }, // v6
{ INST(&V::arm_UQSUB8, "UQSUB8", "cccc01100110nnnndddd11111111mmmm") }, // v6
{ INST(&V::arm_UQSUB16, "UQSUB16", "cccc01100110nnnndddd11110111mmmm") }, // v6
// Parallel Add/Subtract (Halving) instructions
{ INST(&V::arm_SHADD8, "SHADD8", "cccc01100011nnnndddd11111001mmmm") }, // v6
{ INST(&V::arm_SHADD16, "SHADD16", "cccc01100011nnnndddd11110001mmmm") }, // v6
{ INST(&V::arm_SHASX, "SHASX", "cccc01100011nnnndddd11110011mmmm") }, // v6
{ INST(&V::arm_SHSAX, "SHSAX", "cccc01100011nnnndddd11110101mmmm") }, // v6
{ INST(&V::arm_SHSUB8, "SHSUB8", "cccc01100011nnnndddd11111111mmmm") }, // v6
{ INST(&V::arm_SHSUB16, "SHSUB16", "cccc01100011nnnndddd11110111mmmm") }, // v6
{ INST(&V::arm_UHADD8, "UHADD8", "cccc01100111nnnndddd11111001mmmm") }, // v6
{ INST(&V::arm_UHADD16, "UHADD16", "cccc01100111nnnndddd11110001mmmm") }, // v6
{ INST(&V::arm_UHASX, "UHASX", "cccc01100111nnnndddd11110011mmmm") }, // v6
{ INST(&V::arm_UHSAX, "UHSAX", "cccc01100111nnnndddd11110101mmmm") }, // v6
{ INST(&V::arm_UHSUB8, "UHSUB8", "cccc01100111nnnndddd11111111mmmm") }, // v6
{ INST(&V::arm_UHSUB16, "UHSUB16", "cccc01100111nnnndddd11110111mmmm") }, // v6
// Saturated Add/Subtract instructions
{ INST(&V::arm_QADD, "QADD", "cccc00010000nnnndddd00000101mmmm") }, // v5xP
{ INST(&V::arm_QSUB, "QSUB", "cccc00010010nnnndddd00000101mmmm") }, // v5xP
{ INST(&V::arm_QDADD, "QDADD", "cccc00010100nnnndddd00000101mmmm") }, // v5xP
{ INST(&V::arm_QDSUB, "QDSUB", "cccc00010110nnnndddd00000101mmmm") }, // v5xP
// Status Register Access instructions
{ INST(&V::arm_CPS, "CPS", "111100010000---00000000---0-----") }, // v6
{ INST(&V::arm_SETEND, "SETEND", "1111000100000001000000e000000000") }, // v6
{ INST(&V::arm_MRS, "MRS", "----00010-00--------00--00000000") }, // v3
{ INST(&V::arm_MSR, "MSR", "----00-10-10----1111------------") }, // v3
{ INST(&V::arm_RFE, "RFE", "----0001101-0000---------110----") }, // v6
{ INST(&V::arm_SRS, "SRS", "0000011--0-00000000000000001----") }, // v6
#undef INST
}};
template<typename Visitor>
boost::optional<const ArmMatcher<Visitor>&> DecodeArm(u32 instruction) {
const auto& table = g_arm_instruction_table<Visitor>;
const auto matches_instruction = [instruction](const auto& matcher){ return matcher.Matches(instruction); };
auto iter = std::find_if(table.begin(), table.end(), matches_instruction);
return iter != table.end() ? boost::make_optional<const ArmMatcher<Visitor>&>(*iter) : boost::none;
}
} // namespace Arm
} // namespace Dynarmic

View File

@@ -0,0 +1,132 @@
/* 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 <algorithm>
#include <array>
#include <cassert>
#include <tuple>
#include "common/mp.h"
namespace Dynarmic {
namespace Arm {
namespace detail {
/**
* Helper functions for the decoders.
* @tparam MatcherT The type of the matcher. (ARM: ArmMatcher, Thumb1: Thumb1Matcher)
* @tparam InstructionT The type that represents an instruction. (ARM: u32, Thumb1: u16)
* @tparam instruction_bit_size Bit-size for an instruction. (ARM: 32, Thumb1: 16)
*/
template<template<typename> class MatcherT, typename InstructionT, size_t instruction_bit_size>
struct detail {
private:
/**
* Generates the mask and the expected value after masking from a given bitstring.
* A '0' in a bitstring indicates that a zero must be present at that bit position.
* A '1' in a bitstring indicates that a one must be present at that bit position.
*/
static auto GetMaskAndExpect(const char* const bitstring) {
InstructionT mask = 0, expect = 0;
for (size_t i = 0; i < instruction_bit_size; i++) {
const size_t bit_position = instruction_bit_size - i - 1;
switch (bitstring[i]) {
case '0':
mask |= 1 << bit_position;
break;
case '1':
expect |= 1 << bit_position;
mask |= 1 << bit_position;
break;
}
}
return std::make_tuple(mask, expect);
}
/**
* Generates the masks and shifts for each argument.
* A '-' in a bitstring indicates that we don't care about that value.
* An argument is specified by a continuous string of the same character.
*/
template<size_t N>
static auto GetArgInfo(const char* const bitstring) {
std::array<InstructionT, N> masks = {};
std::array<size_t, N> shifts = {};
size_t arg_index = 0;
char ch = 0;
for (size_t i = 0; i < instruction_bit_size; i++) {
const size_t bit_position = instruction_bit_size - i - 1;
if (bitstring[i] == '0' || bitstring[i] == '1' || bitstring[i] == '-') {
if (ch != 0) {
ch = 0;
arg_index++;
}
} else {
if (ch == 0) {
ch = bitstring[i];
} else if (ch != bitstring[i]) {
ch = bitstring[i];
arg_index++;
}
assert(arg_index < N);
masks[arg_index] |= 1 << bit_position;
shifts[arg_index] = bit_position;
}
}
assert(std::all_of(masks.begin(), masks.end(), [](auto m){ return m != 0; }));
return std::make_tuple(masks, shifts);
}
/**
* This struct's Make member function generates a lambda which decodes an instruction based on
* the provided arg_masks and arg_shifts. The Visitor member function to call is provided as a
* template argument.
*/
template<typename FnT, FnT fn>
struct VisitorCaller;
template<typename Visitor, typename ...Args, typename CallRetT, CallRetT (Visitor::*fn)(Args...)>
struct VisitorCaller<CallRetT(Visitor::*)(Args...), fn> {
template<size_t ...iota>
static auto Make(std::integer_sequence<size_t, iota...>,
const std::array<InstructionT, sizeof...(iota)> arg_masks,
const std::array<size_t, sizeof...(iota)> arg_shifts) {
return [arg_masks, arg_shifts](Visitor& v, InstructionT instruction) {
(void)instruction;
return (v.*fn)(static_cast<Args>((instruction & arg_masks[iota]) >> arg_shifts[iota])...);
};
}
};
public:
/**
* Creates a matcher that can match and parse instructions based on bitstring.
* See also: GetMaskAndExpect and GetArgInfo for format of bitstring.
*/
template<typename FnT, FnT fn>
static auto GetMatcher(const char* const name, const char* const bitstring) {
using Visitor = typename mp::MemFnInfo<FnT, fn>::class_type;
constexpr size_t args_count = mp::MemFnInfo<FnT, fn>::args_count;
using Iota = std::make_index_sequence<args_count>;
const auto mask_and_expect = GetMaskAndExpect(bitstring);
const auto arg_info = GetArgInfo<args_count>(bitstring);
const auto proxy_fn = VisitorCaller<FnT, fn>::Make(Iota(), std::get<0>(arg_info), std::get<1>(arg_info));
return MatcherT<Visitor>(name, std::get<0>(mask_and_expect), std::get<1>(mask_and_expect), proxy_fn);
}
};
} // namespace detail
} // namespace Arm
} // namespace Dynarmic

View File

@@ -0,0 +1,165 @@
/* 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 <array>
#include <functional>
#include <tuple>
#include <boost/optional.hpp>
#include "common/common_types.h"
#include "frontend/decoder/decoder_detail.h"
namespace Dynarmic {
namespace Arm {
template <typename Visitor>
struct Thumb1Matcher {
using CallRetT = typename mp::MemFnInfo<decltype(&Visitor::thumb1_UDF), &Visitor::thumb1_UDF>::return_type;
Thumb1Matcher(const char* const name, u16 mask, u16 expect, std::function<CallRetT(Visitor&, u16)> fn)
: name(name), mask(mask), expect(expect), fn(fn) {}
/// Gets the name of this type of instruction.
const char* GetName() const {
return name;
}
/**
* Tests to see if the instruction is this type of instruction.
* @param instruction The instruction to test
* @returns true if the instruction is
*/
bool Matches(u16 instruction) const {
return (instruction & mask) == expect;
}
/**
* Calls the corresponding instruction handler on visitor for this type of instruction.
* @param v The visitor to use
* @param instruction The instruction to decode.
*/
CallRetT call(Visitor& v, u16 instruction) const {
assert(Matches(instruction));
return fn(v, instruction);
}
private:
const char* name;
u16 mask, expect;
std::function<CallRetT(Visitor&, u16)> fn;
};
template <typename V>
static const std::array<Thumb1Matcher<V>, 6> g_thumb1_instruction_table {{
#define INST(fn, name, bitstring) detail::detail<Thumb1Matcher, u16, 16>::GetMatcher<decltype(fn), fn>(name, bitstring)
// Shift (immediate), add, subtract, move and compare instructions
{ INST(&V::thumb1_LSL_imm, "LSL (imm)", "00000vvvvvmmmddd") },
{ INST(&V::thumb1_LSR_imm, "LSR (imm)", "00001vvvvvmmmddd") },
{ INST(&V::thumb1_ASR_imm, "ASR (imm)", "00010vvvvvmmmddd") },
//{ INST(&V::thumb1_ADD_rrr, "ADD (rrr)", "0001100mmmnnnddd") },
//{ INST(&V::thumb1_SUB_rrr, "SUB (rrr)", "0001101mmmnnnddd") },
//{ INST(&V::thumb1_ADD_rri, "ADD (rri)", "0001110mmmnnnddd") },
//{ INST(&V::thumb1_SUB_rri, "SUB (rri)", "0001111mmmnnnddd") },
//{ INST(&V::thumb1_MOV_ri, "MOV (ri)", "00100dddvvvvvvvv") },
//{ INST(&V::thumb1_CMP_ri, "CMP (ri)", "00101dddvvvvvvvv") },
//{ INST(&V::thumb1_ADD_ri, "ADD (ri)", "00110dddvvvvvvvv") },
//{ INST(&V::thumb1_SUB_ri, "SUB (ri)", "00111dddvvvvvvvv") },
// Data-processing instructions
// { INST(&V::thumb1_AND_reg, "AND (reg)", "0100000000mmmddd") },
// { INST(&V::thumb1_EOR_reg, "EOR (reg)", "0100000001mmmddd") },
{ INST(&V::thumb1_LSL_reg, "LSL (reg)", "0100000010mmmddd") },
{ INST(&V::thumb1_LSR_reg, "LSR (reg)", "0100000011sssddd") },
{ INST(&V::thumb1_ASR_reg, "ASR (reg)", "0100000100sssddd") },
//{ INST(&V::thumb1_ADCS_rr, "ADCS (rr)", "0100000101mmmddd") },
//{ INST(&V::thumb1_SBCS_rr, "SBCS (rr)", "0100000110mmmddd") },
//{ INST(&V::thumb1_RORS_rr, "RORS (rr)", "0100000111sssddd") },
//{ INST(&V::thumb1_TST_rr, "TST (rr)", "0100001000mmmnnn") },
//{ INST(&V::thumb1_NEGS_rr, "NEGS (rr)", "0100001001mmmddd") },
//{ INST(&V::thumb1_CMP_rr, "CMP (rr)", "0100001010mmmnnn") },
//{ INST(&V::thumb1_CMN_rr, "CMN (rr)", "0100001011mmmnnn") },
//{ INST(&V::thumb1_ORRS_rr, "ORRS (rr)", "0100001100mmmddd") },
//{ INST(&V::thumb1_MULS_rr, "MULS (rr)", "0100001101mmmddd") },
//{ INST(&V::thumb1_BICS_rr, "BICS (rr)", "0100001110mmmddd") },
//{ INST(&V::thumb1_MVNS_rr, "MVNS (rr)", "0100001111mmmddd") },
// Special data instructions
//{ INST(&V::thumb1_ADD_high, "ADD (high)", "01000100dmmmmddd") }, // v4T, Low regs: v6T2
//{ INST(&V::thumb1_CMP_high, "CMP (high)", "01000101dmmmmddd") }, // v4T
//{ INST(&V::thumb1_MOV_high, "MOV (high)", "01000110dmmmmddd") }, // v4T, Low regs: v6
// Store/Load single data item instructions
//{ INST(&V::thumb1_LDR_lit, "LDR (literal)", "01001dddvvvvvvvv") },
//{ INST(&V::thumb1_STR_rrr, "STR (rrr)", "0101000mmmnnnddd") },
//{ INST(&V::thumb1_STRH_rrr, "STRH (rrr)", "0101001mmmnnnddd") },
//{ INST(&V::thumb1_STRB_rrr, "STRB (rrr)", "0101010mmmnnnddd") },
//{ INST(&V::thumb1_LDRSB_rrr, "LDRSB (rrr)", "0101011mmmnnnddd") },
//{ INST(&V::thumb1_LDR_rrr, "LDR (rrr)", "0101100mmmnnnddd") },
//{ INST(&V::thumb1_LDRH_rrr, "LDRH (rrr)", "0101101mmmnnnddd") },
//{ INST(&V::thumb1_LDRB_rrr, "LDRB (rrr)", "0101110mmmnnnddd") },
//{ INST(&V::thumb1_LDRSH_rrr, "LDRSH (rrr)", "0101111mmmnnnddd") },
//{ INST(&V::thumb1_STRH_rri, "STRH (rri)", "10000vvvvvnnnddd") },
//{ INST(&V::thumb1_LDRH_rri, "LDRH (rri)", "10001vvvvvnnnddd") },
//{ INST(&V::thumb1_STR_sp, "STR (SP)", "10010dddvvvvvvvv") },
//{ INST(&V::thumb1_LDR_sp, "LDR (SP)", "10011dddvvvvvvvv") },
// Generate relative address instruction
//{ INST(&V::thumb1_ADR, "ADR", "10100dddvvvvvvvv") },
//{ INST(&V::thumb1_ADD_sp, "ADD (relative to SP)", "10101dddvvvvvvvv") },
// Miscellaneous 16-bit instructions
//{ INST(&V::thumb1_ADD_spsp, "ADD (imm to SP)", "101100000vvvvvvv") }, // v4T
//{ INST(&V::thumb1_SUB_spsp, "SUB (imm from SP)", "101100001vvvvvvv") }, // v4T
//{ INST(&V::thumb1_SXTH, "SXTH", "1011001000mmmddd") }, // v6
//{ INST(&V::thumb1_SXTB, "SXTB", "1011001001mmmddd") }, // v6
//{ INST(&V::thumb1_UXTH, "UXTH", "1011001010mmmddd") }, // v6
//{ INST(&V::thumb1_UXTB, "UXTB", "1011001011mmmddd") }, // v6
//{ INST(&V::thumb1_PUSH, "PUSH", "1011010rxxxxxxxx") }, // v4T
//{ INST(&V::thumb1_POP, "POP", "1011110rxxxxxxxx") }, // v4T
//{ INST(&V::thumb1_SETEND, "SETEND", "101101100101x000") }, // v6
//{ INST(&V::thumb1_CPS, "CPS", "10110110011m0aif") }, // v6
//{ INST(&V::thumb1_REV, "REV", "1011101000nnnddd") }, // v6
//{ INST(&V::thumb1_REV16, "REV16", "1011101001nnnddd") }, // v6
//{ INST(&V::thumb1_REVSH, "REVSH", "1011101011nnnddd") }, // v6
//{ INST(&V::thumb1_BKPT, "BKPT", "10111110xxxxxxxx") }, // v5
// Store/Load multiple registers
//{ INST(&V::thumb1_STMIA, "STMIA", "11000nnnxxxxxxxx") },
//{ INST(&V::thumb1_LDMIA, "LDMIA", "11001nnnxxxxxxxx") },
// Branch instructions
//{ INST(&V::thumb1_BX, "BX (reg)", "010001110mmmm000") }, // v4T
//{ INST(&V::thumb1_BLX, "BLX (reg)", "010001111mmmm000") }, // v5T
//{ INST(&V::thumb1_UDF, "UDF", "11011110--------") },
//{ INST(&V::thumb1_SWI, "SWI", "11011111xxxxxxxx") },
//{ INST(&V::thumb1_B_cond, "B (cond)", "1101ccccxxxxxxxx") },
//{ INST(&V::thumb1_B_imm, "B (imm)", "11100xxxxxxxxxxx") },
//{ INST(&V::thumb1_BLX_suffix, "BLX (imm, suffix)", "11101xxxxxxxxxx0") },
//{ INST(&V::thumb1_BLX_prefix, "BL/BLX (imm, prefix)", "11110xxxxxxxxxxx") },
//{ INST(&V::thumb1_BL_suffix, "BL (imm, suffix)", "11111xxxxxxxxxxx") },
#undef INST
}};
template<typename Visitor>
boost::optional<const Thumb1Matcher<Visitor>&> DecodeThumb1(u16 instruction) {
const auto& table = g_thumb1_instruction_table<Visitor>;
auto matches_instruction = [instruction](const auto& matcher){ return matcher.Matches(instruction); };
assert(std::count_if(table.begin(), table.end(), matches_instruction) <= 1);
auto iter = std::find_if(table.begin(), table.end(), matches_instruction);
return iter != table.end() ? boost::make_optional<const Thumb1Matcher<Visitor>&>(*iter) : boost::none;
}
} // namespace Arm
} // namespace Dynarmic