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#ifndef ARMv7DOpcode_h
27#define ARMv7DOpcode_h
28
29#if USE(ARMV7_DISASSEMBLER)
30
31#include <stdint.h>
32#include <wtf/Assertions.h>
33
34namespace JSC { namespace ARMv7Disassembler {
35
36class ARMv7DOpcode {
37public:
38    static void init();
39
40    ARMv7DOpcode()
41        : m_opcode(0)
42        , m_bufferOffset(0)
43    {
44        init();
45
46        for (unsigned i = 0; i < 4; i++)
47            m_ifThenConditions[i] = CondNone;
48
49        endITBlock();
50
51        m_formatBuffer[0] = '\0';
52    }
53
54    const char* disassemble(uint16_t*& currentPC);
55
56protected:
57    const unsigned RegSP = 0xd;
58    const unsigned RegLR = 0xe;
59    const unsigned RegPC = 0xf;
60
61    void fetchOpcode(uint16_t*&);
62    bool is32BitInstruction() { return (m_opcode & 0xfffff800) > 0xe000; }
63    bool isFPInstruction() { return (m_opcode & 0xfc000e00) == 0xec000a00; }
64
65    static const char* const s_conditionNames[16];
66    static const char* const s_shiftNames[4];
67    static const char* const s_optionName[8];
68    static const char* const s_specialRegisterNames[3];
69
70    static const char* conditionName(unsigned condition) { return s_conditionNames[condition & 0xf]; }
71    static const char* shiftName(unsigned shiftValue) { return s_shiftNames[shiftValue & 0x3]; }
72
73    bool inITBlock() { return m_ITConditionIndex < m_ITBlocksize; }
74    bool startingITBlock() { return m_ITConditionIndex == m_ITBlocksize + 1; }
75
76    void startITBlock(unsigned, unsigned);
77    void saveITConditionAt(unsigned, unsigned);
78    void endITBlock()
79    {
80        m_currentITCondition = CondNone;
81        m_ITConditionIndex = 0;
82        m_ITBlocksize = 0;
83    }
84
85    void bufferPrintf(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
86    void appendInstructionName(const char*, bool addS = false);
87
88    void appendInstructionNameNoITBlock(const char* instructionName)
89    {
90        bufferPrintf("   %-7.7s", instructionName);
91    }
92
93    void appendRegisterName(unsigned);
94    void appendRegisterList(unsigned);
95    void appendFPRegisterName(char, unsigned);
96
97    void appendSeparator()
98    {
99        bufferPrintf(", ");
100    }
101
102    void appendCharacter(const char c)
103    {
104        bufferPrintf("%c", c);
105    }
106
107    void appendString(const char* string)
108    {
109        bufferPrintf("%s", string);
110    }
111
112    void appendShiftType(unsigned shiftValue)
113    {
114        bufferPrintf("%s ", shiftName(shiftValue));
115    }
116
117    void appendSignedImmediate(int immediate)
118    {
119        bufferPrintf("#%d", immediate);
120    }
121
122    void appendUnsignedImmediate(unsigned immediate)
123    {
124        bufferPrintf("#%u", immediate);
125    }
126
127    void appendPCRelativeOffset(int32_t immediate)
128    {
129        bufferPrintf("0x%x", reinterpret_cast<uint32_t>(m_currentPC + immediate));
130    }
131
132    void appendShiftAmount(unsigned amount)
133    {
134        bufferPrintf("lsl #%u", 16 * amount);
135    }
136
137    static const int bufferSize = 81;
138    static const unsigned char CondNone = 0xe;
139    static const unsigned MaxITBlockSize = 4;
140
141    char m_formatBuffer[bufferSize];
142    unsigned char m_ifThenConditions[MaxITBlockSize];
143    uint16_t* m_currentPC;
144    uint32_t m_opcode;
145    int m_bufferOffset;
146    int m_currentITCondition;
147    unsigned m_ITConditionIndex;
148    unsigned m_ITBlocksize;
149
150private:
151    static bool s_initialized;
152};
153
154#define DEFINE_STATIC_FORMAT16(klass, thisObj) \
155    static const char* format(ARMv7D16BitOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); }
156
157class ARMv7D16BitOpcode : public ARMv7DOpcode {
158private:
159    class OpcodeGroup {
160    public:
161        OpcodeGroup(uint16_t opcodeMask, uint16_t opcodePattern, const char* (*format)(ARMv7D16BitOpcode*))
162            : m_opcodeMask(opcodeMask)
163            , m_opcodePattern(opcodePattern)
164            , m_format(format)
165            , m_next(0)
166        {
167        }
168
169        void setNext(OpcodeGroup* next)
170        {
171            m_next = next;
172        }
173
174        OpcodeGroup* next()
175        {
176            return m_next;
177        }
178
179        bool matches(uint16_t opcode)
180        {
181            return (opcode & m_opcodeMask) == m_opcodePattern;
182        }
183
184        const char* format(ARMv7D16BitOpcode* thisObj)
185        {
186            return m_format(thisObj);
187        }
188
189    public:
190        static const unsigned opcodeTableSize = 32;
191        static const unsigned opcodeTableMask = opcodeTableSize-1;
192
193        // private:
194        uint16_t m_opcodeMask;
195        uint16_t m_opcodePattern;
196        const char* (*m_format)(ARMv7D16BitOpcode*);
197        OpcodeGroup* m_next;
198    };
199
200public:
201    static void init();
202
203    const char* defaultFormat();
204    const char* doDisassemble();
205
206protected:
207    unsigned rm() { return (m_opcode >> 3) & 0x7; }
208    unsigned rd() { return m_opcode & 0x7; }
209    unsigned opcodeGroupNumber(unsigned opcode) { return (opcode >> 11) & OpcodeGroup::opcodeTableMask; }
210
211private:
212    static OpcodeGroup* opcodeTable[OpcodeGroup::opcodeTableSize];
213};
214
215class ARMv7DOpcodeAddRegisterT2 : public ARMv7D16BitOpcode {
216public:
217    static const uint16_t s_mask = 0xff00;
218    static const uint16_t s_pattern = 0x4400;
219
220    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddRegisterT2, thisObj);
221
222protected:
223    const char* format();
224
225    unsigned rdn() { return ((m_opcode >> 4) & 0x8) | (m_opcode & 0x7); }
226    unsigned rm() { return ((m_opcode >> 3) & 0xf); }
227};
228
229class ARMv7DOpcodeAddSPPlusImmediate : public ARMv7D16BitOpcode {
230public:
231    static const uint16_t s_mask = 0xf800;
232    static const uint16_t s_pattern = 0xc800;
233
234    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddSPPlusImmediate, thisObj);
235
236protected:
237    const char* format();
238
239    unsigned rd() { return (m_opcode >> 8) & 0x7; }
240    unsigned immediate8() { return m_opcode & 0x0ff; }
241};
242
243class ARMv7DOpcodeAddSubtract : public ARMv7D16BitOpcode {
244protected:
245    static const char* const s_opNames[2];
246};
247
248class ARMv7DOpcodeAddSubtractT1 : public ARMv7DOpcodeAddSubtract {
249public:
250    static const uint16_t s_mask = 0xfc00;
251    static const uint16_t s_pattern = 0x1800;
252
253    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddSubtractT1, thisObj);
254
255protected:
256    const char* format();
257
258    const char* opName() { return s_opNames[op()]; }
259
260    unsigned op() { return (m_opcode >> 9) & 0x1; }
261    unsigned rm() { return (m_opcode >> 6) & 0x7; }
262    unsigned rn() { return (m_opcode >> 3) & 0x7; }
263};
264
265class ARMv7DOpcodeAddSubtractImmediate3 : public ARMv7DOpcodeAddSubtract {
266public:
267    static const uint16_t s_mask = 0xfc00;
268    static const uint16_t s_pattern = 0x1c00;
269
270    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddSubtractImmediate3, thisObj);
271
272protected:
273    const char* format();
274
275    const char* opName() { return s_opNames[op()]; }
276
277    unsigned op() { return (m_opcode >> 9) & 0x1; }
278    unsigned immediate3() { return (m_opcode >> 6) & 0x3; }
279    unsigned rn() { return (m_opcode >> 3) & 0x7; }
280};
281
282class ARMv7DOpcodeAddSubtractImmediate8 : public ARMv7DOpcodeAddSubtract {
283public:
284    static const uint16_t s_mask = 0xf000;
285    static const uint16_t s_pattern = 0x3000;
286
287    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeAddSubtractImmediate8, thisObj);
288
289protected:
290    const char* format();
291
292    const char* opName() { return s_opNames[op()]; }
293
294    unsigned op() { return (m_opcode >> 11) & 0x1; }
295    unsigned rdn() { return (m_opcode >> 8) & 0x7; }
296    unsigned immediate8() { return m_opcode & 0xff; }
297};
298
299class ARMv7DOpcodeBranchConditionalT1 : public ARMv7D16BitOpcode {
300public:
301    static const uint16_t s_mask = 0xf000;
302    static const uint16_t s_pattern = 0xd000;
303
304    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeBranchConditionalT1, thisObj);
305
306protected:
307    const char* format();
308
309    unsigned condition() { return (m_opcode >> 8) & 0xf; }
310    int offset() { return static_cast<int>(m_opcode & 0xff); }
311};
312
313class ARMv7DOpcodeBranchExchangeT1 : public ARMv7D16BitOpcode {
314public:
315    static const uint16_t s_mask = 0xff00;
316    static const uint16_t s_pattern = 0x4700;
317
318    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeBranchExchangeT1, thisObj);
319
320protected:
321    const char* format();
322
323    const char* opName() { return (m_opcode & 0x80) ? "blx" : "bx"; }
324    unsigned rm() { return ((m_opcode >> 3) & 0xf); }
325};
326
327class ARMv7DOpcodeBranchT2 : public ARMv7D16BitOpcode {
328public:
329    static const uint16_t s_mask = 0xf800;
330    static const uint16_t s_pattern = 0xe000;
331
332    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeBranchT2, thisObj);
333
334protected:
335    const char* format();
336
337    int immediate11() { return static_cast<int>(m_opcode & 0x7ff); }
338};
339
340class ARMv7DOpcodeCompareImmediateT1 : public ARMv7D16BitOpcode {
341public:
342    static const uint16_t s_mask = 0xf800;
343    static const uint16_t s_pattern = 0x2800;
344
345    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeCompareImmediateT1, thisObj);
346
347protected:
348    const char* format();
349
350    unsigned rn() { return (m_opcode >> 8) & 0x3; }
351    unsigned immediate8() { return m_opcode & 0xff; }
352};
353
354class ARMv7DOpcodeCompareRegisterT1 : public ARMv7D16BitOpcode {
355public:
356    static const uint16_t s_mask = 0xffc0;
357    static const uint16_t s_pattern = 0x4280;
358
359    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeCompareRegisterT1, thisObj);
360
361protected:
362    const char* format();
363
364    unsigned rn() { return m_opcode & 0x7; }
365};
366
367class ARMv7DOpcodeCompareRegisterT2 : public ARMv7D16BitOpcode {
368public:
369    static const uint16_t s_mask = 0xff00;
370    static const uint16_t s_pattern = 0x4500;
371
372    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeCompareRegisterT2, thisObj);
373
374protected:
375    const char* format();
376
377    unsigned rn() { return ((m_opcode >> 4) & 0x8) | (m_opcode & 0x7); }
378    unsigned rm() { return ((m_opcode >> 3) & 0xf); }
379};
380
381class ARMv7DOpcodeDataProcessingRegisterT1 : public ARMv7D16BitOpcode {
382private:
383    static const char* const s_opNames[16];
384
385public:
386    static const uint16_t s_mask = 0xfc00;
387    static const uint16_t s_pattern = 0x4000;
388
389    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeDataProcessingRegisterT1, thisObj);
390
391protected:
392    const char* format();
393
394    const char* opName() { return s_opNames[op()]; }
395
396    unsigned op() { return (m_opcode >> 6) & 0xf; }
397
398    unsigned rm() { return (m_opcode >> 3) & 0x7; }
399    unsigned rdn() { return m_opcode & 0x7; }
400};
401
402class ARMv7DOpcodeGeneratePCRelativeAddress : public ARMv7D16BitOpcode {
403public:
404    static const uint16_t s_mask = 0xf800;
405    static const uint16_t s_pattern = 0xa000;
406
407    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeGeneratePCRelativeAddress, thisObj);
408
409protected:
410    const char* format();
411
412    unsigned rd() { return (m_opcode >> 8) & 0x7; }
413    unsigned immediate8() { return m_opcode & 0x0ff; }
414};
415
416class ARMv7DOpcodeLoadFromLiteralPool : public ARMv7D16BitOpcode {
417public:
418    static const uint16_t s_mask = 0xf800;
419    static const uint16_t s_pattern = 0x4800;
420
421    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadFromLiteralPool, thisObj);
422
423protected:
424    const char* format();
425
426    unsigned rt() { return (m_opcode >> 8) & 0x7; }
427    unsigned immediate8() { return m_opcode & 0x0ff; }
428};
429
430class ARMv7DOpcodeLoadStoreRegisterImmediate : public ARMv7D16BitOpcode {
431private:
432    static const char* const s_opNames[6];
433
434public:
435    const char* format();
436
437protected:
438    const char* opName() { return s_opNames[op()]; }
439
440    unsigned op() { return ((m_opcode >> 11) & 0x1f) - 0xc; }
441    unsigned immediate5() { return (m_opcode >> 6) & 0x01f; }
442    unsigned rn() { return (m_opcode >> 3) & 0x7; }
443    unsigned rt() { return m_opcode & 0x7; }
444    unsigned scale() { return 2 - (op() >> 1); }
445};
446
447class ARMv7DOpcodeLoadStoreRegisterImmediateWordAndByte : public ARMv7DOpcodeLoadStoreRegisterImmediate {
448public:
449    static const uint16_t s_mask = 0xe000;
450    static const uint16_t s_pattern = 0x6000;
451
452    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
453};
454
455class ARMv7DOpcodeLoadStoreRegisterImmediateHalfWord : public ARMv7DOpcodeLoadStoreRegisterImmediate {
456public:
457    static const uint16_t s_mask = 0xf800;
458    static const uint16_t s_pattern = 0x8000;
459
460    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterImmediate, thisObj);
461};
462
463class ARMv7DOpcodeLoadStoreRegisterOffsetT1 : public ARMv7D16BitOpcode {
464private:
465    static const char* const s_opNames[8];
466
467public:
468    static const uint16_t s_mask = 0xf000;
469    static const uint16_t s_pattern = 0x5000;
470
471    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterOffsetT1, thisObj);
472
473protected:
474    const char* format();
475
476    const char* opName() { return s_opNames[opB()]; }
477
478    unsigned opB() { return (m_opcode >> 9) & 0x7; }
479    unsigned rm() { return (m_opcode >> 6) & 0x7; }
480    unsigned rn() { return (m_opcode >> 3) & 0x7; }
481    unsigned rt() { return m_opcode & 0x7; }
482};
483
484class ARMv7DOpcodeLoadStoreRegisterSPRelative : public ARMv7D16BitOpcode {
485private:
486    static const char* const s_opNames[8];
487
488public:
489    static const uint16_t s_mask = 0xf000;
490    static const uint16_t s_pattern = 0x9000;
491
492    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLoadStoreRegisterSPRelative, thisObj);
493
494protected:
495    const char* format();
496
497    const char* opName() { return op() ? "ldr" : "str"; }
498
499    unsigned op() { return (m_opcode >> 11) & 0x1; }
500    unsigned rt() { return (m_opcode >> 8) & 0x7; }
501    unsigned immediate8() { return m_opcode & 0xff; }
502};
503
504class ARMv7DOpcodeLogicalImmediateT1 : public ARMv7D16BitOpcode {
505public:
506    static const uint16_t s_mask = 0xe000;
507    static const uint16_t s_pattern = 0x0000;
508
509    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeLogicalImmediateT1, thisObj);
510
511protected:
512    const char* format();
513
514    const char* opName() { return shiftName(op()); }
515
516    unsigned op() { return (m_opcode >> 12) & 0x3; }
517    unsigned immediate5() { return (m_opcode >> 6) & 0x1f; }
518};
519
520class ARMv7DOpcodeMiscAddSubSP : public ARMv7D16BitOpcode {
521public:
522    static const uint16_t s_mask = 0xff00;
523    static const uint16_t s_pattern = 0xb000;
524
525    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscAddSubSP, thisObj);
526
527protected:
528    const char* format();
529
530    const char* opName() { return op() ? "sub" : "add"; }
531    unsigned op() { return (m_opcode >> 7) & 0x1; }
532    unsigned immediate7() { return m_opcode & 0x7f; }
533};
534
535class ARMv7DOpcodeMiscByteHalfwordOps : public ARMv7D16BitOpcode {
536private:
537    static const char* const s_opNames[8];
538
539public:
540    static const uint16_t s_mask = 0xf700;
541    static const uint16_t s_pattern = 0xb200;
542
543    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscByteHalfwordOps, thisObj);
544
545protected:
546    const char* format();
547
548    const char* opName() { return s_opNames[op()]; }
549    unsigned op() { return ((m_opcode >> 9) & 0x4) || ((m_opcode >> 6) & 0x3); }
550};
551
552class ARMv7DOpcodeMiscBreakpointT1 : public ARMv7D16BitOpcode {
553public:
554    static const uint16_t s_mask = 0xff00;
555    static const uint16_t s_pattern = 0xbe00;
556
557    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscBreakpointT1, thisObj);
558
559protected:
560    const char* format();
561
562    unsigned immediate8() { return m_opcode & 0xff; }
563};
564
565class ARMv7DOpcodeMiscCompareAndBranch : public ARMv7D16BitOpcode {
566public:
567    static const uint16_t s_mask = 0xf500;
568    static const uint16_t s_pattern = 0xb100;
569
570    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscCompareAndBranch, thisObj);
571
572protected:
573    const char* format();
574
575    const char* opName() { return op() ? "cbnz" : "cbz"; }
576    unsigned op() { return (m_opcode >> 11) & 0x1; }
577    int32_t immediate6() { return ((m_opcode >> 4) & 0x20) | ((m_opcode >> 3) & 0x1f); }
578    unsigned rn() { return m_opcode & 0x7; }
579};
580
581class ARMv7DOpcodeMiscHint16 : public ARMv7D16BitOpcode {
582private:
583    static const char* const s_opNames[16];
584
585public:
586    static const uint16_t s_mask = 0xff0f;
587    static const uint16_t s_pattern = 0xbf00;
588
589    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscHint16, thisObj);
590
591protected:
592    const char* format();
593
594    const char* opName() { return s_opNames[opA()]; }
595    unsigned opA() { return (m_opcode >> 4) & 0xf; }
596};
597
598class ARMv7DOpcodeMiscIfThenT1 : public ARMv7D16BitOpcode {
599public:
600    static const uint16_t s_mask = 0xff00;
601    static const uint16_t s_pattern = 0xbf00;
602
603    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscIfThenT1, thisObj);
604
605protected:
606    const char* format();
607
608    unsigned firstCondition() { return (m_opcode >> 4) & 0xf; }
609    unsigned mask() { return m_opcode & 0xf; }
610};
611
612class ARMv7DOpcodeMiscPushPop : public ARMv7D16BitOpcode {
613public:
614    static const uint16_t s_mask = 0xf600;
615    static const uint16_t s_pattern = 0xb400;
616
617    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMiscPushPop, thisObj);
618
619protected:
620    const char* format();
621
622    const char* opName() { return op() ? "pop" : "push"; }
623    unsigned op() { return (m_opcode >> 11) & 0x1; }
624    unsigned registerMask() { return ((m_opcode << 6) & 0x4000) | (m_opcode & 0x7f); }
625};
626
627class ARMv7DOpcodeMoveImmediateT1 : public ARMv7D16BitOpcode {
628public:
629    static const uint16_t s_mask = 0xf800;
630    static const uint16_t s_pattern = 0x2000;
631
632    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMoveImmediateT1, thisObj);
633
634protected:
635    const char* format();
636
637    unsigned rd() { return (m_opcode >> 8) & 0x3; }
638    unsigned immediate8() { return m_opcode & 0xff; }
639};
640
641class ARMv7DOpcodeMoveRegisterT1 : public ARMv7D16BitOpcode {
642public:
643    static const uint16_t s_mask = 0xff00;
644    static const uint16_t s_pattern = 0x4600;
645
646    DEFINE_STATIC_FORMAT16(ARMv7DOpcodeMoveRegisterT1, thisObj);
647
648protected:
649    const char* format();
650
651    unsigned rd() { return ((m_opcode >> 4) & 0x8) | (m_opcode & 0x7); }
652    unsigned rm() { return ((m_opcode >> 3) & 0xf); }
653};
654
655// 32 Bit instructions
656
657#define DEFINE_STATIC_FORMAT32(klass, thisObj) \
658    static const char* format(ARMv7D32BitOpcode* thisObj) { return reinterpret_cast< klass *>(thisObj)->format(); }
659
660class ARMv7D32BitOpcode : public ARMv7DOpcode {
661private:
662    class OpcodeGroup {
663    public:
664        OpcodeGroup(uint32_t opcodeMask, uint32_t opcodePattern, const char* (*format)(ARMv7D32BitOpcode*))
665            : m_opcodeMask(opcodeMask)
666            , m_opcodePattern(opcodePattern)
667            , m_format(format)
668            , m_next(0)
669        {
670        }
671
672        void setNext(OpcodeGroup* next)
673        {
674            m_next = next;
675        }
676
677        OpcodeGroup* next()
678        {
679            return m_next;
680        }
681
682        bool matches(uint32_t opcode)
683        {
684            return (opcode & m_opcodeMask) == m_opcodePattern;
685        }
686
687        const char* format(ARMv7D32BitOpcode* thisObj)
688        {
689            return m_format(thisObj);
690        }
691
692    public:
693        static const unsigned opcodeTableSize = 16;
694        static const unsigned opcodeTableMask = opcodeTableSize-1;
695
696    private:
697        uint32_t m_opcodeMask;
698        uint32_t m_opcodePattern;
699        const char* (*m_format)(ARMv7D32BitOpcode*);
700        OpcodeGroup* m_next;
701    };
702
703public:
704    static void init();
705
706    const char* defaultFormat();
707    const char* doDisassemble();
708
709protected:
710    unsigned rd() { return (m_opcode >> 8) & 0xf; }
711    unsigned rm() { return m_opcode & 0xf; }
712    unsigned rn() { return (m_opcode >> 16) & 0xf; }
713    unsigned rt() { return (m_opcode >> 12) & 0xf; }
714
715    unsigned opcodeGroupNumber(unsigned opcode) { return (opcode >> 25) & OpcodeGroup::opcodeTableMask; }
716
717private:
718    static OpcodeGroup* opcodeTable[OpcodeGroup::opcodeTableSize];
719};
720
721class ARMv7DOpcodeBranchRelative : public ARMv7D32BitOpcode {
722protected:
723    unsigned sBit() { return (m_opcode >> 26) & 0x1; }
724    unsigned j1() { return (m_opcode >> 13) & 0x1; }
725    unsigned j2() { return (m_opcode >> 11) & 0x1; }
726    unsigned immediate11() { return m_opcode & 0x7ff; }
727};
728
729class ARMv7DOpcodeConditionalBranchT3 : public ARMv7DOpcodeBranchRelative {
730public:
731    static const uint32_t s_mask = 0xf800d000;
732    static const uint32_t s_pattern = 0xf0008000;
733
734    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeConditionalBranchT3, thisObj);
735
736protected:
737    const char* format();
738
739    int32_t offset() { return ((static_cast<int32_t>(sBit() << 31)) >> 12) | static_cast<int32_t>((j1() << 18) | (j2() << 17) | (immediate6() << 11) | immediate11()); }
740    unsigned condition() { return (m_opcode >> 22) & 0xf; }
741    unsigned immediate6() { return (m_opcode >> 16) & 0x3f; }
742};
743
744class ARMv7DOpcodeBranchOrBranchLink : public ARMv7DOpcodeBranchRelative {
745public:
746    static const uint32_t s_mask = 0xf8009000;
747    static const uint32_t s_pattern = 0xf0009000;
748
749    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeBranchOrBranchLink, thisObj);
750
751protected:
752    const char* format();
753
754    int32_t offset() { return ((static_cast<int32_t>(sBit() << 31)) >> 8) | static_cast<int32_t>((~(j1() ^ sBit()) << 22) | (~(j2() ^ sBit()) << 21) | (immediate10() << 11) | immediate11()); }
755    unsigned immediate10() { return (m_opcode >> 16) & 0x3ff; }
756    bool isBL() { return !!((m_opcode >> 14) & 0x1); }
757};
758
759class ARMv7DOpcodeDataProcessingLogicalAndRithmetic : public ARMv7D32BitOpcode {
760protected:
761    static const char* const s_opNames[16];
762};
763
764class ARMv7DOpcodeDataProcessingModifiedImmediate : public ARMv7DOpcodeDataProcessingLogicalAndRithmetic {
765private:
766    void appendImmShift(unsigned, unsigned);
767
768public:
769    static const uint32_t s_mask = 0xfa008000;
770    static const uint32_t s_pattern = 0xf0000000;
771
772    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingModifiedImmediate, thisObj);
773
774protected:
775    const char* format();
776    void appendModifiedImmediate(unsigned);
777
778    const char* opName() { return s_opNames[op()]; }
779
780    unsigned op() { return (m_opcode >> 21) & 0xf; }
781    unsigned sBit() { return (m_opcode >> 20) & 0x1; }
782    unsigned immediate12() { return ((m_opcode >> 15) & 0x0800) | ((m_opcode >> 4) & 0x0700) | (m_opcode & 0x00ff); }
783};
784
785class ARMv7DOpcodeDataProcessingShiftedReg : public ARMv7DOpcodeDataProcessingLogicalAndRithmetic {
786private:
787    void appendImmShift(unsigned, unsigned);
788
789public:
790    static const uint32_t s_mask = 0xfe000000;
791    static const uint32_t s_pattern = 0xea000000;
792
793    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingShiftedReg, thisObj);
794
795protected:
796    const char* format();
797
798    const char* opName() { return s_opNames[op()]; }
799
800    unsigned sBit() { return (m_opcode >> 20) & 0x1; }
801    unsigned op() { return (m_opcode >> 21) & 0xf; }
802    unsigned immediate5() { return ((m_opcode >> 10) & 0x1c) | ((m_opcode >> 6) & 0x3); }
803    unsigned type() { return (m_opcode >> 4) & 0x3; }
804    unsigned tbBit() { return (m_opcode >> 5) & 0x1; }
805    unsigned tBit() { return (m_opcode >> 4) & 0x1; }
806};
807
808class ARMv7DOpcodeDataProcessingReg : public ARMv7D32BitOpcode {
809protected:
810    unsigned op1() { return (m_opcode >> 20) & 0xf; }
811    unsigned op2() { return (m_opcode >> 4) & 0xf; }
812};
813
814class ARMv7DOpcodeDataProcessingRegShift : public ARMv7DOpcodeDataProcessingReg {
815public:
816    static const uint32_t s_mask = 0xffe0f0f0;
817    static const uint32_t s_pattern = 0xfa00f000;
818
819    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingRegShift, thisObj);
820
821protected:
822    const char* format();
823
824    const char* opName() { return shiftName((op1() >> 1) & 0x3); }
825};
826
827class ARMv7DOpcodeDataProcessingRegExtend : public ARMv7DOpcodeDataProcessingReg {
828private:
829    static const char* const s_opExtendNames[8];
830    static const char* const s_opExtendAndAddNames[8];
831
832public:
833    static const uint32_t s_mask = 0xff80f0c0;
834    static const uint32_t s_pattern = 0xfa00f080;
835
836    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingRegExtend, thisObj);
837
838protected:
839    const char* format();
840
841    const char* opExtendName() { return s_opExtendNames[op1()]; }
842    const char* opExtendAndAddName() { return s_opExtendAndAddNames[op1()]; }
843    unsigned rotate() { return (m_opcode >> 4) & 0x3; }
844};
845
846class ARMv7DOpcodeDataProcessingRegParallel : public ARMv7DOpcodeDataProcessingReg {
847private:
848    static const char* const s_opNames[16];
849
850public:
851    static const uint32_t s_mask = 0xff80f0e0;
852    static const uint32_t s_pattern = 0xfa00f000;
853
854    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingRegParallel, thisObj);
855
856protected:
857    const char* format();
858
859    const char* opName() { return s_opNames[((op1() & 0x7) << 1) | (op2() & 0x1)]; }
860};
861
862class ARMv7DOpcodeDataProcessingRegMisc : public ARMv7DOpcodeDataProcessingReg {
863private:
864    static const char* const s_opNames[16];
865
866public:
867    static const uint32_t s_mask = 0xffc0f0c0;
868    static const uint32_t s_pattern = 0xfa80f080;
869
870    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataProcessingRegMisc, thisObj);
871
872protected:
873    const char* format();
874
875    const char* opName() { return s_opNames[((op1() & 0x3) << 2) | (op2() & 0x3)]; }
876};
877
878class ARMv7DOpcodeHint32 : public ARMv7D32BitOpcode {
879private:
880    static const char* const s_opNames[8];
881
882public:
883    static const uint32_t s_mask = 0xfff0d000;
884    static const uint32_t s_pattern = 0xf3a08000;
885
886    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeHint32, thisObj);
887
888protected:
889    const char* format();
890
891    const char* opName() { return s_opNames[op()]; }
892
893    bool isDebugHint() { return (m_opcode & 0xf0) == 0xf0; }
894    unsigned debugOption() { return m_opcode & 0xf; }
895    unsigned op() { return m_opcode & 0x7; }
896};
897
898class ARMv7DOpcodeFPTransfer : public ARMv7D32BitOpcode {
899public:
900    static const uint32_t s_mask = 0xffc00e7f;
901    static const uint32_t s_pattern = 0xee000a10;
902
903    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeFPTransfer, thisObj);
904
905protected:
906    const char* format();
907
908    void appendFPRegister();
909
910    unsigned opH() { return (m_opcode >> 21) & 0x1; }
911    unsigned opL() { return (m_opcode >> 20) & 0x1; }
912    unsigned rt() { return (m_opcode >> 12) & 0xf; }
913    unsigned opC() { return (m_opcode >> 8) & 0x1; }
914    unsigned opB() { return (m_opcode >> 5) & 0x3; }
915    unsigned vd() { return ((m_opcode >> 3) & 0x10) | ((m_opcode >> 16) & 0xf); }
916    unsigned vn() { return ((m_opcode >> 7) & 0x1) | ((m_opcode >> 15) & 0x1e); }
917};
918
919class ARMv7DOpcodeDataLoad : public ARMv7D32BitOpcode {
920protected:
921    static const char* const s_opNames[8];
922
923protected:
924    const char* opName() { return s_opNames[op()]; }
925
926    unsigned op() { return ((m_opcode >> 22) & 0x4) | ((m_opcode >> 21) & 0x3); }
927};
928
929class ARMv7DOpcodeLoadRegister : public ARMv7DOpcodeDataLoad {
930public:
931    static const uint32_t s_mask = 0xfe900800;
932    static const uint32_t s_pattern = 0xf8100000;
933
934    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeLoadRegister, thisObj);
935
936protected:
937    const char* format();
938
939    unsigned immediate2() { return (m_opcode >> 4) & 0x3; }
940};
941
942class ARMv7DOpcodeLoadSignedImmediate : public ARMv7DOpcodeDataLoad {
943public:
944    static const uint32_t s_mask = 0xfe900800;
945    static const uint32_t s_pattern = 0xf8100800;
946
947    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeLoadSignedImmediate, thisObj);
948
949protected:
950    const char* format();
951
952    unsigned pBit() { return (m_opcode >> 10) & 0x1; }
953    unsigned uBit() { return (m_opcode >> 9) & 0x1; }
954    unsigned wBit() { return (m_opcode >> 8) & 0x1; }
955    unsigned immediate8() { return m_opcode & 0xff; }
956};
957
958class ARMv7DOpcodeLoadUnsignedImmediate : public ARMv7DOpcodeDataLoad {
959public:
960    static const uint32_t s_mask = 0xfe900000;
961    static const uint32_t s_pattern = 0xf8900000;
962
963    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeLoadUnsignedImmediate, thisObj);
964
965protected:
966    const char* format();
967
968    unsigned immediate12() { return m_opcode & 0xfff; }
969};
970
971class ARMv7DOpcodeLongMultipleDivide : public ARMv7D32BitOpcode {
972protected:
973    static const char* const s_opNames[8];
974    static const char* const s_smlalOpNames[4];
975    static const char* const s_smlaldOpNames[2];
976    static const char* const s_smlsldOpNames[2];
977
978public:
979    static const uint32_t s_mask = 0xff800000;
980    static const uint32_t s_pattern = 0xfb800000;
981
982    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeLongMultipleDivide, thisObj);
983
984protected:
985    const char* format();
986
987    const char* opName() { return s_opNames[op1()]; }
988    const char* smlalOpName() { return s_smlalOpNames[(nBit() << 1) | mBit()]; }
989    const char* smlaldOpName() { return s_smlaldOpNames[mBit()]; }
990    const char* smlsldOpName() { return s_smlsldOpNames[mBit()]; }
991
992    unsigned rdLo() { return rt(); }
993    unsigned rdHi() { return rd(); }
994    unsigned op1() { return (m_opcode >> 20) & 0x7; }
995    unsigned op2() { return (m_opcode >> 4) & 0xf; }
996    unsigned nBit() { return (m_opcode >> 5) & 0x1; }
997    unsigned mBit() { return (m_opcode >> 4) & 0x1; }
998};
999
1000class ARMv7DOpcodeDataPushPopSingle : public ARMv7D32BitOpcode {
1001public:
1002    static const uint32_t s_mask = 0xffef0fff;
1003    static const uint32_t s_pattern = 0xf84d0d04;
1004
1005    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeDataPushPopSingle, thisObj);
1006
1007protected:
1008    const char* format();
1009
1010    const char* opName() { return op() ? "pop" : "push"; }
1011    unsigned op() { return (m_opcode >> 20) & 0x1; }
1012};
1013
1014class ARMv7DOpcodeDataStoreSingle : public ARMv7D32BitOpcode {
1015protected:
1016    static const char* const s_opNames[4];
1017
1018protected:
1019    const char* opName() { return s_opNames[op()]; }
1020
1021    unsigned op() { return (m_opcode >> 21) & 0x3; }
1022};
1023
1024class ARMv7DOpcodeStoreSingleImmediate12 : public ARMv7DOpcodeDataStoreSingle {
1025public:
1026    static const uint32_t s_mask = 0xfff00000;
1027    static const uint32_t s_pattern = 0xf8c00000;
1028
1029    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeStoreSingleImmediate12, thisObj);
1030
1031    const char* format();
1032
1033protected:
1034    unsigned immediate12() { return m_opcode & 0xfff; }
1035};
1036
1037class ARMv7DOpcodeStoreSingleImmediate8 : public ARMv7DOpcodeDataStoreSingle {
1038public:
1039    static const uint32_t s_mask = 0xfff00800;
1040    static const uint32_t s_pattern = 0xf8400800;
1041
1042    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeStoreSingleImmediate8, thisObj);
1043
1044    const char* format();
1045
1046protected:
1047    unsigned pBit() { return (m_opcode >> 10) & 0x1; }
1048    unsigned uBit() { return (m_opcode >> 9) & 0x1; }
1049    unsigned wBit() { return (m_opcode >> 8) & 0x1; }
1050    unsigned immediate8() { return m_opcode & 0xff; }
1051};
1052
1053class ARMv7DOpcodeStoreSingleRegister : public ARMv7DOpcodeDataStoreSingle {
1054public:
1055    static const uint32_t s_mask = 0xfff00fc0;
1056    static const uint32_t s_pattern = 0xf8400000;
1057
1058    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeStoreSingleRegister, thisObj);
1059
1060protected:
1061    const char* format();
1062
1063    unsigned immediate2() { return (m_opcode >> 4) & 0x3; }
1064};
1065
1066class ARMv7DOpcodeUnmodifiedImmediate : public ARMv7D32BitOpcode {
1067protected:
1068    static const char* const s_opNames[16];
1069
1070public:
1071    static const uint32_t s_mask = 0xfa008000;
1072    static const uint32_t s_pattern = 0xf2000000;
1073
1074    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeUnmodifiedImmediate, thisObj);
1075
1076protected:
1077    const char* format();
1078
1079    const char* opName() { return s_opNames[op() >> 1]; }
1080
1081    unsigned op() { return (m_opcode >> 20) & 0x1f; }
1082    unsigned shBit() { return (m_opcode >> 21) & 0x1; }
1083    unsigned bitNumOrSatImmediate() { return m_opcode & 0x1f; }
1084    unsigned immediate5() { return ((m_opcode >> 9) & 0x1c) | ((m_opcode >> 6) & 0x3); }
1085    unsigned immediate12() { return ((m_opcode >> 15) & 0x0800) | ((m_opcode >> 4) & 0x0700) | (m_opcode & 0x00ff); }
1086    unsigned immediate16() { return ((m_opcode >> 4) & 0xf000) | ((m_opcode >> 15) & 0x0800) | ((m_opcode >> 4) & 0x0700) | (m_opcode & 0x00ff); }
1087};
1088
1089class ARMv7DOpcodeVMOVDoublePrecision : public ARMv7D32BitOpcode {
1090public:
1091    static const uint32_t s_mask = 0xffe00fd0;
1092    static const uint32_t s_pattern = 0xec400b10;
1093
1094    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVMOVDoublePrecision, thisObj);
1095
1096protected:
1097    const char* format();
1098
1099    unsigned op() { return (m_opcode >> 20) & 0x1; }
1100    unsigned rt2() { return (m_opcode >> 16) & 0xf; }
1101    unsigned rt() { return (m_opcode >> 16) & 0xf; }
1102    unsigned vm() { return (m_opcode & 0xf) | ((m_opcode >> 1) & 0x10); }
1103};
1104
1105class ARMv7DOpcodeVMOVSinglePrecision : public ARMv7D32BitOpcode {
1106public:
1107    static const uint32_t s_mask = 0xffe00fd0;
1108    static const uint32_t s_pattern = 0xec400a10;
1109
1110    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVMOVSinglePrecision, thisObj);
1111
1112protected:
1113    const char* format();
1114
1115    unsigned op() { return (m_opcode >> 20) & 0x1; }
1116    unsigned rt2() { return (m_opcode >> 16) & 0xf; }
1117    unsigned rt() { return (m_opcode >> 16) & 0xf; }
1118    unsigned vm() { return ((m_opcode << 1) & 0x1e) | ((m_opcode >> 5) & 0x1); }
1119};
1120
1121class ARMv7DOpcodeVMSR : public ARMv7D32BitOpcode {
1122public:
1123    static const uint32_t s_mask = 0xffef0fff;
1124    static const uint32_t s_pattern = 0xeee10a10;
1125
1126    DEFINE_STATIC_FORMAT32(ARMv7DOpcodeVMSR, thisObj);
1127
1128protected:
1129    const char* format();
1130
1131    unsigned opL() { return (m_opcode >> 20) & 0x1; }
1132    unsigned rt() { return (m_opcode >> 12) & 0xf; }
1133};
1134
1135
1136} } // namespace JSC::ARMv7Disassembler
1137
1138using JSC::ARMv7Disassembler::ARMv7DOpcode;
1139
1140#endif // #if USE(ARMV7_DISASSEMBLER)
1141
1142#endif // ARMv7DOpcode_h
1143