MIPS: Implemented PC-relative instructions for R6.
Added: JIC, BEQZC, JIALC, LDPC, LWPC, ALUIPC, ADDIUPC, ALIGN/DAILGN, LWUPC, AUIPC, BC, BALC. Additional fixed compact branch offset. TEST=test-assembler-mips[64]/r6_align, r6_dalign, r6_aluipc, r6_lwpc, r6_jic, r6_beqzc, r6_jialc, r6_addiupc, r6_ldpc, r6_lwupc, r6_auipc, r6_bc, r6_balc BUG= Review URL: https://codereview.chromium.org/1195793002 Cr-Commit-Position: refs/heads/master@{#29143}
This commit is contained in:
parent
554bc07d96
commit
f0c4edfdc5
@ -959,6 +959,20 @@ void Assembler::GenInstrImmediate(Opcode opcode,
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
@ -1156,6 +1170,19 @@ void Assembler::bal(int16_t offset) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
@ -1355,7 +1382,7 @@ void Assembler::beqc(Register rs, Register rt, int16_t 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);
|
||||
}
|
||||
|
||||
@ -1370,7 +1397,7 @@ void Assembler::bnec(Register rs, Register rt, int16_t offset) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1422,29 +1449,18 @@ void Assembler::jalr(Register rs, Register rd) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -1757,11 +1773,46 @@ void Assembler::lui(Register rd, int32_t j) {
|
||||
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.
|
||||
@ -1937,8 +1988,8 @@ void Assembler::ext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -1951,6 +2002,14 @@ void Assembler::pref(int32_t hint, const MemOperand& rs) {
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
|
@ -645,6 +645,10 @@ class Assembler : public AssemblerBase {
|
||||
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) {
|
||||
@ -753,8 +757,8 @@ class Assembler : public AssemblerBase {
|
||||
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---------
|
||||
@ -819,6 +823,14 @@ class Assembler : public AssemblerBase {
|
||||
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);
|
||||
@ -879,6 +891,7 @@ class Assembler : public AssemblerBase {
|
||||
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----------------
|
||||
|
||||
@ -1347,6 +1360,8 @@ class Assembler : public AssemblerBase {
|
||||
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,
|
||||
|
@ -141,6 +141,8 @@ bool Instruction::IsForbiddenInBranchDelay() const {
|
||||
case BNEL:
|
||||
case BLEZL:
|
||||
case BGTZL:
|
||||
case BC:
|
||||
case BALC:
|
||||
return true;
|
||||
case REGIMM:
|
||||
switch (RtFieldRaw()) {
|
||||
@ -173,6 +175,11 @@ bool Instruction::IsLinkingInstruction() const {
|
||||
switch (op) {
|
||||
case JAL:
|
||||
return true;
|
||||
case POP76:
|
||||
if (RsFieldRawNoAssert() == JIALC)
|
||||
return true; // JIALC
|
||||
else
|
||||
return false; // BNEZC
|
||||
case REGIMM:
|
||||
switch (RtFieldRaw()) {
|
||||
case BGEZAL:
|
||||
@ -272,8 +279,25 @@ Instruction::Type Instruction::InstructionType() const {
|
||||
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;
|
||||
}
|
||||
@ -309,8 +333,8 @@ Instruction::Type Instruction::InstructionType() const {
|
||||
case BNEL:
|
||||
case BLEZL:
|
||||
case BGTZL:
|
||||
case BEQZC:
|
||||
case BNEZC:
|
||||
case POP66:
|
||||
case POP76:
|
||||
case LB:
|
||||
case LH:
|
||||
case LWL:
|
||||
@ -327,6 +351,9 @@ Instruction::Type Instruction::InstructionType() const {
|
||||
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:
|
||||
|
@ -259,9 +259,15 @@ const int kSaBits = 5;
|
||||
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;
|
||||
@ -294,6 +300,9 @@ const int kFBtrueBits = 1;
|
||||
// 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;
|
||||
@ -311,60 +320,63 @@ const int kJumpAddrMask = (1 << (kImm26Bits + kImmFieldShift)) - 1;
|
||||
// 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,
|
||||
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,
|
||||
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.
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
PREF = ((6 << 3) + 3) << kOpcodeShift,
|
||||
|
||||
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
|
||||
SDC1 = ((7 << 3) + 5) << kOpcodeShift,
|
||||
BNEZC = ((7 << 3) + 6) << 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
|
||||
COP1X = ((1 << 4) + 3) << kOpcodeShift
|
||||
};
|
||||
|
||||
enum SecondaryField {
|
||||
@ -435,7 +447,14 @@ 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,
|
||||
@ -571,6 +590,18 @@ enum SecondaryField {
|
||||
// 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
|
||||
};
|
||||
|
||||
@ -881,6 +912,11 @@ class Instruction {
|
||||
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);
|
||||
@ -924,7 +960,6 @@ class Instruction {
|
||||
}
|
||||
|
||||
inline int SaFieldRaw() const {
|
||||
DCHECK(InstructionType() == kRegisterType);
|
||||
return InstructionBits() & kSaFieldMask;
|
||||
}
|
||||
|
||||
@ -953,13 +988,24 @@ class Instruction {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -81,13 +81,20 @@ class Decoder {
|
||||
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.
|
||||
@ -236,6 +243,12 @@ void Decoder::PrintCc(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
@ -257,6 +270,38 @@ void Decoder::PrintXImm16(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
// 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();
|
||||
@ -264,13 +309,33 @@ void Decoder::PrintXImm21(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
@ -389,25 +454,75 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
} else if (format[3] == '2' && format[4] == '1') {
|
||||
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] == '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;
|
||||
}
|
||||
}
|
||||
@ -442,10 +557,23 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
||||
}
|
||||
}
|
||||
}
|
||||
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"));
|
||||
@ -941,7 +1069,7 @@ void Decoder::DecodeTypeRegisterSPECIAL2(Instruction* instr) {
|
||||
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);
|
||||
@ -949,18 +1077,45 @@ void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* 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;
|
||||
}
|
||||
@ -1087,6 +1242,12 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
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;
|
||||
@ -1152,13 +1313,17 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
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;
|
||||
@ -1270,6 +1435,35 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
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();
|
||||
|
@ -2169,6 +2169,7 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
|
||||
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();
|
||||
|
||||
@ -2411,28 +2412,58 @@ void Simulator::ConfigureTypeRegister(Instruction* instr,
|
||||
*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;
|
||||
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;
|
||||
// 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);
|
||||
// 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;
|
||||
output = output | (static_cast<uint32_t>(o_byte << 24));
|
||||
input = input >> 8;
|
||||
}
|
||||
|
||||
*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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*alu_out = static_cast<int32_t>(output);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -3760,10 +3791,9 @@ void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
|
||||
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:
|
||||
@ -3848,11 +3878,15 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
|
||||
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;
|
||||
@ -3860,12 +3894,17 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
// 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;
|
||||
@ -3979,6 +4018,33 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
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)) {
|
||||
@ -4093,6 +4159,55 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
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();
|
||||
}
|
||||
@ -4170,6 +4285,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
addr = rs + se_imm16;
|
||||
WriteD(addr, get_fpu_register_double(ft_reg), instr);
|
||||
break;
|
||||
case PCREL:
|
||||
set_register(rs_reg, alu_out);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -967,6 +967,20 @@ void Assembler::GenInstrImmediate(Opcode opcode,
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
@ -1111,7 +1125,7 @@ int32_t Assembler::branch_offset21_compact(Label* L,
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
@ -1158,6 +1172,19 @@ void Assembler::bal(int16_t offset) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
@ -1357,7 +1384,7 @@ void Assembler::beqc(Register rs, Register rt, int16_t 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);
|
||||
}
|
||||
|
||||
@ -1372,7 +1399,7 @@ void Assembler::bnec(Register rs, Register rt, int16_t offset) {
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1428,29 +1455,18 @@ void Assembler::jalr(Register rs, Register rd) {
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -1921,6 +1937,7 @@ void Assembler::lui(Register rd, int32_t j) {
|
||||
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);
|
||||
}
|
||||
@ -1984,6 +2001,56 @@ void Assembler::sd(Register rd, const MemOperand& rs) {
|
||||
}
|
||||
|
||||
|
||||
// ---------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.
|
||||
@ -2232,13 +2299,13 @@ void Assembler::dext_(Register rt, Register rs, uint16_t pos, uint16_t size) {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -2250,6 +2317,22 @@ void Assembler::pref(int32_t hint, const MemOperand& rs) {
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
|
@ -636,6 +636,10 @@ class Assembler : public AssemblerBase {
|
||||
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) {
|
||||
@ -745,8 +749,8 @@ class Assembler : public AssemblerBase {
|
||||
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---------
|
||||
@ -849,6 +853,16 @@ class Assembler : public AssemblerBase {
|
||||
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);
|
||||
@ -911,6 +925,8 @@ class Assembler : public AssemblerBase {
|
||||
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----------------
|
||||
|
||||
@ -1388,6 +1404,8 @@ class Assembler : public AssemblerBase {
|
||||
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,
|
||||
|
@ -141,6 +141,8 @@ bool Instruction::IsForbiddenInBranchDelay() const {
|
||||
case BNEL:
|
||||
case BLEZL:
|
||||
case BGTZL:
|
||||
case BC:
|
||||
case BALC:
|
||||
return true;
|
||||
case REGIMM:
|
||||
switch (RtFieldRaw()) {
|
||||
@ -173,6 +175,11 @@ bool Instruction::IsLinkingInstruction() const {
|
||||
switch (op) {
|
||||
case JAL:
|
||||
return true;
|
||||
case POP76:
|
||||
if (RsFieldRawNoAssert() == JIALC)
|
||||
return true; // JIALC
|
||||
else
|
||||
return false; // BNEZC
|
||||
case REGIMM:
|
||||
switch (RtFieldRaw()) {
|
||||
case BGEZAL:
|
||||
@ -290,9 +297,43 @@ Instruction::Type Instruction::InstructionType() const {
|
||||
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;
|
||||
}
|
||||
@ -329,8 +370,8 @@ Instruction::Type Instruction::InstructionType() const {
|
||||
case BNEL:
|
||||
case BLEZL:
|
||||
case BGTZL:
|
||||
case BEQZC:
|
||||
case BNEZC:
|
||||
case POP66:
|
||||
case POP76:
|
||||
case LB:
|
||||
case LH:
|
||||
case LWL:
|
||||
@ -350,6 +391,9 @@ Instruction::Type Instruction::InstructionType() const {
|
||||
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:
|
||||
|
@ -221,9 +221,17 @@ const int kSaBits = 5;
|
||||
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;
|
||||
@ -256,6 +264,9 @@ const int kFBtrueBits = 1;
|
||||
// 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;
|
||||
@ -276,72 +287,75 @@ const int64_t kTh16MaskOf64 = (int64_t)0xffff << 16;
|
||||
// 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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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
|
||||
COP1X = ((1 << 4) + 3) << kOpcodeShift
|
||||
};
|
||||
|
||||
enum SecondaryField {
|
||||
@ -443,12 +457,21 @@ 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,
|
||||
@ -588,6 +611,21 @@ enum SecondaryField {
|
||||
// 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
|
||||
};
|
||||
|
||||
@ -898,6 +936,16 @@ class Instruction {
|
||||
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);
|
||||
@ -941,7 +989,6 @@ class Instruction {
|
||||
}
|
||||
|
||||
inline int SaFieldRaw() const {
|
||||
DCHECK(InstructionType() == kRegisterType);
|
||||
return InstructionBits() & kSaFieldMask;
|
||||
}
|
||||
|
||||
@ -970,13 +1017,24 @@ class Instruction {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -86,10 +86,17 @@ class Decoder {
|
||||
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);
|
||||
|
||||
@ -251,7 +258,8 @@ void Decoder::PrintUImm16(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);
|
||||
}
|
||||
|
||||
@ -263,6 +271,38 @@ void Decoder::PrintXImm16(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
// 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();
|
||||
@ -270,13 +310,35 @@ void Decoder::PrintXImm21(Instruction* instr) {
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
@ -395,25 +457,66 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -448,10 +551,28 @@ int Decoder::FormatOption(Instruction* instr, const char* format) {
|
||||
}
|
||||
}
|
||||
}
|
||||
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"));
|
||||
@ -1135,17 +1256,65 @@ void Decoder::DecodeTypeRegisterSPECIAL3(Instruction* instr) {
|
||||
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;
|
||||
}
|
||||
@ -1248,6 +1417,12 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
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;
|
||||
@ -1313,13 +1488,17 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
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;
|
||||
@ -1454,9 +1633,52 @@ void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -2201,6 +2201,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
|
||||
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();
|
||||
|
||||
@ -2335,7 +2337,8 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
|
||||
// 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:
|
||||
@ -2519,39 +2522,16 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
|
||||
*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;
|
||||
|
||||
@ -2563,15 +2543,96 @@ void Simulator::ConfigureTypeRegister(Instruction* instr, int64_t* alu_out,
|
||||
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;
|
||||
}
|
||||
@ -3853,8 +3914,8 @@ void Simulator::DecodeTypeRegisterSPECIAL3(Instruction* instr,
|
||||
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;
|
||||
@ -3933,7 +3994,31 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
|
||||
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
|
||||
@ -3949,11 +4034,16 @@ void Simulator::DecodeTypeRegister(Instruction* instr) {
|
||||
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);
|
||||
@ -3962,11 +4052,17 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
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;
|
||||
@ -4080,6 +4176,33 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
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:
|
||||
@ -4213,10 +4336,83 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
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();
|
||||
|
||||
@ -4298,6 +4494,8 @@ void Simulator::DecodeTypeImmediate(Instruction* instr) {
|
||||
addr = rs + se_imm16;
|
||||
WriteD(addr, get_fpu_register_double(ft_reg), instr);
|
||||
break;
|
||||
case PCREL:
|
||||
set_register(rs_reg, alu_out);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -4262,10 +4262,12 @@ TEST(DIV_FMT) {
|
||||
|
||||
__ 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));
|
||||
@ -4343,4 +4345,707 @@ TEST(DIV_FMT) {
|
||||
}
|
||||
|
||||
|
||||
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 __
|
||||
|
@ -45,6 +45,7 @@ using namespace v8::internal;
|
||||
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
|
||||
|
||||
@ -4448,4 +4449,918 @@ TEST(DIV_FMT) {
|
||||
}
|
||||
|
||||
|
||||
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 __
|
||||
|
@ -217,12 +217,11 @@ TEST(Type0) {
|
||||
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");
|
||||
@ -230,6 +229,18 @@ TEST(Type0) {
|
||||
"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),
|
||||
@ -506,7 +517,7 @@ TEST(Type0) {
|
||||
}
|
||||
}
|
||||
|
||||
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),
|
||||
@ -534,6 +545,59 @@ TEST(Type0) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
@ -311,6 +311,18 @@ TEST(Type0) {
|
||||
"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),
|
||||
@ -685,6 +697,88 @@ TEST(Type0) {
|
||||
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();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user