Commit f0c4edfd authored by Ilija.Pavlovic's avatar Ilija.Pavlovic Committed by Commit bot

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}
parent 554bc07d
......@@ -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,
J = ((0 << 3) + 2) << kOpcodeShift,
JAL = ((0 << 3) + 3) << kOpcodeShift,
BEQ = ((0 << 3) + 4) << kOpcodeShift,
BNE = ((0 << 3) + 5) << kOpcodeShift,
BLEZ = ((0 << 3) + 6) << kOpcodeShift,
BGTZ = ((0 << 3) + 7) << kOpcodeShift,
ADDI = ((1 << 3) + 0) << kOpcodeShift,
ADDIU = ((1 << 3) + 1) << kOpcodeShift,
SLTI = ((1 << 3) + 2) << kOpcodeShift,
SLTIU = ((1 << 3) + 3) << kOpcodeShift,
ANDI = ((1 << 3) + 4) << kOpcodeShift,
ORI = ((1 << 3) + 5) << kOpcodeShift,
XORI = ((1 << 3) + 6) << kOpcodeShift,
LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
BEQC = ((2 << 3) + 0) << kOpcodeShift,
COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
BEQL = ((2 << 3) + 4) << kOpcodeShift,
BNEL = ((2 << 3) + 5) << kOpcodeShift,
BLEZL = ((2 << 3) + 6) << kOpcodeShift,
BGTZL = ((2 << 3) + 7) << kOpcodeShift,
DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
LB = ((4 << 3) + 0) << kOpcodeShift,
LH = ((4 << 3) + 1) << kOpcodeShift,
LWL = ((4 << 3) + 2) << kOpcodeShift,
LW = ((4 << 3) + 3) << kOpcodeShift,
LBU = ((4 << 3) + 4) << kOpcodeShift,
LHU = ((4 << 3) + 5) << kOpcodeShift,
LWR = ((4 << 3) + 6) << kOpcodeShift,
SB = ((5 << 3) + 0) << kOpcodeShift,
SH = ((5 << 3) + 1) << kOpcodeShift,
SWL = ((5 << 3) + 2) << kOpcodeShift,
SW = ((5 << 3) + 3) << kOpcodeShift,
SWR = ((5 << 3) + 6) << kOpcodeShift,
LWC1 = ((6 << 3) + 1) << kOpcodeShift,
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
BEQZC = ((6 << 3) + 6) << kOpcodeShift,
PREF = ((6 << 3) + 3) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
SDC1 = ((7 << 3) + 5) << kOpcodeShift,
BNEZC = ((7 << 3) + 6) << kOpcodeShift,
COP1X = ((1 << 4) + 3) << kOpcodeShift
SPECIAL = 0 << kOpcodeShift,
REGIMM = 1 << kOpcodeShift,
J = ((0 << 3) + 2) << kOpcodeShift,
JAL = ((0 << 3) + 3) << kOpcodeShift,
BEQ = ((0 << 3) + 4) << kOpcodeShift,
BNE = ((0 << 3) + 5) << kOpcodeShift,
BLEZ = ((0 << 3) + 6) << kOpcodeShift,
BGTZ = ((0 << 3) + 7) << kOpcodeShift,
ADDI = ((1 << 3) + 0) << kOpcodeShift,
ADDIU = ((1 << 3) + 1) << kOpcodeShift,
SLTI = ((1 << 3) + 2) << kOpcodeShift,
SLTIU = ((1 << 3) + 3) << kOpcodeShift,
ANDI = ((1 << 3) + 4) << kOpcodeShift,
ORI = ((1 << 3) + 5) << kOpcodeShift,
XORI = ((1 << 3) + 6) << kOpcodeShift,
LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
BEQC = ((2 << 3) + 0) << kOpcodeShift,
COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
BEQL = ((2 << 3) + 4) << kOpcodeShift,
BNEL = ((2 << 3) + 5) << kOpcodeShift,
BLEZL = ((2 << 3) + 6) << kOpcodeShift,
BGTZL = ((2 << 3) + 7) << kOpcodeShift,
DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
LB = ((4 << 3) + 0) << kOpcodeShift,
LH = ((4 << 3) + 1) << kOpcodeShift,
LWL = ((4 << 3) + 2) << kOpcodeShift,
LW = ((4 << 3) + 3) << kOpcodeShift,
LBU = ((4 << 3) + 4) << kOpcodeShift,
LHU = ((4 << 3) + 5) << kOpcodeShift,
LWR = ((4 << 3) + 6) << kOpcodeShift,
SB = ((5 << 3) + 0) << kOpcodeShift,
SH = ((5 << 3) + 1) << kOpcodeShift,
SWL = ((5 << 3) + 2) << kOpcodeShift,
SW = ((5 << 3) + 3) << kOpcodeShift,
SWR = ((5 << 3) + 6) << kOpcodeShift,
LWC1 = ((6 << 3) + 1) << kOpcodeShift,
BC = ((6 << 3) + 2) << kOpcodeShift,
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
POP66 = ((6 << 3) + 6) << kOpcodeShift,
PREF = ((6 << 3) + 3) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
BALC = ((7 << 3) + 2) << kOpcodeShift,
PCREL = ((7 << 3) + 3) << kOpcodeShift,
SDC1 = ((7 << 3) + 5) << kOpcodeShift,
POP76 = ((7 << 3) + 6) << kOpcodeShift,
COP1X = ((1 << 4) + 3) << kOpcodeShift
};
enum SecondaryField {
......@@ -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);
}
......
This diff is collapsed.
......@@ -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;
// Reverse the bit in byte for each individual byte
for (int i = 0; i < 4; i++) {
output = output >> 8;
i_byte = input & 0xff;
// Fast way to reverse bits in byte
// Devised by Sean Anderson, July 13, 2001
o_byte = static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
(i_byte * 0x8020LU & 0x88440LU)) *
0x10101LU >>
16);
output = output | (static_cast<uint32_t>(o_byte << 24));
input = input >> 8;
}
case BSHFL: {
int sa = instr->SaFieldRaw() >> kSaShift;
switch (sa) {
case BITSWAP: {
uint32_t input = static_cast<uint32_t>(rt);
uint32_t output = 0;
uint8_t i_byte, o_byte;
// Reverse the bit in byte for each individual byte
for (int i = 0; i < 4; i++) {
output = output >> 8;
i_byte = input & 0xff;
// Fast way to reverse bits in byte
// Devised by Sean Anderson, July 13, 2001
o_byte =
static_cast<uint8_t>(((i_byte * 0x0802LU & 0x22110LU) |
(i_byte * 0x8020LU & 0x88440LU)) *
0x10101LU >>
16);
output = output | (static_cast<uint32_t>(o_byte << 24));
input = input >> 8;
}
*alu_out = static_cast<int32_t>(output);
*alu_out = static_cast<int32_t>(output);
break;
}
case SEB:
case SEH:
case WSBH:
UNREACHABLE();
break;
default: {
sa >>= kBp2Bits;
switch (sa) {
case ALIGN: {
if (bp == 0) {
*alu_out = static_cast<int32_t>(rt);
} else {
uint32_t rt_hi = rt << (8 * bp);
uint32_t rs_lo = rs >> (8 * (4 - bp));
*alu_out = static_cast<int32_t>(rt_hi | rs_lo);
}
break;
}
default:
UNREACHABLE();
break;
}
}
}
break;
}
default:
......@@ -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,
J = ((0 << 3) + 2) << kOpcodeShift,
JAL = ((0 << 3) + 3) << kOpcodeShift,
BEQ = ((0 << 3) + 4) << kOpcodeShift,
BNE = ((0 << 3) + 5) << kOpcodeShift,
BLEZ = ((0 << 3) + 6) << kOpcodeShift,
BGTZ = ((0 << 3) + 7) << kOpcodeShift,
ADDI = ((1 << 3) + 0) << kOpcodeShift,
ADDIU = ((1 << 3) + 1) << kOpcodeShift,
SLTI = ((1 << 3) + 2) << kOpcodeShift,
SLTIU = ((1 << 3) + 3) << kOpcodeShift,
ANDI = ((1 << 3) + 4) << kOpcodeShift,
ORI = ((1 << 3) + 5) << kOpcodeShift,
XORI = ((1 << 3) + 6) << kOpcodeShift,
LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
DAUI = ((3 << 3) + 5) << kOpcodeShift,
BEQC = ((2 << 3) + 0) << kOpcodeShift,
COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
BEQL = ((2 << 3) + 4) << kOpcodeShift,
BNEL = ((2 << 3) + 5) << kOpcodeShift,
BLEZL = ((2 << 3) + 6) << kOpcodeShift,
BGTZL = ((2 << 3) + 7) << kOpcodeShift,
DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
DADDIU = ((3 << 3) + 1) << kOpcodeShift,
LDL = ((3 << 3) + 2) << kOpcodeShift,
LDR = ((3 << 3) + 3) << kOpcodeShift,
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
LB = ((4 << 3) + 0) << kOpcodeShift,
LH = ((4 << 3) + 1) << kOpcodeShift,
LWL = ((4 << 3) + 2) << kOpcodeShift,
LW = ((4 << 3) + 3) << kOpcodeShift,
LBU = ((4 << 3) + 4) << kOpcodeShift,
LHU = ((4 << 3) + 5) << kOpcodeShift,
LWR = ((4 << 3) + 6) << kOpcodeShift,
LWU = ((4 << 3) + 7) << kOpcodeShift,
SB = ((5 << 3) + 0) << kOpcodeShift,
SH = ((5 << 3) + 1) << kOpcodeShift,
SWL = ((5 << 3) + 2) << kOpcodeShift,
SW = ((5 << 3) + 3) << kOpcodeShift,
SDL = ((5 << 3) + 4) << kOpcodeShift,
SDR = ((5 << 3) + 5) << kOpcodeShift,
SWR = ((5 << 3) + 6) << kOpcodeShift,
LWC1 = ((6 << 3) + 1) << kOpcodeShift,
LLD = ((6 << 3) + 4) << kOpcodeShift,
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
BEQZC = ((6 << 3) + 6) << kOpcodeShift,
LD = ((6 << 3) + 7) << kOpcodeShift,
PREF = ((6 << 3) + 3) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
SCD = ((7 << 3) + 4) << kOpcodeShift,
SDC1 = ((7 << 3) + 5) << kOpcodeShift,
BNEZC = ((7 << 3) + 6) << kOpcodeShift,
SD = ((7 << 3) + 7) << kOpcodeShift,
COP1X = ((1 << 4) + 3) << kOpcodeShift
SPECIAL = 0 << kOpcodeShift,
REGIMM = 1 << kOpcodeShift,
J = ((0 << 3) + 2) << kOpcodeShift,
JAL = ((0 << 3) + 3) << kOpcodeShift,
BEQ = ((0 << 3) + 4) << kOpcodeShift,
BNE = ((0 << 3) + 5) << kOpcodeShift,
BLEZ = ((0 << 3) + 6) << kOpcodeShift,
BGTZ = ((0 << 3) + 7) << kOpcodeShift,
ADDI = ((1 << 3) + 0) << kOpcodeShift,
ADDIU = ((1 << 3) + 1) << kOpcodeShift,
SLTI = ((1 << 3) + 2) << kOpcodeShift,
SLTIU = ((1 << 3) + 3) << kOpcodeShift,
ANDI = ((1 << 3) + 4) << kOpcodeShift,
ORI = ((1 << 3) + 5) << kOpcodeShift,
XORI = ((1 << 3) + 6) << kOpcodeShift,
LUI = ((1 << 3) + 7) << kOpcodeShift, // LUI/AUI family.
DAUI = ((3 << 3) + 5) << kOpcodeShift,
BEQC = ((2 << 3) + 0) << kOpcodeShift,
COP1 = ((2 << 3) + 1) << kOpcodeShift, // Coprocessor 1 class.
BEQL = ((2 << 3) + 4) << kOpcodeShift,
BNEL = ((2 << 3) + 5) << kOpcodeShift,
BLEZL = ((2 << 3) + 6) << kOpcodeShift,
BGTZL = ((2 << 3) + 7) << kOpcodeShift,
DADDI = ((3 << 3) + 0) << kOpcodeShift, // This is also BNEC.
DADDIU = ((3 << 3) + 1) << kOpcodeShift,
LDL = ((3 << 3) + 2) << kOpcodeShift,
LDR = ((3 << 3) + 3) << kOpcodeShift,
SPECIAL2 = ((3 << 3) + 4) << kOpcodeShift,
SPECIAL3 = ((3 << 3) + 7) << kOpcodeShift,
LB = ((4 << 3) + 0) << kOpcodeShift,
LH = ((4 << 3) + 1) << kOpcodeShift,
LWL = ((4 << 3) + 2) << kOpcodeShift,
LW = ((4 << 3) + 3) << kOpcodeShift,
LBU = ((4 << 3) + 4) << kOpcodeShift,
LHU = ((4 << 3) + 5) << kOpcodeShift,
LWR = ((4 << 3) + 6) << kOpcodeShift,
LWU = ((4 << 3) + 7) << kOpcodeShift,
SB = ((5 << 3) + 0) << kOpcodeShift,
SH = ((5 << 3) + 1) << kOpcodeShift,
SWL = ((5 << 3) + 2) << kOpcodeShift,
SW = ((5 << 3) + 3) << kOpcodeShift,
SDL = ((5 << 3) + 4) << kOpcodeShift,
SDR = ((5 << 3) + 5) << kOpcodeShift,
SWR = ((5 << 3) + 6) << kOpcodeShift,
LWC1 = ((6 << 3) + 1) << kOpcodeShift,
BC = ((6 << 3) + 2) << kOpcodeShift,
LLD = ((6 << 3) + 4) << kOpcodeShift,
LDC1 = ((6 << 3) + 5) << kOpcodeShift,
POP66 = ((6 << 3) + 6) << kOpcodeShift,
LD = ((6 << 3) + 7) << kOpcodeShift,
PREF = ((6 << 3) + 3) << kOpcodeShift,
SWC1 = ((7 << 3) + 1) << kOpcodeShift,
BALC = ((7 << 3) + 2) << kOpcodeShift,
PCREL = ((7 << 3) + 3) << kOpcodeShift,
SCD = ((7 << 3) + 4) << kOpcodeShift,
SDC1 = ((7 << 3) + 5) << kOpcodeShift,
POP76 = ((7 << 3) + 6) << kOpcodeShift,
SD = ((7 << 3) + 7) << kOpcodeShift,
COP1X = ((1 << 4) + 3) << kOpcodeShift
};
enum SecondaryField {
......@@ -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);
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -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();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment