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