}
+void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t j) {
+ DCHECK(rs.is_valid() && (is_uint21(j)));
+ Instr instr = opcode | (rs.code() << kRsShift) | (j & kImm21Mask);
+ emit(instr);
+}
+
+
+void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26) {
+ DCHECK(is_int26(offset26));
+ Instr instr = opcode | (offset26 & kImm26Mask);
+ emit(instr);
+}
+
+
void Assembler::GenInstrJump(Opcode opcode,
uint32_t address) {
BlockTrampolinePoolScope block_trampoline_pool(this);
}
+void Assembler::bc(int32_t offset) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ GenInstrImmediate(BC, offset);
+}
+
+
+void Assembler::balc(int32_t offset) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ positions_recorder()->WriteRecordedPositions();
+ GenInstrImmediate(BALC, offset);
+}
+
+
void Assembler::beq(Register rs, Register rt, int16_t offset) {
BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(BEQ, rs, rt, offset);
void Assembler::beqzc(Register rs, int32_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(!(rs.is(zero_reg)));
- Instr instr = BEQZC | (rs.code() << kRsShift) | offset;
+ Instr instr = POP66 | (rs.code() << kRsShift) | (offset & kImm21Mask);
emit(instr);
}
void Assembler::bnezc(Register rs, int32_t offset) {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(!(rs.is(zero_reg)));
- Instr instr = BNEZC | (rs.code() << kRsShift) | offset;
+ Instr instr = POP76 | (rs.code() << kRsShift) | offset;
emit(instr);
}
}
-void Assembler::j_or_jr(int32_t target, Register rs) {
- // Get pc of delay slot.
- uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
- bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
- (kImm26Bits + kImmFieldShift)) == 0;
- if (in_range) {
- j(target);
- } else {
- jr(t9);
- }
+void Assembler::jic(Register rt, int16_t offset) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ Instr instr = POP66 | (JIC << kRsShift) | (rt.code() << kRtShift) |
+ (offset & kImm16Mask);
+ emit(instr);
}
-void Assembler::jal_or_jalr(int32_t target, Register rs) {
- // Get pc of delay slot.
- uint32_t ipc = reinterpret_cast<uint32_t>(pc_ + 1 * kInstrSize);
- bool in_range = (ipc ^ static_cast<uint32_t>(target) >>
- (kImm26Bits+kImmFieldShift)) == 0;
- if (in_range) {
- jal(target);
- } else {
- jalr(t9);
- }
+void Assembler::jialc(Register rt, int16_t offset) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ positions_recorder()->WriteRecordedPositions();
+ GenInstrImmediate(POP76, zero_reg, rt, offset);
}
void Assembler::aui(Register rs, Register rt, int32_t j) {
// This instruction uses same opcode as 'lui'. The difference in encoding is
// 'lui' has zero reg. for rs field.
+ DCHECK(!(rs.is(zero_reg)));
DCHECK(is_uint16(j));
GenInstrImmediate(LUI, rs, rt, j);
}
+// ---------PC-Relative instructions-----------
+
+void Assembler::addiupc(Register rs, int32_t imm19) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ DCHECK(rs.is_valid() && is_int19(imm19));
+ int32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
+void Assembler::lwpc(Register rs, int32_t offset19) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ DCHECK(rs.is_valid() && is_int19(offset19));
+ int32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
+void Assembler::auipc(Register rs, int16_t imm16) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ DCHECK(rs.is_valid() && is_int16(imm16));
+ int32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
+void Assembler::aluipc(Register rs, int16_t imm16) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ DCHECK(rs.is_valid() && is_int16(imm16));
+ int32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
// -------------Misc-instructions--------------
// Break / Trap instructions.
void Assembler::bitswap(Register rd, Register rt) {
- DCHECK(kArchVariant == kMips32r6);
- GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BITSWAP);
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
}
}
+void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
+ DCHECK(IsMipsArchVariant(kMips32r6));
+ DCHECK(is_uint3(bp));
+ uint16_t sa = (ALIGN << kBp2Bits) | bp;
+ GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
+}
+
+
// --------Coprocessor-instructions----------------
// Load, store, move.
void b(Label* L) { b(branch_offset(L, false)>>2); }
void bal(int16_t offset);
void bal(Label* L) { bal(branch_offset(L, false)>>2); }
+ void bc(int32_t offset);
+ void bc(Label* L) { bc(branch_offset(L, false) >> 2); }
+ void balc(int32_t offset);
+ void balc(Label* L) { balc(branch_offset(L, false) >> 2); }
void beq(Register rs, Register rt, int16_t offset);
void beq(Register rs, Register rt, Label* L) {
void jal(int32_t target);
void jalr(Register rs, Register rd = ra);
void jr(Register target);
- void j_or_jr(int32_t target, Register rs);
- void jal_or_jalr(int32_t target, Register rs);
+ void jic(Register rt, int16_t offset);
+ void jialc(Register rt, int16_t offset);
// -------Data-processing-instructions---------
void swr(Register rd, const MemOperand& rs);
+ // ---------PC-Relative-instructions-----------
+
+ void addiupc(Register rs, int32_t imm19);
+ void lwpc(Register rs, int32_t offset19);
+ void auipc(Register rs, int16_t imm16);
+ void aluipc(Register rs, int16_t imm16);
+
+
// ----------------Prefetch--------------------
void pref(int32_t hint, const MemOperand& rs);
void ins_(Register rt, Register rs, uint16_t pos, uint16_t size);
void ext_(Register rt, Register rs, uint16_t pos, uint16_t size);
void bitswap(Register rd, Register rt);
+ void align(Register rd, Register rs, Register rt, uint8_t bp);
// --------Coprocessor-instructions----------------
Register r1,
FPURegister r2,
int32_t j);
+ void GenInstrImmediate(Opcode opcode, Register rs, int32_t j);
+ void GenInstrImmediate(Opcode opcode, int32_t offset26);
void GenInstrJump(Opcode opcode,
case BNEL:
case BLEZL:
case BGTZL:
+ case BC:
+ case BALC:
return true;
case REGIMM:
switch (RtFieldRaw()) {
switch (op) {
case JAL:
return true;
+ case POP76:
+ if (RsFieldRawNoAssert() == JIALC)
+ return true; // JIALC
+ else
+ return false; // BNEZC
case REGIMM:
switch (RtFieldRaw()) {
case BGEZAL:
switch (FunctionFieldRaw()) {
case INS:
case EXT:
- case BITSWAP:
return kRegisterType;
+ case BSHFL: {
+ int sa = SaFieldRaw() >> kSaShift;
+ switch (sa) {
+ case BITSWAP:
+ return kRegisterType;
+ case WSBH:
+ case SEB:
+ case SEH:
+ return kUnsupported;
+ }
+ sa >>= kBp2Bits;
+ switch (sa) {
+ case ALIGN:
+ return kRegisterType;
+ default:
+ return kUnsupported;
+ }
+ }
default:
return kUnsupported;
}
case BNEL:
case BLEZL:
case BGTZL:
- case BEQZC:
- case BNEZC:
+ case POP66:
+ case POP76:
case LB:
case LH:
case LWL:
case LDC1:
case SWC1:
case SDC1:
+ case PCREL:
+ case BC:
+ case BALC:
return kImmediateType;
// 26 bits immediate type instructions. e.g.: j imm26.
case J:
const int kFunctionShift = 0;
const int kFunctionBits = 6;
const int kLuiShift = 16;
+const int kBp2Shift = 6;
+const int kBp2Bits = 2;
const int kImm16Shift = 0;
const int kImm16Bits = 16;
+const int kImm18Shift = 0;
+const int kImm18Bits = 18;
+const int kImm19Shift = 0;
+const int kImm19Bits = 19;
const int kImm21Shift = 0;
const int kImm21Bits = 21;
const int kImm26Shift = 0;
// Instruction bit masks.
const int kOpcodeMask = ((1 << kOpcodeBits) - 1) << kOpcodeShift;
const int kImm16Mask = ((1 << kImm16Bits) - 1) << kImm16Shift;
+const int kImm18Mask = ((1 << kImm18Bits) - 1) << kImm18Shift;
+const int kImm19Mask = ((1 << kImm19Bits) - 1) << kImm19Shift;
+const int kImm21Mask = ((1 << kImm21Bits) - 1) << kImm21Shift;
const int kImm26Mask = ((1 << kImm26Bits) - 1) << kImm26Shift;
const int kImm28Mask = ((1 << kImm28Bits) - 1) << kImm28Shift;
const int kRsFieldMask = ((1 << kRsBits) - 1) << kRsShift;
// We use this presentation to stay close to the table representation in
// MIPS32 Architecture For Programmers, Volume II: The MIPS32 Instruction Set.
enum Opcode {
- SPECIAL = 0 << kOpcodeShift,
- REGIMM = 1 << kOpcodeShift,
-
- J = ((0 << 3) + 2) << kOpcodeShift,
- JAL = ((0 << 3) + 3) << kOpcodeShift,
- BEQ = ((0 << 3) + 4) << kOpcodeShift,
- BNE = ((0 << 3) + 5) << kOpcodeShift,
- BLEZ = ((0 << 3) + 6) << kOpcodeShift,
- BGTZ = ((0 << 3) + 7) << kOpcodeShift,
-
- ADDI = ((1 << 3) + 0) << kOpcodeShift,
- ADDIU = ((1 << 3) + 1) << kOpcodeShift,
- SLTI = ((1 << 3) + 2) << kOpcodeShift,
- SLTIU = ((1 << 3) + 3) << kOpcodeShift,
- ANDI = ((1 << 3) + 4) << kOpcodeShift,
- ORI = ((1 << 3) + 5) << kOpcodeShift,
- XORI = ((1 << 3) + 6) << kOpcodeShift,
- LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
-
- BEQC = ((2 << 3) + 0) << kOpcodeShift,
- COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
- BEQL = ((2 << 3) + 4) << kOpcodeShift,
- BNEL = ((2 << 3) + 5) << kOpcodeShift,
- BLEZL = ((2 << 3) + 6) << kOpcodeShift,
- BGTZL = ((2 << 3) + 7) << kOpcodeShift,
-
- DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
- SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
- SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
-
- LB = ((4 << 3) + 0) << kOpcodeShift,
- LH = ((4 << 3) + 1) << kOpcodeShift,
- LWL = ((4 << 3) + 2) << kOpcodeShift,
- LW = ((4 << 3) + 3) << kOpcodeShift,
- LBU = ((4 << 3) + 4) << kOpcodeShift,
- LHU = ((4 << 3) + 5) << kOpcodeShift,
- LWR = ((4 << 3) + 6) << kOpcodeShift,
- SB = ((5 << 3) + 0) << kOpcodeShift,
- SH = ((5 << 3) + 1) << kOpcodeShift,
- SWL = ((5 << 3) + 2) << kOpcodeShift,
- SW = ((5 << 3) + 3) << kOpcodeShift,
- SWR = ((5 << 3) + 6) << kOpcodeShift,
-
- LWC1 = ((6 << 3) + 1) << kOpcodeShift,
- LDC1 = ((6 << 3) + 5) << kOpcodeShift,
- BEQZC = ((6 << 3) + 6) << kOpcodeShift,
-
- PREF = ((6 << 3) + 3) << kOpcodeShift,
-
- SWC1 = ((7 << 3) + 1) << kOpcodeShift,
- SDC1 = ((7 << 3) + 5) << kOpcodeShift,
- BNEZC = ((7 << 3) + 6) << kOpcodeShift,
-
- COP1X = ((1 << 4) + 3) << kOpcodeShift
+ SPECIAL = 0 << kOpcodeShift,
+ REGIMM = 1 << kOpcodeShift,
+
+ J = ((0 << 3) + 2) << kOpcodeShift,
+ JAL = ((0 << 3) + 3) << kOpcodeShift,
+ BEQ = ((0 << 3) + 4) << kOpcodeShift,
+ BNE = ((0 << 3) + 5) << kOpcodeShift,
+ BLEZ = ((0 << 3) + 6) << kOpcodeShift,
+ BGTZ = ((0 << 3) + 7) << kOpcodeShift,
+
+ ADDI = ((1 << 3) + 0) << kOpcodeShift,
+ ADDIU = ((1 << 3) + 1) << kOpcodeShift,
+ SLTI = ((1 << 3) + 2) << kOpcodeShift,
+ SLTIU = ((1 << 3) + 3) << kOpcodeShift,
+ ANDI = ((1 << 3) + 4) << kOpcodeShift,
+ ORI = ((1 << 3) + 5) << kOpcodeShift,
+ XORI = ((1 << 3) + 6) << kOpcodeShift,
+ LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
+
+ BEQC = ((2 << 3) + 0) << kOpcodeShift,
+ COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
+ BEQL = ((2 << 3) + 4) << kOpcodeShift,
+ BNEL = ((2 << 3) + 5) << kOpcodeShift,
+ BLEZL = ((2 << 3) + 6) << kOpcodeShift,
+ BGTZL = ((2 << 3) + 7) << kOpcodeShift,
+
+ DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
+ SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
+ SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
+
+ LB = ((4 << 3) + 0) << kOpcodeShift,
+ LH = ((4 << 3) + 1) << kOpcodeShift,
+ LWL = ((4 << 3) + 2) << kOpcodeShift,
+ LW = ((4 << 3) + 3) << kOpcodeShift,
+ LBU = ((4 << 3) + 4) << kOpcodeShift,
+ LHU = ((4 << 3) + 5) << kOpcodeShift,
+ LWR = ((4 << 3) + 6) << kOpcodeShift,
+ SB = ((5 << 3) + 0) << kOpcodeShift,
+ SH = ((5 << 3) + 1) << kOpcodeShift,
+ SWL = ((5 << 3) + 2) << kOpcodeShift,
+ SW = ((5 << 3) + 3) << kOpcodeShift,
+ SWR = ((5 << 3) + 6) << kOpcodeShift,
+
+ LWC1 = ((6 << 3) + 1) << kOpcodeShift,
+ BC = ((6 << 3) + 2) << kOpcodeShift,
+ LDC1 = ((6 << 3) + 5) << kOpcodeShift,
+ POP66 = ((6 << 3) + 6) << kOpcodeShift,
+
+ PREF = ((6 << 3) + 3) << kOpcodeShift,
+
+ SWC1 = ((7 << 3) + 1) << kOpcodeShift,
+ BALC = ((7 << 3) + 2) << kOpcodeShift,
+ PCREL = ((7 << 3) + 3) << kOpcodeShift,
+ SDC1 = ((7 << 3) + 5) << kOpcodeShift,
+ POP76 = ((7 << 3) + 6) << kOpcodeShift,
+
+ COP1X = ((1 << 4) + 3) << kOpcodeShift
};
enum SecondaryField {
// SPECIAL3 Encoding of Function Field.
EXT = ((0 << 3) + 0),
INS = ((0 << 3) + 4),
- BITSWAP = ((4 << 3) + 0),
+ BSHFL = ((4 << 3) + 0),
+
+ // SPECIAL3 Encoding of sa Field.
+ BITSWAP = ((0 << 3) + 0),
+ ALIGN = ((0 << 3) + 2),
+ WSBH = ((0 << 3) + 2),
+ SEB = ((2 << 3) + 0),
+ SEH = ((3 << 3) + 0),
// REGIMM encoding of rt Field.
BLTZ = ((0 << 3) + 0) << 16,
// COP1X Encoding of Function Field.
MADD_D = ((4 << 3) + 1),
+ // PCREL Encoding of rt Field.
+ ADDIUPC = ((0 << 2) + 0),
+ LWPC = ((0 << 2) + 1),
+ AUIPC = ((3 << 3) + 6),
+ ALUIPC = ((3 << 3) + 7),
+
+ // POP66 Encoding of rs Field.
+ JIC = ((0 << 5) + 0),
+
+ // POP76 Encoding of rs Field.
+ JIALC = ((0 << 5) + 0),
+
NULLSF = 0
};
return Bits(kFrShift + kFrBits -1, kFrShift);
}
+ inline int Bp2Value() const {
+ DCHECK(InstructionType() == kRegisterType);
+ return Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift);
+ }
+
// Float Compare condition code instruction bits.
inline int FCccValue() const {
return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
}
inline int SaFieldRaw() const {
- DCHECK(InstructionType() == kRegisterType);
return InstructionBits() & kSaFieldMask;
}
return Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
}
+ inline int32_t Imm18Value() const {
+ DCHECK(InstructionType() == kImmediateType);
+ return Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift);
+ }
+
+ inline int32_t Imm19Value() const {
+ DCHECK(InstructionType() == kImmediateType);
+ return Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift);
+ }
+
inline int32_t Imm21Value() const {
DCHECK(InstructionType() == kImmediateType);
return Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift);
}
inline int32_t Imm26Value() const {
- DCHECK(InstructionType() == kJumpType);
+ DCHECK((InstructionType() == kJumpType) ||
+ (InstructionType() == kImmediateType));
return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
}
void PrintSs2(Instruction* instr);
void PrintBc(Instruction* instr);
void PrintCc(Instruction* instr);
+ void PrintBp2(Instruction* instr);
void PrintFunction(Instruction* instr);
void PrintSecondaryField(Instruction* instr);
void PrintUImm16(Instruction* instr);
void PrintSImm16(Instruction* instr);
void PrintXImm16(Instruction* instr);
+ void PrintXImm18(Instruction* instr);
+ void PrintSImm18(Instruction* instr);
+ void PrintXImm19(Instruction* instr);
+ void PrintSImm19(Instruction* instr);
void PrintXImm21(Instruction* instr);
+ void PrintSImm21(Instruction* instr);
void PrintXImm26(Instruction* instr);
+ void PrintSImm26(Instruction* instr);
void PrintCode(Instruction* instr); // For break and trap instructions.
void PrintFormat(Instruction* instr); // For floating format postfix.
// Printing of instruction name.
}
+void Decoder::PrintBp2(Instruction* instr) {
+ int bp2 = instr->Bp2Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", bp2);
+}
+
+
// Print 16-bit unsigned immediate value.
void Decoder::PrintUImm16(Instruction* instr) {
int32_t imm = instr->Imm16Value();
}
+// Print 18-bit signed immediate value.
+void Decoder::PrintSImm18(Instruction* instr) {
+ int32_t imm =
+ ((instr->Imm18Value()) << (32 - kImm18Bits)) >> (32 - kImm18Bits);
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
+}
+
+
+// Print 18-bit hexa immediate value.
+void Decoder::PrintXImm18(Instruction* instr) {
+ int32_t imm = instr->Imm18Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
+}
+
+
+// Print 19-bit hexa immediate value.
+void Decoder::PrintXImm19(Instruction* instr) {
+ int32_t imm = instr->Imm19Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
+}
+
+
+// Print 19-bit signed immediate value.
+void Decoder::PrintSImm19(Instruction* instr) {
+ int32_t imm19 = instr->Imm19Value();
+ // set sign
+ imm19 <<= (32 - kImm19Bits);
+ imm19 >>= (32 - kImm19Bits);
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm19);
+}
+
+
// Print 21-bit immediate value.
void Decoder::PrintXImm21(Instruction* instr) {
uint32_t imm = instr->Imm21Value();
}
-// Print 26-bit immediate value.
+// Print 21-bit signed immediate value.
+void Decoder::PrintSImm21(Instruction* instr) {
+ int32_t imm21 = instr->Imm21Value();
+ // set sign
+ imm21 <<= (32 - kImm21Bits);
+ imm21 >>= (32 - kImm21Bits);
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm21);
+}
+
+
+// Print 26-bit hex immediate value.
void Decoder::PrintXImm26(Instruction* instr) {
uint32_t imm = instr->Imm26Value() << kImmFieldShift;
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
+// Print 26-bit signed immediate value.
+void Decoder::PrintSImm26(Instruction* instr) {
+ int32_t imm26 = instr->Imm26Value();
+ // set sign
+ imm26 <<= (32 - kImm26Bits);
+ imm26 >>= (32 - kImm26Bits);
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm26);
+}
+
+
// Print 26-bit immediate value.
void Decoder::PrintCode(Instruction* instr) {
if (instr->OpcodeFieldRaw() != SPECIAL)
}
case 'i': { // 'imm16u or 'imm26.
if (format[3] == '1') {
- DCHECK(STRING_STARTS_WITH(format, "imm16"));
- if (format[5] == 's') {
- DCHECK(STRING_STARTS_WITH(format, "imm16s"));
- PrintSImm16(instr);
- } else if (format[5] == 'u') {
- DCHECK(STRING_STARTS_WITH(format, "imm16u"));
- PrintSImm16(instr);
- } else {
- DCHECK(STRING_STARTS_WITH(format, "imm16x"));
- PrintXImm16(instr);
+ if (format[4] == '6') {
+ DCHECK(STRING_STARTS_WITH(format, "imm16"));
+ switch (format[5]) {
+ case 's':
+ DCHECK(STRING_STARTS_WITH(format, "imm16s"));
+ PrintSImm16(instr);
+ break;
+ case 'u':
+ DCHECK(STRING_STARTS_WITH(format, "imm16u"));
+ PrintSImm16(instr);
+ break;
+ case 'x':
+ DCHECK(STRING_STARTS_WITH(format, "imm16x"));
+ PrintXImm16(instr);
+ break;
+ }
+ return 6;
+ } else if (format[4] == '8') {
+ DCHECK(STRING_STARTS_WITH(format, "imm18"));
+ switch (format[5]) {
+ case 's':
+ DCHECK(STRING_STARTS_WITH(format, "imm18s"));
+ PrintSImm18(instr);
+ break;
+ case 'x':
+ DCHECK(STRING_STARTS_WITH(format, "imm18x"));
+ PrintXImm18(instr);
+ break;
+ }
+ return 6;
+ } else if (format[4] == '9') {
+ DCHECK(STRING_STARTS_WITH(format, "imm19"));
+ switch (format[5]) {
+ case 's':
+ DCHECK(STRING_STARTS_WITH(format, "imm19s"));
+ PrintSImm19(instr);
+ break;
+ case 'x':
+ DCHECK(STRING_STARTS_WITH(format, "imm19x"));
+ PrintXImm19(instr);
+ break;
+ }
+ return 6;
}
- return 6;
} else if (format[3] == '2' && format[4] == '1') {
- DCHECK(STRING_STARTS_WITH(format, "imm21x"));
- PrintXImm21(instr);
+ DCHECK(STRING_STARTS_WITH(format, "imm21"));
+ switch (format[5]) {
+ case 's':
+ DCHECK(STRING_STARTS_WITH(format, "imm21s"));
+ PrintSImm21(instr);
+ break;
+ case 'x':
+ DCHECK(STRING_STARTS_WITH(format, "imm21x"));
+ PrintXImm21(instr);
+ break;
+ }
return 6;
} else if (format[3] == '2' && format[4] == '6') {
- DCHECK(STRING_STARTS_WITH(format, "imm26x"));
- PrintXImm26(instr);
+ DCHECK(STRING_STARTS_WITH(format, "imm26"));
+ switch (format[5]) {
+ case 's':
+ DCHECK(STRING_STARTS_WITH(format, "imm26s"));
+ PrintSImm26(instr);
+ break;
+ case 'x':
+ DCHECK(STRING_STARTS_WITH(format, "imm26x"));
+ PrintXImm26(instr);
+ break;
+ }
return 6;
}
}
}
}
}
- case 'b': { // 'bc - Special for bc1 cc field.
- DCHECK(STRING_STARTS_WITH(format, "bc"));
- PrintBc(instr);
- return 2;
+ case 'b': {
+ switch (format[1]) {
+ case 'c': { // 'bc - Special for bc1 cc field.
+ DCHECK(STRING_STARTS_WITH(format, "bc"));
+ PrintBc(instr);
+ return 2;
+ }
+ case 'p': {
+ switch (format[2]) {
+ case '2': { // 'bp2
+ DCHECK(STRING_STARTS_WITH(format, "bp2"));
+ PrintBp2(instr);
+ return 3;
+ }
+ }
+ }
+ }
}
case 'C': { // 'Cc - Special for c.xx.d cc field.
DCHECK(STRING_STARTS_WITH(format, "Cc"));
void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
switch (instr->FunctionFieldRaw()) {
case INS: {
- if (IsMipsArchVariant(kMips32r2)) {
+ if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
Format(instr, "ins 'rt, 'rs, 'sa, 'ss2");
} else {
Unknown(instr);
break;
}
case EXT: {
- if (IsMipsArchVariant(kMips32r2)) {
+ if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
Format(instr, "ext 'rt, 'rs, 'sa, 'ss1");
} else {
Unknown(instr);
}
break;
}
- case BITSWAP: {
- if (IsMipsArchVariant(kMips32r6)) {
- Format(instr, "bitswap 'rd, 'rt");
- } else {
- Unknown(instr);
+ case BSHFL: {
+ int sa = instr->SaFieldRaw() >> kSaShift;
+ switch (sa) {
+ case BITSWAP: {
+ if (IsMipsArchVariant(kMips32r6)) {
+ Format(instr, "bitswap 'rd, 'rt");
+ } else {
+ Unknown(instr);
+ }
+ break;
+ }
+ case SEB:
+ case SEH:
+ case WSBH:
+ UNREACHABLE();
+ break;
+ default: {
+ sa >>= kBp2Bits;
+ switch (sa) {
+ case ALIGN: {
+ if (IsMipsArchVariant(kMips32r6)) {
+ Format(instr, "align 'rd, 'rs, 'rt, 'bp2");
+ } else {
+ Unknown(instr);
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
}
break;
}
case BEQ:
Format(instr, "beq 'rs, 'rt, 'imm16u");
break;
+ case BC:
+ Format(instr, "bc 'imm26s");
+ break;
+ case BALC:
+ Format(instr, "balc 'imm26s");
+ break;
case BNE:
Format(instr, "bne 'rs, 'rt, 'imm16u");
break;
UNREACHABLE();
}
break;
- case BEQZC:
- if (instr->RsFieldRaw() != 0) {
- Format(instr, "beqzc 'rs, 'imm21x");
+ case POP66:
+ if (instr->RsValue() == JIC) {
+ Format(instr, "jic 'rt, 'imm16s");
+ } else {
+ Format(instr, "beqzc 'rs, 'imm21s");
}
break;
- case BNEZC:
- if (instr->RsFieldRaw() != 0) {
+ case POP76:
+ if (instr->RsValue() == JIALC) {
+ Format(instr, "jialc 'rt, 'imm16x");
+ } else {
Format(instr, "bnezc 'rs, 'imm21x");
}
break;
case SDC1:
Format(instr, "sdc1 'ft, 'imm16s('rs)");
break;
+ case PCREL: {
+ int32_t imm21 = instr->Imm21Value();
+ // rt field: 5-bits checking
+ uint8_t rt = (imm21 >> kImm16Bits);
+ switch (rt) {
+ case ALUIPC:
+ Format(instr, "aluipc 'rs, 'imm16s");
+ break;
+ case AUIPC:
+ Format(instr, "auipc 'rs, 'imm16s");
+ break;
+ default: {
+ // rt field: checking of the most significant 2-bits
+ rt = (imm21 >> kImm19Bits);
+ switch (rt) {
+ case LWPC:
+ Format(instr, "lwpc 'rs, 'imm19s");
+ break;
+ case ADDIUPC:
+ Format(instr, "addiupc 'rs, 'imm19s");
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
+ }
default:
printf("a 0x%x \n", instr->OpcodeFieldRaw());
UNREACHABLE();
const uint32_t rt_u = static_cast<uint32_t>(rt);
const int32_t rd_reg = instr->RdValue();
const uint32_t sa = instr->SaValue();
+ const uint8_t bp = instr->Bp2Value();
const int32_t fs_reg = instr->FsValue();
*alu_out = (rs_u & (mask << lsb)) >> lsb;
break;
}
- case BITSWAP: { // Mips32r6 instruction
- uint32_t input = static_cast<uint32_t>(rt);
- uint32_t output = 0;
- uint8_t i_byte, o_byte;
-
- // Reverse the bit in byte for each individual byte
- for (int i = 0; i < 4; i++) {
- output = output >> 8;
- i_byte = input & 0xff;
-
- // Fast way to reverse bits in byte
- // Devised by Sean Anderson, July 13, 2001
- o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
- (i_byte * 0x8020LU & 0x88440LU)) *
- 0x10101LU >>
- 16);
-
- output = output | (static_cast<uint32_t>(o_byte << 24));
- input = input >> 8;
- }
+ case BSHFL: {
+ int sa = instr->SaFieldRaw() >> kSaShift;
+ switch (sa) {
+ case BITSWAP: {
+ uint32_t input = static_cast<uint32_t>(rt);
+ uint32_t output = 0;
+ uint8_t i_byte, o_byte;
+
+ // Reverse the bit in byte for each individual byte
+ for (int i = 0; i < 4; i++) {
+ output = output >> 8;
+ i_byte = input & 0xff;
+
+ // Fast way to reverse bits in byte
+ // Devised by Sean Anderson, July 13, 2001
+ o_byte =
+ static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
+ (i_byte * 0x8020LU & 0x88440LU)) *
+ 0x10101LU >>
+ 16);
+
+ output = output | (static_cast<uint32_t>(o_byte << 24));
+ input = input >> 8;
+ }
- *alu_out = static_cast<int32_t>(output);
+ *alu_out = static_cast<int32_t>(output);
+ break;
+ }
+ case SEB:
+ case SEH:
+ case WSBH:
+ UNREACHABLE();
+ break;
+ default: {
+ sa >>= kBp2Bits;
+ switch (sa) {
+ case ALIGN: {
+ if (bp == 0) {
+ *alu_out = static_cast<int32_t>(rt);
+ } else {
+ uint32_t rt_hi = rt << (8 * bp);
+ uint32_t rs_lo = rs >> (8 * (4 - bp));
+ *alu_out = static_cast<int32_t>(rt_hi | rs_lo);
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
break;
}
default:
set_register(rt_reg, alu_out);
break;
case EXT:
- // Ext instr leaves result in Rt, rather than Rd.
set_register(rt_reg, alu_out);
break;
- case BITSWAP:
+ case BSHFL:
set_register(rd_reg, alu_out);
break;
default:
void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
+ int32_t rs_reg = instr->RsValue();
int32_t rs = get_register(instr->RsValue());
uint32_t rs_u = static_cast<uint32_t>(rs);
int32_t rt_reg = instr->RtValue(); // Destination register.
int32_t rt = get_register(rt_reg);
int16_t imm16 = instr->Imm16Value();
+ int32_t imm19 = instr->Imm19Value();
+ int32_t imm21 = instr->Imm21Value();
+ int32_t imm26 = instr->Imm26Value();
int32_t ft_reg = instr->FtValue(); // Destination register.
int64_t ft;
// Zero extended immediate.
uint32_t oe_imm16 = 0xffff & imm16;
// Sign extended immediate.
- int32_t se_imm16 = imm16;
+ int32_t se_imm16 = imm16;
+ int32_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfff80000 : 0);
+ int32_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfc000000 : 0);
+
// Get current pc.
int32_t current_pc = get_pc();
// Next pc.
int32_t next_pc = bad_ra;
+ // pc increment
+ int16_t pc_increment;
// Used for conditional branch instructions.
bool do_branch = false;
case BGTZ:
do_branch = rs > 0;
break;
+ case POP66: {
+ if (rs_reg) { // BEQZC
+ int32_t se_imm21 =
+ static_cast<int32_t>(imm21 << (kOpcodeBits + kRsBits));
+ se_imm21 = se_imm21 >> (kOpcodeBits + kRsBits);
+ if (rs == 0)
+ next_pc = current_pc + 4 + (se_imm21 << 2);
+ else
+ next_pc = current_pc + 4;
+ } else { // JIC
+ next_pc = rt + imm16;
+ }
+ break;
+ }
+ case BC: {
+ next_pc = current_pc + 4 + (se_imm26 << 2);
+ set_pc(next_pc);
+ pc_modified_ = true;
+ break;
+ }
+ case BALC: {
+ set_register(31, current_pc + 4);
+ next_pc = current_pc + 4 + (se_imm26 << 2);
+ set_pc(next_pc);
+ pc_modified_ = true;
+ break;
+ }
// ------------- Arithmetic instructions.
case ADDI:
if (HaveSameSign(rs, se_imm16)) {
case SDC1:
addr = rs + se_imm16;
break;
+ // ------------- JIALC and BNEZC instructions.
+ case POP76:
+ // Next pc.
+ next_pc = rt + se_imm16;
+ // The instruction after the jump is NOT executed.
+ pc_increment = Instruction::kInstrSize;
+ if (instr->IsLinkingInstruction()) {
+ set_register(31, current_pc + pc_increment);
+ }
+ set_pc(next_pc);
+ pc_modified_ = true;
+ break;
+ // ------------- PC-Relative instructions.
+ case PCREL: {
+ // rt field: checking 5-bits.
+ uint8_t rt = (imm21 >> kImm16Bits);
+ switch (rt) {
+ case ALUIPC:
+ addr = current_pc + (se_imm16 << 16);
+ alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
+ break;
+ case AUIPC:
+ alu_out = current_pc + (se_imm16 << 16);
+ break;
+ default: {
+ // rt field: checking the most significant 2-bits.
+ rt = (imm21 >> kImm19Bits);
+ switch (rt) {
+ case LWPC: {
+ int32_t offset = imm19;
+ // Set sign.
+ offset <<= (kOpcodeBits + kRsBits + 2);
+ offset >>= (kOpcodeBits + kRsBits + 2);
+ addr = current_pc + (offset << 2);
+ uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
+ alu_out = *ptr;
+ break;
+ }
+ case ADDIUPC:
+ alu_out = current_pc + (se_imm19 << 2);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ }
+ }
+ break;
+ }
default:
UNREACHABLE();
}
addr = rs + se_imm16;
WriteD(addr, get_fpu_register_double(ft_reg), instr);
break;
+ case PCREL:
+ set_register(rs_reg, alu_out);
default:
break;
}
}
+void Assembler::GenInstrImmediate(Opcode opcode, Register rs, int32_t j) {
+ DCHECK(rs.is_valid() && (is_uint21(j)));
+ Instr instr = opcode | (rs.code() << kRsShift) | (j & kImm21Mask);
+ emit(instr);
+}
+
+
+void Assembler::GenInstrImmediate(Opcode opcode, int32_t offset26) {
+ DCHECK(is_int26(offset26));
+ Instr instr = opcode | (offset26 & kImm26Mask);
+ emit(instr);
+}
+
+
void Assembler::GenInstrJump(Opcode opcode,
uint32_t address) {
BlockTrampolinePoolScope block_trampoline_pool(this);
}
}
- int32_t offset = target_pos - pc_offset();
+ int32_t offset = target_pos - (pc_offset() + kBranchPCOffset);
DCHECK((offset & 3) == 0);
DCHECK(((offset >> 2) & 0xFFE00000) == 0); // Offset is 21bit width.
}
+void Assembler::bc(int32_t offset) {
+ DCHECK(kArchVariant == kMips64r6);
+ GenInstrImmediate(BC, offset);
+}
+
+
+void Assembler::balc(int32_t offset) {
+ DCHECK(kArchVariant == kMips64r6);
+ positions_recorder()->WriteRecordedPositions();
+ GenInstrImmediate(BALC, offset);
+}
+
+
void Assembler::beq(Register rs, Register rt, int16_t offset) {
BlockTrampolinePoolScope block_trampoline_pool(this);
GenInstrImmediate(BEQ, rs, rt, offset);
void Assembler::beqzc(Register rs, int32_t offset) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(!(rs.is(zero_reg)));
- Instr instr = BEQZC | (rs.code() << kRsShift) | offset;
+ Instr instr = POP66 | (rs.code() << kRsShift) | (offset & kImm21Mask);
emit(instr);
}
void Assembler::bnezc(Register rs, int32_t offset) {
DCHECK(kArchVariant == kMips64r6);
DCHECK(!(rs.is(zero_reg)));
- Instr instr = BNEZC | (rs.code() << kRsShift) | offset;
+ Instr instr = POP76 | (rs.code() << kRsShift) | offset;
emit(instr);
}
}
-void Assembler::j_or_jr(int64_t target, Register rs) {
- // Get pc of delay slot.
- uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize);
- bool in_range = (ipc ^ static_cast<uint64_t>(target) >>
- (kImm26Bits + kImmFieldShift)) == 0;
- if (in_range) {
- j(target);
- } else {
- jr(t9);
- }
+void Assembler::jic(Register rt, int16_t offset) {
+ DCHECK(kArchVariant == kMips64r6);
+ Instr instr = POP66 | (JIC << kRsShift) | (rt.code() << kRtShift) |
+ (offset & kImm16Mask);
+ emit(instr);
}
-void Assembler::jal_or_jalr(int64_t target, Register rs) {
- // Get pc of delay slot.
- uint64_t ipc = reinterpret_cast<uint64_t>(pc_ + 1 * kInstrSize);
- bool in_range = (ipc ^ static_cast<uint64_t>(target) >>
- (kImm26Bits+kImmFieldShift)) == 0;
- if (in_range) {
- jal(target);
- } else {
- jalr(t9);
- }
+void Assembler::jialc(Register rt, int16_t offset) {
+ DCHECK(kArchVariant == kMips64r6);
+ positions_recorder()->WriteRecordedPositions();
+ GenInstrImmediate(POP76, zero_reg, rt, offset);
}
void Assembler::aui(Register rs, Register rt, int32_t j) {
// This instruction uses same opcode as 'lui'. The difference in encoding is
// 'lui' has zero reg. for rs field.
+ DCHECK(!(rs.is(zero_reg)));
DCHECK(is_uint16(j));
GenInstrImmediate(LUI, rs, rt, j);
}
}
+// ---------PC-Relative instructions-----------
+
+void Assembler::addiupc(Register rs, int32_t imm19) {
+ DCHECK(kArchVariant == kMips64r6);
+ DCHECK(rs.is_valid() && is_int19(imm19));
+ int32_t imm21 = ADDIUPC << kImm19Bits | (imm19 & kImm19Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
+void Assembler::lwpc(Register rs, int32_t offset19) {
+ DCHECK(kArchVariant == kMips64r6);
+ DCHECK(rs.is_valid() && is_int19(offset19));
+ int32_t imm21 = LWPC << kImm19Bits | (offset19 & kImm19Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
+void Assembler::lwupc(Register rs, int32_t offset19) {
+ DCHECK(kArchVariant == kMips64r6);
+ DCHECK(rs.is_valid() && is_int19(offset19));
+ int32_t imm21 = LWUPC << kImm19Bits | (offset19 & kImm19Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
+void Assembler::ldpc(Register rs, int32_t offset18) {
+ DCHECK(kArchVariant == kMips64r6);
+ DCHECK(rs.is_valid() && is_int18(offset18));
+ int32_t imm21 = LDPC << kImm18Bits | (offset18 & kImm18Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
+void Assembler::auipc(Register rs, int16_t imm16) {
+ DCHECK(kArchVariant == kMips64r6);
+ DCHECK(rs.is_valid() && is_int16(imm16));
+ int32_t imm21 = AUIPC << kImm16Bits | (imm16 & kImm16Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
+void Assembler::aluipc(Register rs, int16_t imm16) {
+ DCHECK(kArchVariant == kMips64r6);
+ DCHECK(rs.is_valid() && is_int16(imm16));
+ int32_t imm21 = ALUIPC << kImm16Bits | (imm16 & kImm16Mask);
+ GenInstrImmediate(PCREL, rs, imm21);
+}
+
+
// -------------Misc-instructions--------------
// Break / Trap instructions.
void Assembler::bitswap(Register rd, Register rt) {
DCHECK(kArchVariant == kMips64r6);
- GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BITSWAP);
+ GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, BSHFL);
}
void Assembler::dbitswap(Register rd, Register rt) {
DCHECK(kArchVariant == kMips64r6);
- GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, DBITSWAP);
+ GenInstrRegister(SPECIAL3, zero_reg, rt, rd, 0, DBSHFL);
}
}
+void Assembler::align(Register rd, Register rs, Register rt, uint8_t bp) {
+ DCHECK(kArchVariant == kMips64r6);
+ DCHECK(is_uint3(bp));
+ uint16_t sa = (ALIGN << kBp2Bits) | bp;
+ GenInstrRegister(SPECIAL3, rs, rt, rd, sa, BSHFL);
+}
+
+
+void Assembler::dalign(Register rd, Register rs, Register rt, uint8_t bp) {
+ DCHECK(kArchVariant == kMips64r6);
+ DCHECK(is_uint3(bp));
+ uint16_t sa = (DALIGN << kBp3Bits) | bp;
+ GenInstrRegister(SPECIAL3, rs, rt, rd, sa, DBSHFL);
+}
+
+
// --------Coprocessor-instructions----------------
// Load, store, move.
void b(Label* L) { b(branch_offset(L, false)>>2); }
void bal(int16_t offset);
void bal(Label* L) { bal(branch_offset(L, false)>>2); }
+ void bc(int32_t offset);
+ void bc(Label* L) { bc(branch_offset(L, false) >> 2); }
+ void balc(int32_t offset);
+ void balc(Label* L) { balc(branch_offset(L, false) >> 2); }
void beq(Register rs, Register rt, int16_t offset);
void beq(Register rs, Register rt, Label* L) {
void jal(int64_t target);
void jalr(Register rs, Register rd = ra);
void jr(Register target);
- void j_or_jr(int64_t target, Register rs);
- void jal_or_jalr(int64_t target, Register rs);
+ void jic(Register rt, int16_t offset);
+ void jialc(Register rt, int16_t offset);
// -------Data-processing-instructions---------
void sd(Register rd, const MemOperand& rs);
+ // ---------PC-Relative-instructions-----------
+
+ void addiupc(Register rs, int32_t imm19);
+ void lwpc(Register rs, int32_t offset19);
+ void lwupc(Register rs, int32_t offset19);
+ void ldpc(Register rs, int32_t offset18);
+ void auipc(Register rs, int16_t imm16);
+ void aluipc(Register rs, int16_t imm16);
+
+
// ----------------Prefetch--------------------
void pref(int32_t hint, const MemOperand& rs);
void dext_(Register rt, Register rs, uint16_t pos, uint16_t size);
void bitswap(Register rd, Register rt);
void dbitswap(Register rd, Register rt);
+ void align(Register rd, Register rs, Register rt, uint8_t bp);
+ void dalign(Register rd, Register rs, Register rt, uint8_t bp);
// --------Coprocessor-instructions----------------
Register r1,
FPURegister r2,
int32_t j);
+ void GenInstrImmediate(Opcode opcode, Register rs, int32_t j);
+ void GenInstrImmediate(Opcode opcode, int32_t offset26);
void GenInstrJump(Opcode opcode,
case BNEL:
case BLEZL:
case BGTZL:
+ case BC:
+ case BALC:
return true;
case REGIMM:
switch (RtFieldRaw()) {
switch (op) {
case JAL:
return true;
+ case POP76:
+ if (RsFieldRawNoAssert() == JIALC)
+ return true; // JIALC
+ else
+ return false; // BNEZC
case REGIMM:
switch (RtFieldRaw()) {
case BGEZAL:
case INS:
case EXT:
case DEXT:
- case BITSWAP:
- case DBITSWAP:
return kRegisterType;
+ case BSHFL: {
+ int sa = SaFieldRaw() >> kSaShift;
+ switch (sa) {
+ case BITSWAP:
+ return kRegisterType;
+ case WSBH:
+ case SEB:
+ case SEH:
+ return kUnsupported;
+ }
+ sa >>= kBp2Bits;
+ switch (sa) {
+ case ALIGN:
+ return kRegisterType;
+ default:
+ return kUnsupported;
+ }
+ }
+ case DBSHFL: {
+ int sa = SaFieldRaw() >> kSaShift;
+ switch (sa) {
+ case DBITSWAP:
+ return kRegisterType;
+ case DSBH:
+ case DSHD:
+ return kUnsupported;
+ }
+ sa = SaFieldRaw() >> kSaShift;
+ sa >>= kBp3Bits;
+ switch (sa) {
+ case DALIGN:
+ return kRegisterType;
+ default:
+ return kUnsupported;
+ }
+ }
default:
return kUnsupported;
}
case BNEL:
case BLEZL:
case BGTZL:
- case BEQZC:
- case BNEZC:
+ case POP66:
+ case POP76:
case LB:
case LH:
case LWL:
case LDC1:
case SWC1:
case SDC1:
+ case PCREL:
+ case BC:
+ case BALC:
return kImmediateType;
// 26 bits immediate type instructions. e.g.: j imm26.
case J:
const int kFunctionShift = 0;
const int kFunctionBits = 6;
const int kLuiShift = 16;
+const int kBp2Shift = 6;
+const int kBp2Bits = 2;
+const int kBp3Shift = 6;
+const int kBp3Bits = 3;
const int kImm16Shift = 0;
const int kImm16Bits = 16;
+const int kImm18Shift = 0;
+const int kImm18Bits = 18;
+const int kImm19Shift = 0;
+const int kImm19Bits = 19;
const int kImm21Shift = 0;
const int kImm21Bits = 21;
const int kImm26Shift = 0;
// Instruction bit masks.
const int kOpcodeMask = ((1 << kOpcodeBits) - 1) << kOpcodeShift;
const int kImm16Mask = ((1 << kImm16Bits) - 1) << kImm16Shift;
+const int kImm18Mask = ((1 << kImm18Bits) - 1) << kImm18Shift;
+const int kImm19Mask = ((1 << kImm19Bits) - 1) << kImm19Shift;
+const int kImm21Mask = ((1 << kImm21Bits) - 1) << kImm21Shift;
const int kImm26Mask = ((1 << kImm26Bits) - 1) << kImm26Shift;
const int kImm28Mask = ((1 << kImm28Bits) - 1) << kImm28Shift;
const int kRsFieldMask = ((1 << kRsBits) - 1) << kRsShift;
// We use this presentation to stay close to the table representation in
// MIPS32 Architecture For Programmers, Volume II: The MIPS32 Instruction Set.
enum Opcode {
- SPECIAL = 0 << kOpcodeShift,
- REGIMM = 1 << kOpcodeShift,
-
- J = ((0 << 3) + 2) << kOpcodeShift,
- JAL = ((0 << 3) + 3) << kOpcodeShift,
- BEQ = ((0 << 3) + 4) << kOpcodeShift,
- BNE = ((0 << 3) + 5) << kOpcodeShift,
- BLEZ = ((0 << 3) + 6) << kOpcodeShift,
- BGTZ = ((0 << 3) + 7) << kOpcodeShift,
-
- ADDI = ((1 << 3) + 0) << kOpcodeShift,
- ADDIU = ((1 << 3) + 1) << kOpcodeShift,
- SLTI = ((1 << 3) + 2) << kOpcodeShift,
- SLTIU = ((1 << 3) + 3) << kOpcodeShift,
- ANDI = ((1 << 3) + 4) << kOpcodeShift,
- ORI = ((1 << 3) + 5) << kOpcodeShift,
- XORI = ((1 << 3) + 6) << kOpcodeShift,
- LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
- DAUI = ((3 << 3) + 5) << kOpcodeShift,
-
- BEQC = ((2 << 3) + 0) << kOpcodeShift,
- COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
- BEQL = ((2 << 3) + 4) << kOpcodeShift,
- BNEL = ((2 << 3) + 5) << kOpcodeShift,
- BLEZL = ((2 << 3) + 6) << kOpcodeShift,
- BGTZL = ((2 << 3) + 7) << kOpcodeShift,
-
- DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
- DADDIU = ((3 << 3) + 1) << kOpcodeShift,
- LDL = ((3 << 3) + 2) << kOpcodeShift,
- LDR = ((3 << 3) + 3) << kOpcodeShift,
- SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
- SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
-
- LB = ((4 << 3) + 0) << kOpcodeShift,
- LH = ((4 << 3) + 1) << kOpcodeShift,
- LWL = ((4 << 3) + 2) << kOpcodeShift,
- LW = ((4 << 3) + 3) << kOpcodeShift,
- LBU = ((4 << 3) + 4) << kOpcodeShift,
- LHU = ((4 << 3) + 5) << kOpcodeShift,
- LWR = ((4 << 3) + 6) << kOpcodeShift,
- LWU = ((4 << 3) + 7) << kOpcodeShift,
-
- SB = ((5 << 3) + 0) << kOpcodeShift,
- SH = ((5 << 3) + 1) << kOpcodeShift,
- SWL = ((5 << 3) + 2) << kOpcodeShift,
- SW = ((5 << 3) + 3) << kOpcodeShift,
- SDL = ((5 << 3) + 4) << kOpcodeShift,
- SDR = ((5 << 3) + 5) << kOpcodeShift,
- SWR = ((5 << 3) + 6) << kOpcodeShift,
-
- LWC1 = ((6 << 3) + 1) << kOpcodeShift,
- LLD = ((6 << 3) + 4) << kOpcodeShift,
- LDC1 = ((6 << 3) + 5) << kOpcodeShift,
- BEQZC = ((6 << 3) + 6) << kOpcodeShift,
- LD = ((6 << 3) + 7) << kOpcodeShift,
-
- PREF = ((6 << 3) + 3) << kOpcodeShift,
-
- SWC1 = ((7 << 3) + 1) << kOpcodeShift,
- SCD = ((7 << 3) + 4) << kOpcodeShift,
- SDC1 = ((7 << 3) + 5) << kOpcodeShift,
- BNEZC = ((7 << 3) + 6) << kOpcodeShift,
- SD = ((7 << 3) + 7) << kOpcodeShift,
-
- COP1X = ((1 << 4) + 3) << kOpcodeShift
+ SPECIAL = 0 << kOpcodeShift,
+ REGIMM = 1 << kOpcodeShift,
+
+ J = ((0 << 3) + 2) << kOpcodeShift,
+ JAL = ((0 << 3) + 3) << kOpcodeShift,
+ BEQ = ((0 << 3) + 4) << kOpcodeShift,
+ BNE = ((0 << 3) + 5) << kOpcodeShift,
+ BLEZ = ((0 << 3) + 6) << kOpcodeShift,
+ BGTZ = ((0 << 3) + 7) << kOpcodeShift,
+
+ ADDI = ((1 << 3) + 0) << kOpcodeShift,
+ ADDIU = ((1 << 3) + 1) << kOpcodeShift,
+ SLTI = ((1 << 3) + 2) << kOpcodeShift,
+ SLTIU = ((1 << 3) + 3) << kOpcodeShift,
+ ANDI = ((1 << 3) + 4) << kOpcodeShift,
+ ORI = ((1 << 3) + 5) << kOpcodeShift,
+ XORI = ((1 << 3) + 6) << kOpcodeShift,
+ LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
+ DAUI = ((3 << 3) + 5) << kOpcodeShift,
+
+ BEQC = ((2 << 3) + 0) << kOpcodeShift,
+ COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
+ BEQL = ((2 << 3) + 4) << kOpcodeShift,
+ BNEL = ((2 << 3) + 5) << kOpcodeShift,
+ BLEZL = ((2 << 3) + 6) << kOpcodeShift,
+ BGTZL = ((2 << 3) + 7) << kOpcodeShift,
+
+ DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
+ DADDIU = ((3 << 3) + 1) << kOpcodeShift,
+ LDL = ((3 << 3) + 2) << kOpcodeShift,
+ LDR = ((3 << 3) + 3) << kOpcodeShift,
+ SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
+ SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
+
+ LB = ((4 << 3) + 0) << kOpcodeShift,
+ LH = ((4 << 3) + 1) << kOpcodeShift,
+ LWL = ((4 << 3) + 2) << kOpcodeShift,
+ LW = ((4 << 3) + 3) << kOpcodeShift,
+ LBU = ((4 << 3) + 4) << kOpcodeShift,
+ LHU = ((4 << 3) + 5) << kOpcodeShift,
+ LWR = ((4 << 3) + 6) << kOpcodeShift,
+ LWU = ((4 << 3) + 7) << kOpcodeShift,
+
+ SB = ((5 << 3) + 0) << kOpcodeShift,
+ SH = ((5 << 3) + 1) << kOpcodeShift,
+ SWL = ((5 << 3) + 2) << kOpcodeShift,
+ SW = ((5 << 3) + 3) << kOpcodeShift,
+ SDL = ((5 << 3) + 4) << kOpcodeShift,
+ SDR = ((5 << 3) + 5) << kOpcodeShift,
+ SWR = ((5 << 3) + 6) << kOpcodeShift,
+
+ LWC1 = ((6 << 3) + 1) << kOpcodeShift,
+ BC = ((6 << 3) + 2) << kOpcodeShift,
+ LLD = ((6 << 3) + 4) << kOpcodeShift,
+ LDC1 = ((6 << 3) + 5) << kOpcodeShift,
+ POP66 = ((6 << 3) + 6) << kOpcodeShift,
+ LD = ((6 << 3) + 7) << kOpcodeShift,
+
+ PREF = ((6 << 3) + 3) << kOpcodeShift,
+
+ SWC1 = ((7 << 3) + 1) << kOpcodeShift,
+ BALC = ((7 << 3) + 2) << kOpcodeShift,
+ PCREL = ((7 << 3) + 3) << kOpcodeShift,
+ SCD = ((7 << 3) + 4) << kOpcodeShift,
+ SDC1 = ((7 << 3) + 5) << kOpcodeShift,
+ POP76 = ((7 << 3) + 6) << kOpcodeShift,
+ SD = ((7 << 3) + 7) << kOpcodeShift,
+
+ COP1X = ((1 << 4) + 3) << kOpcodeShift
};
enum SecondaryField {
DINSU = ((0 << 3) + 6),
DINS = ((0 << 3) + 7),
- BITSWAP = ((4 << 3) + 0),
- DBITSWAP = ((4 << 3) + 4),
- DSBH = ((4 << 3) + 4),
+ BSHFL = ((4 << 3) + 0),
+ DBSHFL = ((4 << 3) + 4),
// SPECIAL3 Encoding of sa Field.
+ BITSWAP = ((0 << 3) + 0),
+ ALIGN = ((0 << 3) + 2),
+ WSBH = ((0 << 3) + 2),
+ SEB = ((2 << 3) + 0),
+ SEH = ((3 << 3) + 0),
+
+ DBITSWAP = ((0 << 3) + 0),
+ DALIGN = ((0 << 3) + 1),
DBITSWAP_SA = ((0 << 3) + 0) << kSaShift,
+ DSBH = ((0 << 3) + 2),
+ DSHD = ((0 << 3) + 5),
// REGIMM encoding of rt Field.
BLTZ = ((0 << 3) + 0) << 16,
// COP1X Encoding of Function Field.
MADD_D = ((4 << 3) + 1),
+ // PCREL Encoding of rt Field.
+ ADDIUPC = ((0 << 2) + 0),
+ LWPC = ((0 << 2) + 1),
+ LWUPC = ((0 << 2) + 2),
+ LDPC = ((0 << 3) + 6),
+ // reserved ((1 << 3) + 6),
+ AUIPC = ((3 << 3) + 6),
+ ALUIPC = ((3 << 3) + 7),
+
+ // POP66 Encoding of rs Field.
+ JIC = ((0 << 5) + 0),
+
+ // POP76 Encoding of rs Field.
+ JIALC = ((0 << 5) + 0),
+
NULLSF = 0
};
return Bits(kFrShift + kFrBits -1, kFrShift);
}
+ inline int Bp2Value() const {
+ DCHECK(InstructionType() == kRegisterType);
+ return Bits(kBp2Shift + kBp2Bits - 1, kBp2Shift);
+ }
+
+ inline int Bp3Value() const {
+ DCHECK(InstructionType() == kRegisterType);
+ return Bits(kBp3Shift + kBp3Bits - 1, kBp3Shift);
+ }
+
// Float Compare condition code instruction bits.
inline int FCccValue() const {
return Bits(kFCccShift + kFCccBits - 1, kFCccShift);
}
inline int SaFieldRaw() const {
- DCHECK(InstructionType() == kRegisterType);
return InstructionBits() & kSaFieldMask;
}
return Bits(kImm16Shift + kImm16Bits - 1, kImm16Shift);
}
+ inline int32_t Imm18Value() const {
+ DCHECK(InstructionType() == kImmediateType);
+ return Bits(kImm18Shift + kImm18Bits - 1, kImm18Shift);
+ }
+
+ inline int32_t Imm19Value() const {
+ DCHECK(InstructionType() == kImmediateType);
+ return Bits(kImm19Shift + kImm19Bits - 1, kImm19Shift);
+ }
+
inline int32_t Imm21Value() const {
DCHECK(InstructionType() == kImmediateType);
return Bits(kImm21Shift + kImm21Bits - 1, kImm21Shift);
}
- inline int64_t Imm26Value() const {
- DCHECK(InstructionType() == kJumpType);
+ inline int32_t Imm26Value() const {
+ DCHECK((InstructionType() == kJumpType) ||
+ (InstructionType() == kImmediateType));
return Bits(kImm26Shift + kImm26Bits - 1, kImm26Shift);
}
void PrintUImm16(Instruction* instr);
void PrintSImm16(Instruction* instr);
void PrintXImm16(Instruction* instr);
+ void PrintXImm18(Instruction* instr);
+ void PrintSImm18(Instruction* instr);
+ void PrintXImm19(Instruction* instr);
+ void PrintSImm19(Instruction* instr);
void PrintXImm21(Instruction* instr);
void PrintXImm26(Instruction* instr);
+ void PrintSImm26(Instruction* instr);
void PrintCode(Instruction* instr); // For break and trap instructions.
void PrintFormat(Instruction* instr); // For floating format postfix.
+ void PrintBp2(Instruction* instr);
+ void PrintBp3(Instruction* instr);
// Printing of instruction name.
void PrintInstructionName(Instruction* instr);
// Print 16-bit signed immediate value.
void Decoder::PrintSImm16(Instruction* instr) {
- int32_t imm = ((instr->Imm16Value()) << 16) >> 16;
+ int32_t imm =
+ ((instr->Imm16Value()) << (32 - kImm16Bits)) >> (32 - kImm16Bits);
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
}
}
+// Print 18-bit signed immediate value.
+void Decoder::PrintSImm18(Instruction* instr) {
+ int32_t imm =
+ ((instr->Imm18Value()) << (32 - kImm18Bits)) >> (32 - kImm18Bits);
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm);
+}
+
+
+// Print 18-bit hexa immediate value.
+void Decoder::PrintXImm18(Instruction* instr) {
+ int32_t imm = instr->Imm18Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
+}
+
+
+// Print 19-bit hexa immediate value.
+void Decoder::PrintXImm19(Instruction* instr) {
+ int32_t imm = instr->Imm19Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
+}
+
+
+// Print 19-bit signed immediate value.
+void Decoder::PrintSImm19(Instruction* instr) {
+ int32_t imm19 = instr->Imm19Value();
+ // set sign
+ imm19 <<= (32 - kImm19Bits);
+ imm19 >>= (32 - kImm19Bits);
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm19);
+}
+
+
// Print 21-bit immediate value.
void Decoder::PrintXImm21(Instruction* instr) {
uint32_t imm = instr->Imm21Value();
}
-// Print 26-bit immediate value.
+// Print 26-bit hex immediate value.
void Decoder::PrintXImm26(Instruction* instr) {
uint32_t imm = static_cast<uint32_t>(instr->Imm26Value()) << kImmFieldShift;
out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "0x%x", imm);
}
+// Print 26-bit signed immediate value.
+void Decoder::PrintSImm26(Instruction* instr) {
+ int32_t imm26 = instr->Imm26Value();
+ // set sign
+ imm26 <<= (32 - kImm26Bits);
+ imm26 >>= (32 - kImm26Bits);
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", imm26);
+}
+
+
+void Decoder::PrintBp2(Instruction* instr) {
+ int bp2 = instr->Bp2Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", bp2);
+}
+
+
+void Decoder::PrintBp3(Instruction* instr) {
+ int bp3 = instr->Bp3Value();
+ out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", bp3);
+}
+
+
// Print 26-bit immediate value.
void Decoder::PrintCode(Instruction* instr) {
if (instr->OpcodeFieldRaw() != SPECIAL)
}
case 'i': { // 'imm16u or 'imm26.
if (format[3] == '1') {
- DCHECK(STRING_STARTS_WITH(format, "imm16"));
- if (format[5] == 's') {
- DCHECK(STRING_STARTS_WITH(format, "imm16s"));
- PrintSImm16(instr);
- } else if (format[5] == 'u') {
- DCHECK(STRING_STARTS_WITH(format, "imm16u"));
- PrintSImm16(instr);
- } else {
- DCHECK(STRING_STARTS_WITH(format, "imm16x"));
- PrintXImm16(instr);
+ if (format[4] == '6') {
+ DCHECK(STRING_STARTS_WITH(format, "imm16"));
+ switch (format[5]) {
+ case 's':
+ DCHECK(STRING_STARTS_WITH(format, "imm16s"));
+ PrintSImm16(instr);
+ break;
+ case 'u':
+ DCHECK(STRING_STARTS_WITH(format, "imm16u"));
+ PrintSImm16(instr);
+ break;
+ case 'x':
+ DCHECK(STRING_STARTS_WITH(format, "imm16x"));
+ PrintXImm16(instr);
+ break;
+ }
+ return 6;
+ } else if (format[4] == '8') {
+ DCHECK(STRING_STARTS_WITH(format, "imm18"));
+ switch (format[5]) {
+ case 's':
+ DCHECK(STRING_STARTS_WITH(format, "imm18s"));
+ PrintSImm18(instr);
+ break;
+ case 'x':
+ DCHECK(STRING_STARTS_WITH(format, "imm18x"));
+ PrintXImm18(instr);
+ break;
+ }
+ return 6;
+ } else if (format[4] == '9') {
+ DCHECK(STRING_STARTS_WITH(format, "imm19"));
+ switch (format[5]) {
+ case 's':
+ DCHECK(STRING_STARTS_WITH(format, "imm19s"));
+ PrintSImm19(instr);
+ break;
+ case 'x':
+ DCHECK(STRING_STARTS_WITH(format, "imm19x"));
+ PrintXImm19(instr);
+ break;
+ }
+ return 6;
}
- return 6;
} else if (format[3] == '2' && format[4] == '1') {
DCHECK(STRING_STARTS_WITH(format, "imm21x"));
PrintXImm21(instr);
return 6;
} else if (format[3] == '2' && format[4] == '6') {
- DCHECK(STRING_STARTS_WITH(format, "imm26x"));
- PrintXImm26(instr);
+ DCHECK(STRING_STARTS_WITH(format, "imm26"));
+ switch (format[5]) {
+ case 's':
+ DCHECK(STRING_STARTS_WITH(format, "imm26s"));
+ PrintSImm26(instr);
+ break;
+ case 'x':
+ DCHECK(STRING_STARTS_WITH(format, "imm26x"));
+ PrintXImm26(instr);
+ break;
+ }
return 6;
}
}
}
}
}
- case 'b': { // 'bc - Special for bc1 cc field.
- DCHECK(STRING_STARTS_WITH(format, "bc"));
- PrintBc(instr);
- return 2;
+ case 'b': {
+ switch (format[1]) {
+ case 'c': { // 'bc - Special for bc1 cc field.
+ DCHECK(STRING_STARTS_WITH(format, "bc"));
+ PrintBc(instr);
+ return 2;
+ }
+ case 'p': {
+ switch (format[2]) {
+ case '2': { // 'bp2
+ DCHECK(STRING_STARTS_WITH(format, "bp2"));
+ PrintBp2(instr);
+ return 3;
+ }
+ case '3': { // 'bp3
+ DCHECK(STRING_STARTS_WITH(format, "bp3"));
+ PrintBp3(instr);
+ return 3;
+ }
+ }
+ }
+ }
}
case 'C': { // 'Cc - Special for c.xx.d cc field.
DCHECK(STRING_STARTS_WITH(format, "Cc"));
Format(instr, "dext 'rt, 'rs, 'sa, 'ss1");
break;
}
- case BITSWAP: {
- Format(instr, "bitswap 'rd, 'rt");
+ case BSHFL: {
+ int sa = instr->SaFieldRaw() >> kSaShift;
+ switch (sa) {
+ case BITSWAP: {
+ Format(instr, "bitswap 'rd, 'rt");
+ break;
+ }
+ case SEB:
+ case SEH:
+ case WSBH:
+ UNREACHABLE();
+ break;
+ default: {
+ sa >>= kBp2Bits;
+ switch (sa) {
+ case ALIGN: {
+ Format(instr, "align 'rd, 'rs, 'rt, 'bp2");
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+ }
+ }
break;
}
- case DBITSWAP: {
- switch (instr->SaFieldRaw()) {
- case DBITSWAP_SA:
- Format(instr, "dbitswap 'rd, 'rt");
+ case DBSHFL: {
+ int sa = instr->SaFieldRaw() >> kSaShift;
+ switch (sa) {
+ case DBITSWAP: {
+ switch (instr->SaFieldRaw() >> kSaShift) {
+ case DBITSWAP_SA:
+ Format(instr, "dbitswap 'rd, 'rt");
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
break;
- default:
+ }
+ case DSBH:
+ case DSHD:
UNREACHABLE();
+ break;
+ default: {
+ sa >>= kBp3Bits;
+ switch (sa) {
+ case DALIGN: {
+ Format(instr, "dalign 'rd, 'rs, 'rt, 'bp3");
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+ }
}
break;
}
case BEQ:
Format(instr, "beq 'rs, 'rt, 'imm16u");
break;
+ case BC:
+ Format(instr, "bc 'imm26s");
+ break;
+ case BALC:
+ Format(instr, "balc 'imm26s");
+ break;
case BNE:
Format(instr, "bne 'rs, 'rt, 'imm16u");
break;
UNREACHABLE();
}
break;
- case BEQZC:
- if (instr->RsFieldRaw() != 0) {
+ case POP66:
+ if (instr->RsValue() == JIC) {
+ Format(instr, "jic 'rt, 'imm16s");
+ } else {
Format(instr, "beqzc 'rs, 'imm21x");
}
break;
- case BNEZC:
- if (instr->RsFieldRaw() != 0) {
+ case POP76:
+ if (instr->RsValue() == JIALC) {
+ Format(instr, "jialc 'rt, 'imm16x");
+ } else {
Format(instr, "bnezc 'rs, 'imm21x");
}
break;
case SDC1:
Format(instr, "sdc1 'ft, 'imm16s('rs)");
break;
+ case PCREL: {
+ int32_t imm21 = instr->Imm21Value();
+ // rt field: 5-bits checking
+ uint8_t rt = (imm21 >> kImm16Bits);
+ switch (rt) {
+ case ALUIPC:
+ Format(instr, "aluipc 'rs, 'imm16s");
+ break;
+ case AUIPC:
+ Format(instr, "auipc 'rs, 'imm16s");
+ break;
+ default: {
+ // rt field: checking of the most significant 3-bits
+ rt = (imm21 >> kImm18Bits);
+ switch (rt) {
+ case LDPC:
+ Format(instr, "ldpc 'rs, 'imm18s");
+ break;
+ default: {
+ // rt field: checking of the most significant 2-bits
+ rt = (imm21 >> kImm19Bits);
+ switch (rt) {
+ case LWUPC:
+ Format(instr, "lwupc 'rs, 'imm19s");
+ break;
+ case LWPC:
+ Format(instr, "lwpc 'rs, 'imm19s");
+ break;
+ case ADDIUPC:
+ Format(instr, "addiupc 'rs, 'imm19s");
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
default:
printf("a 0x%x \n", instr->OpcodeFieldRaw());
- UNREACHABLE();
+ UNREACHABLE();
break;
}
}
const uint64_t rt_u = static_cast<uint64_t>(rt);
const int32_t rd_reg = instr->RdValue();
const uint64_t sa = instr->SaValue();
+ const uint8_t bp2 = instr->Bp2Value();
+ const uint8_t bp3 = instr->Bp3Value();
const int32_t fs_reg = instr->FsValue();
// MIPS spec: If no bits were set in GPR rs, the result written to
// GPR rd is 32.
DCHECK(instr->SaValue() == 1);
- *alu_out = base::bits::CountLeadingZeros32(rs_u);
+ *alu_out =
+ base::bits::CountLeadingZeros32(static_cast<int32_t>(rs_u));
}
break;
case MFLO:
*alu_out = static_cast<int64_t>((rs_u & (mask << lsb)) >> lsb);
break;
}
- case BITSWAP: { // Mips32r6 instruction
- uint32_t input = static_cast<uint32_t>(rt);
- uint32_t output = 0;
- uint8_t i_byte, o_byte;
-
- // Reverse the bit in byte for each individual byte
- for (int i = 0; i < 4; i++) {
- output = output >> 8;
- i_byte = input & 0xff;
-
- // Fast way to reverse bits in byte
- // Devised by Sean Anderson, July 13, 2001
- o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
- (i_byte * 0x8020LU & 0x88440LU)) *
- 0x10101LU >>
- 16);
-
- output = output | (static_cast<uint32_t>(o_byte << 24));
- input = input >> 8;
- }
-
- *alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
- break;
- }
- case DBITSWAP: {
- switch (instr->SaFieldRaw()) {
- case DBITSWAP_SA: { // Mips64r6
- uint64_t input = static_cast<uint64_t>(rt);
- uint64_t output = 0;
+ case BSHFL: {
+ int sa = instr->SaFieldRaw() >> kSaShift;
+ switch (sa) {
+ case BITSWAP: {
+ uint32_t input = static_cast<uint32_t>(rt);
+ uint32_t output = 0;
uint8_t i_byte, o_byte;
// Reverse the bit in byte for each individual byte
- for (int i = 0; i < 8; i++) {
+ for (int i = 0; i < 4; i++) {
output = output >> 8;
i_byte = input & 0xff;
0x10101LU >>
16);
- output = output | ((static_cast<uint64_t>(o_byte) << 56));
+ output = output | (static_cast<uint32_t>(o_byte << 24));
input = input >> 8;
}
- *alu_out = static_cast<int64_t>(output);
+ *alu_out = static_cast<int64_t>(static_cast<int32_t>(output));
break;
}
- default:
+ case SEB:
+ case SEH:
+ case WSBH:
UNREACHABLE();
+ break;
+ default: {
+ sa >>= kBp2Bits;
+ switch (sa) {
+ case ALIGN: {
+ if (bp2 == 0) {
+ *alu_out = static_cast<int32_t>(rt);
+ } else {
+ uint64_t rt_hi = rt << (8 * bp2);
+ uint64_t rs_lo = rs >> (8 * (4 - bp2));
+ *alu_out = static_cast<int32_t>(rt_hi | rs_lo);
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ case DBSHFL: {
+ int sa = instr->SaFieldRaw() >> kSaShift;
+ switch (sa) {
+ case DBITSWAP: {
+ switch (instr->SaFieldRaw() >> kSaShift) {
+ case DBITSWAP_SA: { // Mips64r6
+ uint64_t input = static_cast<uint64_t>(rt);
+ uint64_t output = 0;
+ uint8_t i_byte, o_byte;
+
+ // Reverse the bit in byte for each individual byte
+ for (int i = 0; i < 8; i++) {
+ output = output >> 8;
+ i_byte = input & 0xff;
+
+ // Fast way to reverse bits in byte
+ // Devised by Sean Anderson, July 13, 2001
+ o_byte =
+ static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
+ (i_byte * 0x8020LU & 0x88440LU)) *
+ 0x10101LU >>
+ 16);
+
+ output = output | ((static_cast<uint64_t>(o_byte) << 56));
+ input = input >> 8;
+ }
+
+ *alu_out = static_cast<int64_t>(output);
+ break;
+ }
+ }
+ break;
+ }
+ case DSBH:
+ case DSHD:
+ UNREACHABLE();
+ break;
+ default: {
+ sa >>= kBp3Bits;
+ switch (sa) {
+ case DALIGN: {
+ if (bp3 == 0) {
+ *alu_out = static_cast<int64_t>(rt);
+ } else {
+ uint64_t rt_hi = rt << (8 * bp3);
+ uint64_t rs_lo = rs >> (8 * (8 - bp3));
+ *alu_out = static_cast<int64_t>(rt_hi | rs_lo);
+ }
+ break;
+ }
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+ }
}
break;
}
set_register(rt_reg, alu_out);
TraceRegWr(alu_out);
break;
- case BITSWAP:
- case DBITSWAP:
+ case BSHFL:
+ case DBSHFL:
set_register(rd_reg, alu_out);
TraceRegWr(alu_out);
break;
DecodeTypeRegisterSPECIAL2(instr, rd_reg, alu_out);
break;
case SPECIAL3:
- DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
+ switch (instr->FunctionFieldRaw()) {
+ case BSHFL: {
+ int sa = instr->SaValue();
+ sa >>= kBp2Bits;
+ switch (sa) {
+ case ALIGN: {
+ DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
+ break;
+ }
+ }
+ }
+ case DBSHFL: {
+ int sa = instr->SaValue();
+ sa >>= kBp3Bits;
+ switch (sa) {
+ case DALIGN: {
+ DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
+ break;
+ }
+ }
+ }
+ default:
+ DecodeTypeRegisterSPECIAL3(instr, rt_reg, rd_reg, alu_out);
+ break;
+ }
break;
// Unimplemented opcodes raised an error in the configuration step before,
// so we can use the default here to set the destination register in common
void Simulator::DecodeTypeImmediate(Instruction* instr) {
// Instruction fields.
Opcode op = instr->OpcodeFieldRaw();
+ int32_t rs_reg = instr->RsValue();
int64_t rs = get_register(instr->RsValue());
uint64_t rs_u = static_cast<uint64_t>(rs);
int32_t rt_reg = instr->RtValue(); // Destination register.
int64_t rt = get_register(rt_reg);
int16_t imm16 = instr->Imm16Value();
+ int32_t imm18 = instr->Imm18Value();
+ int32_t imm19 = instr->Imm19Value();
+ int32_t imm21 = instr->Imm21Value();
+ int32_t imm26 = instr->Imm26Value();
int32_t ft_reg = instr->FtValue(); // Destination register.
int64_t ft = get_fpu_register(ft_reg);
uint64_t oe_imm16 = 0xffff & imm16;
// Sign extended immediate.
int64_t se_imm16 = imm16;
+ int64_t se_imm18 = imm18 | ((imm18 & 0x20000) ? 0xfffffffffffc0000 : 0);
+ int64_t se_imm19 = imm19 | ((imm19 & 0x40000) ? 0xfffffffffff80000 : 0);
+ int64_t se_imm26 = imm26 | ((imm26 & 0x2000000) ? 0xfffffffffc000000 : 0);
+
// Get current pc.
int64_t current_pc = get_pc();
// Next pc.
int64_t next_pc = bad_ra;
+ // pc increment
+ int16_t pc_increment;
// Used for conditional branch instructions.
bool do_branch = false;
case BGTZ:
do_branch = rs > 0;
break;
+ case POP66: {
+ if (rs_reg) { // BEQZC
+ int32_t se_imm21 =
+ static_cast<int32_t>(imm21 << (kOpcodeBits + kRsBits));
+ se_imm21 = se_imm21 >> (kOpcodeBits + kRsBits);
+ if (rs == 0)
+ next_pc = current_pc + 4 + (se_imm21 << 2);
+ else
+ next_pc = current_pc + 4;
+ } else { // JIC
+ next_pc = rt + imm16;
+ }
+ break;
+ }
+ case BC: {
+ next_pc = current_pc + 4 + (se_imm26 << 2);
+ set_pc(next_pc);
+ pc_modified_ = true;
+ break;
+ }
+ case BALC: {
+ set_register(31, current_pc + 4);
+ next_pc = current_pc + 4 + (se_imm26 << 2);
+ set_pc(next_pc);
+ pc_modified_ = true;
+ break;
+ }
// ------------- Arithmetic instructions.
case ADDI:
case DADDI:
case SDC1:
addr = rs + se_imm16;
break;
+ // ------------- JIALC and BNEZC instructions.
+ case POP76:
+ // Next pc.
+ next_pc = rt + se_imm16;
+ // The instruction after the jump is NOT executed.
+ pc_increment = Instruction::kInstrSize;
+ if (instr->IsLinkingInstruction()) {
+ set_register(31, current_pc + pc_increment);
+ }
+ set_pc(next_pc);
+ pc_modified_ = true;
+ break;
+ // ------------- PC-Relative instructions.
+ case PCREL: {
+ // rt field: checking 5-bits.
+ uint8_t rt = (imm21 >> kImm16Bits);
+ switch (rt) {
+ case ALUIPC:
+ addr = current_pc + (se_imm16 << 16);
+ alu_out = static_cast<int64_t>(~0x0FFFF) & addr;
+ break;
+ case AUIPC:
+ alu_out = current_pc + (se_imm16 << 16);
+ break;
+ default: {
+ // rt field: checking the most significant 3-bits.
+ rt = (imm21 >> kImm18Bits);
+ switch (rt) {
+ case LDPC:
+ addr =
+ (current_pc & static_cast<int64_t>(~0x7)) + (se_imm18 << 3);
+ alu_out = Read2W(addr, instr);
+ break;
+ default: {
+ // rt field: checking the most significant 2-bits.
+ rt = (imm21 >> kImm19Bits);
+ switch (rt) {
+ case LWUPC: {
+ int32_t offset = imm19;
+ // Set sign.
+ offset <<= (kOpcodeBits + kRsBits + 2);
+ offset >>= (kOpcodeBits + kRsBits + 2);
+ addr = current_pc + (offset << 2);
+ uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
+ alu_out = *ptr;
+ break;
+ }
+ case LWPC: {
+ int32_t offset = imm19;
+ // Set sign.
+ offset <<= (kOpcodeBits + kRsBits + 2);
+ offset >>= (kOpcodeBits + kRsBits + 2);
+ addr = current_pc + (offset << 2);
+ int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+ alu_out = *ptr;
+ break;
+ }
+ case ADDIUPC:
+ alu_out = current_pc + (se_imm19 << 2);
+ break;
+ default:
+ UNREACHABLE();
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
default:
UNREACHABLE();
}
+
// ---------- Raise exceptions triggered.
SignalExceptions();
addr = rs + se_imm16;
WriteD(addr, get_fpu_register_double(ft_reg), instr);
break;
+ case PCREL:
+ set_register(rs_reg, alu_out);
default:
break;
}
__ jr(ra);
__ nop();
+
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
F3 f = FUNCTION_CAST<F3>(code->entry());
(CALL_GENERATED_CODE(f, &test, 0, 0, 0, 0));
}
+uint32_t run_align(uint32_t rs_value, uint32_t rt_value, uint8_t bp) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ __ align(v0, a0, a1, bp);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint32_t res =
+ reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, rs_value,
+ rt_value,
+ 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_align) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseAlign {
+ uint32_t rs_value;
+ uint32_t rt_value;
+ uint8_t bp;
+ uint32_t expected_res;
+ };
+
+ struct TestCaseAlign tc[] = {
+ // rs_value, rt_value, bp, expected_res
+ { 0x11223344, 0xaabbccdd, 0, 0xaabbccdd },
+ { 0x11223344, 0xaabbccdd, 1, 0xbbccdd11 },
+ { 0x11223344, 0xaabbccdd, 2, 0xccdd1122 },
+ { 0x11223344, 0xaabbccdd, 3, 0xdd112233 },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAlign);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ CHECK_EQ(tc[i].expected_res, run_align(tc[i].rs_value,
+ tc[i].rt_value, tc[i].bp));
+ }
+ }
+}
+
+uint32_t PC; // The program counter.
+
+uint32_t run_aluipc(int16_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ __ aluipc(v0, offset);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+ PC = (uint32_t) f; // Set the program counter.
+
+ uint32_t res =
+ reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_aluipc) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseAluipc {
+ int16_t offset;
+ };
+
+ struct TestCaseAluipc tc[] = {
+ // offset
+ { -32768 }, // 0x8000
+ { -1 }, // 0xFFFF
+ { 0 },
+ { 1 },
+ { 32767 }, // 0x7FFF
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAluipc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ PC = 0;
+ uint32_t res = run_aluipc(tc[i].offset);
+ // Now, the program_counter (PC) is set.
+ uint32_t expected_res = ~0x0FFFF & (PC + (tc[i].offset << 16));
+ CHECK_EQ(expected_res, res);
+ }
+ }
+}
+
+
+uint32_t run_auipc(int16_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ __ auipc(v0, offset);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+ PC = (uint32_t) f; // Set the program counter.
+
+ uint32_t res =
+ reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_auipc) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseAuipc {
+ int16_t offset;
+ };
+
+ struct TestCaseAuipc tc[] = {
+ // offset
+ { -32768 }, // 0x8000
+ { -1 }, // 0xFFFF
+ { 0 },
+ { 1 },
+ { 32767 }, // 0x7FFF
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAuipc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ PC = 0;
+ uint32_t res = run_auipc(tc[i].offset);
+ // Now, the program_counter (PC) is set.
+ uint32_t expected_res = PC + (tc[i].offset << 16);
+ CHECK_EQ(expected_res, res);
+ }
+ }
+}
+
+
+uint32_t run_lwpc(int offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ // 256k instructions; 2^8k
+ // addiu t7, t0, 0xffff; (0x250fffff)
+ // ...
+ // addiu t4, t0, 0x0000; (0x250c0000)
+ uint32_t addiu_start_1 = 0x25000000;
+ for (int32_t i = 0xfffff; i >= 0xc0000; --i) {
+ uint32_t addiu_new = addiu_start_1 + i;
+ __ dd(addiu_new);
+ }
+
+ __ lwpc(t8, offset); // offset 0; 0xef080000 (t8 register)
+ __ mov(v0, t8);
+
+ // 256k instructions; 2^8k
+ // addiu t0, t0, 0x0000; (0x25080000)
+ // ...
+ // addiu t3, t0, 0xffff; (0x250bffff)
+ uint32_t addiu_start_2 = 0x25000000;
+ for (int32_t i = 0x80000; i <= 0xbffff; ++i) {
+ uint32_t addiu_new = addiu_start_2 + i;
+ __ dd(addiu_new);
+ }
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint32_t res =
+ reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_lwpc) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseLwpc {
+ int offset;
+ uint32_t expected_res;
+ };
+
+ struct TestCaseLwpc tc[] = {
+ // offset, expected_res
+ { -262144, 0x250fffff }, // offset 0x40000
+ { -4, 0x250c0003 },
+ { -1, 0x250c0000 },
+ { 0, 0xef080000 },
+ { 1, 0x03001025 }, // mov(v0, t8)
+ { 2, 0x25080000 },
+ { 4, 0x25080002 },
+ { 262143, 0x250bfffd }, // offset 0x3ffff
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLwpc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint32_t res = run_lwpc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+uint32_t run_jic(int16_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label get_program_counter, stop_execution;
+ __ push(ra);
+ __ li(v0, 0);
+ __ li(t1, 0x66);
+
+ __ addiu(v0, v0, 0x1); // <-- offset = -32
+ __ addiu(v0, v0, 0x2);
+ __ addiu(v0, v0, 0x10);
+ __ addiu(v0, v0, 0x20);
+ __ beq(v0, t1, &stop_execution);
+ __ nop();
+
+ __ bal(&get_program_counter); // t0 <- program counter
+ __ nop();
+ __ jic(t0, offset);
+
+ __ addiu(v0, v0, 0x100);
+ __ addiu(v0, v0, 0x200);
+ __ addiu(v0, v0, 0x1000);
+ __ addiu(v0, v0, 0x2000); // <--- offset = 16
+ __ pop(ra);
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&get_program_counter);
+ __ mov(t0, ra);
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&stop_execution);
+ __ pop(ra);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint32_t res =
+ reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_jic) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseJic {
+ // As rt will be used t0 register which will have value of
+ // the program counter for the jic instruction.
+ int16_t offset;
+ uint32_t expected_res;
+ };
+
+ struct TestCaseJic tc[] = {
+ // offset, expected_result
+ { 16, 0x2033 },
+ { 4, 0x3333 },
+ { -32, 0x66 },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJic);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint32_t res = run_jic(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_beqzc(int32_t value, int32_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label stop_execution;
+ __ li(v0, 0);
+ __ li(t1, 0x66);
+ __ push(ra);
+
+ __ addiu(v0, v0, 0x1); // <-- offset = -32
+ __ addiu(v0, v0, 0x2);
+ __ addiu(v0, v0, 0x10);
+ __ addiu(v0, v0, 0x20);
+ __ beq(v0, t1, &stop_execution);
+ __ nop();
+
+ __ beqzc(a0, offset); // BEQZC rs, offset
+
+ __ addiu(v0, v0, 0x1);
+ __ addiu(v0, v0, 0x100);
+ __ addiu(v0, v0, 0x200);
+ __ addiu(v0, v0, 0x1000);
+ __ addiu(v0, v0, 0x2000); // <--- offset = 16
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&stop_execution);
+ __ pop(ra);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint32_t res =
+ reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, value, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_beqzc) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseBeqzc {
+ uint32_t value;
+ int32_t offset;
+ uint32_t expected_res;
+ };
+
+ struct TestCaseBeqzc tc[] = {
+ // value, offset, expected_res
+ { 0x0, -8, 0x66 },
+ { 0x0, 0, 0x3334 },
+ { 0x0, 1, 0x3333 },
+ { 0xabc, 1, 0x3334 },
+ { 0x0, 4, 0x2033 },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBeqzc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint32_t res = run_beqzc(tc[i].value, tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+uint32_t run_jialc(int16_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label main_block, get_program_counter;
+ __ push(ra);
+ __ li(v0, 0);
+ __ beq(v0, v0, &main_block);
+ __ nop();
+
+ // Block 1
+ __ addiu(v0, v0, 0x1); // <-- offset = -40
+ __ addiu(v0, v0, 0x2);
+ __ jr(ra);
+ __ nop();
+
+ // Block 2
+ __ addiu(v0, v0, 0x10); // <-- offset = -24
+ __ addiu(v0, v0, 0x20);
+ __ jr(ra);
+ __ nop();
+
+ // Block 3 (Main)
+ __ bind(&main_block);
+ __ bal(&get_program_counter); // t0 <- program counter
+ __ nop();
+ __ jialc(t0, offset);
+ __ addiu(v0, v0, 0x4);
+ __ pop(ra);
+ __ jr(ra);
+ __ nop();
+
+ // Block 4
+ __ addiu(v0, v0, 0x100); // <-- offset = 20
+ __ addiu(v0, v0, 0x200);
+ __ jr(ra);
+ __ nop();
+
+ // Block 5
+ __ addiu(v0, v0, 0x1000); // <--- offset = 36
+ __ addiu(v0, v0, 0x2000);
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&get_program_counter);
+ __ mov(t0, ra);
+ __ jr(ra);
+ __ nop();
+
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint32_t res =
+ reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_jialc) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseJialc {
+ int16_t offset;
+ uint32_t expected_res;
+ };
+
+ struct TestCaseJialc tc[] = {
+ // offset, expected_res
+ { -40, 0x7 },
+ { -24, 0x34 },
+ { 20, 0x304 },
+ { 36, 0x3004 }
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJialc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint32_t res = run_jialc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_addiupc(int32_t imm19) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ __ addiupc(v0, imm19);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+ PC = (uint32_t) f; // Set the program counter.
+
+ uint32_t rs =
+ reinterpret_cast<uint32_t>(CALL_GENERATED_CODE(f, imm19, 0, 0, 0, 0));
+
+ return rs;
+}
+
+
+TEST(r6_addiupc) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseAddiupc {
+ int32_t imm19;
+ };
+
+ struct TestCaseAddiupc tc[] = {
+ // imm19
+ { -262144 }, // 0x40000
+ { -1 }, // 0x7FFFF
+ { 0 },
+ { 1 }, // 0x00001
+ { 262143 } // 0x3FFFF
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAddiupc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ PC = 0;
+ uint32_t res = run_addiupc(tc[i].imm19);
+ // Now, the program_counter (PC) is set.
+ uint32_t expected_res = PC + (tc[i].imm19 << 2);
+ CHECK_EQ(expected_res, res);
+ }
+ }
+}
+
+
+int32_t run_bc(int32_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label continue_1, stop_execution;
+ __ push(ra);
+ __ li(v0, 0);
+ __ li(t8, 0);
+ __ li(t9, 2); // A condition for stopping execution.
+
+ uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
+ for (int32_t i = -100; i <= -11; ++i) {
+ __ dd(instruction_addiu);
+ }
+
+ __ addiu(t8, t8, 1); // -10
+
+ __ beq(t8, t9, &stop_execution); // -9
+ __ nop(); // -8
+ __ beq(t8, t8, &continue_1); // -7
+ __ nop(); // -6
+
+ __ bind(&stop_execution);
+ __ pop(ra); // -5, -4
+ __ jr(ra); // -3
+ __ nop(); // -2
+
+ __ bind(&continue_1);
+ __ bc(offset); // -1
+
+ for (int32_t i = 0; i <= 99; ++i) {
+ __ dd(instruction_addiu);
+ }
+
+ __ pop(ra);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ int32_t res =
+ reinterpret_cast<int32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_bc) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseBc {
+ int32_t offset;
+ int32_t expected_res;
+ };
+
+ struct TestCaseBc tc[] = {
+ // offset, expected_result
+ { -100, (abs(-100) - 10) * 2 },
+ { -11, (abs(-100) - 10 + 1) },
+ { 0, (abs(-100) - 10 + 1 + 99) },
+ { 1, (abs(-100) - 10 + 99) },
+ { 99, (abs(-100) - 10 + 1) },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ int32_t res = run_bc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+int32_t run_balc(int32_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label continue_1, stop_execution;
+ __ push(ra);
+ __ li(v0, 0);
+ __ li(t8, 0);
+ __ li(t9, 2); // A condition for stopping execution.
+
+ __ beq(t8, t8, &continue_1);
+ __ nop();
+
+ uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
+ for (int32_t i = -117; i <= -57; ++i) {
+ __ dd(instruction_addiu);
+ }
+ __ jr(ra); // -56
+ __ nop(); // -55
+
+ for (int32_t i = -54; i <= -4; ++i) {
+ __ dd(instruction_addiu);
+ }
+ __ jr(ra); // -3
+ __ nop(); // -2
+
+ __ bind(&continue_1);
+ __ balc(offset); // -1
+
+ __ pop(ra); // 0, 1
+ __ jr(ra); // 2
+ __ nop(); // 3
+
+ for (int32_t i = 4; i <= 44; ++i) {
+ __ dd(instruction_addiu);
+ }
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ int32_t res =
+ reinterpret_cast<int32_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_balc) {
+ if (IsMipsArchVariant(kMips32r6)) {
+ CcTest::InitializeVM();
+
+ struct TestCaseBalc {
+ int32_t offset;
+ int32_t expected_res;
+ };
+
+ struct TestCaseBalc tc[] = {
+ // offset, expected_result
+ { -117, 61 },
+ { -54, 51 },
+ { 0, 0 },
+ { 4, 41 },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBalc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ int32_t res = run_balc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
#undef __
typedef Object* (*F1)(int x, int p1, int p2, int p3, int p4);
typedef Object* (*F2)(int x, int y, int p2, int p3, int p4);
typedef Object* (*F3)(void* p, int p1, int p2, int p3, int p4);
+typedef Object* (*F4)(int64_t x, int64_t y, int64_t p2, int64_t p3, int64_t p4);
// clang-format off
}
+uint64_t run_align(uint64_t rs_value, uint64_t rt_value, uint8_t bp) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ __ align(v0, a0, a1, bp);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, rs_value,
+ rt_value,
+ 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_align) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseAlign {
+ uint64_t rs_value;
+ uint64_t rt_value;
+ uint8_t bp;
+ uint64_t expected_res;
+ };
+
+ struct TestCaseAlign tc[] = {
+ // rs_value, rt_value, bp, expected_res
+ { 0x11223344, 0xaabbccdd, 0, 0xffffffffaabbccdd },
+ { 0x11223344, 0xaabbccdd, 1, 0xffffffffbbccdd11 },
+ { 0x11223344, 0xaabbccdd, 2, 0xffffffffccdd1122 },
+ { 0x11223344, 0xaabbccdd, 3, 0xffffffffdd112233 },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAlign);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ CHECK_EQ(tc[i].expected_res, run_align(tc[i].rs_value,
+ tc[i].rt_value,
+ tc[i].bp));
+ }
+ }
+}
+
+
+uint64_t run_dalign(uint64_t rs_value, uint64_t rt_value, uint8_t bp) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ __ dalign(v0, a0, a1, bp);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F4 f = FUNCTION_CAST<F4>(code->entry());
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, rs_value,
+ rt_value,
+ 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_dalign) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseDalign {
+ uint64_t rs_value;
+ uint64_t rt_value;
+ uint8_t bp;
+ uint64_t expected_res;
+ };
+
+ struct TestCaseDalign tc[] = {
+ // rs_value, rt_value, bp, expected_res
+ { 0x1122334455667700, 0xaabbccddeeff8899, 0, 0xaabbccddeeff8899 },
+ { 0x1122334455667700, 0xaabbccddeeff8899, 1, 0xbbccddeeff889911 },
+ { 0x1122334455667700, 0xaabbccddeeff8899, 2, 0xccddeeff88991122 },
+ { 0x1122334455667700, 0xaabbccddeeff8899, 3, 0xddeeff8899112233 },
+ { 0x1122334455667700, 0xaabbccddeeff8899, 4, 0xeeff889911223344 },
+ { 0x1122334455667700, 0xaabbccddeeff8899, 5, 0xff88991122334455 },
+ { 0x1122334455667700, 0xaabbccddeeff8899, 6, 0x8899112233445566 },
+ { 0x1122334455667700, 0xaabbccddeeff8899, 7, 0x9911223344556677 }
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseDalign);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ CHECK_EQ(tc[i].expected_res, run_dalign(tc[i].rs_value,
+ tc[i].rt_value,
+ tc[i].bp));
+ }
+ }
+}
+
+
+uint64_t PC; // The program counter.
+
+uint64_t run_aluipc(int16_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ __ aluipc(v0, offset);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+ PC = (uint64_t) f; // Set the program counter.
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_aluipc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseAluipc {
+ int16_t offset;
+ };
+
+ struct TestCaseAluipc tc[] = {
+ // offset
+ { -32768 }, // 0x8000
+ { -1 }, // 0xFFFF
+ { 0 },
+ { 1 },
+ { 32767 }, // 0x7FFF
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAluipc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ PC = 0;
+ uint64_t res = run_aluipc(tc[i].offset);
+ // Now, the program_counter (PC) is set.
+ uint64_t expected_res = ~0x0FFFF & (PC + (tc[i].offset << 16));
+ CHECK_EQ(expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_auipc(int16_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ __ auipc(v0, offset);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+ PC = (uint64_t) f; // Set the program counter.
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_auipc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseAuipc {
+ int16_t offset;
+ };
+
+ struct TestCaseAuipc tc[] = {
+ // offset
+ { -32768 }, // 0x8000
+ { -1 }, // 0xFFFF
+ { 0 },
+ { 1 },
+ { 32767 }, // 0x7FFF
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAuipc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ PC = 0;
+ uint64_t res = run_auipc(tc[i].offset);
+ // Now, the program_counter (PC) is set.
+ uint64_t expected_res = PC + (tc[i].offset << 16);
+ CHECK_EQ(expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_lwpc(int offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ // 256k instructions; 2^8k
+ // addiu t3, a4, 0xffff; (0x250fffff)
+ // ...
+ // addiu t0, a4, 0x0000; (0x250c0000)
+ uint32_t addiu_start_1 = 0x25000000;
+ for (int32_t i = 0xfffff; i >= 0xc0000; --i) {
+ uint32_t addiu_new = addiu_start_1 + i;
+ __ dd(addiu_new);
+ }
+
+ __ lwpc(t8, offset); // offset 0; 0xef080000 (t8 register)
+ __ mov(v0, t8);
+
+ // 256k instructions; 2^8k
+ // addiu a4, a4, 0x0000; (0x25080000)
+ // ...
+ // addiu a7, a4, 0xffff; (0x250bffff)
+ uint32_t addiu_start_2 = 0x25000000;
+ for (int32_t i = 0x80000; i <= 0xbffff; ++i) {
+ uint32_t addiu_new = addiu_start_2 + i;
+ __ dd(addiu_new);
+ }
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_lwpc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseLwpc {
+ int offset;
+ uint64_t expected_res;
+ };
+
+ struct TestCaseLwpc tc[] = {
+ // offset, expected_res
+ { -262144, 0x250fffff }, // offset 0x40000
+ { -4, 0x250c0003 },
+ { -1, 0x250c0000 },
+ { 0, 0xffffffffef080000 },
+ { 1, 0x03001025 }, // mov(v0, t8)
+ { 2, 0x25080000 },
+ { 4, 0x25080002 },
+ { 262143, 0x250bfffd }, // offset 0x3ffff
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLwpc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint64_t res = run_lwpc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_lwupc(int offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ // 256k instructions; 2^8k
+ // addiu t3, a4, 0xffff; (0x250fffff)
+ // ...
+ // addiu t0, a4, 0x0000; (0x250c0000)
+ uint32_t addiu_start_1 = 0x25000000;
+ for (int32_t i = 0xfffff; i >= 0xc0000; --i) {
+ uint32_t addiu_new = addiu_start_1 + i;
+ __ dd(addiu_new);
+ }
+
+ __ lwupc(t8, offset); // offset 0; 0xef080000 (t8 register)
+ __ mov(v0, t8);
+
+ // 256k instructions; 2^8k
+ // addiu a4, a4, 0x0000; (0x25080000)
+ // ...
+ // addiu a7, a4, 0xffff; (0x250bffff)
+ uint32_t addiu_start_2 = 0x25000000;
+ for (int32_t i = 0x80000; i <= 0xbffff; ++i) {
+ uint32_t addiu_new = addiu_start_2 + i;
+ __ dd(addiu_new);
+ }
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_lwupc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseLwupc {
+ int offset;
+ uint64_t expected_res;
+ };
+
+ struct TestCaseLwupc tc[] = {
+ // offset, expected_res
+ { -262144, 0x250fffff }, // offset 0x40000
+ { -4, 0x250c0003 },
+ { -1, 0x250c0000 },
+ { 0, 0xef100000 },
+ { 1, 0x03001025 }, // mov(v0, t8)
+ { 2, 0x25080000 },
+ { 4, 0x25080002 },
+ { 262143, 0x250bfffd }, // offset 0x3ffff
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLwupc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint64_t res = run_lwupc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_jic(int16_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label get_program_counter, stop_execution;
+ __ push(ra);
+ __ li(v0, 0);
+ __ li(t1, 0x66);
+
+ __ addiu(v0, v0, 0x1); // <-- offset = -32
+ __ addiu(v0, v0, 0x2);
+ __ addiu(v0, v0, 0x10);
+ __ addiu(v0, v0, 0x20);
+ __ beq(v0, t1, &stop_execution);
+ __ nop();
+
+ __ bal(&get_program_counter); // t0 <- program counter
+ __ nop();
+ __ jic(t0, offset);
+
+ __ addiu(v0, v0, 0x100);
+ __ addiu(v0, v0, 0x200);
+ __ addiu(v0, v0, 0x1000);
+ __ addiu(v0, v0, 0x2000); // <--- offset = 16
+ __ pop(ra);
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&get_program_counter);
+ __ mov(t0, ra);
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&stop_execution);
+ __ pop(ra);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_jic) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseJic {
+ // As rt will be used t0 register which will have value of
+ // the program counter for the jic instruction.
+ int16_t offset;
+ uint32_t expected_res;
+ };
+
+ struct TestCaseJic tc[] = {
+ // offset, expected_result
+ { 16, 0x2033 },
+ { 4, 0x3333 },
+ { -32, 0x66 },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJic);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint64_t res = run_jic(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_beqzc(int32_t value, int32_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label stop_execution;
+ __ li(v0, 0);
+ __ li(t1, 0x66);
+
+ __ addiu(v0, v0, 0x1); // <-- offset = -8
+ __ addiu(v0, v0, 0x2);
+ __ addiu(v0, v0, 0x10);
+ __ addiu(v0, v0, 0x20);
+ __ beq(v0, t1, &stop_execution);
+ __ nop();
+
+ __ beqzc(a0, offset);
+
+ __ addiu(v0, v0, 0x1);
+ __ addiu(v0, v0, 0x100);
+ __ addiu(v0, v0, 0x200);
+ __ addiu(v0, v0, 0x1000);
+ __ addiu(v0, v0, 0x2000); // <--- offset = 4
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&stop_execution);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, value, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_beqzc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseBeqzc {
+ uint32_t value;
+ int32_t offset;
+ uint32_t expected_res;
+ };
+
+ struct TestCaseBeqzc tc[] = {
+ // value, offset, expected_res
+ { 0x0, -8, 0x66 },
+ { 0x0, 0, 0x3334 },
+ { 0x0, 1, 0x3333 },
+ { 0xabc, 1, 0x3334 },
+ { 0x0, 4, 0x2033 },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBeqzc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint64_t res = run_beqzc(tc[i].value, tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_jialc(int16_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label main_block, get_program_counter;
+ __ push(ra);
+ __ li(v0, 0);
+ __ beq(v0, v0, &main_block);
+ __ nop();
+
+ // Block 1
+ __ addiu(v0, v0, 0x1); // <-- offset = -40
+ __ addiu(v0, v0, 0x2);
+ __ jr(ra);
+ __ nop();
+
+ // Block 2
+ __ addiu(v0, v0, 0x10); // <-- offset = -24
+ __ addiu(v0, v0, 0x20);
+ __ jr(ra);
+ __ nop();
+
+ // Block 3 (Main)
+ __ bind(&main_block);
+ __ bal(&get_program_counter); // t0 <- program counter
+ __ nop();
+ __ jialc(t0, offset);
+ __ addiu(v0, v0, 0x4);
+ __ pop(ra);
+ __ jr(ra);
+ __ nop();
+
+ // Block 4
+ __ addiu(v0, v0, 0x100); // <-- offset = 20
+ __ addiu(v0, v0, 0x200);
+ __ jr(ra);
+ __ nop();
+
+ // Block 5
+ __ addiu(v0, v0, 0x1000); // <--- offset = 36
+ __ addiu(v0, v0, 0x2000);
+ __ jr(ra);
+ __ nop();
+
+ __ bind(&get_program_counter);
+ __ mov(t0, ra);
+ __ jr(ra);
+ __ nop();
+
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_jialc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseJialc {
+ // As rt will be used t0 register which will have value of
+ // the program counter for the jialc instruction.
+ int16_t offset;
+ uint32_t expected_res;
+ };
+
+ struct TestCaseJialc tc[] = {
+ // offset, expected_res
+ { -40, 0x7 },
+ { -24, 0x34 },
+ { 20, 0x304 },
+ { 36, 0x3004 }
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseJialc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint64_t res = run_jialc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_addiupc(int32_t imm19) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ __ addiupc(v0, imm19);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+ PC = (uint64_t) f; // Set the program counter.
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_addiupc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseAddiupc {
+ int32_t imm19;
+ };
+
+ struct TestCaseAddiupc tc[] = {
+ // imm19
+ { -262144 }, // 0x40000
+ { -1 }, // 0x7FFFF
+ { 0 },
+ { 1 }, // 0x00001
+ { 262143 } // 0x3FFFF
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseAddiupc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ PC = 0;
+ uint64_t res = run_addiupc(tc[i].imm19);
+ // Now, the program_counter (PC) is set.
+ uint64_t expected_res = PC + (tc[i].imm19 << 2);
+ CHECK_EQ(expected_res, res);
+ }
+ }
+}
+
+
+uint64_t run_ldpc(int offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ // 256k instructions; 2 * 2^7k = 2^8k
+ // addiu t3, a4, 0xffff; (0x250fffff)
+ // ...
+ // addiu t0, a4, 0x0000; (0x250c0000)
+ uint32_t addiu_start_1 = 0x25000000;
+ for (int32_t i = 0xfffff; i >= 0xc0000; --i) {
+ uint32_t addiu_new = addiu_start_1 + i;
+ __ dd(addiu_new);
+ }
+
+ __ ldpc(t8, offset); // offset 0; 0xef080000 (t8 register)
+ __ mov(v0, t8);
+
+ // 256k instructions; 2 * 2^7k = 2^8k
+ // addiu a4, a4, 0x0000; (0x25080000)
+ // ...
+ // addiu a7, a4, 0xffff; (0x250bffff)
+ uint32_t addiu_start_2 = 0x25000000;
+ for (int32_t i = 0x80000; i <= 0xbffff; ++i) {
+ uint32_t addiu_new = addiu_start_2 + i;
+ __ dd(addiu_new);
+ }
+
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ uint64_t res =
+ reinterpret_cast<uint64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_ldpc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseLdpc {
+ int offset;
+ uint64_t expected_res;
+ };
+
+ struct TestCaseLdpc tc[] = {
+ // offset, expected_res
+ { -131072, 0x250ffffe250fffff },
+ { -4, 0x250c0006250c0007 },
+ { -1, 0x250c0000250c0001 },
+ { 0, 0x03001025ef180000 },
+ { 1, 0x2508000125080000 },
+ { 4, 0x2508000725080006 },
+ { 131071, 0x250bfffd250bfffc },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseLdpc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ uint64_t res = run_ldpc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+int64_t run_bc(int32_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label continue_1, stop_execution;
+ __ push(ra);
+ __ li(v0, 0);
+ __ li(t8, 0);
+ __ li(t9, 2); // Condition for the stopping execution.
+
+ uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
+ for (int32_t i = -100; i <= -11; ++i) {
+ __ dd(instruction_addiu);
+ }
+
+ __ addiu(t8, t8, 1); // -10
+
+ __ beq(t8, t9, &stop_execution); // -9
+ __ nop(); // -8
+ __ beq(t8, t8, &continue_1); // -7
+ __ nop(); // -6
+
+ __ bind(&stop_execution);
+ __ pop(ra); // -5, -4
+ __ jr(ra); // -3
+ __ nop(); // -2
+
+ __ bind(&continue_1);
+ __ bc(offset); // -1
+
+ for (int32_t i = 0; i <= 99; ++i) {
+ __ dd(instruction_addiu);
+ }
+
+ __ pop(ra);
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ int64_t res =
+ reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_bc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseBc {
+ int32_t offset;
+ int64_t expected_res;
+ };
+
+ struct TestCaseBc tc[] = {
+ // offset, expected_result
+ { -100, (abs(-100) - 10) * 2 },
+ { -11, (abs(-100) - 10 + 1) },
+ { 0, (abs(-100) - 10 + 1 + 99) },
+ { 1, (abs(-100) - 10 + 99) },
+ { 99, (abs(-100) - 10 + 1) },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ int64_t res = run_bc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
+int64_t run_balc(int32_t offset) {
+ Isolate* isolate = CcTest::i_isolate();
+ HandleScope scope(isolate);
+
+ MacroAssembler assm(isolate, NULL, 0);
+
+ Label continue_1, stop_execution;
+ __ push(ra);
+ __ li(v0, 0);
+ __ li(t8, 0);
+ __ li(t9, 2); // Condition for stopping execution.
+
+ __ beq(t8, t8, &continue_1);
+ __ nop();
+
+ uint32_t instruction_addiu = 0x24420001; // addiu v0, v0, 1
+ for (int32_t i = -117; i <= -57; ++i) {
+ __ dd(instruction_addiu);
+ }
+ __ jr(ra); // -56
+ __ nop(); // -55
+
+ for (int32_t i = -54; i <= -4; ++i) {
+ __ dd(instruction_addiu);
+ }
+ __ jr(ra); // -3
+ __ nop(); // -2
+
+ __ bind(&continue_1);
+ __ balc(offset); // -1
+
+ __ pop(ra); // 0, 1
+ __ jr(ra); // 2
+ __ nop(); // 3
+
+ for (int32_t i = 4; i <= 44; ++i) {
+ __ dd(instruction_addiu);
+ }
+ __ jr(ra);
+ __ nop();
+
+ CodeDesc desc;
+ assm.GetCode(&desc);
+ Handle<Code> code = isolate->factory()->NewCode(
+ desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+
+ F2 f = FUNCTION_CAST<F2>(code->entry());
+
+ int64_t res =
+ reinterpret_cast<int64_t>(CALL_GENERATED_CODE(f, 0, 0, 0, 0, 0));
+
+ return res;
+}
+
+
+TEST(r6_balc) {
+ if (kArchVariant == kMips64r6) {
+ CcTest::InitializeVM();
+
+ struct TestCaseBalc {
+ int32_t offset;
+ int64_t expected_res;
+ };
+
+ struct TestCaseBalc tc[] = {
+ // offset, expected_result
+ { -117, 61 },
+ { -54, 51 },
+ { 0, 0 },
+ { 4, 41 },
+ };
+
+ size_t nr_test_cases = sizeof(tc) / sizeof(TestCaseBalc);
+ for (size_t i = 0; i < nr_test_cases; ++i) {
+ int64_t res = run_balc(tc[i].offset);
+ CHECK_EQ(tc[i].expected_res, res);
+ }
+ }
+}
+
+
#undef __
COMPARE(bnvc(a1, a0, -32768),
"60a48000 bnvc a1, a0, -32768");
- COMPARE(beqzc(a0, 0),
- "d8800000 beqzc a0, 0x0");
- COMPARE(beqzc(a0, 0xfffff), // 0x0fffff == 1048575.
- "d88fffff beqzc a0, 0xfffff");
- COMPARE(beqzc(a0, 0x100000), // 0x100000 == -1048576.
- "d8900000 beqzc a0, 0x100000");
+ COMPARE(beqzc(a0, -1048576), "d8900000 beqzc a0, -1048576");
+ COMPARE(beqzc(a0, -1), "d89fffff beqzc a0, -1");
+ COMPARE(beqzc(a0, 0), "d8800000 beqzc a0, 0");
+ COMPARE(beqzc(a0, 1), "d8800001 beqzc a0, 1");
+ COMPARE(beqzc(a0, 1048575), "d88fffff beqzc a0, 1048575");
COMPARE(bnezc(a0, 0),
"f8800000 bnezc a0, 0x0");
"f88fffff bnezc a0, 0xfffff");
COMPARE(bnezc(a0, 0x100000), // 0x100000 == -1048576.
"f8900000 bnezc a0, 0x100000");
+
+ COMPARE(bc(-33554432), "ca000000 bc -33554432");
+ COMPARE(bc(-1), "cbffffff bc -1");
+ COMPARE(bc(0), "c8000000 bc 0");
+ COMPARE(bc(1), "c8000001 bc 1");
+ COMPARE(bc(33554431), "c9ffffff bc 33554431");
+
+ COMPARE(balc(-33554432), "ea000000 balc -33554432");
+ COMPARE(balc(-1), "ebffffff balc -1");
+ COMPARE(balc(0), "e8000000 balc 0");
+ COMPARE(balc(1), "e8000001 balc 1");
+ COMPARE(balc(33554431), "e9ffffff balc 33554431");
}
COMPARE(addiu(a0, a1, 0x0),
}
}
- if (IsMipsArchVariant(kMips32r2)) {
+ if (IsMipsArchVariant(kMips32r2) || IsMipsArchVariant(kMips32r6)) {
COMPARE(ins_(a0, a1, 31, 1),
"7ca4ffc4 ins a0, a1, 31, 1");
COMPARE(ins_(s6, s7, 30, 2),
COMPARE(div_s(f2, f4, f6), "46062083 div.s f2, f4, f6");
COMPARE(div_d(f2, f4, f6), "46262083 div.d f2, f4, f6");
+ if (IsMipsArchVariant(kMips32r6)) {
+ COMPARE(align(v0, a0, a1, 0), "7c851220 align v0, a0, a1, 0");
+ COMPARE(align(v0, a0, a1, 1), "7c851260 align v0, a0, a1, 1");
+ COMPARE(align(v0, a0, a1, 2), "7c8512a0 align v0, a0, a1, 2");
+ COMPARE(align(v0, a0, a1, 3), "7c8512e0 align v0, a0, a1, 3");
+ }
+
+ if (IsMipsArchVariant(kMips32r6)) {
+ COMPARE(aluipc(v0, 0), "ec5f0000 aluipc v0, 0");
+ COMPARE(aluipc(v0, 1), "ec5f0001 aluipc v0, 1");
+ COMPARE(aluipc(v0, 32767), "ec5f7fff aluipc v0, 32767");
+ COMPARE(aluipc(v0, -32768), "ec5f8000 aluipc v0, -32768");
+ COMPARE(aluipc(v0, -1), "ec5fffff aluipc v0, -1");
+ }
+
+ if (IsMipsArchVariant(kMips32r6)) {
+ COMPARE(auipc(t8, 0), "ef1e0000 auipc t8, 0");
+ COMPARE(auipc(t8, 1), "ef1e0001 auipc t8, 1");
+ COMPARE(auipc(t8, 32767), "ef1e7fff auipc t8, 32767");
+ COMPARE(auipc(t8, -32768), "ef1e8000 auipc t8, -32768");
+ COMPARE(auipc(t8, -1), "ef1effff auipc t8, -1");
+ }
+
+ if (IsMipsArchVariant(kMips32r6)) {
+ COMPARE(lwpc(t1, 0), "ed280000 lwpc t1, 0");
+ COMPARE(lwpc(t1, 4), "ed280004 lwpc t1, 4");
+ COMPARE(lwpc(t1, -4), "ed2ffffc lwpc t1, -4");
+ }
+
+ if (IsMipsArchVariant(kMips32r6)) {
+ COMPARE(jic(t0, -32768), "d8088000 jic t0, -32768");
+ COMPARE(jic(t0, -1), "d808ffff jic t0, -1");
+ COMPARE(jic(t0, 0), "d8080000 jic t0, 0");
+ COMPARE(jic(t0, 4), "d8080004 jic t0, 4");
+ COMPARE(jic(t0, 32767), "d8087fff jic t0, 32767");
+ }
+
+ if (IsMipsArchVariant(kMips32r6)) {
+ COMPARE(addiupc(a0, 262143), "ec83ffff addiupc a0, 262143");
+ COMPARE(addiupc(a0, -1), "ec87ffff addiupc a0, -1");
+ COMPARE(addiupc(v0, 0), "ec400000 addiupc v0, 0");
+ COMPARE(addiupc(s1, 1), "ee200001 addiupc s1, 1");
+ COMPARE(addiupc(a0, -262144), "ec840000 addiupc a0, -262144");
+ }
+
+ if (IsMipsArchVariant(kMips32r6)) {
+ COMPARE(jialc(a0, -32768), "f8048000 jialc a0, 0x8000");
+ COMPARE(jialc(a0, -1), "f804ffff jialc a0, 0xffff");
+ COMPARE(jialc(v0, 0), "f8020000 jialc v0, 0x0");
+ COMPARE(jialc(s1, 1), "f8110001 jialc s1, 0x1");
+ COMPARE(jialc(a0, 32767), "f8047fff jialc a0, 0x7fff");
+ }
+
VERIFY_RUN();
}
"f88fffff bnezc a0, 0xfffff");
COMPARE(bnezc(a0, 0x100000), // 0x100000 == -1048576.
"f8900000 bnezc a0, 0x100000");
+
+ COMPARE(bc(-33554432), "ca000000 bc -33554432");
+ COMPARE(bc(-1), "cbffffff bc -1");
+ COMPARE(bc(0), "c8000000 bc 0");
+ COMPARE(bc(1), "c8000001 bc 1");
+ COMPARE(bc(33554431), "c9ffffff bc 33554431");
+
+ COMPARE(balc(-33554432), "ea000000 balc -33554432");
+ COMPARE(balc(-1), "ebffffff balc -1");
+ COMPARE(balc(0), "e8000000 balc 0");
+ COMPARE(balc(1), "e8000001 balc 1");
+ COMPARE(balc(33554431), "e9ffffff balc 33554431");
}
COMPARE(addiu(a0, a1, 0x0),
COMPARE(div_s(f2, f4, f6), "46062083 div.s f2, f4, f6");
COMPARE(div_d(f2, f4, f6), "46262083 div.d f2, f4, f6");
+ if (kArchVariant == kMips64r6) {
+ COMPARE(align(v0, a0, a1, 0), "7c851220 align v0, a0, a1, 0");
+ COMPARE(align(v0, a0, a1, 1), "7c851260 align v0, a0, a1, 1");
+ COMPARE(align(v0, a0, a1, 2), "7c8512a0 align v0, a0, a1, 2");
+ COMPARE(align(v0, a0, a1, 3), "7c8512e0 align v0, a0, a1, 3");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(dalign(v0, a0, a1, 0), "7c851224 dalign v0, a0, a1, 0");
+ COMPARE(dalign(v0, a0, a1, 1), "7c851264 dalign v0, a0, a1, 1");
+ COMPARE(dalign(v0, a0, a1, 2), "7c8512a4 dalign v0, a0, a1, 2");
+ COMPARE(dalign(v0, a0, a1, 3), "7c8512e4 dalign v0, a0, a1, 3");
+ COMPARE(dalign(v0, a0, a1, 4), "7c851324 dalign v0, a0, a1, 4");
+ COMPARE(dalign(v0, a0, a1, 5), "7c851364 dalign v0, a0, a1, 5");
+ COMPARE(dalign(v0, a0, a1, 6), "7c8513a4 dalign v0, a0, a1, 6");
+ COMPARE(dalign(v0, a0, a1, 7), "7c8513e4 dalign v0, a0, a1, 7");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(aluipc(v0, 0), "ec5f0000 aluipc v0, 0");
+ COMPARE(aluipc(v0, 1), "ec5f0001 aluipc v0, 1");
+ COMPARE(aluipc(v0, 32767), "ec5f7fff aluipc v0, 32767");
+ COMPARE(aluipc(v0, -32768), "ec5f8000 aluipc v0, -32768");
+ COMPARE(aluipc(v0, -1), "ec5fffff aluipc v0, -1");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(auipc(t8, 0), "ef1e0000 auipc t8, 0");
+ COMPARE(auipc(t8, 1), "ef1e0001 auipc t8, 1");
+ COMPARE(auipc(t8, 32767), "ef1e7fff auipc t8, 32767");
+ COMPARE(auipc(t8, -32768), "ef1e8000 auipc t8, -32768");
+ COMPARE(auipc(t8, -1), "ef1effff auipc t8, -1");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(lwpc(a5, 0), "ed280000 lwpc a5, 0");
+ COMPARE(lwpc(a5, 4), "ed280004 lwpc a5, 4");
+ COMPARE(lwpc(a5, -4), "ed2ffffc lwpc a5, -4");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(lwupc(a0, -262144), "ec940000 lwupc a0, -262144");
+ COMPARE(lwupc(a0, -1), "ec97ffff lwupc a0, -1");
+ COMPARE(lwupc(a0, 0), "ec900000 lwupc a0, 0");
+ COMPARE(lwupc(a0, 1), "ec900001 lwupc a0, 1");
+ COMPARE(lwupc(a0, 262143), "ec93ffff lwupc a0, 262143");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(jic(t0, 16), "d80c0010 jic t0, 16");
+ COMPARE(jic(t0, 4), "d80c0004 jic t0, 4");
+ COMPARE(jic(t0, -32), "d80cffe0 jic t0, -32");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(beqzc(a0, 16), "d8800010 beqzc a0, 0x10");
+ COMPARE(beqzc(a0, 4), "d8800004 beqzc a0, 0x4");
+ COMPARE(beqzc(a0, -32), "d89fffe0 beqzc a0, 0x1fffe0");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(ldpc(v0, 256), "ec580100 ldpc v0, 256");
+ COMPARE(ldpc(a0, -1), "ec9bffff ldpc a0, -1");
+ COMPARE(ldpc(a1, 0), "ecb80000 ldpc a1, 0");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(addiupc(a0, 262143), "ec83ffff addiupc a0, 262143");
+ COMPARE(addiupc(a0, -1), "ec87ffff addiupc a0, -1");
+ COMPARE(addiupc(v0, 0), "ec400000 addiupc v0, 0");
+ COMPARE(addiupc(s1, 1), "ee200001 addiupc s1, 1");
+ COMPARE(addiupc(a0, -262144), "ec840000 addiupc a0, -262144");
+ }
+
+ if (kArchVariant == kMips64r6) {
+ COMPARE(jialc(a0, -32768), "f8048000 jialc a0, 0x8000");
+ COMPARE(jialc(a0, -1), "f804ffff jialc a0, 0xffff");
+ COMPARE(jialc(v0, 0), "f8020000 jialc v0, 0x0");
+ COMPARE(jialc(s1, 1), "f8110001 jialc s1, 0x1");
+ COMPARE(jialc(a0, 32767), "f8047fff jialc a0, 0x7fff");
+ }
+
VERIFY_RUN();
}