| Index: src/mips/disasm-mips.cc
|
| diff --git a/src/mips/disasm-mips.cc b/src/mips/disasm-mips.cc
|
| index f541e9143f5001e74a789cfca26f179301b399cd..8d50be1c0021f1c5d2358db38baa50b30c90352c 100644
|
| --- a/src/mips/disasm-mips.cc
|
| +++ b/src/mips/disasm-mips.cc
|
| @@ -59,6 +59,17 @@ class Decoder {
|
| int InstructionDecode(byte* instruction);
|
|
|
| private:
|
| + const uint32_t kMsaI8Mask = ((3U << 24) | ((1 << 6) - 1));
|
| + const uint32_t kMsaI5Mask = ((7U << 23) | ((1 << 6) - 1));
|
| + const uint32_t kMsaMI10Mask = (15U << 2);
|
| + const uint32_t kMsaBITMask = ((7U << 23) | ((1 << 6) - 1));
|
| + const uint32_t kMsaELMMask = (15U << 22);
|
| + const uint32_t kMsa3RMask = ((7U << 23) | ((1 << 6) - 1));
|
| + const uint32_t kMsa3RFMask = ((15U << 22) | ((1 << 6) - 1));
|
| + const uint32_t kMsaVECMask = (23U << 21);
|
| + const uint32_t kMsa2RMask = (7U << 18);
|
| + const uint32_t kMsa2RFMask = (15U << 17);
|
| +
|
| // Bottleneck functions to print into the out_buffer.
|
| void PrintChar(const char ch);
|
| void Print(const char* str);
|
| @@ -66,7 +77,9 @@ class Decoder {
|
| // Printing of common values.
|
| void PrintRegister(int reg);
|
| void PrintFPURegister(int freg);
|
| + void PrintMSARegister(int wreg);
|
| void PrintFPUStatusRegister(int freg);
|
| + void PrintMSAControlRegister(int creg);
|
| void PrintRs(Instruction* instr);
|
| void PrintRt(Instruction* instr);
|
| void PrintRd(Instruction* instr);
|
| @@ -100,12 +113,22 @@ class Decoder {
|
| void PrintPCImm26(Instruction* instr);
|
| void PrintCode(Instruction* instr); // For break and trap instructions.
|
| void PrintFormat(Instruction* instr); // For floating format postfix.
|
| + void PrintMsaDataFormat(Instruction* instr);
|
| + void PrintMsaXImm8(Instruction* instr);
|
| + void PrintMsaImm8(Instruction* instr);
|
| + void PrintMsaImm5(Instruction* instr);
|
| + void PrintMsaSImm5(Instruction* instr);
|
| + void PrintMsaSImm10(Instruction* instr, bool is_mi10 = false);
|
| + void PrintMsaImmBit(Instruction* instr);
|
| + void PrintMsaImmElm(Instruction* instr);
|
| + void PrintMsaCopy(Instruction* instr);
|
| // Printing of instruction name.
|
| void PrintInstructionName(Instruction* instr);
|
|
|
| // Handle formatting of instructions and their options.
|
| int FormatRegister(Instruction* instr, const char* option);
|
| int FormatFPURegister(Instruction* instr, const char* option);
|
| + int FormatMSARegister(Instruction* instr, const char* option);
|
| int FormatOption(Instruction* instr, const char* option);
|
| void Format(Instruction* instr, const char* format);
|
| void Unknown(Instruction* instr);
|
| @@ -123,6 +146,17 @@ class Decoder {
|
| void DecodeTypeRegister(Instruction* instr);
|
| void DecodeTypeImmediate(Instruction* instr);
|
| void DecodeTypeJump(Instruction* instr);
|
| + void DecodeTypeMsaI8(Instruction* instr);
|
| + void DecodeTypeMsaI5(Instruction* instr);
|
| + void DecodeTypeMsaI10(Instruction* instr);
|
| + void DecodeTypeMsaELM(Instruction* instr);
|
| + void DecodeTypeMsaBIT(Instruction* instr);
|
| + void DecodeTypeMsaMI10(Instruction* instr);
|
| + void DecodeTypeMsa3R(Instruction* instr);
|
| + void DecodeTypeMsa3RF(Instruction* instr);
|
| + void DecodeTypeMsaVec(Instruction* instr);
|
| + void DecodeTypeMsa2R(Instruction* instr);
|
| + void DecodeTypeMsa2RF(Instruction* instr);
|
|
|
| const disasm::NameConverter& converter_;
|
| v8::internal::Vector<char> out_buffer_;
|
| @@ -183,6 +217,7 @@ void Decoder::PrintFPURegister(int freg) {
|
| Print(converter_.NameOfXMMRegister(freg));
|
| }
|
|
|
| +void Decoder::PrintMSARegister(int wreg) { Print(MSARegisters::Name(wreg)); }
|
|
|
| void Decoder::PrintFPUStatusRegister(int freg) {
|
| switch (freg) {
|
| @@ -194,6 +229,18 @@ void Decoder::PrintFPUStatusRegister(int freg) {
|
| }
|
| }
|
|
|
| +void Decoder::PrintMSAControlRegister(int creg) {
|
| + switch (creg) {
|
| + case kMSAIRRegister:
|
| + Print("MSAIR");
|
| + break;
|
| + case kMSACSRRegister:
|
| + Print("MSACSR");
|
| + break;
|
| + default:
|
| + Print("no_msacreg");
|
| + }
|
| +}
|
|
|
| void Decoder::PrintFs(Instruction* instr) {
|
| int freg = instr->RsValue();
|
| @@ -441,6 +488,53 @@ void Decoder::PrintCode(Instruction* instr) {
|
| }
|
| }
|
|
|
| +void Decoder::PrintMsaXImm8(Instruction* instr) {
|
| + int32_t imm = instr->MsaImm8Value();
|
| + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
|
| +}
|
| +
|
| +void Decoder::PrintMsaImm8(Instruction* instr) {
|
| + int32_t imm = instr->MsaImm8Value();
|
| + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
|
| +}
|
| +
|
| +void Decoder::PrintMsaImm5(Instruction* instr) {
|
| + int32_t imm = instr->MsaImm5Value();
|
| + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", imm);
|
| +}
|
| +
|
| +void Decoder::PrintMsaSImm5(Instruction* instr) {
|
| + int32_t imm = instr->MsaImm5Value();
|
| + imm <<= (32 - kMsaImm5Bits);
|
| + imm >>= (32 - kMsaImm5Bits);
|
| + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
|
| +}
|
| +
|
| +void Decoder::PrintMsaSImm10(Instruction* instr, bool is_mi10) {
|
| + int32_t imm = is_mi10 ? instr->MsaImmMI10Value() : instr->MsaImm10Value();
|
| + imm <<= (32 - kMsaImm10Bits);
|
| + imm >>= (32 - kMsaImm10Bits);
|
| + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
|
| +}
|
| +
|
| +void Decoder::PrintMsaImmBit(Instruction* instr) {
|
| + int32_t m = instr->MsaBitMValue();
|
| + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", m);
|
| +}
|
| +
|
| +void Decoder::PrintMsaImmElm(Instruction* instr) {
|
| + int32_t n = instr->MsaElmNValue();
|
| + out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%u", n);
|
| +}
|
| +
|
| +void Decoder::PrintMsaCopy(Instruction* instr) {
|
| + int32_t rd = instr->WdValue();
|
| + int32_t ws = instr->WsValue();
|
| + int32_t n = instr->MsaElmNValue();
|
| + out_buffer_pos_ +=
|
| + SNPrintF(out_buffer_ + out_buffer_pos_, "%s, %s[%u]",
|
| + converter_.NameOfCPURegister(rd), MSARegisters::Name(ws), n);
|
| +}
|
|
|
| void Decoder::PrintFormat(Instruction* instr) {
|
| char formatLetter = ' ';
|
| @@ -464,6 +558,84 @@ void Decoder::PrintFormat(Instruction* instr) {
|
| PrintChar(formatLetter);
|
| }
|
|
|
| +void Decoder::PrintMsaDataFormat(Instruction* instr) {
|
| + DCHECK(instr->IsMSAInstr());
|
| + char df = ' ';
|
| + if (instr->IsMSABranchInstr()) {
|
| + switch (instr->RsFieldRaw()) {
|
| + case BZ_V:
|
| + case BNZ_V:
|
| + df = 'v';
|
| + break;
|
| + case BZ_B:
|
| + case BNZ_B:
|
| + df = 'b';
|
| + break;
|
| + case BZ_H:
|
| + case BNZ_H:
|
| + df = 'h';
|
| + break;
|
| + case BZ_W:
|
| + case BNZ_W:
|
| + df = 'w';
|
| + break;
|
| + case BZ_D:
|
| + case BNZ_D:
|
| + df = 'd';
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + } else {
|
| + char DF[] = {'b', 'h', 'w', 'd'};
|
| + switch (instr->MSAMinorOpcodeField()) {
|
| + case kMsaMinorI5:
|
| + case kMsaMinorI10:
|
| + case kMsaMinor3R:
|
| + df = DF[instr->Bits(22, 21)];
|
| + break;
|
| + case kMsaMinorMI10:
|
| + df = DF[instr->Bits(1, 0)];
|
| + break;
|
| + case kMsaMinorBIT:
|
| + df = DF[instr->MsaBitDf()];
|
| + break;
|
| + case kMsaMinorELM:
|
| + df = DF[instr->MsaElmDf()];
|
| + break;
|
| + case kMsaMinor3RF: {
|
| + uint32_t opcode = instr->InstructionBits() & kMsa3RFMask;
|
| + switch (opcode) {
|
| + case FEXDO:
|
| + case FTQ:
|
| + case MUL_Q:
|
| + case MADD_Q:
|
| + case MSUB_Q:
|
| + case MULR_Q:
|
| + case MADDR_Q:
|
| + case MSUBR_Q:
|
| + df = DF[1 + instr->Bit(21)];
|
| + break;
|
| + default:
|
| + df = DF[2 + instr->Bit(21)];
|
| + break;
|
| + }
|
| + } break;
|
| + case kMsaMinor2R:
|
| + df = DF[instr->Bits(17, 16)];
|
| + break;
|
| + case kMsaMinor2RF:
|
| + df = DF[2 + instr->Bit(16)];
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + }
|
| +
|
| + PrintChar(df);
|
| +}
|
|
|
| // Printing of instruction name.
|
| void Decoder::PrintInstructionName(Instruction* instr) {
|
| @@ -537,6 +709,27 @@ int Decoder::FormatFPURegister(Instruction* instr, const char* format) {
|
| return -1;
|
| }
|
|
|
| +// Handle all MSARegister based formatting in this function to reduce the
|
| +// complexity of FormatOption.
|
| +int Decoder::FormatMSARegister(Instruction* instr, const char* format) {
|
| + DCHECK(format[0] == 'w');
|
| + if (format[1] == 's') {
|
| + int reg = instr->WsValue();
|
| + PrintMSARegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 't') {
|
| + int reg = instr->WtValue();
|
| + PrintMSARegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 'd') {
|
| + int reg = instr->WdValue();
|
| + PrintMSARegister(reg);
|
| + return 2;
|
| + }
|
| +
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
|
|
| // FormatOption takes a formatting string and interprets it based on
|
| // the current instructions. The format string points to the first
|
| @@ -613,6 +806,16 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
| break;
|
| }
|
| return 6;
|
| + } else if (format[4] == '0' && format[5] == 's') {
|
| + DCHECK(STRING_STARTS_WITH(format, "imm10s"));
|
| + if (format[6] == '1') {
|
| + DCHECK(STRING_STARTS_WITH(format, "imm10s1"));
|
| + PrintMsaSImm10(instr, false);
|
| + } else if (format[6] == '2') {
|
| + DCHECK(STRING_STARTS_WITH(format, "imm10s2"));
|
| + PrintMsaSImm10(instr, true);
|
| + }
|
| + return 7;
|
| }
|
| } else if (format[3] == '2' && format[4] == '1') {
|
| DCHECK(STRING_STARTS_WITH(format, "imm21"));
|
| @@ -681,6 +884,28 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
| }
|
| }
|
| return 6;
|
| + } else if (format[3] == '5') {
|
| + DCHECK(STRING_STARTS_WITH(format, "imm5"));
|
| + if (format[4] == 'u') {
|
| + DCHECK(STRING_STARTS_WITH(format, "imm5u"));
|
| + PrintMsaImm5(instr);
|
| + } else if (format[4] == 's') {
|
| + DCHECK(STRING_STARTS_WITH(format, "imm5s"));
|
| + PrintMsaSImm5(instr);
|
| + }
|
| + return 5;
|
| + } else if (format[3] == '8') {
|
| + DCHECK(STRING_STARTS_WITH(format, "imm8"));
|
| + PrintMsaImm8(instr);
|
| + return 4;
|
| + } else if (format[3] == 'b') {
|
| + DCHECK(STRING_STARTS_WITH(format, "immb"));
|
| + PrintMsaImmBit(instr);
|
| + return 4;
|
| + } else if (format[3] == 'e') {
|
| + DCHECK(STRING_STARTS_WITH(format, "imme"));
|
| + PrintMsaImmElm(instr);
|
| + return 4;
|
| }
|
| }
|
| case 'r': { // 'r: registers.
|
| @@ -689,6 +914,9 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
| case 'f': { // 'f: FPUregisters.
|
| return FormatFPURegister(instr, format);
|
| }
|
| + case 'w': { // 'w: MSA Register
|
| + return FormatMSARegister(instr, format);
|
| + }
|
| case 's': { // 'sa.
|
| switch (format[1]) {
|
| case 'a':
|
| @@ -744,7 +972,11 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
| return 2;
|
| }
|
| case 't':
|
| - PrintFormat(instr);
|
| + if (instr->IsMSAInstr()) {
|
| + PrintMsaDataFormat(instr);
|
| + } else {
|
| + PrintFormat(instr);
|
| + }
|
| return 1;
|
| }
|
| UNREACHABLE();
|
| @@ -1401,6 +1633,27 @@ void Decoder::DecodeTypeRegister(Instruction* instr) {
|
| case SPECIAL3:
|
| DecodeTypeRegisterSPECIAL3(instr);
|
| break;
|
| + case MSA:
|
| + switch (instr->MSAMinorOpcodeField()) {
|
| + case kMsaMinor3R:
|
| + DecodeTypeMsa3R(instr);
|
| + break;
|
| + case kMsaMinor3RF:
|
| + DecodeTypeMsa3RF(instr);
|
| + break;
|
| + case kMsaMinorVEC:
|
| + DecodeTypeMsaVec(instr);
|
| + break;
|
| + case kMsaMinor2R:
|
| + DecodeTypeMsa2R(instr);
|
| + break;
|
| + case kMsaMinor2RF:
|
| + DecodeTypeMsa2RF(instr);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + break;
|
| default:
|
| UNREACHABLE();
|
| }
|
| @@ -1424,6 +1677,20 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
| case BC1NEZ:
|
| Format(instr, "bc1nez 'ft, 'imm16u -> 'imm16p4s2");
|
| break;
|
| + case BZ_V:
|
| + case BZ_B:
|
| + case BZ_H:
|
| + case BZ_W:
|
| + case BZ_D:
|
| + Format(instr, "bz.'t 'wt, 'imm16s -> 'imm16p4s2");
|
| + break;
|
| + case BNZ_V:
|
| + case BNZ_B:
|
| + case BNZ_H:
|
| + case BNZ_W:
|
| + case BNZ_D:
|
| + Format(instr, "bnz.'t 'wt, 'imm16s -> 'imm16p4s2");
|
| + break;
|
| default:
|
| UNREACHABLE();
|
| }
|
| @@ -1683,6 +1950,31 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
| }
|
| break;
|
| }
|
| + case MSA:
|
| + switch (instr->MSAMinorOpcodeField()) {
|
| + case kMsaMinorI8:
|
| + DecodeTypeMsaI8(instr);
|
| + break;
|
| + case kMsaMinorI5:
|
| + DecodeTypeMsaI5(instr);
|
| + break;
|
| + case kMsaMinorI10:
|
| + DecodeTypeMsaI10(instr);
|
| + break;
|
| + case kMsaMinorELM:
|
| + DecodeTypeMsaELM(instr);
|
| + break;
|
| + case kMsaMinorBIT:
|
| + DecodeTypeMsaBIT(instr);
|
| + break;
|
| + case kMsaMinorMI10:
|
| + DecodeTypeMsaMI10(instr);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + break;
|
| default:
|
| printf("a 0x%x \n", instr->OpcodeFieldRaw());
|
| UNREACHABLE();
|
| @@ -1704,6 +1996,636 @@ void Decoder::DecodeTypeJump(Instruction* instr) {
|
| }
|
| }
|
|
|
| +void Decoder::DecodeTypeMsaI8(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsaI8Mask;
|
| +
|
| + switch (opcode) {
|
| + case ANDI_B:
|
| + Format(instr, "andi.b 'wd, 'ws, 'imm8");
|
| + break;
|
| + case ORI_B:
|
| + Format(instr, "ori.b 'wd, 'ws, 'imm8");
|
| + break;
|
| + case NORI_B:
|
| + Format(instr, "nori.b 'wd, 'ws, 'imm8");
|
| + break;
|
| + case XORI_B:
|
| + Format(instr, "xori.b 'wd, 'ws, 'imm8");
|
| + break;
|
| + case BMNZI_B:
|
| + Format(instr, "bmnzi.b 'wd, 'ws, 'imm8");
|
| + break;
|
| + case BMZI_B:
|
| + Format(instr, "bmzi.b 'wd, 'ws, 'imm8");
|
| + break;
|
| + case BSELI_B:
|
| + Format(instr, "bseli.b 'wd, 'ws, 'imm8");
|
| + break;
|
| + case SHF_B:
|
| + Format(instr, "shf.b 'wd, 'ws, 'imm8");
|
| + break;
|
| + case SHF_H:
|
| + Format(instr, "shf.h 'wd, 'ws, 'imm8");
|
| + break;
|
| + case SHF_W:
|
| + Format(instr, "shf.w 'wd, 'ws, 'imm8");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsaI5(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsaI5Mask;
|
| +
|
| + switch (opcode) {
|
| + case ADDVI:
|
| + Format(instr, "addvi.'t 'wd, 'ws, 'imm5u");
|
| + break;
|
| + case SUBVI:
|
| + Format(instr, "subvi.'t 'wd, 'ws, 'imm5u");
|
| + break;
|
| + case MAXI_S:
|
| + Format(instr, "maxi_s.'t 'wd, 'ws, 'imm5s");
|
| + break;
|
| + case MAXI_U:
|
| + Format(instr, "maxi_u.'t 'wd, 'ws, 'imm5u");
|
| + break;
|
| + case MINI_S:
|
| + Format(instr, "mini_s.'t 'wd, 'ws, 'imm5s");
|
| + break;
|
| + case MINI_U:
|
| + Format(instr, "mini_u.'t 'wd, 'ws, 'imm5u");
|
| + break;
|
| + case CEQI:
|
| + Format(instr, "ceqi.'t 'wd, 'ws, 'imm5s");
|
| + break;
|
| + case CLTI_S:
|
| + Format(instr, "clti_s.'t 'wd, 'ws, 'imm5s");
|
| + break;
|
| + case CLTI_U:
|
| + Format(instr, "clti_u.'t 'wd, 'ws, 'imm5u");
|
| + break;
|
| + case CLEI_S:
|
| + Format(instr, "clei_s.'t 'wd, 'ws, 'imm5s");
|
| + break;
|
| + case CLEI_U:
|
| + Format(instr, "clei_u.'t 'wd, 'ws, 'imm5u");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsaI10(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsaI5Mask;
|
| + if (opcode == LDI) {
|
| + Format(instr, "ldi.'t 'wd, 'imm10s1");
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsaELM(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsaELMMask;
|
| + switch (opcode) {
|
| + case SLDI:
|
| + if (instr->Bits(21, 16) == 0x3E) {
|
| + Format(instr, "ctcmsa ");
|
| + PrintMSAControlRegister(instr->WdValue());
|
| + Print(", ");
|
| + PrintRegister(instr->WsValue());
|
| + } else {
|
| + Format(instr, "sldi.'t 'wd, 'ws['imme]");
|
| + }
|
| + break;
|
| + case SPLATI:
|
| + if (instr->Bits(21, 16) == 0x3E) {
|
| + Format(instr, "cfcmsa ");
|
| + PrintRegister(instr->WdValue());
|
| + Print(", ");
|
| + PrintMSAControlRegister(instr->WsValue());
|
| + } else {
|
| + Format(instr, "splati.'t 'wd, 'ws['imme]");
|
| + }
|
| + break;
|
| + case COPY_S:
|
| + if (instr->Bits(21, 16) == 0x3E) {
|
| + Format(instr, "move.v 'wd, 'ws");
|
| + } else {
|
| + Format(instr, "copy_s.'t ");
|
| + PrintMsaCopy(instr);
|
| + }
|
| + break;
|
| + case COPY_U:
|
| + Format(instr, "copy_u.'t ");
|
| + PrintMsaCopy(instr);
|
| + break;
|
| + case INSERT:
|
| + Format(instr, "insert.'t 'wd['imme], ");
|
| + PrintRegister(instr->WsValue());
|
| + break;
|
| + case INSVE:
|
| + Format(instr, "insve.'t 'wd['imme], 'ws[0]");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsaBIT(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsaBITMask;
|
| +
|
| + switch (opcode) {
|
| + case SLLI:
|
| + Format(instr, "slli.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case SRAI:
|
| + Format(instr, "srai.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case SRLI:
|
| + Format(instr, "srli.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case BCLRI:
|
| + Format(instr, "bclri.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case BSETI:
|
| + Format(instr, "bseti.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case BNEGI:
|
| + Format(instr, "bnegi.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case BINSLI:
|
| + Format(instr, "binsli.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case BINSRI:
|
| + Format(instr, "binsri.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case SAT_S:
|
| + Format(instr, "sat_s.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case SAT_U:
|
| + Format(instr, "sat_u.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case SRARI:
|
| + Format(instr, "srari.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + case SRLRI:
|
| + Format(instr, "srlri.'t 'wd, 'ws, 'immb");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsaMI10(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsaMI10Mask;
|
| + if (opcode == MSA_LD) {
|
| + Format(instr, "ld.'t 'wd, 'imm10s2(");
|
| + PrintRegister(instr->WsValue());
|
| + Print(")");
|
| + } else if (opcode == MSA_ST) {
|
| + Format(instr, "st.'t 'wd, 'imm10s2(");
|
| + PrintRegister(instr->WsValue());
|
| + Print(")");
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsa3R(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsa3RMask;
|
| + switch (opcode) {
|
| + case SLL_MSA:
|
| + Format(instr, "sll.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SRA_MSA:
|
| + Format(instr, "sra.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SRL_MSA:
|
| + Format(instr, "srl.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case BCLR:
|
| + Format(instr, "bclr.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case BSET:
|
| + Format(instr, "bset.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case BNEG:
|
| + Format(instr, "bneg.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case BINSL:
|
| + Format(instr, "binsl.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case BINSR:
|
| + Format(instr, "binsr.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ADDV:
|
| + Format(instr, "addv.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SUBV:
|
| + Format(instr, "subv.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MAX_S:
|
| + Format(instr, "max_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MAX_U:
|
| + Format(instr, "max_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MIN_S:
|
| + Format(instr, "min_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MIN_U:
|
| + Format(instr, "min_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MAX_A:
|
| + Format(instr, "max_a.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MIN_A:
|
| + Format(instr, "min_a.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case CEQ:
|
| + Format(instr, "ceq.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case CLT_S:
|
| + Format(instr, "clt_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case CLT_U:
|
| + Format(instr, "clt_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case CLE_S:
|
| + Format(instr, "cle_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case CLE_U:
|
| + Format(instr, "cle_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ADD_A:
|
| + Format(instr, "add_a.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ADDS_A:
|
| + Format(instr, "adds_a.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ADDS_S:
|
| + Format(instr, "adds_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ADDS_U:
|
| + Format(instr, "adds_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case AVE_S:
|
| + Format(instr, "ave_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case AVE_U:
|
| + Format(instr, "ave_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case AVER_S:
|
| + Format(instr, "aver_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case AVER_U:
|
| + Format(instr, "aver_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SUBS_S:
|
| + Format(instr, "subs_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SUBS_U:
|
| + Format(instr, "subs_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SUBSUS_U:
|
| + Format(instr, "subsus_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SUBSUU_S:
|
| + Format(instr, "subsuu_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ASUB_S:
|
| + Format(instr, "asub_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ASUB_U:
|
| + Format(instr, "asub_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MULV:
|
| + Format(instr, "mulv.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MADDV:
|
| + Format(instr, "maddv.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MSUBV:
|
| + Format(instr, "msubv.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case DIV_S_MSA:
|
| + Format(instr, "div_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case DIV_U:
|
| + Format(instr, "div_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MOD_S:
|
| + Format(instr, "mod_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MOD_U:
|
| + Format(instr, "mod_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case DOTP_S:
|
| + Format(instr, "dotp_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case DOTP_U:
|
| + Format(instr, "dotp_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case DPADD_S:
|
| + Format(instr, "dpadd_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case DPADD_U:
|
| + Format(instr, "dpadd_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case DPSUB_S:
|
| + Format(instr, "dpsub_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case DPSUB_U:
|
| + Format(instr, "dpsub_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SLD:
|
| + Format(instr, "sld.'t 'wd, 'ws['rt]");
|
| + break;
|
| + case SPLAT:
|
| + Format(instr, "splat.'t 'wd, 'ws['rt]");
|
| + break;
|
| + case PCKEV:
|
| + Format(instr, "pckev.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case PCKOD:
|
| + Format(instr, "pckod.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ILVL:
|
| + Format(instr, "ilvl.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ILVR:
|
| + Format(instr, "ilvr.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ILVEV:
|
| + Format(instr, "ilvev.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case ILVOD:
|
| + Format(instr, "ilvod.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case VSHF:
|
| + Format(instr, "vshf.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SRAR:
|
| + Format(instr, "srar.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case SRLR:
|
| + Format(instr, "srlr.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case HADD_S:
|
| + Format(instr, "hadd_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case HADD_U:
|
| + Format(instr, "hadd_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case HSUB_S:
|
| + Format(instr, "hsub_s.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case HSUB_U:
|
| + Format(instr, "hsub_u.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsa3RF(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsa3RFMask;
|
| + switch (opcode) {
|
| + case FCAF:
|
| + Format(instr, "fcaf.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCUN:
|
| + Format(instr, "fcun.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCEQ:
|
| + Format(instr, "fceq.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCUEQ:
|
| + Format(instr, "fcueq.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCLT:
|
| + Format(instr, "fclt.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCULT:
|
| + Format(instr, "fcult.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCLE:
|
| + Format(instr, "fcle.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCULE:
|
| + Format(instr, "fcule.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSAF:
|
| + Format(instr, "fsaf.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSUN:
|
| + Format(instr, "fsun.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSEQ:
|
| + Format(instr, "fseq.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSUEQ:
|
| + Format(instr, "fsueq.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSLT:
|
| + Format(instr, "fslt.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSULT:
|
| + Format(instr, "fsult.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSLE:
|
| + Format(instr, "fsle.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSULE:
|
| + Format(instr, "fsule.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FADD:
|
| + Format(instr, "fadd.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSUB:
|
| + Format(instr, "fsub.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FMUL:
|
| + Format(instr, "fmul.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FDIV:
|
| + Format(instr, "fdiv.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FMADD:
|
| + Format(instr, "fmadd.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FMSUB:
|
| + Format(instr, "fmsub.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FEXP2:
|
| + Format(instr, "fexp2.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FEXDO:
|
| + Format(instr, "fexdo.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FTQ:
|
| + Format(instr, "ftq.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FMIN:
|
| + Format(instr, "fmin.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FMIN_A:
|
| + Format(instr, "fmin_a.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FMAX:
|
| + Format(instr, "fmax.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FMAX_A:
|
| + Format(instr, "fmax_a.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCOR:
|
| + Format(instr, "fcor.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCUNE:
|
| + Format(instr, "fcune.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FCNE:
|
| + Format(instr, "fcne.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MUL_Q:
|
| + Format(instr, "mul_q.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MADD_Q:
|
| + Format(instr, "madd_q.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MSUB_Q:
|
| + Format(instr, "msub_q.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSOR:
|
| + Format(instr, "fsor.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSUNE:
|
| + Format(instr, "fsune.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case FSNE:
|
| + Format(instr, "fsne.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MULR_Q:
|
| + Format(instr, "mulr_q.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MADDR_Q:
|
| + Format(instr, "maddr_q.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + case MSUBR_Q:
|
| + Format(instr, "msubr_q.'t 'wd, 'ws, 'wt");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsaVec(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsaVECMask;
|
| + switch (opcode) {
|
| + case AND_V:
|
| + Format(instr, "and.v 'wd, 'ws, 'wt");
|
| + break;
|
| + case OR_V:
|
| + Format(instr, "or.v 'wd, 'ws, 'wt");
|
| + break;
|
| + case NOR_V:
|
| + Format(instr, "nor.v 'wd, 'ws, 'wt");
|
| + break;
|
| + case XOR_V:
|
| + Format(instr, "xor.v 'wd, 'ws, 'wt");
|
| + break;
|
| + case BMNZ_V:
|
| + Format(instr, "bmnz.v 'wd, 'ws, 'wt");
|
| + break;
|
| + case BMZ_V:
|
| + Format(instr, "bmz.v 'wd, 'ws, 'wt");
|
| + break;
|
| + case BSEL_V:
|
| + Format(instr, "bsel.v 'wd, 'ws, 'wt");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsa2R(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsa2RMask;
|
| + switch (opcode) {
|
| + case FILL: {
|
| + Format(instr, "fill.'t 'wd, ");
|
| + PrintRegister(instr->WsValue()); // rs value is in ws field
|
| + } break;
|
| + case PCNT:
|
| + Format(instr, "pcnt.'t 'wd, 'ws");
|
| + break;
|
| + case NLOC:
|
| + Format(instr, "nloc.'t 'wd, 'ws");
|
| + break;
|
| + case NLZC:
|
| + Format(instr, "nlzc.'t 'wd, 'ws");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +void Decoder::DecodeTypeMsa2RF(Instruction* instr) {
|
| + uint32_t opcode = instr->InstructionBits() & kMsa2RFMask;
|
| + switch (opcode) {
|
| + case FCLASS:
|
| + Format(instr, "fclass.'t 'wd, 'ws");
|
| + break;
|
| + case FTRUNC_S:
|
| + Format(instr, "ftrunc_s.'t 'wd, 'ws");
|
| + break;
|
| + case FTRUNC_U:
|
| + Format(instr, "ftrunc_u.'t 'wd, 'ws");
|
| + break;
|
| + case FSQRT:
|
| + Format(instr, "fsqrt.'t 'wd, 'ws");
|
| + break;
|
| + case FRSQRT:
|
| + Format(instr, "frsqrt.'t 'wd, 'ws");
|
| + break;
|
| + case FRCP:
|
| + Format(instr, "frcp.'t 'wd, 'ws");
|
| + break;
|
| + case FRINT:
|
| + Format(instr, "frint.'t 'wd, 'ws");
|
| + break;
|
| + case FLOG2:
|
| + Format(instr, "flog2.'t 'wd, 'ws");
|
| + break;
|
| + case FEXUPL:
|
| + Format(instr, "fexupl.'t 'wd, 'ws");
|
| + break;
|
| + case FEXUPR:
|
| + Format(instr, "fexupr.'t 'wd, 'ws");
|
| + break;
|
| + case FFQL:
|
| + Format(instr, "ffql.'t 'wd, 'ws");
|
| + break;
|
| + case FFQR:
|
| + Format(instr, "ffqr.'t 'wd, 'ws");
|
| + break;
|
| + case FTINT_S:
|
| + Format(instr, "ftint_s.'t 'wd, 'ws");
|
| + break;
|
| + case FTINT_U:
|
| + Format(instr, "ftint_u.'t 'wd, 'ws");
|
| + break;
|
| + case FFINT_S:
|
| + Format(instr, "ffint_s.'t 'wd, 'ws");
|
| + break;
|
| + case FFINT_U:
|
| + Format(instr, "ffint_u.'t 'wd, 'ws");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
|
|
| // Disassemble the instruction at *instr_ptr into the output buffer.
|
| int Decoder::InstructionDecode(byte* instr_ptr) {
|
|
|