1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#if USE(ARMV7_DISASSEMBLER)
29
30#include "ARMv7DOpcode.h"
31
32#include <stdarg.h>
33#include <stdint.h>
34#include <stdio.h>
35
36namespace JSC { namespace ARMv7Disassembler {
37
38ARMv7D16BitOpcode::OpcodeGroup* ARMv7D16BitOpcode::opcodeTable[32];
39ARMv7D32BitOpcode::OpcodeGroup* ARMv7D32BitOpcode::opcodeTable[16];
40
41const char* const ARMv7DOpcode::s_conditionNames[16] = {
42    "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
43    "hi", "ls", "ge", "lt", "gt", "le", "al", "al"
44};
45
46const char* const ARMv7DOpcode::s_optionName[8] = {
47    "uxtb", "uxth", "uxtw", "uxtx", "sxtb", "sxth", "sxtw", "sxtx"
48};
49
50const char* const ARMv7DOpcode::s_shiftNames[4] = {
51    "lsl", "lsr", "asl", "ror"
52};
53
54const char* const ARMv7DOpcode::s_specialRegisterNames[3] = { "sp", "lr", "pc" };
55
56template <typename OpcodeType, typename InstructionType>
57struct OpcodeGroupInitializer {
58    unsigned m_opcodeGroupNumber;
59    InstructionType m_mask;
60    InstructionType m_pattern;
61    const char* (*m_format)(OpcodeType*);
62};
63
64#define OPCODE_GROUP_ENTRY(groupIndex, groupClass) \
65{ groupIndex, groupClass::s_mask, groupClass::s_pattern, groupClass::format }
66
67typedef OpcodeGroupInitializer<ARMv7D16BitOpcode, uint16_t> Opcode16GroupInitializer;
68typedef OpcodeGroupInitializer<ARMv7D32BitOpcode, uint32_t> Opcode32GroupInitializer;
69
70static Opcode16GroupInitializer opcode16BitGroupList[] = {
71    OPCODE_GROUP_ENTRY(0x0, ARMv7DOpcodeLogicalImmediateT1),
72    OPCODE_GROUP_ENTRY(0x1, ARMv7DOpcodeLogicalImmediateT1),
73    OPCODE_GROUP_ENTRY(0x2, ARMv7DOpcodeLogicalImmediateT1),
74    OPCODE_GROUP_ENTRY(0x3, ARMv7DOpcodeAddSubtractT1),
75    OPCODE_GROUP_ENTRY(0x3, ARMv7DOpcodeAddSubtractImmediate3),
76    OPCODE_GROUP_ENTRY(0x4, ARMv7DOpcodeMoveImmediateT1),
77    OPCODE_GROUP_ENTRY(0x5, ARMv7DOpcodeCompareImmediateT1),
78    OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeAddSubtractImmediate8),
79    OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeAddSubtractImmediate8),
80    OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingRegisterT1),
81    OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeAddRegisterT2),
82    OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeCompareRegisterT2),
83    OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeCompareRegisterT1),
84    OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeMoveRegisterT1),
85    OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchExchangeT1),
86    OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeLoadFromLiteralPool),
87    OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeLoadStoreRegisterOffsetT1),
88    OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeLoadStoreRegisterOffsetT1),
89    OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
90    OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
91    OPCODE_GROUP_ENTRY(0xe, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
92    OPCODE_GROUP_ENTRY(0xf, ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte),
93    OPCODE_GROUP_ENTRY(0x10, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord),
94    OPCODE_GROUP_ENTRY(0x11, ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord),
95    OPCODE_GROUP_ENTRY(0x12, ARMv7DOpcodeLoadStoreRegisterSPRelative),
96    OPCODE_GROUP_ENTRY(0x13, ARMv7DOpcodeLoadStoreRegisterSPRelative),
97    OPCODE_GROUP_ENTRY(0x14, ARMv7DOpcodeGeneratePCRelativeAddress),
98    OPCODE_GROUP_ENTRY(0x15, ARMv7DOpcodeAddSPPlusImmediate),
99    OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscCompareAndBranch),
100    OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscByteHalfwordOps),
101    OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscPushPop),
102    OPCODE_GROUP_ENTRY(0x16, ARMv7DOpcodeMiscAddSubSP),
103    OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscHint16), // Needs to be before IfThenT1
104    OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscIfThenT1),
105    OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscByteHalfwordOps),
106    OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscCompareAndBranch),
107    OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscPushPop),
108    OPCODE_GROUP_ENTRY(0x17, ARMv7DOpcodeMiscBreakpointT1),
109    OPCODE_GROUP_ENTRY(0x1a, ARMv7DOpcodeBranchConditionalT1),
110    OPCODE_GROUP_ENTRY(0x1b, ARMv7DOpcodeBranchConditionalT1),
111    OPCODE_GROUP_ENTRY(0x1c, ARMv7DOpcodeBranchT2)
112};
113
114static Opcode32GroupInitializer opcode32BitGroupList[] = {
115    OPCODE_GROUP_ENTRY(0x5, ARMv7DOpcodeDataProcessingShiftedReg),
116    OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVSinglePrecision),
117    OPCODE_GROUP_ENTRY(0x6, ARMv7DOpcodeVMOVDoublePrecision),
118    OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeFPTransfer),
119    OPCODE_GROUP_ENTRY(0x7, ARMv7DOpcodeVMSR),
120    OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeDataProcessingModifiedImmediate),
121    OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeConditionalBranchT3),
122    OPCODE_GROUP_ENTRY(0x8, ARMv7DOpcodeBranchOrBranchLink),
123    OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeUnmodifiedImmediate),
124    OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeHint32),
125    OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeConditionalBranchT3),
126    OPCODE_GROUP_ENTRY(0x9, ARMv7DOpcodeBranchOrBranchLink),
127    OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeDataProcessingModifiedImmediate),
128    OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeConditionalBranchT3),
129    OPCODE_GROUP_ENTRY(0xa, ARMv7DOpcodeBranchOrBranchLink),
130    OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeUnmodifiedImmediate),
131    OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeConditionalBranchT3),
132    OPCODE_GROUP_ENTRY(0xb, ARMv7DOpcodeBranchOrBranchLink),
133    OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadRegister),
134    OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeDataPushPopSingle), // Should be before StoreSingle*
135    OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleRegister),
136    OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate12),
137    OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeStoreSingleImmediate8),
138    OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadSignedImmediate),
139    OPCODE_GROUP_ENTRY(0xc, ARMv7DOpcodeLoadUnsignedImmediate),
140    OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeLongMultipleDivide),
141    OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegShift),
142    OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegExtend),
143    OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegParallel),
144    OPCODE_GROUP_ENTRY(0xd, ARMv7DOpcodeDataProcessingRegMisc),
145};
146
147bool ARMv7DOpcode::s_initialized = false;
148
149void ARMv7DOpcode::init()
150{
151    if (s_initialized)
152        return;
153
154    ARMv7D16BitOpcode::init();
155    ARMv7D32BitOpcode::init();
156
157    s_initialized = true;
158}
159
160void ARMv7DOpcode::startITBlock(unsigned blocksize, unsigned firstCondition)
161{
162    ASSERT(blocksize > 0 && blocksize <= MaxITBlockSize);
163    m_ITBlocksize = blocksize;
164    m_ITConditionIndex = m_ITBlocksize + 1;
165    m_currentITCondition = 0;
166    m_ifThenConditions[0] = firstCondition;
167}
168
169void ARMv7DOpcode::saveITConditionAt(unsigned blockPosition, unsigned condition)
170{
171    if (blockPosition < m_ITBlocksize)
172        m_ifThenConditions[blockPosition] = static_cast<unsigned char>(condition);
173}
174
175void ARMv7DOpcode::fetchOpcode(uint16_t*& newPC)
176{
177    m_bufferOffset = 0;
178    m_formatBuffer[0] = '\0';
179    m_currentPC = newPC;
180
181    m_opcode = *newPC++;
182
183    if (is32BitInstruction()) {
184        m_opcode <<= 16;
185        m_opcode |= *newPC++;
186    }
187
188    if (m_ITConditionIndex < m_ITBlocksize)
189        m_currentITCondition = m_ifThenConditions[m_ITConditionIndex];
190    else
191        m_currentITCondition = CondNone;
192}
193
194const char* ARMv7DOpcode::disassemble(uint16_t*& currentPC)
195{
196    const char* result;
197    fetchOpcode(currentPC);
198
199    if (is32BitInstruction())
200        result = reinterpret_cast<ARMv7D32BitOpcode*>(this)->doDisassemble();
201    else
202        result = reinterpret_cast<ARMv7D16BitOpcode*>(this)->doDisassemble();
203
204    if (startingITBlock())
205        m_ITConditionIndex = 0;
206    else if (inITBlock() && (++m_ITConditionIndex >= m_ITBlocksize))
207        endITBlock();
208
209    return result;
210}
211
212void ARMv7DOpcode::bufferPrintf(const char* format, ...)
213{
214    if (m_bufferOffset >= bufferSize)
215        return;
216
217    va_list argList;
218    va_start(argList, format);
219
220    m_bufferOffset += vsnprintf(m_formatBuffer + m_bufferOffset, bufferSize - m_bufferOffset, format, argList);
221
222    va_end(argList);
223}
224
225void ARMv7DOpcode::appendInstructionName(const char* instructionName, bool addS)
226{
227    if (!inITBlock()  && !addS) {
228        appendInstructionNameNoITBlock(instructionName);
229
230        return;
231    }
232
233    const char sevenSpaces[8] = "       ";
234
235    unsigned length = strlen(instructionName);
236
237    bufferPrintf("   %s", instructionName);
238    if (inITBlock()) {
239        const char* condition = conditionName(m_currentITCondition);
240        length += strlen(condition);
241        appendString(condition);
242    } else if (addS) {
243        length++;
244        appendCharacter('s');
245    }
246
247    if (length >= 7)
248        length = 6;
249
250    appendString(sevenSpaces + length);
251}
252
253void ARMv7DOpcode::appendRegisterName(unsigned registerNumber)
254{
255    registerNumber &= 0xf;
256
257    if (registerNumber > 12) {
258        appendString(s_specialRegisterNames[registerNumber - 13]);
259        return;
260    }
261
262    bufferPrintf("r%u", registerNumber);
263}
264
265void ARMv7DOpcode::appendRegisterList(unsigned registers)
266{
267    unsigned numberPrinted = 0;
268
269    appendCharacter('{');
270
271    for (unsigned i = 0; i < 16; i++) {
272        if (registers & i) {
273            if (numberPrinted++)
274                appendSeparator();
275            appendRegisterName(i);
276        }
277    }
278
279    appendCharacter('}');
280}
281
282void ARMv7DOpcode::appendFPRegisterName(char registerPrefix, unsigned registerNumber)
283{
284    bufferPrintf("%c%u", registerPrefix, registerNumber);
285}
286
287// 16 Bit Instructions
288
289void ARMv7D16BitOpcode::init()
290{
291    OpcodeGroup* lastGroups[OpcodeGroup::opcodeTableSize];
292
293    for (unsigned i = 0; i < OpcodeGroup::opcodeTableSize; i++) {
294        opcodeTable[i] = 0;
295        lastGroups[i] = 0;
296    }
297
298    for (unsigned i = 0; i < sizeof(opcode16BitGroupList) / sizeof(Opcode16GroupInitializer); i++) {
299        OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcode16BitGroupList[i].m_mask, opcode16BitGroupList[i].m_pattern, opcode16BitGroupList[i].m_format);
300        uint16_t opcodeGroupNumber = opcode16BitGroupList[i].m_opcodeGroupNumber;
301
302        if (!opcodeTable[opcodeGroupNumber])
303            opcodeTable[opcodeGroupNumber] = newOpcodeGroup;
304        else
305            lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup);
306        lastGroups[opcodeGroupNumber] = newOpcodeGroup;
307    }
308}
309
310const char* ARMv7D16BitOpcode::doDisassemble()
311{
312    OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)];
313
314    while (opGroup) {
315        if (opGroup->matches(static_cast<uint16_t>(m_opcode)))
316            return opGroup->format(this);
317        opGroup = opGroup->next();
318    }
319
320    return defaultFormat();
321}
322
323const char* ARMv7D16BitOpcode::defaultFormat()
324{
325    bufferPrintf("   .word  %04x", m_opcode);
326    return m_formatBuffer;
327}
328
329const char* ARMv7DOpcodeAddRegisterT2::format()
330{
331    appendInstructionName("add");
332    appendRegisterName(rdn());
333    appendSeparator();
334    appendRegisterName(rm());
335
336    return m_formatBuffer;
337}
338
339const char* ARMv7DOpcodeAddSPPlusImmediate::format()
340{
341    appendInstructionName("add");
342    appendRegisterName(rd());
343    appendSeparator();
344    appendRegisterName(RegSP);
345    appendSeparator();
346    appendUnsignedImmediate(immediate8());
347
348    return m_formatBuffer;
349}
350
351const char* const ARMv7DOpcodeAddSubtract::s_opNames[2] = { "add", "sub" };
352
353const char* ARMv7DOpcodeAddSubtractT1::format()
354{
355    appendInstructionName(opName(), !inITBlock());
356    appendRegisterName(rd());
357    appendSeparator();
358    appendRegisterName(rn());
359    appendSeparator();
360    appendRegisterName(rm());
361
362    return m_formatBuffer;
363}
364
365const char* ARMv7DOpcodeAddSubtractImmediate3::format()
366{
367    appendInstructionName(opName(), !inITBlock());
368    appendRegisterName(rd());
369    appendSeparator();
370    appendRegisterName(rn());
371    appendSeparator();
372    appendUnsignedImmediate(immediate3());
373
374    return m_formatBuffer;
375}
376
377const char* ARMv7DOpcodeAddSubtractImmediate8::format()
378{
379    appendInstructionName(opName(), !inITBlock());
380    appendRegisterName(rdn());
381    appendSeparator();
382    appendUnsignedImmediate(immediate8());
383
384    return m_formatBuffer;
385}
386
387const char* ARMv7DOpcodeBranchConditionalT1::format()
388{
389    if (condition() == 0xe)
390        return defaultFormat();
391
392    if (condition() == 0xf) {
393        appendInstructionName("svc");
394        appendUnsignedImmediate(offset());
395
396        return m_formatBuffer;
397    }
398
399    bufferPrintf("   b%-6.6s", conditionName(condition()));
400    appendPCRelativeOffset(static_cast<int32_t>(offset()) + 2);
401
402    return m_formatBuffer;
403}
404
405const char* ARMv7DOpcodeBranchExchangeT1::format()
406{
407    appendInstructionName(opName());
408    appendRegisterName(rm());
409
410    return m_formatBuffer;
411}
412
413const char* ARMv7DOpcodeBranchT2::format()
414{
415    appendInstructionName("b");
416    appendPCRelativeOffset(static_cast<int32_t>(immediate11()) + 2);
417
418    return m_formatBuffer;
419}
420
421const char* ARMv7DOpcodeCompareImmediateT1::format()
422{
423    appendInstructionName("cmp");
424    appendRegisterName(rn());
425    appendSeparator();
426    appendUnsignedImmediate(immediate8());
427
428    return m_formatBuffer;
429}
430
431const char* ARMv7DOpcodeCompareRegisterT1::format()
432{
433    appendInstructionName("cmp");
434    appendRegisterName(rn());
435    appendSeparator();
436    appendRegisterName(rm());
437
438    return m_formatBuffer;
439}
440
441const char* ARMv7DOpcodeCompareRegisterT2::format()
442{
443    appendInstructionName("compare");
444    appendRegisterName(rn());
445    appendSeparator();
446    appendRegisterName(rm());
447
448    return m_formatBuffer;
449}
450
451const char* const ARMv7DOpcodeDataProcessingRegisterT1::s_opNames[16] = {
452    "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror", "tst", "rsb", "cmp", "cmn", "orr", "mul", "bic", "mvn"
453};
454
455const char* ARMv7DOpcodeDataProcessingRegisterT1::format()
456{
457    appendInstructionName(opName(), inITBlock() && (!(op() == 0x8) || (op() == 0xa) || (op() == 0xb)));
458    appendRegisterName(rdn());
459    appendSeparator();
460    appendRegisterName(rm());
461    if (op() == 0x9) // rsb T1
462        appendString(", #0");
463    else if (op() == 0xd) { // mul T1
464        appendSeparator();
465        appendRegisterName(rdn());
466    }
467
468    return m_formatBuffer;
469}
470
471const char* ARMv7DOpcodeGeneratePCRelativeAddress::format()
472{
473    appendInstructionName("adr");
474    appendRegisterName(rd());
475    appendSeparator();
476    appendPCRelativeOffset(static_cast<int32_t>(immediate8()));
477
478    return m_formatBuffer;
479}
480
481const char* ARMv7DOpcodeLoadFromLiteralPool::format()
482{
483    appendInstructionName("ldr");
484    appendRegisterName(rt());
485    appendSeparator();
486    appendPCRelativeOffset(static_cast<int32_t>(immediate8()));
487
488    return m_formatBuffer;
489}
490
491const char* const ARMv7DOpcodeLoadStoreRegisterImmediate::s_opNames[6] = {
492    "str", "ldr", "strb",  "ldrb", "strh", "ldrh"
493};
494
495const char* ARMv7DOpcodeLoadStoreRegisterImmediate::format()
496{
497    const char* instructionName = opName();
498
499    if (!instructionName)
500        return defaultFormat();
501
502    appendInstructionName(opName());
503    appendRegisterName(rt());
504    appendSeparator();
505    appendCharacter('[');
506    appendRegisterName(rn());
507    if (immediate5()) {
508        appendSeparator();
509        appendUnsignedImmediate(immediate5() << scale());
510    }
511    appendCharacter(']');
512
513    return m_formatBuffer;
514}
515
516const char* const ARMv7DOpcodeLoadStoreRegisterOffsetT1::s_opNames[8] = {
517    "str", "strh", "strb", "ldrsb", "ldr", "ldrh", "ldrb", "ldrsh"
518};
519
520const char* ARMv7DOpcodeLoadStoreRegisterOffsetT1::format()
521{
522    appendInstructionName(opName());
523    appendRegisterName(rt());
524    appendSeparator();
525    appendCharacter('[');
526    appendRegisterName(rn());
527    appendSeparator();
528    appendRegisterName(rm());
529    appendCharacter(']');
530
531    return m_formatBuffer;
532}
533
534const char* ARMv7DOpcodeLoadStoreRegisterSPRelative::format()
535{
536    appendInstructionName(opName());
537    appendRegisterName(rt());
538    appendSeparator();
539    appendCharacter('[');
540    appendRegisterName(RegSP);
541    if (immediate8()) {
542        appendSeparator();
543        appendUnsignedImmediate(immediate8() << 2);
544    }
545    appendCharacter(']');
546
547    return m_formatBuffer;
548}
549
550const char* ARMv7DOpcodeLogicalImmediateT1::format()
551{
552    if (!op() && !immediate5()) {
553        // mov T2
554        appendInstructionName("movs");
555        appendRegisterName(rd());
556        appendSeparator();
557        appendRegisterName(rm());
558
559        return m_formatBuffer;
560    }
561
562    appendInstructionName(opName(), !inITBlock());
563    appendRegisterName(rd());
564    appendSeparator();
565    appendRegisterName(rm());
566    appendSeparator();
567    appendUnsignedImmediate((op() && !immediate5()) ? 32 : immediate5());
568
569    return m_formatBuffer;
570}
571
572const char* ARMv7DOpcodeMiscAddSubSP::format()
573{
574    appendInstructionName(opName());
575    appendRegisterName(RegSP);
576    appendSeparator();
577    appendRegisterName(RegSP);
578    appendSeparator();
579    appendUnsignedImmediate(immediate7());
580
581    return m_formatBuffer;
582}
583
584const char* ARMv7DOpcodeMiscBreakpointT1::format()
585{
586    appendInstructionNameNoITBlock("bkpt");
587    appendUnsignedImmediate(immediate8());
588
589    return m_formatBuffer;
590}
591
592const char* const ARMv7DOpcodeMiscByteHalfwordOps::s_opNames[8] = {
593    "sxth", "sxb", "uxth", "uxtb", "rev", "rev16", "revsh"
594};
595
596const char* ARMv7DOpcodeMiscByteHalfwordOps::format()
597{
598    const char* instructionName = opName();
599
600    if (!instructionName)
601        return defaultFormat();
602
603    appendInstructionName(instructionName);
604    appendRegisterName(rd());
605    appendSeparator();
606    appendRegisterName(rm());
607
608    return m_formatBuffer;
609}
610
611const char* ARMv7DOpcodeMiscCompareAndBranch::format()
612{
613    appendInstructionName(opName());
614    appendPCRelativeOffset(immediate6() + 2);
615
616    return m_formatBuffer;
617}
618
619const char* const ARMv7DOpcodeMiscHint16::s_opNames[16] = {
620    "nop", "yield", "wfe", "wfi", "sev"
621};
622
623const char* ARMv7DOpcodeMiscHint16::format()
624{
625    if (opA() > 4)
626        return defaultFormat();
627
628    appendInstructionName(opName());
629
630    return m_formatBuffer;
631}
632
633const char* ARMv7DOpcodeMiscIfThenT1::format()
634{
635    char opName[6];
636    opName[0] = 'i';
637    opName[1] = 't';
638
639    unsigned condition = firstCondition();
640    unsigned maskBits = mask();
641    unsigned blockLength = 0;
642
643    for (unsigned i = 0; i < 4; ++i) {
644        if (maskBits & (1 << i)) {
645            blockLength = 4 - i;
646            break;
647        }
648    }
649
650    startITBlock(blockLength, condition);
651
652    for (unsigned i = 1; i < blockLength; ++i) {
653        unsigned currMaskBit = (maskBits >> (4-i)) & 0x1;
654        opName[i + 1] = (currMaskBit ^ (condition & 1)) ? 'e' : 't';
655        saveITConditionAt(i, (condition & ~1) | currMaskBit);
656    }
657    opName[blockLength + 1] = '\0';
658
659    appendInstructionNameNoITBlock(opName);
660    appendString(conditionName(condition));
661
662    return m_formatBuffer;
663}
664
665const char* ARMv7DOpcodeMiscPushPop::format()
666{
667    appendInstructionName(opName());
668    appendRegisterList(registerMask());
669
670    return m_formatBuffer;
671}
672
673const char* ARMv7DOpcodeMoveImmediateT1::format()
674{
675    appendInstructionName("mov", !inITBlock());
676    appendRegisterName(rd());
677    appendSeparator();
678    appendUnsignedImmediate(immediate8());
679
680    return m_formatBuffer;
681}
682
683const char* ARMv7DOpcodeMoveRegisterT1::format()
684{
685    appendInstructionName("mov");
686    appendRegisterName(rd());
687    appendSeparator();
688    appendRegisterName(rm());
689
690    return m_formatBuffer;
691}
692
693// 32 bit Intructions
694
695void ARMv7D32BitOpcode::init()
696{
697    OpcodeGroup* lastGroups[OpcodeGroup::opcodeTableSize];
698
699    for (unsigned i = 0; i < OpcodeGroup::opcodeTableSize; i++) {
700        opcodeTable[i] = 0;
701        lastGroups[i] = 0;
702    }
703
704    for (unsigned i = 0; i < sizeof(opcode32BitGroupList) / sizeof(Opcode32GroupInitializer); i++) {
705        OpcodeGroup* newOpcodeGroup = new OpcodeGroup(opcode32BitGroupList[i].m_mask, opcode32BitGroupList[i].m_pattern, opcode32BitGroupList[i].m_format);
706        uint16_t opcodeGroupNumber = opcode32BitGroupList[i].m_opcodeGroupNumber;
707
708        if (!opcodeTable[opcodeGroupNumber])
709            opcodeTable[opcodeGroupNumber] = newOpcodeGroup;
710        else
711            lastGroups[opcodeGroupNumber]->setNext(newOpcodeGroup);
712        lastGroups[opcodeGroupNumber] = newOpcodeGroup;
713    }
714}
715
716const char* ARMv7D32BitOpcode::doDisassemble()
717{
718    OpcodeGroup* opGroup = opcodeTable[opcodeGroupNumber(m_opcode)];
719
720    while (opGroup) {
721        if (opGroup->matches(m_opcode))
722            return opGroup->format(this);
723        opGroup = opGroup->next();
724    }
725
726    return defaultFormat();
727}
728
729const char* ARMv7D32BitOpcode::defaultFormat()
730{
731    bufferPrintf("   .long  %08x", m_opcode);
732    return m_formatBuffer;
733}
734
735const char* ARMv7DOpcodeConditionalBranchT3::format()
736{
737    if (condition() < 0xe)
738        bufferPrintf("   b%-6.6s", conditionName(condition()));
739    else
740        appendInstructionName("b");
741    appendPCRelativeOffset(offset() + 2);
742
743    return m_formatBuffer;
744}
745
746const char* ARMv7DOpcodeBranchOrBranchLink::format()
747{
748    appendInstructionName(isBL() ? "bl" : "b");
749    appendPCRelativeOffset(offset() + 2);
750
751    return m_formatBuffer;
752}
753
754const char* const ARMv7DOpcodeDataProcessingLogicalAndRithmetic::s_opNames[16] = {
755    "and", "bic", "orr", "orn", "eor", 0, "pkh", 0, "add", 0, "adc", "sbc", 0, "sub", "rsb", 0
756};
757
758void ARMv7DOpcodeDataProcessingModifiedImmediate::appendModifiedImmediate(unsigned immediate12)
759{
760    if (!(immediate12 & 0xc00)) {
761        unsigned immediate = 0;
762        unsigned lower8Bits = immediate12 & 0xff;
763
764        switch ((immediate12 >> 8) & 3) {
765        case 0:
766            immediate = lower8Bits;
767            break;
768        case 1:
769            immediate = (lower8Bits << 16) | lower8Bits;
770            break;
771        case 2:
772            immediate = (lower8Bits << 24) | (lower8Bits << 8);
773            break;
774        case 3:
775            immediate = (lower8Bits << 24) | (lower8Bits << 16) | (lower8Bits << 8) | lower8Bits;
776            break;
777        }
778        appendUnsignedImmediate(immediate);
779        return;
780    }
781
782    unsigned immediate8 = 0x80 | (immediate12 & 0x7f);
783    unsigned shiftAmount = 32 - ((immediate12 >> 7) & 0x1f);
784
785    appendUnsignedImmediate(immediate8 << shiftAmount);
786}
787
788const char* ARMv7DOpcodeDataProcessingModifiedImmediate::format()
789{
790    if ((op() == 0x5) || (op() == 0x6) || (op() == 0x7) || (op() == 0x9) || (op() == 0xc) || (op() == 0xf))
791        return defaultFormat();
792
793    const char* instructionName = opName();
794
795    if (rn() == 15) {
796        if (op() == 2) {
797            // MOV T2
798            instructionName = sBit() ? "movs" : "mov";
799            appendInstructionName(instructionName);
800            appendRegisterName(rd());
801            appendSeparator();
802            appendModifiedImmediate(immediate12());
803
804            return m_formatBuffer;
805        }
806
807        if (op() == 3) {
808            // MVN T1
809            instructionName = sBit() ? "mvns" : "mvn";
810            appendInstructionName(instructionName);
811            appendRegisterName(rd());
812            appendSeparator();
813            appendModifiedImmediate(immediate12());
814
815            return m_formatBuffer;
816        }
817    }
818
819    if (rd() == 15) {
820        if (sBit()) {
821            bool testOrCmpInstruction = false;
822
823            switch (op()) {
824            case 0x0:
825                instructionName = "tst";
826                testOrCmpInstruction = true;
827                break;
828            case 0x4:
829                instructionName = "teq";
830                testOrCmpInstruction = true;
831                break;
832            case 0x8:
833                instructionName = "cmn";
834                testOrCmpInstruction = true;
835                break;
836            case 0xd:
837                instructionName = "cmp";
838                testOrCmpInstruction = true;
839                break;
840            }
841
842            if (testOrCmpInstruction) {
843                appendInstructionName(instructionName);
844                appendRegisterName(rn());
845                appendSeparator();
846                appendModifiedImmediate(immediate12());
847
848                return m_formatBuffer;
849            }
850        }
851    }
852
853    appendInstructionName(instructionName);
854    appendRegisterName(rd());
855    appendSeparator();
856    appendRegisterName(rn());
857    appendSeparator();
858    appendModifiedImmediate(immediate12());
859
860    return m_formatBuffer;
861}
862
863void ARMv7DOpcodeDataProcessingShiftedReg::appendImmShift(unsigned type, unsigned immediate)
864{
865    if (type || immediate) {
866        appendSeparator();
867
868        if (!immediate) {
869            switch (type) {
870            case 1:
871            case 2:
872                immediate = 32;
873                break;
874            case 3:
875                appendString("rrx");
876                return;
877            }
878        }
879
880        appendShiftType(type);
881        appendUnsignedImmediate(immediate);
882    }
883}
884
885const char* ARMv7DOpcodeDataProcessingShiftedReg::format()
886{
887    if ((op() == 0x5) || (op() == 0x7) || (op() == 0x9) || (op() == 0xc) || (op() == 0xf))
888        return defaultFormat();
889
890    if (op() == 6) {
891        // pkhbt or pkhtb
892        if (sBit() || tBit())
893            return defaultFormat();
894
895        if (tbBit())
896            appendInstructionName("pkhtb");
897        else
898            appendInstructionName("pkhbt");
899        appendRegisterName(rd());
900        appendSeparator();
901        appendRegisterName(rn());
902        appendSeparator();
903        appendRegisterName(rm());
904        appendImmShift(tbBit() << 1, immediate5());
905
906        return m_formatBuffer;
907    }
908
909    const char* instructionName = opName();
910
911    if (rn() == 15) {
912        if (op() == 2) {
913            if (!type() && !immediate5()) {
914                // MOV T3
915                instructionName = sBit() ? "movs" : "mov";
916                appendInstructionName(instructionName);
917                appendRegisterName(rd());
918                appendSeparator();
919                appendRegisterName(rm());
920
921                return m_formatBuffer;
922            }
923
924            if (type() == 3 && !immediate5()) {
925                // RRX T1
926                instructionName = sBit() ? "rrx" : "rrx";
927                appendInstructionName(instructionName);
928                appendRegisterName(rd());
929                appendSeparator();
930                appendRegisterName(rm());
931
932                return m_formatBuffer;
933            }
934
935            // Logical
936            if (sBit())
937                bufferPrintf("%ss ", shiftName(type()));
938            else
939                appendInstructionName(shiftName(type()));
940            appendRegisterName(rd());
941            appendSeparator();
942            appendRegisterName(rm());
943            appendSeparator();
944            appendUnsignedImmediate(immediate5());
945
946            return m_formatBuffer;
947        }
948
949        if (op() == 3) {
950            // MVN T2
951            instructionName = sBit() ? "mvns" : "mvn";
952            appendInstructionName(instructionName);
953            appendRegisterName(rd());
954            appendSeparator();
955            appendRegisterName(rm());
956            appendImmShift(type(), immediate5());
957
958            return m_formatBuffer;
959        }
960    }
961
962    if (rd() == 15) {
963        if (sBit()) {
964            bool testOrCmpInstruction = false;
965
966            switch (op()) {
967            case 0x0:
968                instructionName = "tst";
969                testOrCmpInstruction = true;
970                break;
971            case 0x4:
972                instructionName = "teq";
973                testOrCmpInstruction = true;
974                break;
975            case 0x8:
976                instructionName = "cmn";
977                testOrCmpInstruction = true;
978                break;
979            case 0xd:
980                instructionName = "cmp";
981                testOrCmpInstruction = true;
982                break;
983            }
984
985            if (testOrCmpInstruction) {
986                appendInstructionName(instructionName);
987                appendRegisterName(rn());
988                appendSeparator();
989                appendRegisterName(rm());
990                appendImmShift(type(), immediate5());
991
992                return m_formatBuffer;
993            }
994        }
995    }
996
997    appendInstructionName(instructionName);
998    appendRegisterName(rd());
999    appendSeparator();
1000    appendRegisterName(rn());
1001    appendSeparator();
1002    appendRegisterName(rm());
1003    appendImmShift(type(), immediate5());
1004
1005    return m_formatBuffer;
1006}
1007
1008const char* ARMv7DOpcodeFPTransfer::format()
1009{
1010    appendInstructionName("vmov");
1011
1012    if (opL()) {
1013        appendFPRegister();
1014        appendSeparator();
1015    }
1016
1017    appendRegisterName(rt());
1018
1019    if (!opL()) {
1020        appendSeparator();
1021        appendFPRegister();
1022    }
1023
1024    return m_formatBuffer;
1025}
1026
1027void ARMv7DOpcodeFPTransfer::appendFPRegister()
1028{
1029    if (opC()) {
1030        appendFPRegisterName('d', vd());
1031        bufferPrintf("[%u]", opH());
1032    } else
1033        appendFPRegisterName('s', vn());
1034}
1035
1036const char* ARMv7DOpcodeDataProcessingRegShift::format()
1037{
1038    appendInstructionName(opName());
1039    appendRegisterName(rd());
1040    appendSeparator();
1041    appendRegisterName(rn());
1042    appendSeparator();
1043    appendRegisterName(rm());
1044
1045    return m_formatBuffer;
1046}
1047
1048const char* const ARMv7DOpcodeDataProcessingRegExtend::s_opExtendNames[8] = {
1049    "sxth", "uxth", "sxtb16", "uxtb16", "sxtb", "uxtb"
1050};
1051
1052const char* const ARMv7DOpcodeDataProcessingRegExtend::s_opExtendAndAddNames[8] = {
1053    "sxtah", "uxtah", "sxtab16", "uxtab16", "sxtab", "uxtab"
1054};
1055
1056const char* ARMv7DOpcodeDataProcessingRegExtend::format()
1057{
1058    const char* instructionName;
1059
1060    if (rn() == 0xf)
1061        instructionName = opExtendName();
1062    else
1063        instructionName = opExtendAndAddName();
1064
1065    if (!instructionName)
1066        return defaultFormat();
1067
1068    appendInstructionName(instructionName);
1069    appendRegisterName(rd());
1070    appendSeparator();
1071    appendRegisterName(rn());
1072    appendSeparator();
1073    appendRegisterName(rm());
1074
1075    if (rotate()) {
1076        appendSeparator();
1077        appendString("ror ");
1078        appendUnsignedImmediate(rotate() * 8);
1079    }
1080
1081    return m_formatBuffer;
1082}
1083
1084const char* const ARMv7DOpcodeDataProcessingRegParallel::s_opNames[16] = {
1085    "sadd8", "sadd16", "sasx", 0, "ssub8", "ssub16", "ssax", 0,
1086    "qadd8", "qadd16", "qasx", 0, "qsub8", "qsub16", "qsax", 0
1087};
1088
1089const char* ARMv7DOpcodeDataProcessingRegParallel::format()
1090{
1091    const char* instructionName;
1092
1093    instructionName = opName();
1094
1095    if (!instructionName)
1096        return defaultFormat();
1097
1098    appendInstructionName(instructionName);
1099    appendRegisterName(rd());
1100    appendSeparator();
1101    appendRegisterName(rn());
1102    appendSeparator();
1103    appendRegisterName(rm());
1104
1105    return m_formatBuffer;
1106}
1107
1108const char* const ARMv7DOpcodeDataProcessingRegMisc::s_opNames[16] = {
1109    "qadd", "qdadd", "qsub", "qdsub", "rev", "rev16", "rbit", "revsh",
1110    "sel", 0, 0, 0, "clz"
1111};
1112
1113const char* ARMv7DOpcodeDataProcessingRegMisc::format()
1114{
1115    const char* instructionName;
1116
1117    instructionName = opName();
1118
1119    if (!instructionName)
1120        return defaultFormat();
1121
1122    if ((op1() & 0x1) && (rn() != rm()))
1123        return defaultFormat();
1124
1125    appendInstructionName(instructionName);
1126    appendRegisterName(rd());
1127    appendSeparator();
1128
1129    if (op1() == 0x2) { // sel
1130        appendRegisterName(rn());
1131        appendSeparator();
1132        appendRegisterName(rm());
1133
1134        return m_formatBuffer;
1135    }
1136
1137    appendRegisterName(rm());
1138
1139    if (!(op1() & 0x1)) {
1140        appendSeparator();
1141        appendRegisterName(rn());
1142    }
1143
1144    return m_formatBuffer;
1145}
1146
1147const char* const ARMv7DOpcodeHint32::s_opNames[8] = {
1148    "nop", "yield", "wfe", "wfi", "sev"
1149};
1150
1151const char* ARMv7DOpcodeHint32::format()
1152{
1153    if (isDebugHint()) {
1154        appendInstructionName("debug");
1155        appendUnsignedImmediate(debugOption());
1156
1157        return m_formatBuffer;
1158    }
1159
1160    if (op() > 0x4)
1161        return defaultFormat();
1162
1163    appendInstructionName(opName());
1164
1165    return m_formatBuffer;
1166}
1167
1168const char* const ARMv7DOpcodeDataLoad::s_opNames[8] = {
1169    "ldrb", "ldrh", "ldr", 0, "ldrsb", "ldrsh"
1170};
1171
1172const char* ARMv7DOpcodeLoadRegister::format()
1173{
1174    appendInstructionName(opName());
1175    appendRegisterName(rt());
1176    appendSeparator();
1177    appendCharacter('[');
1178    appendRegisterName(rn());
1179    appendSeparator();
1180    appendRegisterName(rm());
1181    if (immediate2()) {
1182        appendSeparator();
1183        appendUnsignedImmediate(immediate2());
1184    }
1185    appendCharacter(']');
1186
1187    return m_formatBuffer;
1188}
1189
1190const char* ARMv7DOpcodeLoadSignedImmediate::format()
1191{
1192    appendInstructionName(opName());
1193    appendRegisterName(rt());
1194    appendSeparator();
1195    appendCharacter('[');
1196    appendRegisterName(rn());
1197    if (pBit()) {
1198        if (wBit() || immediate8()) {
1199            appendSeparator();
1200            if (uBit())
1201                appendUnsignedImmediate(immediate8());
1202            else
1203                appendSignedImmediate(0 - static_cast<int>(immediate8()));
1204        }
1205        appendCharacter(']');
1206        if (wBit())
1207            appendCharacter('!');
1208    } else {
1209        appendCharacter(']');
1210        appendSeparator();
1211        if (uBit())
1212            appendUnsignedImmediate(immediate8());
1213        else
1214            appendSignedImmediate(0 - static_cast<int>(immediate8()));
1215    }
1216
1217    return m_formatBuffer;
1218}
1219
1220const char* ARMv7DOpcodeLoadUnsignedImmediate::format()
1221{
1222    appendInstructionName(opName());
1223    appendRegisterName(rt());
1224    appendSeparator();
1225    appendCharacter('[');
1226    appendRegisterName(rn());
1227    if (immediate12()) {
1228        appendSeparator();
1229        appendUnsignedImmediate(immediate12());
1230    }
1231    appendCharacter(']');
1232
1233    return m_formatBuffer;
1234}
1235
1236const char* const ARMv7DOpcodeLongMultipleDivide::s_opNames[8] = {
1237    "smull", "sdiv", "umull", "udiv", "smlal", "smlsld", "umlal", 0
1238};
1239
1240const char* const ARMv7DOpcodeLongMultipleDivide::s_smlalOpNames[4] = {
1241    "smlalbb", "smlalbt", "smlaltb", "smlaltt"
1242};
1243
1244const char* const ARMv7DOpcodeLongMultipleDivide::s_smlaldOpNames[2] = {
1245    "smlald", "smlaldx"
1246};
1247
1248const char* const ARMv7DOpcodeLongMultipleDivide::s_smlsldOpNames[2] = {
1249    "smlsld", "smlsldx"
1250};
1251
1252const char* ARMv7DOpcodeLongMultipleDivide::format()
1253{
1254    const char* instructionName = opName();
1255
1256    switch (op1()) {
1257    case 0x0:
1258    case 0x2:
1259        if (op2())
1260            return defaultFormat();
1261        break;
1262    case 0x1:
1263    case 0x3:
1264        if (op2() != 0xf)
1265            return defaultFormat();
1266        break;
1267    case 0x4:
1268        if ((op2() & 0xc) == 0x8)
1269            instructionName = smlalOpName();
1270        else if ((op2() & 0xe) == 0xc)
1271            instructionName = smlaldOpName();
1272        else if (op2())
1273            return defaultFormat();
1274        break;
1275    case 0x5:
1276        if ((op2() & 0xe) == 0xc)
1277            instructionName = smlaldOpName();
1278        else
1279            return defaultFormat();
1280        break;
1281    case 0x6:
1282        if (op2() == 0x5)
1283            instructionName = "umaal";
1284        else if (op2())
1285            return defaultFormat();
1286        break;
1287    case 0x7:
1288        return defaultFormat();
1289        break;
1290    }
1291
1292    appendInstructionName(instructionName);
1293    if ((op1() & 0x5) == 0x1) { // sdiv and udiv
1294        if (rt() != 0xf)
1295            return defaultFormat();
1296    } else {
1297        appendRegisterName(rdLo());
1298        appendSeparator();
1299    }
1300    appendRegisterName(rdHi());
1301    appendSeparator();
1302    appendRegisterName(rn());
1303    appendSeparator();
1304    appendRegisterName(rm());
1305
1306    return m_formatBuffer;
1307}
1308
1309const char* const ARMv7DOpcodeUnmodifiedImmediate::s_opNames[16] = {
1310    "addw", 0, "movw", 0, 0, "subw", "movt", 0,
1311    "ssat", "ssat16", "sbfx", "bfi", "usat" , "usat16", "ubfx", 0
1312};
1313
1314const char* ARMv7DOpcodeUnmodifiedImmediate::format()
1315{
1316    const char* instructionName = opName();
1317
1318    switch (op() >> 1) {
1319    case 0x0:
1320    case 0x5:
1321        if (rn() == 0xf)
1322            instructionName = "adr";
1323        break;
1324    case 0x9:
1325        if (immediate5())
1326            instructionName = "ssat";
1327        break;
1328    case 0xb:
1329        if (rn() == 0xf)
1330            instructionName = "bfc";
1331        break;
1332    case 0xd:
1333        if (immediate5())
1334            instructionName = "usat";
1335        break;
1336    }
1337
1338    if (!instructionName)
1339        return defaultFormat();
1340
1341    appendInstructionName(instructionName);
1342    appendRegisterName(rd());
1343    appendSeparator();
1344
1345    if ((op() & 0x17) == 0x4) { // movw or movt
1346        appendUnsignedImmediate(immediate16());
1347
1348        return m_formatBuffer;
1349    }
1350
1351    if (!op() || (op() == 0xa)) { // addw, subw and adr
1352        if (rn() == 0xf) {
1353            int32_t offset;
1354
1355            if ((op() == 0xa) && (rn() == 0xf))
1356                offset = 0 - static_cast<int32_t>(immediate12());
1357            else
1358                offset = static_cast<int32_t>(immediate12());
1359
1360            appendPCRelativeOffset(offset);
1361
1362            return m_formatBuffer;
1363        }
1364
1365        appendRegisterName(rn());
1366        appendSeparator();
1367        appendUnsignedImmediate(immediate12());
1368
1369        return m_formatBuffer;
1370    }
1371
1372    if (((op() & 0x15) == 0x10) || (((op() & 0x17) == 0x12) && immediate5())) { // ssat, usat, ssat16 & usat16
1373        appendSeparator();
1374        appendUnsignedImmediate(bitNumOrSatImmediate() + 1);
1375        appendSeparator();
1376        appendRegisterName(rn());
1377        if (shBit() || immediate5()) {
1378            appendSeparator();
1379            appendShiftType(shBit() << 1);
1380            appendUnsignedImmediate(immediate5());
1381        }
1382
1383        return m_formatBuffer;
1384    }
1385
1386    if (op() == 0x16) { // bfi or bfc
1387        int width = static_cast<int>(bitNumOrSatImmediate()) - static_cast<int>(immediate5()) + 1;
1388
1389        if (width < 0)
1390            return defaultFormat();
1391
1392        if (rn() != 0xf) {
1393            appendSeparator();
1394            appendRegisterName(rn());
1395        }
1396        appendSeparator();
1397        appendUnsignedImmediate(immediate5());
1398        appendSeparator();
1399        appendSignedImmediate(width);
1400
1401        return m_formatBuffer;
1402    }
1403
1404    // Must be sbfx or ubfx
1405    appendSeparator();
1406    appendRegisterName(rn());
1407    appendSeparator();
1408    appendUnsignedImmediate(immediate5());
1409    appendSeparator();
1410    appendUnsignedImmediate(bitNumOrSatImmediate() + 1);
1411
1412    return m_formatBuffer;
1413}
1414
1415const char* const ARMv7DOpcodeDataStoreSingle::s_opNames[4] = {
1416    "strb", "strh", "str", 0
1417};
1418
1419const char* ARMv7DOpcodeDataPushPopSingle::format()
1420{
1421    appendInstructionName(opName());
1422    appendRegisterName(rt());
1423
1424    return m_formatBuffer;
1425}
1426
1427const char* ARMv7DOpcodeStoreSingleImmediate12::format()
1428{
1429    appendInstructionName(opName());
1430    appendRegisterName(rt());
1431    appendSeparator();
1432    appendCharacter('[');
1433    appendRegisterName(rn());
1434    if (immediate12()) {
1435        appendSeparator();
1436        appendUnsignedImmediate(immediate12());
1437    }
1438    appendCharacter(']');
1439
1440    return m_formatBuffer;
1441}
1442
1443const char* ARMv7DOpcodeStoreSingleImmediate8::format()
1444{
1445    if (pBit() && uBit() && !wBit()) // Really undecoded strt
1446        return defaultFormat();
1447
1448    if ((rn() == 0xf) || (!pBit() && !wBit()))
1449        return defaultFormat();
1450
1451    appendInstructionName(opName());
1452    appendRegisterName(rt());
1453    appendSeparator();
1454    appendCharacter('[');
1455    appendRegisterName(rn());
1456
1457    if (!pBit()) {
1458        appendCharacter(']');
1459        appendSeparator();
1460        appendSignedImmediate(uBit() ? static_cast<int32_t>(immediate8()) : (0 - static_cast<int32_t>(immediate8())));
1461
1462        return m_formatBuffer;
1463    }
1464
1465    if (immediate8()) {
1466        appendSeparator();
1467        appendSignedImmediate(uBit() ? static_cast<int32_t>(immediate8()) : (0 - static_cast<int32_t>(immediate8())));
1468    }
1469    appendCharacter(']');
1470
1471    if (wBit())
1472        appendCharacter('!');
1473
1474    return m_formatBuffer;
1475}
1476
1477const char* ARMv7DOpcodeStoreSingleRegister::format()
1478{
1479    appendInstructionName(opName());
1480    appendRegisterName(rt());
1481    appendSeparator();
1482    appendCharacter('[');
1483    appendRegisterName(rn());
1484    appendSeparator();
1485    appendRegisterName(rm());
1486    if (immediate2()) {
1487        appendSeparator();
1488        appendString("lsl ");
1489        appendUnsignedImmediate(immediate2());
1490    }
1491    appendCharacter(']');
1492
1493    return m_formatBuffer;
1494}
1495
1496const char* ARMv7DOpcodeVMOVDoublePrecision::format()
1497{
1498    appendInstructionName("vmov");
1499    if (op()) {
1500        appendRegisterName(rt());
1501        appendSeparator();
1502        appendRegisterName(rt2());
1503        appendSeparator();
1504    }
1505
1506    appendFPRegisterName('d', vm());
1507
1508    if (!op()) {
1509        appendSeparator();
1510        appendRegisterName(rt());
1511        appendSeparator();
1512        appendRegisterName(rt2());
1513    }
1514
1515    return m_formatBuffer;
1516}
1517
1518const char* ARMv7DOpcodeVMOVSinglePrecision::format()
1519{
1520    appendInstructionName("vmov");
1521    if (op()) {
1522        appendRegisterName(rt());
1523        appendSeparator();
1524        appendRegisterName(rt2());
1525        appendSeparator();
1526    }
1527
1528    appendFPRegisterName('s', vm());
1529    appendSeparator();
1530    appendFPRegisterName('s', (vm() + 1) % 32);
1531
1532    if (!op()) {
1533        appendSeparator();
1534        appendRegisterName(rt());
1535        appendSeparator();
1536        appendRegisterName(rt2());
1537    }
1538
1539    return m_formatBuffer;
1540}
1541
1542const char* ARMv7DOpcodeVMSR::format()
1543{
1544    appendInstructionName("vmrs");
1545    if (opL()) {
1546        if (rt() == 0xf)
1547            appendString("apsr_nzcv");
1548        else
1549            appendRegisterName(rt());
1550        appendSeparator();
1551    }
1552
1553    appendString("fpscr");
1554
1555    if (!opL()) {
1556        appendSeparator();
1557        appendRegisterName(rt());
1558    }
1559
1560    return m_formatBuffer;
1561}
1562
1563} } // namespace JSC::ARMv7Disassembler
1564
1565#endif // #if USE(ARMV7_DISASSEMBLER)
1566