in runtime/vm/simulator_arm.cc [2488:2884]
void Simulator::DecodeType7(Instr* instr) {
if (instr->Bit(24) == 1) {
// Format(instr, "svc #'svc");
SupervisorCall(instr);
} else if (instr->IsVFPDataProcessingOrSingleTransfer()) {
if (instr->Bit(4) == 0) {
// VFP Data Processing
SRegister sd;
SRegister sn;
SRegister sm;
DRegister dd;
DRegister dn;
DRegister dm;
if (instr->Bit(8) == 0) {
sd = instr->SdField();
sn = instr->SnField();
sm = instr->SmField();
dd = kNoDRegister;
dn = kNoDRegister;
dm = kNoDRegister;
} else {
sd = kNoSRegister;
sn = kNoSRegister;
sm = kNoSRegister;
dd = instr->DdField();
dn = instr->DnField();
dm = instr->DmField();
}
switch (instr->Bits(20, 4) & 0xb) {
case 1: // vnmla, vnmls, vnmul
default: {
UnimplementedInstruction(instr);
break;
}
case 0: { // vmla, vmls floating-point
if (instr->Bit(8) == 0) {
float addend = get_sregister(sn) * get_sregister(sm);
float sd_val = get_sregister(sd);
if (instr->Bit(6) == 0) {
// Format(instr, "vmlas'cond 'sd, 'sn, 'sm");
} else {
// Format(instr, "vmlss'cond 'sd, 'sn, 'sm");
addend = -addend;
}
set_sregister(sd, sd_val + addend);
} else {
double addend = get_dregister(dn) * get_dregister(dm);
double dd_val = get_dregister(dd);
if (instr->Bit(6) == 0) {
// Format(instr, "vmlad'cond 'dd, 'dn, 'dm");
} else {
// Format(instr, "vmlsd'cond 'dd, 'dn, 'dm");
addend = -addend;
}
set_dregister(dd, dd_val + addend);
}
break;
}
case 2: { // vmul
if (instr->Bit(8) == 0) {
// Format(instr, "vmuls'cond 'sd, 'sn, 'sm");
set_sregister(sd, get_sregister(sn) * get_sregister(sm));
} else {
// Format(instr, "vmuld'cond 'dd, 'dn, 'dm");
set_dregister(dd, get_dregister(dn) * get_dregister(dm));
}
break;
}
case 8: { // vdiv
if (instr->Bit(8) == 0) {
// Format(instr, "vdivs'cond 'sd, 'sn, 'sm");
set_sregister(sd, get_sregister(sn) / get_sregister(sm));
} else {
// Format(instr, "vdivd'cond 'dd, 'dn, 'dm");
set_dregister(dd, get_dregister(dn) / get_dregister(dm));
}
break;
}
case 3: { // vadd, vsub floating-point
if (instr->Bit(8) == 0) {
if (instr->Bit(6) == 0) {
// Format(instr, "vadds'cond 'sd, 'sn, 'sm");
set_sregister(sd, get_sregister(sn) + get_sregister(sm));
} else {
// Format(instr, "vsubs'cond 'sd, 'sn, 'sm");
set_sregister(sd, get_sregister(sn) - get_sregister(sm));
}
} else {
if (instr->Bit(6) == 0) {
// Format(instr, "vaddd'cond 'dd, 'dn, 'dm");
set_dregister(dd, get_dregister(dn) + get_dregister(dm));
} else {
// Format(instr, "vsubd'cond 'dd, 'dn, 'dm");
set_dregister(dd, get_dregister(dn) - get_dregister(dm));
}
}
break;
}
case 0xb: { // Other VFP data-processing instructions
if (instr->Bit(6) == 0) { // vmov immediate
if (instr->Bit(8) == 0) {
// Format(instr, "vmovs'cond 'sd, #'immf");
set_sregister(sd, instr->ImmFloatField());
} else {
// Format(instr, "vmovd'cond 'dd, #'immd");
set_dregister(dd, instr->ImmDoubleField());
}
break;
}
switch (instr->Bits(16, 4)) {
case 0: { // vmov immediate, vmov register, vabs
switch (instr->Bits(6, 2)) {
case 1: { // vmov register
if (instr->Bit(8) == 0) {
// Format(instr, "vmovs'cond 'sd, 'sm");
set_sregister(sd, get_sregister(sm));
} else {
// Format(instr, "vmovd'cond 'dd, 'dm");
set_dregister(dd, get_dregister(dm));
}
break;
}
case 3: { // vabs
if (instr->Bit(8) == 0) {
// Format(instr, "vabss'cond 'sd, 'sm");
set_sregister(sd, fabsf(get_sregister(sm)));
} else {
// Format(instr, "vabsd'cond 'dd, 'dm");
set_dregister(dd, fabs(get_dregister(dm)));
}
break;
}
default: {
UnimplementedInstruction(instr);
break;
}
}
break;
}
case 1: { // vneg, vsqrt
switch (instr->Bits(6, 2)) {
case 1: { // vneg
if (instr->Bit(8) == 0) {
// Format(instr, "vnegs'cond 'sd, 'sm");
set_sregister(sd, -get_sregister(sm));
} else {
// Format(instr, "vnegd'cond 'dd, 'dm");
set_dregister(dd, -get_dregister(dm));
}
break;
}
case 3: { // vsqrt
if (instr->Bit(8) == 0) {
// Format(instr, "vsqrts'cond 'sd, 'sm");
set_sregister(sd, sqrtf(get_sregister(sm)));
} else {
// Format(instr, "vsqrtd'cond 'dd, 'dm");
set_dregister(dd, sqrt(get_dregister(dm)));
}
break;
}
default: {
UnimplementedInstruction(instr);
break;
}
}
break;
}
case 4: // vcmp, vcmpe
case 5: { // vcmp #0.0, vcmpe #0.0
if (instr->Bit(7) == 1) { // vcmpe
UnimplementedInstruction(instr);
} else {
fp_n_flag_ = false;
fp_z_flag_ = false;
fp_c_flag_ = false;
fp_v_flag_ = false;
if (instr->Bit(8) == 0) { // vcmps
float sd_val = get_sregister(sd);
float sm_val;
if (instr->Bit(16) == 0) {
// Format(instr, "vcmps'cond 'sd, 'sm");
sm_val = get_sregister(sm);
} else {
// Format(instr, "vcmps'cond 'sd, #0.0");
sm_val = 0.0f;
}
if (isnan(sd_val) || isnan(sm_val)) {
fp_c_flag_ = true;
fp_v_flag_ = true;
} else if (sd_val == sm_val) {
fp_z_flag_ = true;
fp_c_flag_ = true;
} else if (sd_val < sm_val) {
fp_n_flag_ = true;
} else {
fp_c_flag_ = true;
}
} else { // vcmpd
double dd_val = get_dregister(dd);
double dm_val;
if (instr->Bit(16) == 0) {
// Format(instr, "vcmpd'cond 'dd, 'dm");
dm_val = get_dregister(dm);
} else {
// Format(instr, "vcmpd'cond 'dd, #0.0");
dm_val = 0.0;
}
if (isnan(dd_val) || isnan(dm_val)) {
fp_c_flag_ = true;
fp_v_flag_ = true;
} else if (dd_val == dm_val) {
fp_z_flag_ = true;
fp_c_flag_ = true;
} else if (dd_val < dm_val) {
fp_n_flag_ = true;
} else {
fp_c_flag_ = true;
}
}
}
break;
}
case 7: { // vcvt between double-precision and single-precision
if (instr->Bit(8) == 0) {
// Format(instr, "vcvtds'cond 'dd, 'sm");
dd = instr->DdField();
set_dregister(dd, static_cast<double>(get_sregister(sm)));
} else {
// Format(instr, "vcvtsd'cond 'sd, 'dm");
sd = instr->SdField();
set_sregister(sd, static_cast<float>(get_dregister(dm)));
}
break;
}
case 8: { // vcvt, vcvtr between floating-point and integer
sm = instr->SmField();
int32_t sm_int = get_sregister_bits(sm);
uint32_t ud_val = 0;
int32_t id_val = 0;
if (instr->Bit(7) == 0) { // vcvtsu, vcvtdu
ud_val = static_cast<uint32_t>(sm_int);
} else { // vcvtsi, vcvtdi
id_val = sm_int;
}
if (instr->Bit(8) == 0) {
float sd_val;
if (instr->Bit(7) == 0) {
// Format(instr, "vcvtsu'cond 'sd, 'sm");
sd_val = static_cast<float>(ud_val);
} else {
// Format(instr, "vcvtsi'cond 'sd, 'sm");
sd_val = static_cast<float>(id_val);
}
set_sregister(sd, sd_val);
} else {
double dd_val;
if (instr->Bit(7) == 0) {
// Format(instr, "vcvtdu'cond 'dd, 'sm");
dd_val = static_cast<double>(ud_val);
} else {
// Format(instr, "vcvtdi'cond 'dd, 'sm");
dd_val = static_cast<double>(id_val);
}
set_dregister(dd, dd_val);
}
break;
}
case 12:
case 13: { // vcvt, vcvtr between floating-point and integer
// We do not need to record exceptions in the FPSCR cumulative
// flags, because we do not use them.
if (instr->Bit(7) == 0) {
// We only support round-to-zero mode
UnimplementedInstruction(instr);
break;
}
int32_t id_val = 0;
uint32_t ud_val = 0;
if (instr->Bit(8) == 0) {
float sm_val = get_sregister(sm);
if (instr->Bit(16) == 0) {
// Format(instr, "vcvtus'cond 'sd, 'sm");
if (sm_val >= static_cast<float>(INT32_MAX)) {
ud_val = INT32_MAX;
} else if (sm_val > 0.0) {
ud_val = static_cast<uint32_t>(sm_val);
}
} else {
// Format(instr, "vcvtis'cond 'sd, 'sm");
if (sm_val <= static_cast<float>(INT32_MIN)) {
id_val = INT32_MIN;
} else if (sm_val >= static_cast<float>(INT32_MAX)) {
id_val = INT32_MAX;
} else {
id_val = static_cast<int32_t>(sm_val);
}
ASSERT((id_val >= 0) || !(sm_val >= 0.0));
}
} else {
sd = instr->SdField();
double dm_val = get_dregister(dm);
if (instr->Bit(16) == 0) {
// Format(instr, "vcvtud'cond 'sd, 'dm");
if (dm_val >= static_cast<double>(INT32_MAX)) {
ud_val = INT32_MAX;
} else if (dm_val > 0.0) {
ud_val = static_cast<uint32_t>(dm_val);
}
} else {
// Format(instr, "vcvtid'cond 'sd, 'dm");
if (dm_val <= static_cast<double>(INT32_MIN)) {
id_val = INT32_MIN;
} else if (dm_val >= static_cast<double>(INT32_MAX)) {
id_val = INT32_MAX;
} else if (isnan(dm_val)) {
id_val = 0;
} else {
id_val = static_cast<int32_t>(dm_val);
}
ASSERT((id_val >= 0) || !(dm_val >= 0.0));
}
}
int32_t sd_val;
if (instr->Bit(16) == 0) {
sd_val = static_cast<int32_t>(ud_val);
} else {
sd_val = id_val;
}
set_sregister_bits(sd, sd_val);
break;
}
case 2: // vcvtb, vcvtt
case 3: // vcvtb, vcvtt
case 9: // undefined
case 10: // vcvt between floating-point and fixed-point
case 11: // vcvt between floating-point and fixed-point
case 14: // vcvt between floating-point and fixed-point
case 15: // vcvt between floating-point and fixed-point
default: {
UnimplementedInstruction(instr);
break;
}
}
} break;
}
} else {
// 8, 16, or 32-bit Transfer between ARM Core and VFP
if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) {
Register rd = instr->RdField();
SRegister sn = instr->SnField();
if (instr->Bit(20) == 0) {
// Format(instr, "vmovs'cond 'sn, 'rd");
set_sregister_bits(sn, get_register(rd));
} else {
// Format(instr, "vmovr'cond 'rd, 'sn");
set_register(rd, get_sregister_bits(sn));
}
} else if ((instr->Bits(22, 3) == 0) && (instr->Bit(20) == 0) &&
(instr->Bit(8) == 1) && (instr->Bits(5, 2) == 0)) {
DRegister dn = instr->DnField();
Register rd = instr->RdField();
const int32_t src_value = get_register(rd);
const int64_t dst_value = get_dregister_bits(dn);
int32_t dst_lo = Utils::Low32Bits(dst_value);
int32_t dst_hi = Utils::High32Bits(dst_value);
if (instr->Bit(21) == 0) {
// Format(instr, "vmovd'cond 'dn[0], 'rd");
dst_lo = src_value;
} else {
// Format(instr, "vmovd'cond 'dn[1], 'rd");
dst_hi = src_value;
}
set_dregister_bits(dn, Utils::LowHighTo64Bits(dst_lo, dst_hi));
} else if ((instr->Bits(20, 4) == 0xf) && (instr->Bit(8) == 0)) {
if (instr->Bits(12, 4) == 0xf) {
// Format(instr, "vmrs'cond APSR, FPSCR");
n_flag_ = fp_n_flag_;
z_flag_ = fp_z_flag_;
c_flag_ = fp_c_flag_;
v_flag_ = fp_v_flag_;
} else {
// Format(instr, "vmrs'cond 'rd, FPSCR");
const int32_t n_flag = fp_n_flag_ ? (1 << 31) : 0;
const int32_t z_flag = fp_z_flag_ ? (1 << 30) : 0;
const int32_t c_flag = fp_c_flag_ ? (1 << 29) : 0;
const int32_t v_flag = fp_v_flag_ ? (1 << 28) : 0;
set_register(instr->RdField(), n_flag | z_flag | c_flag | v_flag);
}
} else {
UnimplementedInstruction(instr);
}
}
} else {
UnimplementedInstruction(instr);
}
}