Commit 1f068187 authored by dusan.simicic's avatar dusan.simicic Committed by Commit bot

MIPS[64]: Implement fill.df, copy_u.df, copy_s.df instructions in simulator

- Increase FPUregisters_[] element size to 128b in order to support MSA regs
- Add skeleton for MSA instr. decoding in mips32 and mips64 simulator
- Add support for fill.df, copy_u.df and copy_s.df MSA instructions
- Assembler test for fill.df, copy_u.df and copy_s.df

BUG=

Review-Url: https://codereview.chromium.org/2799923002
Cr-Commit-Position: refs/heads/master@{#45529}
parent b67139bf
......@@ -370,6 +370,16 @@ const int kImm5Mask = ((1 << 5) - 1);
const int kImm8Mask = ((1 << 8) - 1);
const int kImm10Mask = ((1 << 10) - 1);
const int kMsaI5I10Mask = ((7U << 23) | ((1 << 6) - 1));
const int kMsaI8Mask = ((3U << 24) | ((1 << 6) - 1));
const int kMsaI5Mask = ((7U << 23) | ((1 << 6) - 1));
const int kMsaMI10Mask = (15U << 2);
const int kMsaBITMask = ((7U << 23) | ((1 << 6) - 1));
const int kMsaELMMask = (15U << 22);
const int kMsa3RMask = ((7U << 23) | ((1 << 6) - 1));
const int kMsa3RFMask = ((15U << 22) | ((1 << 6) - 1));
const int kMsaVECMask = (23U << 21);
const int kMsa2RMask = (7U << 18);
const int kMsa2RFMask = (15U << 17);
const int kRsFieldMask = ((1 << kRsBits) - 1) << kRsShift;
const int kRtFieldMask = ((1 << kRtBits) - 1) << kRtShift;
const int kRdFieldMask = ((1 << kRdBits) - 1) << kRdShift;
......
......@@ -59,17 +59,6 @@ class Decoder {
int InstructionDecode(byte* instruction);
private:
const uint32_t kMsaI8Mask = ((3U << 24) | ((1 << 6) - 1));
const uint32_t kMsaI5Mask = ((7U << 23) | ((1 << 6) - 1));
const uint32_t kMsaMI10Mask = (15U << 2);
const uint32_t kMsaBITMask = ((7U << 23) | ((1 << 6) - 1));
const uint32_t kMsaELMMask = (15U << 22);
const uint32_t kMsa3RMask = ((7U << 23) | ((1 << 6) - 1));
const uint32_t kMsa3RFMask = ((15U << 22) | ((1 << 6) - 1));
const uint32_t kMsaVECMask = (23U << 21);
const uint32_t kMsa2RMask = (7U << 18);
const uint32_t kMsa2RFMask = (15U << 17);
// Bottleneck functions to print into the out_buffer.
void PrintChar(const char ch);
void Print(const char* str);
......
......@@ -907,7 +907,8 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
registers_[i] = 0;
}
for (int i = 0; i < kNumFPURegisters; i++) {
FPUregisters_[i] = 0;
FPUregisters_[2 * i] = 0;
FPUregisters_[2 * i + 1] = 0; // upper part for MSA ASE
}
if (IsMipsArchVariant(kMips32r6)) {
FCSR_ = kFCSRNaN2008FlagMask;
......@@ -1063,7 +1064,7 @@ void Simulator::set_dw_register(int reg, const int* dbl) {
void Simulator::set_fpu_register(int fpureg, int64_t value) {
DCHECK(IsFp64Mode());
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
FPUregisters_[fpureg] = value;
FPUregisters_[fpureg * 2] = value;
}
......@@ -1071,7 +1072,7 @@ void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
// Set ONLY lower 32-bits, leaving upper bits untouched.
// TODO(plind): big endian issue.
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
int32_t *pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
int32_t* pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]);
*pword = value;
}
......@@ -1080,21 +1081,22 @@ void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
// Set ONLY upper 32-bits, leaving lower bits untouched.
// TODO(plind): big endian issue.
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
int32_t *phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
int32_t* phiword =
(reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2])) + 1;
*phiword = value;
}
void Simulator::set_fpu_register_float(int fpureg, float value) {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
*bit_cast<float*>(&FPUregisters_[fpureg]) = value;
*bit_cast<float*>(&FPUregisters_[fpureg * 2]) = value;
}
void Simulator::set_fpu_register_double(int fpureg, double value) {
if (IsFp64Mode()) {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
*bit_cast<double*>(&FPUregisters_[fpureg]) = value;
*bit_cast<double*>(&FPUregisters_[fpureg * 2]) = value;
} else {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
int64_t i64 = bit_cast<int64_t>(value);
......@@ -1132,7 +1134,7 @@ double Simulator::get_double_from_register_pair(int reg) {
int64_t Simulator::get_fpu_register(int fpureg) const {
if (IsFp64Mode()) {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return FPUregisters_[fpureg];
return FPUregisters_[fpureg * 2];
} else {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
uint64_t i64;
......@@ -1145,32 +1147,32 @@ int64_t Simulator::get_fpu_register(int fpureg) const {
int32_t Simulator::get_fpu_register_word(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xffffffff);
}
int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xffffffff);
}
int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
return static_cast<int32_t>((FPUregisters_[fpureg * 2] >> 32) & 0xffffffff);
}
float Simulator::get_fpu_register_float(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg * 2]));
}
double Simulator::get_fpu_register_double(int fpureg) const {
if (IsFp64Mode()) {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return *bit_cast<double*>(&FPUregisters_[fpureg]);
return *bit_cast<double*>(&FPUregisters_[fpureg * 2]);
} else {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters) && ((fpureg % 2) == 0));
int64_t i64;
......@@ -1180,6 +1182,17 @@ double Simulator::get_fpu_register_double(int fpureg) const {
}
}
template <typename T>
void Simulator::get_msa_register(int wreg, T* value) {
DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
memcpy(value, FPUregisters_ + wreg * 2, kSimd128Size);
}
template <typename T>
void Simulator::set_msa_register(int wreg, const T* value) {
DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
memcpy(FPUregisters_ + wreg * 2, value, kSimd128Size);
}
// Runtime FP routines take up to two double arguments and zero
// or one integer arguments. All are constructed here,
......@@ -1744,6 +1757,59 @@ void Simulator::TraceRegWr(int64_t value, TraceType t) {
}
}
template <typename T>
void Simulator::TraceMSARegWr(T* value, TraceType t) {
if (::v8::internal::FLAG_trace_sim) {
union {
uint8_t b[16];
uint16_t h[8];
uint32_t w[4];
uint64_t d[2];
float f[4];
double df[2];
} v;
memcpy(v.b, value, kSimd128Size);
switch (t) {
case BYTE:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
v.d[0], v.d[1], icount_);
break;
case HALF:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
v.d[0], v.d[1], icount_);
break;
case WORD:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") int32[0..3]:%" PRId32 " %" PRId32 " %" PRId32
" %" PRId32,
v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
break;
case DWORD:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
v.d[0], v.d[1], icount_);
break;
case FLOAT:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") flt[0..3]:%e %e %e %e",
v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
break;
case DOUBLE:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") dbl[0..1]:%e %e",
v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
break;
default:
UNREACHABLE();
}
}
}
// TODO(plind): consider making icount_ printing a flag option.
void Simulator::TraceMemRd(int32_t addr, int32_t value, TraceType t) {
if (::v8::internal::FLAG_trace_sim) {
......@@ -4116,6 +4182,454 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
}
}
int Simulator::DecodeMsaDataFormat() {
int df = -1;
if (instr_.IsMSABranchInstr()) {
switch (instr_.RsFieldRaw()) {
case BZ_V:
case BNZ_V:
df = MSA_VECT;
break;
case BZ_B:
case BNZ_B:
df = MSA_BYTE;
break;
case BZ_H:
case BNZ_H:
df = MSA_HALF;
break;
case BZ_W:
case BNZ_W:
df = MSA_WORD;
break;
case BZ_D:
case BNZ_D:
df = MSA_DWORD;
break;
default:
UNREACHABLE();
break;
}
} else {
int DF[] = {MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD};
switch (instr_.MSAMinorOpcodeField()) {
case kMsaMinorI5:
case kMsaMinorI10:
case kMsaMinor3R:
df = DF[instr_.Bits(22, 21)];
break;
case kMsaMinorMI10:
df = DF[instr_.Bits(1, 0)];
break;
case kMsaMinorBIT:
df = DF[instr_.MsaBitDf()];
break;
case kMsaMinorELM:
df = DF[instr_.MsaElmDf()];
break;
case kMsaMinor3RF: {
uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
switch (opcode) {
case FEXDO:
case FTQ:
case MUL_Q:
case MADD_Q:
case MSUB_Q:
case MULR_Q:
case MADDR_Q:
case MSUBR_Q:
df = DF[1 + instr_.Bit(21)];
break;
default:
df = DF[2 + instr_.Bit(21)];
break;
}
} break;
case kMsaMinor2R:
df = DF[instr_.Bits(17, 16)];
break;
case kMsaMinor2RF:
df = DF[2 + instr_.Bit(16)];
break;
default:
UNREACHABLE();
break;
}
}
return df;
}
void Simulator::DecodeTypeMsaI8() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaI8Mask;
switch (opcode) {
case ANDI_B:
case ORI_B:
case NORI_B:
case XORI_B:
case BMNZI_B:
case BMZI_B:
case BSELI_B:
case SHF_B:
case SHF_H:
case SHF_W:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaI5() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
switch (opcode) {
case ADDVI:
case SUBVI:
case MAXI_S:
case MAXI_U:
case MINI_S:
case MINI_U:
case CEQI:
case CLTI_S:
case CLTI_U:
case CLEI_S:
case CLEI_U:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaI10() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
if (opcode == LDI) {
UNIMPLEMENTED();
} else {
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaELM() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaELMMask;
int32_t n = instr_.MsaElmNValue();
int32_t alu_out;
switch (opcode) {
case COPY_S:
case COPY_U:
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
DCHECK(n < 16);
int8_t ws[16];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFu : alu_out);
break;
}
case MSA_HALF: {
DCHECK(n < 8);
int16_t ws[8];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFFFu : alu_out);
break;
}
case MSA_WORD: {
DCHECK(n < 4);
int32_t ws[4];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
SetResult(wd_reg(), alu_out);
break;
}
default:
UNREACHABLE();
}
break;
case SLDI:
case SPLATI:
case INSERT:
case INSVE:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaBIT() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
switch (opcode) {
case SLLI:
case SRAI:
case SRLI:
case BCLRI:
case BSETI:
case BNEGI:
case BINSLI:
case BINSRI:
case SAT_S:
case SAT_U:
case SRARI:
case SRLRI:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaMI10() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaMI10Mask;
if (opcode == MSA_LD) {
UNIMPLEMENTED();
} else if (opcode == MSA_ST) {
UNIMPLEMENTED();
} else {
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsa3R() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa3RMask;
switch (opcode) {
case SLL_MSA:
case SRA_MSA:
case SRL_MSA:
case BCLR:
case BSET:
case BNEG:
case BINSL:
case BINSR:
case ADDV:
case SUBV:
case MAX_S:
case MAX_U:
case MIN_S:
case MIN_U:
case MAX_A:
case MIN_A:
case CEQ:
case CLT_S:
case CLT_U:
case CLE_S:
case CLE_U:
case ADD_A:
case ADDS_A:
case ADDS_S:
case ADDS_U:
case AVE_S:
case AVE_U:
case AVER_S:
case AVER_U:
case SUBS_S:
case SUBS_U:
case SUBSUS_U:
case SUBSUU_S:
case ASUB_S:
case ASUB_U:
case MULV:
case MADDV:
case MSUBV:
case DIV_S_MSA:
case DIV_U:
case MOD_S:
case MOD_U:
case DOTP_S:
case DOTP_U:
case DPADD_S:
case DPADD_U:
case DPSUB_S:
case DPSUB_U:
case SLD:
case SPLAT:
case PCKEV:
case PCKOD:
case ILVL:
case ILVR:
case ILVEV:
case ILVOD:
case VSHF:
case SRAR:
case SRLR:
case HADD_S:
case HADD_U:
case HSUB_S:
case HSUB_U:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsa3RF() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
switch (opcode) {
case FCAF:
case FCUN:
case FCEQ:
case FCUEQ:
case FCLT:
case FCULT:
case FCLE:
case FCULE:
case FSAF:
case FSUN:
case FSEQ:
case FSUEQ:
case FSLT:
case FSULT:
case FSLE:
case FSULE:
case FADD:
case FSUB:
case FMUL:
case FDIV:
case FMADD:
case FMSUB:
case FEXP2:
case FEXDO:
case FTQ:
case FMIN:
case FMIN_A:
case FMAX:
case FMAX_A:
case FCOR:
case FCUNE:
case FCNE:
case MUL_Q:
case MADD_Q:
case MSUB_Q:
case FSOR:
case FSUNE:
case FSNE:
case MULR_Q:
case MADDR_Q:
case MSUBR_Q:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaVec() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaVECMask;
switch (opcode) {
case AND_V:
case OR_V:
case NOR_V:
case XOR_V:
case BMNZ_V:
case BMZ_V:
case BSEL_V:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsa2R() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa2RMask;
switch (opcode) {
case FILL:
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
int8_t wd[16];
int32_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 16; i++) {
wd[i] = rs & 0xFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, BYTE);
break;
}
case MSA_HALF: {
int16_t wd[8];
int32_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 8; i++) {
wd[i] = rs & 0xFFFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, HALF);
break;
}
case MSA_WORD: {
int32_t wd[4];
int32_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 4; i++) {
wd[i] = rs;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, WORD);
break;
}
default:
UNREACHABLE();
}
break;
case PCNT:
case NLOC:
case NLZC:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsa2RF() {
DCHECK(IsMipsArchVariant(kMips32r6));
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa2RFMask;
switch (opcode) {
case FCLASS:
case FTRUNC_S:
case FTRUNC_U:
case FSQRT:
case FRSQRT:
case FRCP:
case FRINT:
case FLOG2:
case FEXUPL:
case FEXUPR:
case FFQL:
case FFQR:
case FTINT_S:
case FTINT_U:
case FFINT_S:
case FFINT_U:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeRegister() {
// ---------- Execution.
switch (instr_.OpcodeFieldRaw()) {
......@@ -4134,6 +4648,27 @@ void Simulator::DecodeTypeRegister() {
case SPECIAL3:
DecodeTypeRegisterSPECIAL3();
break;
case MSA:
switch (instr_.MSAMinorOpcodeField()) {
case kMsaMinor3R:
DecodeTypeMsa3R();
break;
case kMsaMinor3RF:
DecodeTypeMsa3RF();
break;
case kMsaMinorVEC:
DecodeTypeMsaVec();
break;
case kMsaMinor2R:
DecodeTypeMsa2R();
break;
case kMsaMinor2RF:
DecodeTypeMsa2RF();
break;
default:
UNREACHABLE();
}
break;
default:
UNREACHABLE();
}
......@@ -4238,6 +4773,18 @@ void Simulator::DecodeTypeImmediate() {
case BC1NEZ:
BranchHelper(get_fpu_register(ft_reg) & 0x1);
break;
case BZ_V:
case BZ_B:
case BZ_H:
case BZ_W:
case BZ_D:
case BNZ_V:
case BNZ_B:
case BNZ_H:
case BNZ_W:
case BNZ_D:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
......@@ -4580,6 +5127,31 @@ void Simulator::DecodeTypeImmediate() {
SetResult(rs_reg, alu_out);
break;
}
case MSA:
switch (instr_.MSAMinorOpcodeField()) {
case kMsaMinorI8:
DecodeTypeMsaI8();
break;
case kMsaMinorI5:
DecodeTypeMsaI5();
break;
case kMsaMinorI10:
DecodeTypeMsaI10();
break;
case kMsaMinorELM:
DecodeTypeMsaELM();
break;
case kMsaMinorBIT:
DecodeTypeMsaBIT();
break;
case kMsaMinorMI10:
DecodeTypeMsaMI10();
break;
default:
UNREACHABLE();
break;
}
break;
default:
UNREACHABLE();
}
......
......@@ -181,6 +181,43 @@ class Simulator {
kNumFPURegisters
};
// MSA registers
enum MSARegister {
w0,
w1,
w2,
w3,
w4,
w5,
w6,
w7,
w8,
w9,
w10,
w11,
w12,
w13,
w14,
w15,
w16,
w17,
w18,
w19,
w20,
w21,
w22,
w23,
w24,
w25,
w26,
w27,
w28,
w29,
w30,
w31,
kNumMSARegisters
};
explicit Simulator(Isolate* isolate);
~Simulator();
......@@ -213,6 +250,10 @@ class Simulator {
int32_t get_fpu_register_hi_word(int fpureg) const;
float get_fpu_register_float(int fpureg) const;
double get_fpu_register_double(int fpureg) const;
template <typename T>
void get_msa_register(int wreg, T* value);
template <typename T>
void set_msa_register(int wreg, const T* value);
void set_fcsr_bit(uint32_t cc, bool value);
bool test_fcsr_bit(uint32_t cc);
void set_fcsr_rounding_mode(FPURoundingMode mode);
......@@ -293,6 +334,9 @@ class Simulator {
// Helpers for data value tracing.
enum TraceType { BYTE, HALF, WORD, DWORD, FLOAT, DOUBLE, FLOAT_DOUBLE };
// MSA Data Format
enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD };
// Read and write memory.
inline uint32_t ReadBU(int32_t addr);
inline int32_t ReadB(int32_t addr);
......@@ -313,6 +357,8 @@ class Simulator {
void TraceRegWr(int32_t value, TraceType t = WORD);
void TraceRegWr(int64_t value, TraceType t = DWORD);
template <typename T>
void TraceMSARegWr(T* value, TraceType t);
void TraceMemWr(int32_t addr, int32_t value, TraceType t = WORD);
void TraceMemRd(int32_t addr, int32_t value, TraceType t = WORD);
void TraceMemWr(int32_t addr, int64_t value, TraceType t = DWORD);
......@@ -352,6 +398,19 @@ class Simulator {
void DecodeTypeRegisterLRsType();
int DecodeMsaDataFormat();
void DecodeTypeMsaI8();
void DecodeTypeMsaI5();
void DecodeTypeMsaI10();
void DecodeTypeMsaELM();
void DecodeTypeMsaBIT();
void DecodeTypeMsaMI10();
void DecodeTypeMsa3R();
void DecodeTypeMsa3RF();
void DecodeTypeMsaVec();
void DecodeTypeMsa2R();
void DecodeTypeMsa2RF();
inline int32_t rs_reg() const { return instr_.RsValue(); }
inline int32_t rs() const { return get_register(rs_reg()); }
inline uint32_t rs_u() const {
......@@ -369,6 +428,9 @@ class Simulator {
inline int32_t fd_reg() const { return instr_.FdValue(); }
inline int32_t sa() const { return instr_.SaValue(); }
inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
inline int32_t ws_reg() const { return instr_.WsValue(); }
inline int32_t wt_reg() const { return instr_.WtValue(); }
inline int32_t wd_reg() const { return instr_.WdValue(); }
inline void SetResult(int32_t rd_reg, int32_t alu_out) {
set_register(rd_reg, alu_out);
......@@ -480,7 +542,9 @@ class Simulator {
// Coprocessor Registers.
// Note: FP32 mode uses only the lower 32-bit part of each element,
// the upper 32-bit is unpredictable.
int64_t FPUregisters_[kNumFPURegisters];
// Note: FPUregisters_[] array is increased to 64 * 8B = 32 * 16B in
// order to support MSA registers
int64_t FPUregisters_[kNumFPURegisters * 2];
// FPU control register.
uint32_t FCSR_;
......
......@@ -333,6 +333,16 @@ const int kImm5Mask = ((1 << 5) - 1);
const int kImm8Mask = ((1 << 8) - 1);
const int kImm10Mask = ((1 << 10) - 1);
const int kMsaI5I10Mask = ((7U << 23) | ((1 << 6) - 1));
const int kMsaI8Mask = ((3U << 24) | ((1 << 6) - 1));
const int kMsaI5Mask = ((7U << 23) | ((1 << 6) - 1));
const int kMsaMI10Mask = (15U << 2);
const int kMsaBITMask = ((7U << 23) | ((1 << 6) - 1));
const int kMsaELMMask = (15U << 22);
const int kMsa3RMask = ((7U << 23) | ((1 << 6) - 1));
const int kMsa3RFMask = ((15U << 22) | ((1 << 6) - 1));
const int kMsaVECMask = (23U << 21);
const int kMsa2RMask = (7U << 18);
const int kMsa2RFMask = (15U << 17);
const int kRsFieldMask = ((1 << kRsBits) - 1) << kRsShift;
const int kRtFieldMask = ((1 << kRtBits) - 1) << kRtShift;
const int kRdFieldMask = ((1 << kRdBits) - 1) << kRdShift;
......
......@@ -60,17 +60,6 @@ class Decoder {
int InstructionDecode(byte* instruction);
private:
const uint32_t kMsaI8Mask = ((3U << 24) | ((1 << 6) - 1));
const uint32_t kMsaI5Mask = ((7U << 23) | ((1 << 6) - 1));
const uint32_t kMsaMI10Mask = (15U << 2);
const uint32_t kMsaBITMask = ((7U << 23) | ((1 << 6) - 1));
const uint32_t kMsaELMMask = (15U << 22);
const uint32_t kMsa3RMask = ((7U << 23) | ((1 << 6) - 1));
const uint32_t kMsa3RFMask = ((15U << 22) | ((1 << 6) - 1));
const uint32_t kMsaVECMask = (23U << 21);
const uint32_t kMsa2RMask = (7U << 18);
const uint32_t kMsa2RFMask = (15U << 17);
// Bottleneck functions to print into the out_buffer.
void PrintChar(const char ch);
void Print(const char* str);
......
......@@ -839,7 +839,8 @@ Simulator::Simulator(Isolate* isolate) : isolate_(isolate) {
registers_[i] = 0;
}
for (int i = 0; i < kNumFPURegisters; i++) {
FPUregisters_[i] = 0;
FPUregisters_[2 * i] = 0;
FPUregisters_[2 * i + 1] = 0; // upper part for MSA ASE
}
if (kArchVariant == kMips64r6) {
......@@ -996,7 +997,7 @@ void Simulator::set_dw_register(int reg, const int* dbl) {
void Simulator::set_fpu_register(int fpureg, int64_t value) {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
FPUregisters_[fpureg] = value;
FPUregisters_[fpureg * 2] = value;
}
......@@ -1005,9 +1006,9 @@ void Simulator::set_fpu_register_word(int fpureg, int32_t value) {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
int32_t* pword;
if (kArchEndian == kLittle) {
pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]);
} else {
pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]) + 1;
pword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]) + 1;
}
*pword = value;
}
......@@ -1018,9 +1019,9 @@ void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
int32_t* phiword;
if (kArchEndian == kLittle) {
phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg])) + 1;
phiword = (reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2])) + 1;
} else {
phiword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg]);
phiword = reinterpret_cast<int32_t*>(&FPUregisters_[fpureg * 2]);
}
*phiword = value;
}
......@@ -1028,13 +1029,13 @@ void Simulator::set_fpu_register_hi_word(int fpureg, int32_t value) {
void Simulator::set_fpu_register_float(int fpureg, float value) {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
*bit_cast<float*>(&FPUregisters_[fpureg]) = value;
*bit_cast<float*>(&FPUregisters_[fpureg * 2]) = value;
}
void Simulator::set_fpu_register_double(int fpureg, double value) {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
*bit_cast<double*>(&FPUregisters_[fpureg]) = value;
*bit_cast<double*>(&FPUregisters_[fpureg * 2]) = value;
}
......@@ -1065,39 +1066,50 @@ double Simulator::get_double_from_register_pair(int reg) {
int64_t Simulator::get_fpu_register(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return FPUregisters_[fpureg];
return FPUregisters_[fpureg * 2];
}
int32_t Simulator::get_fpu_register_word(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xffffffff);
}
int32_t Simulator::get_fpu_register_signed_word(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return static_cast<int32_t>(FPUregisters_[fpureg] & 0xffffffff);
return static_cast<int32_t>(FPUregisters_[fpureg * 2] & 0xffffffff);
}
int32_t Simulator::get_fpu_register_hi_word(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return static_cast<int32_t>((FPUregisters_[fpureg] >> 32) & 0xffffffff);
return static_cast<int32_t>((FPUregisters_[fpureg * 2] >> 32) & 0xffffffff);
}
float Simulator::get_fpu_register_float(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg]));
return *bit_cast<float*>(const_cast<int64_t*>(&FPUregisters_[fpureg * 2]));
}
double Simulator::get_fpu_register_double(int fpureg) const {
DCHECK((fpureg >= 0) && (fpureg < kNumFPURegisters));
return *bit_cast<double*>(&FPUregisters_[fpureg]);
return *bit_cast<double*>(&FPUregisters_[fpureg * 2]);
}
template <typename T>
void Simulator::get_msa_register(int wreg, T* value) {
DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
memcpy(value, FPUregisters_ + wreg * 2, kSimd128Size);
}
template <typename T>
void Simulator::set_msa_register(int wreg, const T* value) {
DCHECK((wreg >= 0) && (wreg < kNumMSARegisters));
memcpy(FPUregisters_ + wreg * 2, value, kSimd128Size);
}
// Runtime FP routines take up to two double arguments and zero
// or one integer arguments. All are constructed here,
......@@ -1672,6 +1684,59 @@ void Simulator::TraceRegWr(int64_t value, TraceType t) {
}
}
template <typename T>
void Simulator::TraceMSARegWr(T* value, TraceType t) {
if (::v8::internal::FLAG_trace_sim) {
union {
uint8_t b[16];
uint16_t h[8];
uint32_t w[4];
uint64_t d[2];
float f[4];
double df[2];
} v;
memcpy(v.b, value, kSimd128Size);
switch (t) {
case BYTE:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
v.d[0], v.d[1], icount_);
break;
case HALF:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
v.d[0], v.d[1], icount_);
break;
case WORD:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") int32[0..3]:%" PRId32 " %" PRId32 " %" PRId32
" %" PRId32,
v.d[0], v.d[1], icount_, v.w[0], v.w[1], v.w[2], v.w[3]);
break;
case DWORD:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64 ")",
v.d[0], v.d[1], icount_);
break;
case FLOAT:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") flt[0..3]:%e %e %e %e",
v.d[0], v.d[1], icount_, v.f[0], v.f[1], v.f[2], v.f[3]);
break;
case DOUBLE:
SNPrintF(trace_buf_,
"LO: %016" PRIx64 " HI: %016" PRIx64 " (%" PRIu64
") dbl[0..1]:%e %e",
v.d[0], v.d[1], icount_, v.df[0], v.df[1]);
break;
default:
UNREACHABLE();
}
}
}
// TODO(plind): consider making icount_ printing a flag option.
void Simulator::TraceMemRd(int64_t addr, int64_t value, TraceType t) {
if (::v8::internal::FLAG_trace_sim) {
......@@ -4339,6 +4404,471 @@ void Simulator::DecodeTypeRegisterSPECIAL3() {
}
}
int Simulator::DecodeMsaDataFormat() {
int df = -1;
if (instr_.IsMSABranchInstr()) {
switch (instr_.RsFieldRaw()) {
case BZ_V:
case BNZ_V:
df = MSA_VECT;
break;
case BZ_B:
case BNZ_B:
df = MSA_BYTE;
break;
case BZ_H:
case BNZ_H:
df = MSA_HALF;
break;
case BZ_W:
case BNZ_W:
df = MSA_WORD;
break;
case BZ_D:
case BNZ_D:
df = MSA_DWORD;
break;
default:
UNREACHABLE();
break;
}
} else {
int DF[] = {MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD};
switch (instr_.MSAMinorOpcodeField()) {
case kMsaMinorI5:
case kMsaMinorI10:
case kMsaMinor3R:
df = DF[instr_.Bits(22, 21)];
break;
case kMsaMinorMI10:
df = DF[instr_.Bits(1, 0)];
break;
case kMsaMinorBIT:
df = DF[instr_.MsaBitDf()];
break;
case kMsaMinorELM:
df = DF[instr_.MsaElmDf()];
break;
case kMsaMinor3RF: {
uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
switch (opcode) {
case FEXDO:
case FTQ:
case MUL_Q:
case MADD_Q:
case MSUB_Q:
case MULR_Q:
case MADDR_Q:
case MSUBR_Q:
df = DF[1 + instr_.Bit(21)];
break;
default:
df = DF[2 + instr_.Bit(21)];
break;
}
} break;
case kMsaMinor2R:
df = DF[instr_.Bits(17, 16)];
break;
case kMsaMinor2RF:
df = DF[2 + instr_.Bit(16)];
break;
default:
UNREACHABLE();
break;
}
}
return df;
}
void Simulator::DecodeTypeMsaI8() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaI8Mask;
switch (opcode) {
case ANDI_B:
case ORI_B:
case NORI_B:
case XORI_B:
case BMNZI_B:
case BMZI_B:
case BSELI_B:
case SHF_B:
case SHF_H:
case SHF_W:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaI5() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
switch (opcode) {
case ADDVI:
case SUBVI:
case MAXI_S:
case MAXI_U:
case MINI_S:
case MINI_U:
case CEQI:
case CLTI_S:
case CLTI_U:
case CLEI_S:
case CLEI_U:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaI10() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaI5Mask;
if (opcode == LDI) {
UNIMPLEMENTED();
} else {
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaELM() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaELMMask;
int32_t n = instr_.MsaElmNValue();
int64_t alu_out;
switch (opcode) {
case COPY_S:
case COPY_U:
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
DCHECK(n < 16);
int8_t ws[16];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFu : alu_out);
break;
}
case MSA_HALF: {
DCHECK(n < 8);
int16_t ws[8];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
SetResult(wd_reg(), (opcode == COPY_U) ? alu_out & 0xFFFFu : alu_out);
break;
}
case MSA_WORD: {
DCHECK(n < 4);
int32_t ws[4];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int32_t>(ws[n]);
SetResult(wd_reg(),
(opcode == COPY_U) ? alu_out & 0xFFFFFFFFu : alu_out);
break;
}
case MSA_DWORD: {
DCHECK(n < 2);
int64_t ws[2];
get_msa_register(instr_.WsValue(), ws);
alu_out = static_cast<int64_t>(ws[n]);
SetResult(wd_reg(), alu_out);
break;
}
default:
UNREACHABLE();
}
break;
case SLDI:
case SPLATI:
case INSERT:
case INSVE:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaBIT() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaBITMask;
switch (opcode) {
case SLLI:
case SRAI:
case SRLI:
case BCLRI:
case BSETI:
case BNEGI:
case BINSLI:
case BINSRI:
case SAT_S:
case SAT_U:
case SRARI:
case SRLRI:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaMI10() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaMI10Mask;
if (opcode == MSA_LD) {
UNIMPLEMENTED();
} else if (opcode == MSA_ST) {
UNIMPLEMENTED();
} else {
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsa3R() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa3RMask;
switch (opcode) {
case SLL_MSA:
case SRA_MSA:
case SRL_MSA:
case BCLR:
case BSET:
case BNEG:
case BINSL:
case BINSR:
case ADDV:
case SUBV:
case MAX_S:
case MAX_U:
case MIN_S:
case MIN_U:
case MAX_A:
case MIN_A:
case CEQ:
case CLT_S:
case CLT_U:
case CLE_S:
case CLE_U:
case ADD_A:
case ADDS_A:
case ADDS_S:
case ADDS_U:
case AVE_S:
case AVE_U:
case AVER_S:
case AVER_U:
case SUBS_S:
case SUBS_U:
case SUBSUS_U:
case SUBSUU_S:
case ASUB_S:
case ASUB_U:
case MULV:
case MADDV:
case MSUBV:
case DIV_S_MSA:
case DIV_U:
case MOD_S:
case MOD_U:
case DOTP_S:
case DOTP_U:
case DPADD_S:
case DPADD_U:
case DPSUB_S:
case DPSUB_U:
case SLD:
case SPLAT:
case PCKEV:
case PCKOD:
case ILVL:
case ILVR:
case ILVEV:
case ILVOD:
case VSHF:
case SRAR:
case SRLR:
case HADD_S:
case HADD_U:
case HSUB_S:
case HSUB_U:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsa3RF() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa3RFMask;
switch (opcode) {
case FCAF:
case FCUN:
case FCEQ:
case FCUEQ:
case FCLT:
case FCULT:
case FCLE:
case FCULE:
case FSAF:
case FSUN:
case FSEQ:
case FSUEQ:
case FSLT:
case FSULT:
case FSLE:
case FSULE:
case FADD:
case FSUB:
case FMUL:
case FDIV:
case FMADD:
case FMSUB:
case FEXP2:
case FEXDO:
case FTQ:
case FMIN:
case FMIN_A:
case FMAX:
case FMAX_A:
case FCOR:
case FCUNE:
case FCNE:
case MUL_Q:
case MADD_Q:
case MSUB_Q:
case FSOR:
case FSUNE:
case FSNE:
case MULR_Q:
case MADDR_Q:
case MSUBR_Q:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsaVec() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsaVECMask;
switch (opcode) {
case AND_V:
case OR_V:
case NOR_V:
case XOR_V:
case BMNZ_V:
case BMZ_V:
case BSEL_V:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsa2R() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa2RMask;
switch (opcode) {
case FILL:
switch (DecodeMsaDataFormat()) {
case MSA_BYTE: {
int8_t wd[16];
int64_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 16; i++) {
wd[i] = rs & 0xFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, BYTE);
break;
}
case MSA_HALF: {
int16_t wd[8];
int64_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 8; i++) {
wd[i] = rs & 0xFFFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, HALF);
break;
}
case MSA_WORD: {
int32_t wd[4];
int64_t rs = get_register(instr_.WsValue());
for (int i = 0; i < 4; i++) {
wd[i] = rs & 0xFFFFFFFFu;
}
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, WORD);
break;
}
case MSA_DWORD: {
int64_t wd[2];
int64_t rs = get_register(instr_.WsValue());
wd[0] = wd[1] = rs;
set_msa_register(instr_.WdValue(), wd);
TraceMSARegWr(wd, DWORD);
break;
}
default:
UNREACHABLE();
}
break;
case PCNT:
case NLOC:
case NLZC:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeMsa2RF() {
DCHECK(kArchVariant == kMips64r6);
DCHECK(CpuFeatures::IsSupported(MIPS_SIMD));
uint32_t opcode = instr_.InstructionBits() & kMsa2RFMask;
switch (opcode) {
case FCLASS:
case FTRUNC_S:
case FTRUNC_U:
case FSQRT:
case FRSQRT:
case FRCP:
case FRINT:
case FLOG2:
case FEXUPL:
case FEXUPR:
case FFQL:
case FFQR:
case FTINT_S:
case FTINT_U:
case FFINT_S:
case FFINT_U:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
}
void Simulator::DecodeTypeRegister() {
// ---------- Execution.
switch (instr_.OpcodeFieldRaw()) {
......@@ -4357,6 +4887,27 @@ void Simulator::DecodeTypeRegister() {
case SPECIAL3:
DecodeTypeRegisterSPECIAL3();
break;
case MSA:
switch (instr_.MSAMinorOpcodeField()) {
case kMsaMinor3R:
DecodeTypeMsa3R();
break;
case kMsaMinor3RF:
DecodeTypeMsa3RF();
break;
case kMsaMinorVEC:
DecodeTypeMsaVec();
break;
case kMsaMinor2R:
DecodeTypeMsa2R();
break;
case kMsaMinor2RF:
DecodeTypeMsa2RF();
break;
default:
UNREACHABLE();
}
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
// cases.
......@@ -4469,6 +5020,18 @@ void Simulator::DecodeTypeImmediate() {
case BC1NEZ:
BranchHelper(get_fpu_register(ft_reg) & 0x1);
break;
case BZ_V:
case BZ_B:
case BZ_H:
case BZ_W:
case BZ_D:
case BNZ_V:
case BNZ_B:
case BNZ_H:
case BNZ_W:
case BNZ_D:
UNIMPLEMENTED();
break;
default:
UNREACHABLE();
}
......@@ -4891,6 +5454,31 @@ void Simulator::DecodeTypeImmediate() {
SetResult(rs_reg, alu_out);
break;
}
case MSA:
switch (instr_.MSAMinorOpcodeField()) {
case kMsaMinorI8:
DecodeTypeMsaI8();
break;
case kMsaMinorI5:
DecodeTypeMsaI5();
break;
case kMsaMinorI10:
DecodeTypeMsaI10();
break;
case kMsaMinorELM:
DecodeTypeMsaELM();
break;
case kMsaMinorBIT:
DecodeTypeMsaBIT();
break;
case kMsaMinorMI10:
DecodeTypeMsaMI10();
break;
default:
UNREACHABLE();
break;
}
break;
default:
UNREACHABLE();
}
......
......@@ -189,6 +189,43 @@ class Simulator {
kNumFPURegisters
};
// MSA registers
enum MSARegister {
w0,
w1,
w2,
w3,
w4,
w5,
w6,
w7,
w8,
w9,
w10,
w11,
w12,
w13,
w14,
w15,
w16,
w17,
w18,
w19,
w20,
w21,
w22,
w23,
w24,
w25,
w26,
w27,
w28,
w29,
w30,
w31,
kNumMSARegisters
};
explicit Simulator(Isolate* isolate);
~Simulator();
......@@ -222,6 +259,10 @@ class Simulator {
int32_t get_fpu_register_hi_word(int fpureg) const;
float get_fpu_register_float(int fpureg) const;
double get_fpu_register_double(int fpureg) const;
template <typename T>
void get_msa_register(int wreg, T* value);
template <typename T>
void set_msa_register(int wreg, const T* value);
void set_fcsr_bit(uint32_t cc, bool value);
bool test_fcsr_bit(uint32_t cc);
bool set_fcsr_round_error(double original, double rounded);
......@@ -311,6 +352,9 @@ class Simulator {
WORD_DWORD
};
// MSA Data Format
enum MSADataFormat { MSA_VECT = 0, MSA_BYTE, MSA_HALF, MSA_WORD, MSA_DWORD };
// Read and write memory.
inline uint32_t ReadBU(int64_t addr);
inline int32_t ReadB(int64_t addr);
......@@ -336,6 +380,8 @@ class Simulator {
inline void DieOrDebug();
void TraceRegWr(int64_t value, TraceType t = DWORD);
template <typename T>
void TraceMSARegWr(T* value, TraceType t);
void TraceMemWr(int64_t addr, int64_t value, TraceType t);
void TraceMemRd(int64_t addr, int64_t value, TraceType t = DWORD);
......@@ -369,6 +415,19 @@ class Simulator {
void DecodeTypeRegisterLRsType();
int DecodeMsaDataFormat();
void DecodeTypeMsaI8();
void DecodeTypeMsaI5();
void DecodeTypeMsaI10();
void DecodeTypeMsaELM();
void DecodeTypeMsaBIT();
void DecodeTypeMsaMI10();
void DecodeTypeMsa3R();
void DecodeTypeMsa3RF();
void DecodeTypeMsaVec();
void DecodeTypeMsa2R();
void DecodeTypeMsa2RF();
// Executing is handled based on the instruction type.
void DecodeTypeRegister();
......@@ -389,6 +448,9 @@ class Simulator {
inline int32_t fd_reg() const { return instr_.FdValue(); }
inline int32_t sa() const { return instr_.SaValue(); }
inline int32_t lsa_sa() const { return instr_.LsaSaValue(); }
inline int32_t ws_reg() const { return instr_.WsValue(); }
inline int32_t wt_reg() const { return instr_.WtValue(); }
inline int32_t wd_reg() const { return instr_.WdValue(); }
inline void SetResult(const int32_t rd_reg, const int64_t alu_out) {
set_register(rd_reg, alu_out);
......@@ -508,7 +570,9 @@ class Simulator {
// Registers.
int64_t registers_[kNumSimuRegisters];
// Coprocessor Registers.
int64_t FPUregisters_[kNumFPURegisters];
// Note: FPUregisters_[] array is increased to 64 * 8B = 32 * 16B in
// order to support MSA registers
int64_t FPUregisters_[kNumFPURegisters * 2];
// FPU control register.
uint32_t FCSR_;
......
......@@ -46,7 +46,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)(void* p0, void* p1, int p2, int p3, int p4);
#define __ assm.
......@@ -5587,4 +5587,192 @@ TEST(Subu) {
}
}
TEST(MSA_fill_copy) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
typedef struct {
uint32_t u8;
uint32_t u16;
uint32_t u32;
uint32_t s8;
uint32_t s16;
uint32_t s32;
} T;
T t;
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
if (!IsMipsArchVariant(kMips32r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
{
CpuFeatureScope fscope(&assm, MIPS_SIMD);
__ li(t0, 0xa512b683);
__ fill_b(w0, t0);
__ fill_h(w2, t0);
__ fill_w(w4, t0);
__ copy_u_b(t1, w0, 11);
__ sw(t1, MemOperand(a0, offsetof(T, u8)));
__ copy_u_h(t1, w2, 6);
__ sw(t1, MemOperand(a0, offsetof(T, u16)));
__ copy_u_w(t1, w4, 3);
__ sw(t1, MemOperand(a0, offsetof(T, u32)));
__ copy_s_b(t1, w0, 8);
__ sw(t1, MemOperand(a0, offsetof(T, s8)));
__ copy_s_h(t1, w2, 5);
__ sw(t1, MemOperand(a0, offsetof(T, s16)));
__ copy_s_w(t1, w4, 1);
__ sw(t1, MemOperand(a0, offsetof(T, s32)));
__ jr(ra);
__ nop();
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
Object* dummy = CALL_GENERATED_CODE(isolate, f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(0x83u, t.u8);
CHECK_EQ(0xb683u, t.u16);
CHECK_EQ(0xa512b683u, t.u32);
CHECK_EQ(0xffffff83u, t.s8);
CHECK_EQ(0xffffb683u, t.s16);
CHECK_EQ(0xa512b683u, t.s32);
}
TEST(MSA_fill_copy_2) {
// Similar to MSA_fill_copy test, but also check overlaping between MSA and
// FPU registers with same numbers
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
typedef struct {
uint32_t w0;
uint32_t w1;
uint32_t w2;
uint32_t w3;
} T;
T t[2];
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
if (!IsMipsArchVariant(kMips32r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
{
CpuFeatureScope fscope(&assm, MIPS_SIMD);
__ li(t0, 0xaaaaaaaa);
__ li(t1, 0x55555555);
__ fill_w(w0, t0);
__ fill_w(w2, t0);
__ FmoveLow(f0, t1);
__ FmoveHigh(f2, t1);
#define STORE_MSA_REG(w_reg, base, scratch) \
__ copy_u_w(scratch, w_reg, 0); \
__ sw(scratch, MemOperand(base, offsetof(T, w0))); \
__ copy_u_w(scratch, w_reg, 1); \
__ sw(scratch, MemOperand(base, offsetof(T, w1))); \
__ copy_u_w(scratch, w_reg, 2); \
__ sw(scratch, MemOperand(base, offsetof(T, w2))); \
__ copy_u_w(scratch, w_reg, 3); \
__ sw(scratch, MemOperand(base, offsetof(T, w3)));
STORE_MSA_REG(w0, a0, t2)
STORE_MSA_REG(w2, a1, t2)
#undef STORE_MSA_REG
__ jr(ra);
__ nop();
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F4 f = FUNCTION_CAST<F4>(code->entry());
Object* dummy = CALL_GENERATED_CODE(isolate, f, &t[0], &t[1], 0, 0, 0);
USE(dummy);
CHECK_EQ(0x55555555, t[0].w0);
CHECK_EQ(0xaaaaaaaa, t[0].w1);
CHECK_EQ(0xaaaaaaaa, t[0].w2);
CHECK_EQ(0xaaaaaaaa, t[0].w3);
CHECK_EQ(0xaaaaaaaa, t[1].w0);
CHECK_EQ(0x55555555, t[1].w1);
CHECK_EQ(0xaaaaaaaa, t[1].w2);
CHECK_EQ(0xaaaaaaaa, t[1].w3);
}
TEST(MSA_fill_copy_3) {
// Similar to MSA_fill_copy test, but also check overlaping between MSA and
// FPU registers with same numbers
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
typedef struct {
uint64_t d0;
uint64_t d1;
} T;
T t[2];
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
if (!IsMipsArchVariant(kMips32r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
{
CpuFeatureScope fscope(&assm, MIPS_SIMD);
__ li(t0, 0xaaaaaaaa);
__ li(t1, 0x55555555);
__ Move(f0, t0, t0);
__ Move(f2, t0, t0);
__ fill_w(w0, t1);
__ fill_w(w2, t1);
__ Sdc1(f0, MemOperand(a0, offsetof(T, d0)));
__ Sdc1(f2, MemOperand(a1, offsetof(T, d0)));
__ jr(ra);
__ nop();
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F4 f = FUNCTION_CAST<F4>(code->entry());
Object* dummy = CALL_GENERATED_CODE(isolate, f, &t[0], &t[1], 0, 0, 0);
USE(dummy);
CHECK_EQ(0x5555555555555555, t[0].d0);
CHECK_EQ(0x5555555555555555, t[1].d0);
}
#undef __
......@@ -46,7 +46,7 @@ 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);
typedef Object* (*F5)(void* p0, void* p1, int p2, int p3, int p4);
#define __ assm.
......@@ -6408,4 +6408,187 @@ TEST(Dins) {
}
}
TEST(MSA_fill_copy) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
typedef struct {
uint64_t u8;
uint64_t u16;
uint64_t u32;
uint64_t s8;
uint64_t s16;
uint64_t s32;
uint64_t s64;
} T;
T t;
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
{
CpuFeatureScope fscope(&assm, MIPS_SIMD);
__ li(t0, 0x9e7689aca512b683);
__ fill_b(w0, t0);
__ fill_h(w2, t0);
__ fill_w(w4, t0);
__ fill_d(w6, t0);
__ copy_u_b(t1, w0, 11);
__ sd(t1, MemOperand(a0, offsetof(T, u8)));
__ copy_u_h(t1, w2, 6);
__ sd(t1, MemOperand(a0, offsetof(T, u16)));
__ copy_u_w(t1, w4, 3);
__ sd(t1, MemOperand(a0, offsetof(T, u32)));
__ copy_s_b(t1, w0, 8);
__ sd(t1, MemOperand(a0, offsetof(T, s8)));
__ copy_s_h(t1, w2, 5);
__ sd(t1, MemOperand(a0, offsetof(T, s16)));
__ copy_s_w(t1, w4, 1);
__ sd(t1, MemOperand(a0, offsetof(T, s32)));
__ copy_s_d(t1, w6, 0);
__ sd(t1, MemOperand(a0, offsetof(T, s64)));
__ jr(ra);
__ nop();
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F3 f = FUNCTION_CAST<F3>(code->entry());
Object* dummy = CALL_GENERATED_CODE(isolate, f, &t, 0, 0, 0, 0);
USE(dummy);
CHECK_EQ(0x83u, t.u8);
CHECK_EQ(0xb683u, t.u16);
CHECK_EQ(0xa512b683u, t.u32);
CHECK_EQ(0xffffffffffffff83u, t.s8);
CHECK_EQ(0xffffffffffffb683u, t.s16);
CHECK_EQ(0xffffffffa512b683u, t.s32);
CHECK_EQ(0x9e7689aca512b683u, t.s64);
}
TEST(MSA_fill_copy_2) {
// Similar to MSA_fill_copy test, but also check overlaping between MSA and
// FPU registers with same numbers
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
typedef struct {
uint64_t d0;
uint64_t d1;
} T;
T t[2];
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
{
CpuFeatureScope fscope(&assm, MIPS_SIMD);
__ li(t0, 0xaaaaaaaaaaaaaaaa);
__ li(t1, 0x5555555555555555);
__ fill_d(w0, t0);
__ fill_d(w2, t0);
__ Move(f0, t1);
__ Move(f2, t1);
#define STORE_MSA_REG(w_reg, base, scratch) \
__ copy_s_d(scratch, w_reg, 0); \
__ sd(scratch, MemOperand(base, offsetof(T, d0))); \
__ copy_s_d(scratch, w_reg, 1); \
__ sd(scratch, MemOperand(base, offsetof(T, d1)));
STORE_MSA_REG(w0, a0, t2)
STORE_MSA_REG(w2, a1, t2)
#undef STORE_MSA_REG
__ jr(ra);
__ nop();
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F5 f = FUNCTION_CAST<F5>(code->entry());
Object* dummy = CALL_GENERATED_CODE(isolate, f, &t[0], &t[1], 0, 0, 0);
USE(dummy);
CHECK_EQ(0x5555555555555555, t[0].d0);
CHECK_EQ(0xaaaaaaaaaaaaaaaa, t[0].d1);
CHECK_EQ(0x5555555555555555, t[1].d0);
CHECK_EQ(0xaaaaaaaaaaaaaaaa, t[1].d1);
}
TEST(MSA_fill_copy_3) {
// Similar to MSA_fill_copy test, but also check overlaping between MSA and
// FPU registers with same numbers
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
typedef struct {
uint64_t d0;
uint64_t d1;
} T;
T t[2];
MacroAssembler assm(isolate, NULL, 0, v8::internal::CodeObjectRequired::kYes);
if ((kArchVariant != kMips64r6) || !CpuFeatures::IsSupported(MIPS_SIMD))
return;
{
CpuFeatureScope fscope(&assm, MIPS_SIMD);
__ li(t0, 0xaaaaaaaaaaaaaaaa);
__ li(t1, 0x5555555555555555);
__ Move(f0, t0);
__ Move(f2, t0);
__ fill_d(w0, t1);
__ fill_d(w2, t1);
__ Sdc1(f0, MemOperand(a0, offsetof(T, d0)));
__ Sdc1(f2, MemOperand(a1, offsetof(T, d0)));
__ jr(ra);
__ nop();
}
CodeDesc desc;
assm.GetCode(&desc);
Handle<Code> code = isolate->factory()->NewCode(
desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
#ifdef OBJECT_PRINT
code->Print(std::cout);
#endif
F5 f = FUNCTION_CAST<F5>(code->entry());
Object* dummy = CALL_GENERATED_CODE(isolate, f, &t[0], &t[1], 0, 0, 0);
USE(dummy);
CHECK_EQ(0x5555555555555555, t[0].d0);
CHECK_EQ(0x5555555555555555, t[1].d0);
}
#undef __
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