160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes/*
260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes * Copyright (C) 2012 The Android Open Source Project
360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes *
460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes * you may not use this file except in compliance with the License.
660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes * You may obtain a copy of the License at
760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes *
860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes *
1060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes * Unless required by applicable law or agreed to in writing, software
1160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
1260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes * See the License for the specific language governing permissions and
1460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes * limitations under the License.
1560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes */
1660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
1760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes#include "disassembler_mips.h"
1860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
19cf7f19135f0e273f7b0136315633c2abfc715343Ian Rogers#include <ostream>
20c7dd295a4e0cc1d15c0c96088e55a85389bade74Ian Rogers#include <sstream>
2160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
2207ed66b5ae659c452cbe1ab20c3dbf1d6f546461Elliott Hughes#include "base/logging.h"
23e222ee0b794f941af4fb1b32fb8224e32942ea7bElliott Hughes#include "base/stringprintf.h"
2460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes#include "thread.h"
2560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
2660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesnamespace art {
2760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesnamespace mips {
2860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
2960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstruct MipsInstruction {
3060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  uint32_t mask;
3160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  uint32_t value;
3260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  const char* name;
3360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  const char* args_fmt;
3460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
3560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  bool Matches(uint32_t instruction) const {
3660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes    return (instruction & mask) == value;
3760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  }
3860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes};
3960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
4060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstatic const uint32_t kOpcodeShift = 26;
4160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
4260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstatic const uint32_t kCop1 = (17 << kOpcodeShift);
4360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
4460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstatic const uint32_t kITypeMask = (0x3f << kOpcodeShift);
4560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstatic const uint32_t kJTypeMask = (0x3f << kOpcodeShift);
4660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstatic const uint32_t kRTypeMask = ((0x3f << kOpcodeShift) | (0x3f));
47403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevicstatic const uint32_t kSpecial0Mask = (0x3f << kOpcodeShift);
4860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstatic const uint32_t kSpecial2Mask = (0x3f << kOpcodeShift);
492fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsenstatic const uint32_t kSpecial3Mask = (0x3f << kOpcodeShift);
5060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstatic const uint32_t kFpMask = kRTypeMask;
5160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
5260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstatic const MipsInstruction gMipsInstructions[] = {
5360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  // "sll r0, r0, 0" is the canonical "nop", used in delay slots.
5460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { 0xffffffff, 0, "nop", "" },
5560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
5660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  // R-type instructions.
5760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 0, "sll", "DTA", },
5860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  // 0, 1, movci
5992d9060c0cdff7c726549a9d9494e5655404bed7Alexey Frunze  { kRTypeMask | (0x1f << 21), 2, "srl", "DTA", },
6060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 3, "sra", "DTA", },
617d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 6), 4, "sllv", "DTS", },
627d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 6), 6, "srlv", "DTS", },
637d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 6), (1 << 6) | 6, "rotrv", "DTS", },
647d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 6), 7, "srav", "DTS", },
6560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 8, "jr", "S", },
667934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  { kRTypeMask | (0x1f << 11), 9 | (31 << 11), "jalr", "S", },  // rd = 31 is implicit.
67403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kRTypeMask | (0x1f << 11), 9, "jr", "S", },  // rd = 0 is implicit.
687934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  { kRTypeMask, 9, "jalr", "DS", },  // General case.
6960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask | (0x1f << 6), 10, "movz", "DST", },
7060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask | (0x1f << 6), 11, "movn", "DST", },
717934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  { kRTypeMask, 12, "syscall", "", },  // TODO: code
727934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  { kRTypeMask, 13, "break", "", },  // TODO: code
737934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  { kRTypeMask, 15, "sync", "", },  // TODO: type
7460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 16, "mfhi", "D", },
7560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 17, "mthi", "S", },
7660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 18, "mflo", "D", },
7760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 19, "mtlo", "S", },
787d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 6), 20, "dsllv", "DTS", },
797d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 6), 22, "dsrlv", "DTS", },
807d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 6), (1 << 6) | 22, "drotrv", "DTS", },
817d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 6), 23, "dsrav", "DTS", },
82027f0ff64c2512b9a5f1f54f3fea1bec481eb0f5Douglas Leung  { kRTypeMask | (0x1f << 6), 24, "mult", "ST", },
83027f0ff64c2512b9a5f1f54f3fea1bec481eb0f5Douglas Leung  { kRTypeMask | (0x1f << 6), 25, "multu", "ST", },
84027f0ff64c2512b9a5f1f54f3fea1bec481eb0f5Douglas Leung  { kRTypeMask | (0x1f << 6), 26, "div", "ST", },
85027f0ff64c2512b9a5f1f54f3fea1bec481eb0f5Douglas Leung  { kRTypeMask | (0x1f << 6), 27, "divu", "ST", },
86027f0ff64c2512b9a5f1f54f3fea1bec481eb0f5Douglas Leung  { kRTypeMask | (0x1f << 6), 24 + (2 << 6), "mul", "DST", },
87027f0ff64c2512b9a5f1f54f3fea1bec481eb0f5Douglas Leung  { kRTypeMask | (0x1f << 6), 24 + (3 << 6), "muh", "DST", },
88027f0ff64c2512b9a5f1f54f3fea1bec481eb0f5Douglas Leung  { kRTypeMask | (0x1f << 6), 26 + (2 << 6), "div", "DST", },
89027f0ff64c2512b9a5f1f54f3fea1bec481eb0f5Douglas Leung  { kRTypeMask | (0x1f << 6), 26 + (3 << 6), "mod", "DST", },
9060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 32, "add", "DST", },
9160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 33, "addu", "DST", },
9260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 34, "sub", "DST", },
9360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 35, "subu", "DST", },
9460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 36, "and", "DST", },
9560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 37, "or", "DST", },
9660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 38, "xor", "DST", },
9760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 39, "nor", "DST", },
9860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 42, "slt", "DST", },
9960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kRTypeMask, 43, "sltu", "DST", },
100403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kRTypeMask, 45, "daddu", "DST", },
101403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kRTypeMask, 46, "dsub", "DST", },
102403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kRTypeMask, 47, "dsubu", "DST", },
103403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  // TODO: tge[u], tlt[u], teg, tne
1047d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 21), 56, "dsll", "DTA", },
1057d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 21), 58, "dsrl", "DTA", },
1067d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 21), (1 << 21) | 58, "drotr", "DTA", },
1077d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 21), 59, "dsra", "DTA", },
1087d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 21), 60, "dsll32", "DTA", },
1097d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 21), 62, "dsrl32", "DTA", },
1107d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 21), (1 << 21) | 62, "drotr32", "DTA", },
1117d4152f3520a3899ab57b61b884a17a2ba49a2adChris Larsen  { kRTypeMask | (0x1f << 21), 63, "dsra32", "DTA", },
112403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic
113403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  // SPECIAL0
114cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kSpecial0Mask | 0x307ff, 1, "movf", "DSc" },
115cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kSpecial0Mask | 0x307ff, 0x10001, "movt", "DSc" },
116403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (2 << 6) | 24, "mul", "DST" },
117403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (3 << 6) | 24, "muh", "DST" },
118403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (2 << 6) | 25, "mulu", "DST" },
119403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (3 << 6) | 25, "muhu", "DST" },
120403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (2 << 6) | 26, "div", "DST" },
121403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (3 << 6) | 26, "mod", "DST" },
122403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (2 << 6) | 27, "divu", "DST" },
123403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (3 << 6) | 27, "modu", "DST" },
124403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (2 << 6) | 28, "dmul", "DST" },
125403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (3 << 6) | 28, "dmuh", "DST" },
126403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (2 << 6) | 29, "dmulu", "DST" },
127403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (3 << 6) | 29, "dmuhu", "DST" },
128403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (2 << 6) | 30, "ddiv", "DST" },
129403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (3 << 6) | 30, "dmod", "DST" },
130403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (2 << 6) | 31, "ddivu", "DST" },
131403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kSpecial0Mask | 0x7ff, (3 << 6) | 31, "dmodu", "DST" },
1322fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial0Mask | 0x7ff, (0 << 6) | 53, "seleqz", "DST" },
1332fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial0Mask | 0x7ff, (0 << 6) | 55, "selnez", "DST" },
1342fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial0Mask | (0x1f << 21) | 0x3f, (1 << 21) | 2, "rotr", "DTA", },
1352fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x10, "clz", "DS" },
1362fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x11, "clo", "DS" },
1372fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x12, "dclz", "DS" },
1382fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial0Mask | (0x1f << 16) | 0x7ff, (0x01 << 6) | 0x13, "dclo", "DS" },
139403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  // TODO: sdbbp
14060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
14160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  // SPECIAL2
14260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 2, "mul", "DST" },
14360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 32, "clz", "DS" },
144e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen  { kSpecial2Mask | 0x7ff, (28 << kOpcodeShift) | 33, "clo", "DS" },
14560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 0, "madd", "ST" },
14660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 1, "maddu", "ST" },
14760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 2, "mul", "DST" },
14860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 4, "msub", "ST" },
14960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kSpecial2Mask | 0xffff, (28 << kOpcodeShift) | 5, "msubu", "ST" },
1507934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  { kSpecial2Mask | 0x3f, (28 << kOpcodeShift) | 0x3f, "sdbbp", "" },  // TODO: code
15160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
1522fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  // SPECIAL3
1535c7aed3b9844e240cf785e5885524ac133a04396Alexey Frunze  { kSpecial3Mask | 0x3f, (31 << kOpcodeShift), "ext", "TSAZ", },
1542fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 3, "dext", "TSAZ", },
1555c7aed3b9844e240cf785e5885524ac133a04396Alexey Frunze  { kSpecial3Mask | 0x3f, (31 << kOpcodeShift) | 4, "ins", "TSAz", },
156e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen  { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f,
157e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    (31 << kOpcodeShift) | (16 << 6) | 32,
158e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "seb",
159e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "DT", },
160e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen  { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f,
161e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    (31 << kOpcodeShift) | (24 << 6) | 32,
162e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "seh",
163e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "DT", },
164e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen  { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f,
165e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    (31 << kOpcodeShift) | 32,
166e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "bitswap",
167e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "DT", },
168e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen  { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f,
169e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    (31 << kOpcodeShift) | 36,
170e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "dbitswap",
171e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "DT", },
172e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen  { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f,
173e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    (31 << kOpcodeShift) | (2 << 6) | 36,
174e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "dsbh",
175e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "DT", },
176e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen  { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f,
177e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    (31 << kOpcodeShift) | (5 << 6) | 36,
178e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "dshd",
179e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "DT", },
180e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen  { kSpecial3Mask | (0x1f << 21) | (0x1f << 6) | 0x3f,
181e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    (31 << kOpcodeShift) | (2 << 6) | 32,
182e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "wsbh",
183e384547851a9d9e5d89ae5bb4c16bfd7d93cc12eChris Larsen    "DT", },
1842fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x26, "sc", "Tl", },
1852fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x27, "scd", "Tl", },
1862fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x36, "ll", "Tl", },
1872fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kSpecial3Mask | 0x7f, (31 << kOpcodeShift) | 0x37, "lld", "Tl", },
1882fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen
18960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  // J-type instructions.
19060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kJTypeMask, 2 << kOpcodeShift, "j", "L" },
19160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kJTypeMask, 3 << kOpcodeShift, "jal", "L" },
19260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
19360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  // I-type instructions.
19460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask, 4 << kOpcodeShift, "beq", "STB" },
19560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask, 5 << kOpcodeShift, "bne", "STB" },
19660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (1 << 16), "bgez", "SB" },
19760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (0 << 16), "bltz", "SB" },
19860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (2 << 16), "bltzl", "SB" },
19960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (16 << 16), "bltzal", "SB" },
20060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (18 << 16), "bltzall", "SB" },
20160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask | (0x1f << 16), 6 << kOpcodeShift | (0 << 16), "blez", "SB" },
2024dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask, 6 << kOpcodeShift, "bgeuc", "STB" },
20360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask | (0x1f << 16), 7 << kOpcodeShift | (0 << 16), "bgtz", "SB" },
2044dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask, 7 << kOpcodeShift, "bltuc", "STB" },
205403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (6 << 16), "dahi", "Si", },
206403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask | (0x1f << 16), 1 << kOpcodeShift | (30 << 16), "dati", "Si", },
20760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
20860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { 0xffff0000, (4 << kOpcodeShift), "b", "B" },
20960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { 0xffff0000, (1 << kOpcodeShift) | (17 << 16), "bal", "B" },
21060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
2114dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask, 8 << kOpcodeShift, "beqc", "STB" },
2124dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
21360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask, 8 << kOpcodeShift, "addi", "TSi", },
21460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask, 9 << kOpcodeShift, "addiu", "TSi", },
21560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask, 10 << kOpcodeShift, "slti", "TSi", },
21660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask, 11 << kOpcodeShift, "sltiu", "TSi", },
21760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask, 12 << kOpcodeShift, "andi", "TSi", },
21860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  { kITypeMask, 13 << kOpcodeShift, "ori", "TSi", },
219403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask, 14 << kOpcodeShift, "xori", "TSi", },
220403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask | (0x1f << 21), 15 << kOpcodeShift, "lui", "TI", },
221403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask, 15 << kOpcodeShift, "aui", "TSI", },
2224dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
223cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kITypeMask | (0x3e3 << 16), (17 << kOpcodeShift) | (8 << 21), "bc1f", "cB" },
224cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kITypeMask | (0x3e3 << 16), (17 << kOpcodeShift) | (8 << 21) | (1 << 16), "bc1t", "cB" },
225cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kITypeMask | (0x1f << 21), (17 << kOpcodeShift) | (9 << 21), "bc1eqz", "tB" },
226cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kITypeMask | (0x1f << 21), (17 << kOpcodeShift) | (13 << 21), "bc1nez", "tB" },
227cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze
2284dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x1f << 21), 22 << kOpcodeShift, "blezc", "TB" },
2294dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
2304dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  // TODO: de-dup
2314dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (1  << 21) | (1  << 16), "bgezc", "TB" },
2324dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (2  << 21) | (2  << 16), "bgezc", "TB" },
2334dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (3  << 21) | (3  << 16), "bgezc", "TB" },
2344dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (4  << 21) | (4  << 16), "bgezc", "TB" },
2354dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (5  << 21) | (5  << 16), "bgezc", "TB" },
2364dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (6  << 21) | (6  << 16), "bgezc", "TB" },
2374dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (7  << 21) | (7  << 16), "bgezc", "TB" },
2384dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (8  << 21) | (8  << 16), "bgezc", "TB" },
2394dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (9  << 21) | (9  << 16), "bgezc", "TB" },
2404dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (10 << 21) | (10 << 16), "bgezc", "TB" },
2414dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (11 << 21) | (11 << 16), "bgezc", "TB" },
2424dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (12 << 21) | (12 << 16), "bgezc", "TB" },
2434dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (13 << 21) | (13 << 16), "bgezc", "TB" },
2444dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (14 << 21) | (14 << 16), "bgezc", "TB" },
2454dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (15 << 21) | (15 << 16), "bgezc", "TB" },
2464dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (16 << 21) | (16 << 16), "bgezc", "TB" },
2474dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (17 << 21) | (17 << 16), "bgezc", "TB" },
2484dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (18 << 21) | (18 << 16), "bgezc", "TB" },
2494dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (19 << 21) | (19 << 16), "bgezc", "TB" },
2504dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (20 << 21) | (20 << 16), "bgezc", "TB" },
2514dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (21 << 21) | (21 << 16), "bgezc", "TB" },
2524dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (22 << 21) | (22 << 16), "bgezc", "TB" },
2534dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (23 << 21) | (23 << 16), "bgezc", "TB" },
2544dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (24 << 21) | (24 << 16), "bgezc", "TB" },
2554dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (25 << 21) | (25 << 16), "bgezc", "TB" },
2564dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (26 << 21) | (26 << 16), "bgezc", "TB" },
2574dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (27 << 21) | (27 << 16), "bgezc", "TB" },
2584dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (28 << 21) | (28 << 16), "bgezc", "TB" },
2594dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (29 << 21) | (29 << 16), "bgezc", "TB" },
2604dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (30 << 21) | (30 << 16), "bgezc", "TB" },
2614dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (22 << kOpcodeShift) | (31 << 21) | (31 << 16), "bgezc", "TB" },
2624dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
2634dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask, 22 << kOpcodeShift, "bgec", "STB" },
2644dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
2654dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x1f << 21), 23 << kOpcodeShift, "bgtzc", "TB" },
2664dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
2674dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  // TODO: de-dup
2684dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (1  << 21) | (1  << 16), "bltzc", "TB" },
2694dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (2  << 21) | (2  << 16), "bltzc", "TB" },
2704dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (3  << 21) | (3  << 16), "bltzc", "TB" },
2714dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (4  << 21) | (4  << 16), "bltzc", "TB" },
2724dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (5  << 21) | (5  << 16), "bltzc", "TB" },
2734dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (6  << 21) | (6  << 16), "bltzc", "TB" },
2744dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (7  << 21) | (7  << 16), "bltzc", "TB" },
2754dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (8  << 21) | (8  << 16), "bltzc", "TB" },
2764dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (9  << 21) | (9  << 16), "bltzc", "TB" },
2774dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (10 << 21) | (10 << 16), "bltzc", "TB" },
2784dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (11 << 21) | (11 << 16), "bltzc", "TB" },
2794dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (12 << 21) | (12 << 16), "bltzc", "TB" },
2804dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (13 << 21) | (13 << 16), "bltzc", "TB" },
2814dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (14 << 21) | (14 << 16), "bltzc", "TB" },
2824dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (15 << 21) | (15 << 16), "bltzc", "TB" },
2834dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (16 << 21) | (16 << 16), "bltzc", "TB" },
2844dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (17 << 21) | (17 << 16), "bltzc", "TB" },
2854dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (18 << 21) | (18 << 16), "bltzc", "TB" },
2864dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (19 << 21) | (19 << 16), "bltzc", "TB" },
2874dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (20 << 21) | (20 << 16), "bltzc", "TB" },
2884dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (21 << 21) | (21 << 16), "bltzc", "TB" },
2894dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (22 << 21) | (22 << 16), "bltzc", "TB" },
2904dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (23 << 21) | (23 << 16), "bltzc", "TB" },
2914dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (24 << 21) | (24 << 16), "bltzc", "TB" },
2924dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (25 << 21) | (25 << 16), "bltzc", "TB" },
2934dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (26 << 21) | (26 << 16), "bltzc", "TB" },
2944dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (27 << 21) | (27 << 16), "bltzc", "TB" },
2954dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (28 << 21) | (28 << 16), "bltzc", "TB" },
2964dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (29 << 21) | (29 << 16), "bltzc", "TB" },
2974dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (30 << 21) | (30 << 16), "bltzc", "TB" },
2984dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x3ff << 16), (23 << kOpcodeShift) | (31 << 21) | (31 << 16), "bltzc", "TB" },
2994dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
3004dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask, 23 << kOpcodeShift, "bltc", "STB" },
3014dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
3024dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask, 24 << kOpcodeShift, "bnec", "STB" },
3034dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
304403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask, 25 << kOpcodeShift, "daddiu", "TSi", },
305403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask, 29 << kOpcodeShift, "daui", "TSi", },
30660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
307d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 32u << kOpcodeShift, "lb", "TO", },
308d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 33u << kOpcodeShift, "lh", "TO", },
3093acee732f9475fbfc6b046e0044b764e7ff5ac01Chris Larsen  { kITypeMask, 34u << kOpcodeShift, "lwl", "TO", },
310d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 35u << kOpcodeShift, "lw", "TO", },
311d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 36u << kOpcodeShift, "lbu", "TO", },
312d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 37u << kOpcodeShift, "lhu", "TO", },
3133acee732f9475fbfc6b046e0044b764e7ff5ac01Chris Larsen  { kITypeMask, 38u << kOpcodeShift, "lwr", "TO", },
314403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask, 39u << kOpcodeShift, "lwu", "TO", },
315d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 40u << kOpcodeShift, "sb", "TO", },
316d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 41u << kOpcodeShift, "sh", "TO", },
3173acee732f9475fbfc6b046e0044b764e7ff5ac01Chris Larsen  { kITypeMask, 42u << kOpcodeShift, "swl", "TO", },
318d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 43u << kOpcodeShift, "sw", "TO", },
3193acee732f9475fbfc6b046e0044b764e7ff5ac01Chris Larsen  { kITypeMask, 46u << kOpcodeShift, "swr", "TO", },
32051aff3a6564303cab0b7ac82495b4e2e349c6ff3Alexey Frunze  { kITypeMask, 48u << kOpcodeShift, "ll", "TO", },
321d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 49u << kOpcodeShift, "lwc1", "tO", },
3228c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic  { kJTypeMask, 50u << kOpcodeShift, "bc", "P" },
3238d36591d93920e7b7830c3ffee3759b561f5339eAndreas Gampe  { kITypeMask, 53u << kOpcodeShift, "ldc1", "tO", },
3244dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x1f << 21), 54u << kOpcodeShift, "jic", "Ti" },
3254dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 21), (54u << kOpcodeShift) | (1 << 21), "beqzc", "Sb" },  // TODO: de-dup?
3264dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 22), (54u << kOpcodeShift) | (1 << 22), "beqzc", "Sb" },
3274dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 23), (54u << kOpcodeShift) | (1 << 23), "beqzc", "Sb" },
3284dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 24), (54u << kOpcodeShift) | (1 << 24), "beqzc", "Sb" },
3294dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 25), (54u << kOpcodeShift) | (1 << 25), "beqzc", "Sb" },
330403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask, 55u << kOpcodeShift, "ld", "TO", },
33151aff3a6564303cab0b7ac82495b4e2e349c6ff3Alexey Frunze  { kITypeMask, 56u << kOpcodeShift, "sc", "TO", },
332d74e41b1cce5373aa24fd2fbea735173f6113d5aBrian Carlstrom  { kITypeMask, 57u << kOpcodeShift, "swc1", "tO", },
3334dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x1f << 16), (59u << kOpcodeShift) | (30 << 16), "auipc", "Si" },
3348c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic  { kITypeMask | (0x3 << 19), (59u << kOpcodeShift) | (0 << 19), "addiupc", "Sp" },
3358d36591d93920e7b7830c3ffee3759b561f5339eAndreas Gampe  { kITypeMask, 61u << kOpcodeShift, "sdc1", "tO", },
3364dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (0x1f << 21), 62u << kOpcodeShift, "jialc", "Ti" },
3374dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 21), (62u << kOpcodeShift) | (1 << 21), "bnezc", "Sb" },  // TODO: de-dup?
3384dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 22), (62u << kOpcodeShift) | (1 << 22), "bnezc", "Sb" },
3394dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 23), (62u << kOpcodeShift) | (1 << 23), "bnezc", "Sb" },
3404dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 24), (62u << kOpcodeShift) | (1 << 24), "bnezc", "Sb" },
3414dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  { kITypeMask | (1 << 25), (62u << kOpcodeShift) | (1 << 25), "bnezc", "Sb" },
342403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kITypeMask, 63u << kOpcodeShift, "sd", "TO", },
34360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
34460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  // Floating point.
345403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kFpMask | (0x1f << 21), kCop1 | (0x00 << 21), "mfc1", "Td" },
346403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kFpMask | (0x1f << 21), kCop1 | (0x01 << 21), "dmfc1", "Td" },
347403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kFpMask | (0x1f << 21), kCop1 | (0x03 << 21), "mfhc1", "Td" },
348403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kFpMask | (0x1f << 21), kCop1 | (0x04 << 21), "mtc1", "Td" },
349403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kFpMask | (0x1f << 21), kCop1 | (0x05 << 21), "dmtc1", "Td" },
350403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic  { kFpMask | (0x1f << 21), kCop1 | (0x07 << 21), "mthc1", "Td" },
351cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 1, "cmp.un.s", "adt" },
352cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 2, "cmp.eq.s", "adt" },
353cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 3, "cmp.ueq.s", "adt" },
354cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 4, "cmp.lt.s", "adt" },
355cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 5, "cmp.ult.s", "adt" },
356cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 6, "cmp.le.s", "adt" },
357cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 7, "cmp.ule.s", "adt" },
358cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 17, "cmp.or.s", "adt" },
359cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 18, "cmp.une.s", "adt" },
360cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x14 << 21) | 19, "cmp.ne.s", "adt" },
361cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 1, "cmp.un.d", "adt" },
362cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 2, "cmp.eq.d", "adt" },
363cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 3, "cmp.ueq.d", "adt" },
364cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 4, "cmp.lt.d", "adt" },
365cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 5, "cmp.ult.d", "adt" },
366cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 6, "cmp.le.d", "adt" },
367cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 7, "cmp.ule.d", "adt" },
368cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 17, "cmp.or.d", "adt" },
369cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 18, "cmp.une.d", "adt" },
370cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x1f << 21), kCop1 | (0x15 << 21) | 19, "cmp.ne.d", "adt" },
3711cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 0, "add", "fadt" },
3721cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 1, "sub", "fadt" },
3731cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 2, "mul", "fadt" },
3741cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 3, "div", "fadt" },
3751cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 4, "sqrt", "fad" },
3761cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 5, "abs", "fad" },
3771cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 6, "mov", "fad" },
3781cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 7, "neg", "fad" },
3791cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 8, "round.l", "fad" },
3801cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 9, "trunc.l", "fad" },
3811cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 10, "ceil.l", "fad" },
3821cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 11, "floor.l", "fad" },
3831cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 12, "round.w", "fad" },
3841cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 13, "trunc.w", "fad" },
3851cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 14, "ceil.w", "fad" },
3861cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 15, "floor.w", "fad" },
3872fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 26, "rint", "fad" },
3882fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 27, "class", "fad" },
3891cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 32, "cvt.s", "fad" },
3901cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 33, "cvt.d", "fad" },
3911cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 36, "cvt.w", "fad" },
3921cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 37, "cvt.l", "fad" },
3931cd27903529ee10229fa639dc8438a75517de492Douglas Leung  { kFpMask | (0x21f << 16), kCop1 | (0x200 << 16) | 38, "cvt.ps", "fad" },
394cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 49, "c.un", "fCdt" },
395cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 50, "c.eq", "fCdt" },
396cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 51, "c.ueq", "fCdt" },
397cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 52, "c.olt", "fCdt" },
398cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 53, "c.ult", "fCdt" },
399cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 54, "c.ole", "fCdt" },
400cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze  { kFpMask | (0x10 << 21), kCop1 | (0x10 << 21) | 55, "c.ule", "fCdt" },
4012fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kFpMask, kCop1 | 0x10, "sel", "fadt" },
4022fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kFpMask, kCop1 | 0x1e, "max", "fadt" },
4032fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen  { kFpMask, kCop1 | 0x1c, "min", "fadt" },
40460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes};
40560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
40660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesstatic uint32_t ReadU32(const uint8_t* ptr) {
4074f8f04ad94e68d2307a955d6bd72415fc0852725jeffhao  // We only support little-endian MIPS.
4084f8f04ad94e68d2307a955d6bd72415fc0852725jeffhao  return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
40960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes}
41060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
4112cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstromsize_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* instr_ptr) {
41260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  uint32_t instruction = ReadU32(instr_ptr);
41360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
4147934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  uint32_t rs = (instruction >> 21) & 0x1f;  // I-type, R-type.
4157934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  uint32_t rt = (instruction >> 16) & 0x1f;  // I-type, R-type.
4167934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  uint32_t rd = (instruction >> 11) & 0x1f;  // R-type.
4177934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  uint32_t sa = (instruction >>  6) & 0x1f;  // R-type.
41860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
41960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  std::string opcode;
42060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  std::ostringstream args;
42160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
42260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  // TODO: remove this!
42360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  uint32_t op = (instruction >> 26) & 0x3f;
4247934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom  uint32_t function = (instruction & 0x3f);  // R-type.
42560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  opcode = StringPrintf("op=%d fn=%d", op, function);
42660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
42760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  for (size_t i = 0; i < arraysize(gMipsInstructions); ++i) {
42860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes    if (gMipsInstructions[i].Matches(instruction)) {
42960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes      opcode = gMipsInstructions[i].name;
43060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes      for (const char* args_fmt = gMipsInstructions[i].args_fmt; *args_fmt; ++args_fmt) {
43160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes        switch (*args_fmt) {
4325c7aed3b9844e240cf785e5885524ac133a04396Alexey Frunze          case 'A':  // sa (shift amount or [d]ins/[d]ext position).
43360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            args << sa;
43460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            break;
4357934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom          case 'B':  // Branch offset.
43660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            {
43760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              int32_t offset = static_cast<int16_t>(instruction & 0xffff);
43860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              offset <<= 2;
4397934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom              offset += 4;  // Delay slot.
4402cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom              args << FormatInstructionPointer(instr_ptr + offset)
4412cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom                   << StringPrintf("  ; %+d", offset);
44260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            }
44360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            break;
4444dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze          case 'b':  // 21-bit branch offset.
4454dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze            {
4464dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze              int32_t offset = (instruction & 0x1fffff) - ((instruction & 0x100000) << 1);
4474dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze              offset <<= 2;
4484dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze              offset += 4;  // Delay slot.
4494dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze              args << FormatInstructionPointer(instr_ptr + offset)
4504dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze                   << StringPrintf("  ; %+d", offset);
4514dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze            }
4524dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze            break;
453cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze          case 'C':  // Floating-point condition code flag in c.<cond>.fmt.
454cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze            args << "cc" << (sa >> 2);
455cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze            break;
456cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze          case 'c':  // Floating-point condition code flag in bc1f/bc1t and movf/movt.
457cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze            args << "cc" << (rt >> 2);
458cd7b0ee296b0462961c63e51d99c9c323e2690dfAlexey Frunze            break;
45960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes          case 'D': args << 'r' << rd; break;
46060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes          case 'd': args << 'f' << rd; break;
4611cd27903529ee10229fa639dc8438a75517de492Douglas Leung          case 'a': args << 'f' << sa; break;
4627934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom          case 'f':  // Floating point "fmt".
46360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            {
4647934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom              size_t fmt = (instruction >> 21) & 0x7;  // TODO: other fmts?
46560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              switch (fmt) {
46660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes                case 0: opcode += ".s"; break;
46760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes                case 1: opcode += ".d"; break;
46860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes                case 4: opcode += ".w"; break;
46960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes                case 5: opcode += ".l"; break;
47060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes                case 6: opcode += ".ps"; break;
47160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes                default: opcode += ".?"; break;
47260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              }
4737934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom              continue;  // No ", ".
47460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            }
4757934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom          case 'I':  // Upper 16-bit immediate.
47660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            args << reinterpret_cast<void*>((instruction & 0xffff) << 16);
47760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            break;
4787934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom          case 'i':  // Sign-extended lower 16-bit immediate.
47960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            args << static_cast<int16_t>(instruction & 0xffff);
48060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            break;
4817934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom          case 'L':  // Jump label.
48260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            {
48360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              // TODO: is this right?
48460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              uint32_t instr_index = (instruction & 0x1ffffff);
48560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              uint32_t target = (instr_index << 2);
48660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              target |= (reinterpret_cast<uintptr_t>(instr_ptr + 4) & 0xf0000000);
48760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              args << reinterpret_cast<void*>(target);
48860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            }
48960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            break;
4902fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen          case 'l':  // 9-bit signed offset
4912fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen            {
4922fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen              int32_t offset = static_cast<int16_t>(instruction) >> 7;
4932fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen              args << StringPrintf("%+d(r%d)", offset, rs);
4942fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen            }
4952fadd7bb67abf5bc3c5370f9508cfb5959d6e536Chris Larsen            break;
4967934ac288acfb2552bb0b06ec1f61e5820d924a4Brian Carlstrom          case 'O':  // +x(rs)
49760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            {
49860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              int32_t offset = static_cast<int16_t>(instruction & 0xffff);
49960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              args << StringPrintf("%+d(r%d)", offset, rs);
50060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              if (rs == 17) {
50160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes                args << "  ; ";
502403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic                if (is64bit_) {
503403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic                  Thread::DumpThreadOffset<8>(args, offset);
504403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic                } else {
505403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic                  Thread::DumpThreadOffset<4>(args, offset);
506403e0d55a3e9c18d4228d0aab31dec0c908dc73dGoran Jakovljevic                }
50760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes              }
50860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            }
50960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes            break;
5108c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic          case 'P':  // 26-bit offset in bc.
5118c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic            {
5128c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic              int32_t offset = (instruction & 0x3ffffff) - ((instruction & 0x2000000) << 1);
5138c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic              offset <<= 2;
5148c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic              offset += 4;
5158c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic              args << FormatInstructionPointer(instr_ptr + offset);
5168c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic              args << StringPrintf("  ; %+d", offset);
5178c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic            }
5188c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic            break;
5198c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic          case 'p':  // 19-bit offset in addiupc.
5208c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic            {
5218c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic              int32_t offset = (instruction & 0x7ffff) - ((instruction & 0x40000) << 1);
5228c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic              args << offset << "  ; move r" << rs << ", ";
5238c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic              args << FormatInstructionPointer(instr_ptr + (offset << 2));
5248c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic            }
5258c434dcc78d497e18590461700894d1c3e96013dGoran Jakovljevic            break;
52660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes          case 'S': args << 'r' << rs; break;
52760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes          case 's': args << 'f' << rs; break;
52860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes          case 'T': args << 'r' << rt; break;
52960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes          case 't': args << 'f' << rt; break;
5305c7aed3b9844e240cf785e5885524ac133a04396Alexey Frunze          case 'Z': args << (rd + 1); break;  // sz ([d]ext size).
5315c7aed3b9844e240cf785e5885524ac133a04396Alexey Frunze          case 'z': args << (rd - sa + 1); break;  // sz ([d]ins size).
53260454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes        }
53360454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes        if (*(args_fmt + 1)) {
53460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes          args << ", ";
53560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes        }
53660454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes      }
53760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes      break;
53860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes    }
53960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  }
54060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
5414dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  // Special cases for sequences of:
5424dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  //   pc-relative +/- 2GB branch:
5434dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  //     auipc  reg, imm
5444dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  //     jic    reg, imm
5454dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  //   pc-relative +/- 2GB branch and link:
5464dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  //     auipc  reg, imm
5474dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  //     daddiu reg, reg, imm
5484dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  //     jialc  reg, 0
5494dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  if (((op == 0x36 && rs == 0 && rt != 0) ||  // jic
5504dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze       (op == 0x19 && rs == rt && rt != 0)) &&  // daddiu
5514dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze      last_ptr_ && (intptr_t)instr_ptr - (intptr_t)last_ptr_ == 4 &&
5524dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze      (last_instr_ & 0xFC1F0000) == 0xEC1E0000 &&  // auipc
5534dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze      ((last_instr_ >> 21) & 0x1F) == rt) {
5544dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze    uint32_t offset = (last_instr_ << 16) | (instruction & 0xFFFF);
5554dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze    offset -= (offset & 0x8000) << 1;
5564dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze    offset -= 4;
5574dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze    if (op == 0x36) {
5584dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze      args << "  ; b ";
5594dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze    } else {
5604dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze      args << "  ; move r" << rt << ", ";
5614dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze    }
5624dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze    args << FormatInstructionPointer(instr_ptr + (int32_t)offset);
5634dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze    args << StringPrintf("  ; %+d", (int32_t)offset);
5644dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  }
5654dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze
5662cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom  os << FormatInstructionPointer(instr_ptr)
5672cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom     << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str())
5682cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom     << args.str() << '\n';
5694dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  last_ptr_ = instr_ptr;
5704dda3376b71209fae07f5c3c8ac3eb4b54207aa8Alexey Frunze  last_instr_ = instruction;
571b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers  return 4;
572b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers}
573b23a7729cf7855fa05345d03a4d84111d5ec7172Ian Rogers
57460454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughesvoid DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
57560454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  for (const uint8_t* cur = begin; cur < end; cur += 4) {
5762cbaccb67e22c0b313a9785bfc65bcb4b25d0676Brian Carlstrom    Dump(os, cur);
57760454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes  }
57860454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes}
57960454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes
58060454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes}  // namespace mips
58160454e8b48663e6e5cb4bb301cec5edf93f8ce54Elliott Hughes}  // namespace art
582