1 /* This file is part of the dynarmic project.
2  * Copyright (c) 2016 MerryMage
3  * SPDX-License-Identifier: 0BSD
4  */
5 
6 #pragma once
7 
8 #include <algorithm>
9 #include <functional>
10 #include <optional>
11 #include <vector>
12 
13 #include "common/common_types.h"
14 #include "frontend/decoder/decoder_detail.h"
15 #include "frontend/decoder/matcher.h"
16 
17 namespace Dynarmic::A32 {
18 
19 template <typename Visitor>
20 using Thumb16Matcher = Decoder::Matcher<Visitor, u16>;
21 
22 template<typename V>
DecodeThumb16(u16 instruction)23 std::optional<std::reference_wrapper<const Thumb16Matcher<V>>> DecodeThumb16(u16 instruction) {
24     static const std::vector<Thumb16Matcher<V>> table = {
25 
26 #define INST(fn, name, bitstring) Decoder::detail::detail<Thumb16Matcher<V>>::GetMatcher(fn, name, bitstring)
27 
28         // Shift (immediate), add, subtract, move and compare instructions
29         INST(&V::thumb16_LSL_imm,        "LSL (imm)",                "00000vvvvvmmmddd"),
30         INST(&V::thumb16_LSR_imm,        "LSR (imm)",                "00001vvvvvmmmddd"),
31         INST(&V::thumb16_ASR_imm,        "ASR (imm)",                "00010vvvvvmmmddd"),
32         INST(&V::thumb16_ADD_reg_t1,     "ADD (reg, T1)",            "0001100mmmnnnddd"),
33         INST(&V::thumb16_SUB_reg,        "SUB (reg)",                "0001101mmmnnnddd"),
34         INST(&V::thumb16_ADD_imm_t1,     "ADD (imm, T1)",            "0001110vvvnnnddd"),
35         INST(&V::thumb16_SUB_imm_t1,     "SUB (imm, T1)",            "0001111vvvnnnddd"),
36         INST(&V::thumb16_MOV_imm,        "MOV (imm)",                "00100dddvvvvvvvv"),
37         INST(&V::thumb16_CMP_imm,        "CMP (imm)",                "00101nnnvvvvvvvv"),
38         INST(&V::thumb16_ADD_imm_t2,     "ADD (imm, T2)",            "00110dddvvvvvvvv"),
39         INST(&V::thumb16_SUB_imm_t2,     "SUB (imm, T2)",            "00111dddvvvvvvvv"),
40 
41          // Data-processing instructions
42         INST(&V::thumb16_AND_reg,        "AND (reg)",                "0100000000mmmddd"),
43         INST(&V::thumb16_EOR_reg,        "EOR (reg)",                "0100000001mmmddd"),
44         INST(&V::thumb16_LSL_reg,        "LSL (reg)",                "0100000010mmmddd"),
45         INST(&V::thumb16_LSR_reg,        "LSR (reg)",                "0100000011mmmddd"),
46         INST(&V::thumb16_ASR_reg,        "ASR (reg)",                "0100000100mmmddd"),
47         INST(&V::thumb16_ADC_reg,        "ADC (reg)",                "0100000101mmmddd"),
48         INST(&V::thumb16_SBC_reg,        "SBC (reg)",                "0100000110mmmddd"),
49         INST(&V::thumb16_ROR_reg,        "ROR (reg)",                "0100000111sssddd"),
50         INST(&V::thumb16_TST_reg,        "TST (reg)",                "0100001000mmmnnn"),
51         INST(&V::thumb16_RSB_imm,        "RSB (imm)",                "0100001001nnnddd"),
52         INST(&V::thumb16_CMP_reg_t1,     "CMP (reg, T1)",            "0100001010mmmnnn"),
53         INST(&V::thumb16_CMN_reg,        "CMN (reg)",                "0100001011mmmnnn"),
54         INST(&V::thumb16_ORR_reg,        "ORR (reg)",                "0100001100mmmddd"),
55         INST(&V::thumb16_MUL_reg,        "MUL (reg)",                "0100001101nnnddd"),
56         INST(&V::thumb16_BIC_reg,        "BIC (reg)",                "0100001110mmmddd"),
57         INST(&V::thumb16_MVN_reg,        "MVN (reg)",                "0100001111mmmddd"),
58 
59         // Special data instructions
60         INST(&V::thumb16_ADD_reg_t2,     "ADD (reg, T2)",            "01000100Dmmmmddd"), // v4T, Low regs: v6T2
61         INST(&V::thumb16_CMP_reg_t2,     "CMP (reg, T2)",            "01000101Nmmmmnnn"), // v4T
62         INST(&V::thumb16_MOV_reg,        "MOV (reg)",                "01000110Dmmmmddd"), // v4T, Low regs: v6
63 
64         // Store/Load single data item instructions
65         INST(&V::thumb16_LDR_literal,    "LDR (literal)",            "01001tttvvvvvvvv"),
66         INST(&V::thumb16_STR_reg,        "STR (reg)",                "0101000mmmnnnttt"),
67         INST(&V::thumb16_STRH_reg,       "STRH (reg)",               "0101001mmmnnnttt"),
68         INST(&V::thumb16_STRB_reg,       "STRB (reg)",               "0101010mmmnnnttt"),
69         INST(&V::thumb16_LDRSB_reg,      "LDRSB (reg)",              "0101011mmmnnnttt"),
70         INST(&V::thumb16_LDR_reg,        "LDR (reg)",                "0101100mmmnnnttt"),
71         INST(&V::thumb16_LDRH_reg,       "LDRH (reg)",               "0101101mmmnnnttt"),
72         INST(&V::thumb16_LDRB_reg,       "LDRB (reg)",               "0101110mmmnnnttt"),
73         INST(&V::thumb16_LDRSH_reg,      "LDRSH (reg)",              "0101111mmmnnnttt"),
74         INST(&V::thumb16_STR_imm_t1,     "STR (imm, T1)",            "01100vvvvvnnnttt"),
75         INST(&V::thumb16_LDR_imm_t1,     "LDR (imm, T1)",            "01101vvvvvnnnttt"),
76         INST(&V::thumb16_STRB_imm,       "STRB (imm)",               "01110vvvvvnnnttt"),
77         INST(&V::thumb16_LDRB_imm,       "LDRB (imm)",               "01111vvvvvnnnttt"),
78         INST(&V::thumb16_STRH_imm,       "STRH (imm)",               "10000vvvvvnnnttt"),
79         INST(&V::thumb16_LDRH_imm,       "LDRH (imm)",               "10001vvvvvnnnttt"),
80         INST(&V::thumb16_STR_imm_t2,     "STR (imm, T2)",            "10010tttvvvvvvvv"),
81         INST(&V::thumb16_LDR_imm_t2,     "LDR (imm, T2)",            "10011tttvvvvvvvv"),
82 
83         // Generate relative address instructions
84         INST(&V::thumb16_ADR,            "ADR",                      "10100dddvvvvvvvv"),
85         INST(&V::thumb16_ADD_sp_t1,      "ADD (SP plus imm, T1)",    "10101dddvvvvvvvv"),
86         INST(&V::thumb16_ADD_sp_t2,      "ADD (SP plus imm, T2)",    "101100000vvvvvvv"), // v4T
87         INST(&V::thumb16_SUB_sp,         "SUB (SP minus imm)",       "101100001vvvvvvv"), // v4T
88 
89         // Hint instructions
90         INST(&V::thumb16_NOP,            "NOP",                      "1011111100000000"), // v6T2
91         INST(&V::thumb16_SEV,            "SEV",                      "1011111101000000"), // v7
92         INST(&V::thumb16_SEVL,           "SEVL",                     "1011111101010000"), // v8
93         INST(&V::thumb16_WFE,            "WFE",                      "1011111100100000"), // v7
94         INST(&V::thumb16_WFI,            "WFI",                      "1011111100110000"), // v7
95         INST(&V::thumb16_YIELD,          "YIELD",                    "1011111100010000"), // v7
96 
97         // Miscellaneous 16-bit instructions
98         INST(&V::thumb16_SXTH,           "SXTH",                     "1011001000mmmddd"), // v6
99         INST(&V::thumb16_SXTB,           "SXTB",                     "1011001001mmmddd"), // v6
100         INST(&V::thumb16_UXTH,           "UXTH",                     "1011001010mmmddd"), // v6
101         INST(&V::thumb16_UXTB,           "UXTB",                     "1011001011mmmddd"), // v6
102         INST(&V::thumb16_PUSH,           "PUSH",                     "1011010Mxxxxxxxx"), // v4T
103         INST(&V::thumb16_POP,            "POP",                      "1011110Pxxxxxxxx"), // v4T
104         INST(&V::thumb16_SETEND,         "SETEND",                   "101101100101x000"), // v6
105         INST(&V::thumb16_CPS,            "CPS",                      "10110110011m0aif"), // v6
106         INST(&V::thumb16_REV,            "REV",                      "1011101000mmmddd"), // v6
107         INST(&V::thumb16_REV16,          "REV16",                    "1011101001mmmddd"), // v6
108         INST(&V::thumb16_REVSH,          "REVSH",                    "1011101011mmmddd"), // v6
109         INST(&V::thumb16_BKPT,           "BKPT",                     "10111110xxxxxxxx"), // v5
110 
111         // Store/Load multiple registers
112         INST(&V::thumb16_STMIA,          "STMIA",                    "11000nnnxxxxxxxx"),
113         INST(&V::thumb16_LDMIA,          "LDMIA",                    "11001nnnxxxxxxxx"),
114 
115         // Branch instructions
116         INST(&V::thumb16_BX,             "BX",                       "010001110mmmm000"), // v4T
117         INST(&V::thumb16_BLX_reg,        "BLX (reg)",                "010001111mmmm000"), // v5T
118         INST(&V::thumb16_CBZ_CBNZ,       "CBZ/CBNZ",                 "1011o0i1iiiiinnn"), // v6T2
119         INST(&V::thumb16_UDF,            "UDF",                      "11011110--------"),
120         INST(&V::thumb16_SVC,            "SVC",                      "11011111xxxxxxxx"),
121         INST(&V::thumb16_B_t1,           "B (T1)",                   "1101ccccvvvvvvvv"),
122         INST(&V::thumb16_B_t2,           "B (T2)",                   "11100vvvvvvvvvvv"),
123 
124 #undef INST
125 
126     };
127 
128     const auto matches_instruction = [instruction](const auto& matcher){ return matcher.Matches(instruction); };
129 
130     auto iter = std::find_if(table.begin(), table.end(), matches_instruction);
131     return iter != table.end() ? std::optional<std::reference_wrapper<const Thumb16Matcher<V>>>(*iter) : std::nullopt;
132 }
133 
134 } // namespace Dynarmic::A32
135