| Index: src/s390/simulator-s390.cc
|
| diff --git a/src/s390/simulator-s390.cc b/src/s390/simulator-s390.cc
|
| index 74a25d53572d4fd5b7e08af3a8312fe05bbfa34d..d387812bd7164097a9a57ad4669171967f60dab2 100644
|
| --- a/src/s390/simulator-s390.cc
|
| +++ b/src/s390/simulator-s390.cc
|
| @@ -2412,3149 +2412,6 @@ void Simulator::PrintStopInfo(uint32_t code) {
|
| #define CheckOverflowForShiftLeft(src1, src2) \
|
| (((src1) << (src2)) >> (src2) != (src1))
|
|
|
| -// S390 Decode and simulate helpers
|
| -bool Simulator::DecodeTwoByte(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| -
|
| - switch (op) {
|
| - // RR format instructions
|
| - case AR:
|
| - case SR:
|
| - case MR:
|
| - case DR:
|
| - case OR:
|
| - case NR:
|
| - case XR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - bool isOF = false;
|
| - switch (op) {
|
| - case AR:
|
| - isOF = CheckOverflowForIntAdd(r1_val, r2_val, int32_t);
|
| - r1_val += r2_val;
|
| - SetS390ConditionCode<int32_t>(r1_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - case SR:
|
| - isOF = CheckOverflowForIntSub(r1_val, r2_val, int32_t);
|
| - r1_val -= r2_val;
|
| - SetS390ConditionCode<int32_t>(r1_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - case OR:
|
| - r1_val |= r2_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(r1_val);
|
| - break;
|
| - case NR:
|
| - r1_val &= r2_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(r1_val);
|
| - break;
|
| - case XR:
|
| - r1_val ^= r2_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(r1_val);
|
| - break;
|
| - case MR: {
|
| - DCHECK(r1 % 2 == 0);
|
| - r1_val = get_low_register<int32_t>(r1 + 1);
|
| - int64_t product =
|
| - static_cast<int64_t>(r1_val) * static_cast<int64_t>(r2_val);
|
| - int32_t high_bits = product >> 32;
|
| - r1_val = high_bits;
|
| - int32_t low_bits = product & 0x00000000FFFFFFFF;
|
| - set_low_register(r1, high_bits);
|
| - set_low_register(r1 + 1, low_bits);
|
| - break;
|
| - }
|
| - case DR: {
|
| - // reg-reg pair should be even-odd pair, assert r1 is an even register
|
| - DCHECK(r1 % 2 == 0);
|
| - // leftmost 32 bits of the dividend are in r1
|
| - // rightmost 32 bits of the dividend are in r1+1
|
| - // get the signed value from r1
|
| - int64_t dividend = static_cast<int64_t>(r1_val) << 32;
|
| - // get unsigned value from r1+1
|
| - // avoid addition with sign-extended r1+1 value
|
| - dividend += get_low_register<uint32_t>(r1 + 1);
|
| - int32_t remainder = dividend % r2_val;
|
| - int32_t quotient = dividend / r2_val;
|
| - r1_val = remainder;
|
| - set_low_register(r1, remainder);
|
| - set_low_register(r1 + 1, quotient);
|
| - break; // reg pair
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - break;
|
| - }
|
| - set_low_register(r1, r1_val);
|
| - break;
|
| - }
|
| - case LR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - set_low_register(r1, get_low_register<int32_t>(r2));
|
| - break;
|
| - }
|
| - case LDR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - int64_t r2_val = get_d_register(r2);
|
| - set_d_register(r1, r2_val);
|
| - break;
|
| - }
|
| - case CR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - SetS390ConditionCode<int32_t>(r1_val, r2_val);
|
| - break;
|
| - }
|
| - case CLR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - uint32_t r1_val = get_low_register<uint32_t>(r1);
|
| - uint32_t r2_val = get_low_register<uint32_t>(r2);
|
| - SetS390ConditionCode<uint32_t>(r1_val, r2_val);
|
| - break;
|
| - }
|
| - case BCR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - if (TestConditionCode(Condition(r1))) {
|
| - intptr_t r2_val = get_register(r2);
|
| -#if (!V8_TARGET_ARCH_S390X && V8_HOST_ARCH_S390)
|
| - // On 31-bit, the top most bit may be 0 or 1, but is ignored by the
|
| - // hardware. Cleanse the top bit before jumping to it, unless it's one
|
| - // of the special PCs
|
| - if (r2_val != bad_lr && r2_val != end_sim_pc) r2_val &= 0x7FFFFFFF;
|
| -#endif
|
| - set_pc(r2_val);
|
| - }
|
| - break;
|
| - }
|
| - case LTR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - SetS390ConditionCode<int32_t>(r2_val, 0);
|
| - set_low_register(r1, r2_val);
|
| - break;
|
| - }
|
| - case ALR:
|
| - case SLR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - uint32_t r1_val = get_low_register<uint32_t>(r1);
|
| - uint32_t r2_val = get_low_register<uint32_t>(r2);
|
| - uint32_t alu_out = 0;
|
| - bool isOF = false;
|
| - if (ALR == op) {
|
| - alu_out = r1_val + r2_val;
|
| - isOF = CheckOverflowForUIntAdd(r1_val, r2_val);
|
| - } else if (SLR == op) {
|
| - alu_out = r1_val - r2_val;
|
| - isOF = CheckOverflowForUIntSub(r1_val, r2_val);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - SetS390ConditionCodeCarry<uint32_t>(alu_out, isOF);
|
| - break;
|
| - }
|
| - case LNR: {
|
| - // Load Negative (32)
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - r2_val = (r2_val >= 0) ? -r2_val : r2_val; // If pos, then negate it.
|
| - set_low_register(r1, r2_val);
|
| - condition_reg_ = (r2_val == 0) ? CC_EQ : CC_LT; // CC0 - result is zero
|
| - // CC1 - result is negative
|
| - break;
|
| - }
|
| - case BASR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - intptr_t link_addr = get_pc() + 2;
|
| - // If R2 is zero, the BASR does not branch.
|
| - int64_t r2_val = (r2 == 0) ? link_addr : get_register(r2);
|
| -#if (!V8_TARGET_ARCH_S390X && V8_HOST_ARCH_S390)
|
| - // On 31-bit, the top most bit may be 0 or 1, which can cause issues
|
| - // for stackwalker. The top bit should either be cleanse before being
|
| - // pushed onto the stack, or during stack walking when dereferenced.
|
| - // For simulator, we'll take the worst case scenario and always tag
|
| - // the high bit, to flush out more problems.
|
| - link_addr |= 0x80000000;
|
| -#endif
|
| - set_register(r1, link_addr);
|
| - set_pc(r2_val);
|
| - break;
|
| - }
|
| - case LCR: {
|
| - RRInstruction* rrinst = reinterpret_cast<RRInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - int32_t original_r2_val = r2_val;
|
| - r2_val = ~r2_val;
|
| - r2_val = r2_val + 1;
|
| - set_low_register(r1, r2_val);
|
| - SetS390ConditionCode<int32_t>(r2_val, 0);
|
| - // Checks for overflow where r2_val = -2147483648.
|
| - // Cannot do int comparison due to GCC 4.8 bug on x86.
|
| - // Detect INT_MIN alternatively, as it is the only value where both
|
| - // original and result are negative due to overflow.
|
| - if (r2_val < 0 && original_r2_val < 0) {
|
| - SetS390OverflowCode(true);
|
| - }
|
| - break;
|
| - }
|
| - case BKPT: {
|
| - set_pc(get_pc() + 2);
|
| - S390Debugger dbg(this);
|
| - dbg.Debug();
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - return false;
|
| - break;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// Decode routine for four-byte instructions
|
| -bool Simulator::DecodeFourByte(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| -
|
| - // Pre-cast instruction to various types
|
| - RREInstruction* rreInst = reinterpret_cast<RREInstruction*>(instr);
|
| - SIInstruction* siInstr = reinterpret_cast<SIInstruction*>(instr);
|
| -
|
| - switch (op) {
|
| - case POPCNT_Z: {
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - int64_t r2_val = get_register(r2);
|
| - int64_t r1_val = 0;
|
| -
|
| - uint8_t* r2_val_ptr = reinterpret_cast<uint8_t*>(&r2_val);
|
| - uint8_t* r1_val_ptr = reinterpret_cast<uint8_t*>(&r1_val);
|
| - for (int i = 0; i < 8; i++) {
|
| - uint32_t x = static_cast<uint32_t>(r2_val_ptr[i]);
|
| -#if defined(__GNUC__)
|
| - r1_val_ptr[i] = __builtin_popcount(x);
|
| -#else
|
| -#error unsupport __builtin_popcount
|
| -#endif
|
| - }
|
| -
|
| - set_register(r1, static_cast<uint64_t>(r1_val));
|
| - break;
|
| - }
|
| - case LLGFR: {
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - uint64_t r2_finalval =
|
| - (static_cast<uint64_t>(r2_val) & 0x00000000ffffffff);
|
| - set_register(r1, r2_finalval);
|
| - break;
|
| - }
|
| - case EX: {
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int r1 = rxinst->R1Value();
|
| - int b2 = rxinst->B2Value();
|
| - int x2 = rxinst->X2Value();
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| -
|
| - SixByteInstr the_instr = Instruction::InstructionBits(
|
| - reinterpret_cast<const byte*>(b2_val + x2_val + d2_val));
|
| - int length = Instruction::InstructionLength(
|
| - reinterpret_cast<const byte*>(b2_val + x2_val + d2_val));
|
| -
|
| - char new_instr_buf[8];
|
| - char* addr = reinterpret_cast<char*>(&new_instr_buf[0]);
|
| - the_instr |= static_cast<SixByteInstr>(r1_val & 0xff)
|
| - << (8 * length - 16);
|
| - Instruction::SetInstructionBits<SixByteInstr>(
|
| - reinterpret_cast<byte*>(addr), static_cast<SixByteInstr>(the_instr));
|
| - ExecuteInstruction(reinterpret_cast<Instruction*>(addr), false);
|
| - break;
|
| - }
|
| - case LGR: {
|
| - // Load Register (64)
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - set_register(r1, get_register(r2));
|
| - break;
|
| - }
|
| - case LDGR: {
|
| - // Load FPR from GPR (L <- 64)
|
| - uint64_t int_val = get_register(rreInst->R2Value());
|
| - // double double_val = bit_cast<double, uint64_t>(int_val);
|
| - // set_d_register_from_double(rreInst->R1Value(), double_val);
|
| - set_d_register(rreInst->R1Value(), int_val);
|
| - break;
|
| - }
|
| - case LGDR: {
|
| - // Load GPR from FPR (64 <- L)
|
| - int64_t double_val = get_d_register(rreInst->R2Value());
|
| - set_register(rreInst->R1Value(), double_val);
|
| - break;
|
| - }
|
| - case LTGR: {
|
| - // Load Register (64)
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - int64_t r2_val = get_register(r2);
|
| - SetS390ConditionCode<int64_t>(r2_val, 0);
|
| - set_register(r1, get_register(r2));
|
| - break;
|
| - }
|
| - case LZDR: {
|
| - int r1 = rreInst->R1Value();
|
| - set_d_register_from_double(r1, 0.0);
|
| - break;
|
| - }
|
| - case LTEBR: {
|
| - RREInstruction* rreinst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreinst->R1Value();
|
| - int r2 = rreinst->R2Value();
|
| - int64_t r2_val = get_d_register(r2);
|
| - float fr2_val = get_float32_from_d_register(r2);
|
| - SetS390ConditionCode<float>(fr2_val, 0.0);
|
| - set_d_register(r1, r2_val);
|
| - break;
|
| - }
|
| - case LTDBR: {
|
| - RREInstruction* rreinst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreinst->R1Value();
|
| - int r2 = rreinst->R2Value();
|
| - int64_t r2_val = get_d_register(r2);
|
| - SetS390ConditionCode<double>(bit_cast<double, int64_t>(r2_val), 0.0);
|
| - set_d_register(r1, r2_val);
|
| - break;
|
| - }
|
| - case CGR: {
|
| - // Compare (64)
|
| - int64_t r1_val = get_register(rreInst->R1Value());
|
| - int64_t r2_val = get_register(rreInst->R2Value());
|
| - SetS390ConditionCode<int64_t>(r1_val, r2_val);
|
| - break;
|
| - }
|
| - case CLGR: {
|
| - // Compare Logical (64)
|
| - uint64_t r1_val = static_cast<uint64_t>(get_register(rreInst->R1Value()));
|
| - uint64_t r2_val = static_cast<uint64_t>(get_register(rreInst->R2Value()));
|
| - SetS390ConditionCode<uint64_t>(r1_val, r2_val);
|
| - break;
|
| - }
|
| - case LH: {
|
| - // Load Halfword
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int r1 = rxinst->R1Value();
|
| - int x2 = rxinst->X2Value();
|
| - int b2 = rxinst->B2Value();
|
| -
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - intptr_t mem_addr = x2_val + b2_val + d2_val;
|
| -
|
| - int32_t result = static_cast<int32_t>(ReadH(mem_addr, instr));
|
| - set_low_register(r1, result);
|
| - break;
|
| - }
|
| - case LHI: {
|
| - RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
| - int r1 = riinst->R1Value();
|
| - int i = riinst->I2Value();
|
| - set_low_register(r1, i);
|
| - break;
|
| - }
|
| - case LGHI: {
|
| - RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
| - int r1 = riinst->R1Value();
|
| - int64_t i = riinst->I2Value();
|
| - set_register(r1, i);
|
| - break;
|
| - }
|
| - case CHI: {
|
| - RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
| - int r1 = riinst->R1Value();
|
| - int16_t i = riinst->I2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - SetS390ConditionCode<int32_t>(r1_val, i);
|
| - break;
|
| - }
|
| - case CGHI: {
|
| - RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
| - int r1 = riinst->R1Value();
|
| - int64_t i = static_cast<int64_t>(riinst->I2Value());
|
| - int64_t r1_val = get_register(r1);
|
| - SetS390ConditionCode<int64_t>(r1_val, i);
|
| - break;
|
| - }
|
| - case BRAS: {
|
| - // Branch Relative and Save
|
| - RILInstruction* rilInstr = reinterpret_cast<RILInstruction*>(instr);
|
| - int r1 = rilInstr->R1Value();
|
| - intptr_t d2 = rilInstr->I2Value();
|
| - intptr_t pc = get_pc();
|
| - // Set PC of next instruction to register
|
| - set_register(r1, pc + sizeof(FourByteInstr));
|
| - // Update PC to branch target
|
| - set_pc(pc + d2 * 2);
|
| - break;
|
| - }
|
| - case BRC: {
|
| - // Branch Relative on Condition
|
| - RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
| - int m1 = riinst->M1Value();
|
| - if (TestConditionCode((Condition)m1)) {
|
| - intptr_t offset = riinst->I2Value() * 2;
|
| - set_pc(get_pc() + offset);
|
| - }
|
| - break;
|
| - }
|
| - case BRCT:
|
| - case BRCTG: {
|
| - // Branch On Count (32/64).
|
| - RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
| - int r1 = riinst->R1Value();
|
| - int64_t value =
|
| - (op == BRCT) ? get_low_register<int32_t>(r1) : get_register(r1);
|
| - if (BRCT == op)
|
| - set_low_register(r1, --value);
|
| - else
|
| - set_register(r1, --value);
|
| - // Branch if value != 0
|
| - if (value != 0) {
|
| - intptr_t offset = riinst->I2Value() * 2;
|
| - set_pc(get_pc() + offset);
|
| - }
|
| - break;
|
| - }
|
| - case BXH: {
|
| - RSInstruction* rsinst = reinterpret_cast<RSInstruction*>(instr);
|
| - int r1 = rsinst->R1Value();
|
| - int r3 = rsinst->R3Value();
|
| - int b2 = rsinst->B2Value();
|
| - int d2 = rsinst->D2Value();
|
| -
|
| - // r1_val is the first operand, r3_val is the increment
|
| - int32_t r1_val = r1 == 0 ? 0 : get_register(r1);
|
| - int32_t r3_val = r2 == 0 ? 0 : get_register(r3);
|
| - intptr_t b2_val = b2 == 0 ? 0 : get_register(b2);
|
| - intptr_t branch_address = b2_val + d2;
|
| - // increment r1_val
|
| - r1_val += r3_val;
|
| -
|
| - // if the increment is even, then it designates a pair of registers
|
| - // and the contents of the even and odd registers of the pair are used as
|
| - // the increment and compare value respectively. If the increment is odd,
|
| - // the increment itself is used as both the increment and compare value
|
| - int32_t compare_val = r3 % 2 == 0 ? get_register(r3 + 1) : r3_val;
|
| - if (r1_val > compare_val) {
|
| - // branch to address if r1_val is greater than compare value
|
| - set_pc(branch_address);
|
| - }
|
| -
|
| - // update contents of register in r1 with the new incremented value
|
| - set_register(r1, r1_val);
|
| - break;
|
| - }
|
| - case IIHH:
|
| - case IIHL:
|
| - case IILH:
|
| - case IILL: {
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| - case STM:
|
| - case LM: {
|
| - // Store Multiple 32-bits.
|
| - RSInstruction* rsinstr = reinterpret_cast<RSInstruction*>(instr);
|
| - int r1 = rsinstr->R1Value();
|
| - int r3 = rsinstr->R3Value();
|
| - int rb = rsinstr->B2Value();
|
| - int offset = rsinstr->D2Value();
|
| -
|
| - // Regs roll around if r3 is less than r1.
|
| - // Artifically increase r3 by 16 so we can calculate
|
| - // the number of regs stored properly.
|
| - if (r3 < r1) r3 += 16;
|
| -
|
| - int32_t rb_val = (rb == 0) ? 0 : get_low_register<int32_t>(rb);
|
| -
|
| - // Store each register in ascending order.
|
| - for (int i = 0; i <= r3 - r1; i++) {
|
| - if (op == STM) {
|
| - int32_t value = get_low_register<int32_t>((r1 + i) % 16);
|
| - WriteW(rb_val + offset + 4 * i, value, instr);
|
| - } else if (op == LM) {
|
| - int32_t value = ReadW(rb_val + offset + 4 * i, instr);
|
| - set_low_register((r1 + i) % 16, value);
|
| - }
|
| - }
|
| - break;
|
| - }
|
| - case SLL:
|
| - case SRL: {
|
| - RSInstruction* rsInstr = reinterpret_cast<RSInstruction*>(instr);
|
| - int r1 = rsInstr->R1Value();
|
| - int b2 = rsInstr->B2Value();
|
| - intptr_t d2 = rsInstr->D2Value();
|
| - // only takes rightmost 6bits
|
| - int64_t b2_val = b2 == 0 ? 0 : get_register(b2);
|
| - int shiftBits = (b2_val + d2) & 0x3F;
|
| - uint32_t r1_val = get_low_register<uint32_t>(r1);
|
| - uint32_t alu_out = 0;
|
| - if (SLL == op) {
|
| - alu_out = r1_val << shiftBits;
|
| - } else if (SRL == op) {
|
| - alu_out = r1_val >> shiftBits;
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - break;
|
| - }
|
| - case SLDL: {
|
| - RSInstruction* rsInstr = reinterpret_cast<RSInstruction*>(instr);
|
| - int r1 = rsInstr->R1Value();
|
| - int b2 = rsInstr->B2Value();
|
| - intptr_t d2 = rsInstr->D2Value();
|
| - // only takes rightmost 6bits
|
| - int64_t b2_val = b2 == 0 ? 0 : get_register(b2);
|
| - int shiftBits = (b2_val + d2) & 0x3F;
|
| -
|
| - DCHECK(r1 % 2 == 0);
|
| - uint32_t r1_val = get_low_register<uint32_t>(r1);
|
| - uint32_t r1_next_val = get_low_register<uint32_t>(r1 + 1);
|
| - uint64_t alu_out = (static_cast<uint64_t>(r1_val) << 32) |
|
| - (static_cast<uint64_t>(r1_next_val));
|
| - alu_out <<= shiftBits;
|
| - set_low_register(r1 + 1, static_cast<uint32_t>(alu_out));
|
| - set_low_register(r1, static_cast<uint32_t>(alu_out >> 32));
|
| - break;
|
| - }
|
| - case SLA:
|
| - case SRA: {
|
| - RSInstruction* rsInstr = reinterpret_cast<RSInstruction*>(instr);
|
| - int r1 = rsInstr->R1Value();
|
| - int b2 = rsInstr->B2Value();
|
| - intptr_t d2 = rsInstr->D2Value();
|
| - // only takes rightmost 6bits
|
| - int64_t b2_val = b2 == 0 ? 0 : get_register(b2);
|
| - int shiftBits = (b2_val + d2) & 0x3F;
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - int32_t alu_out = 0;
|
| - bool isOF = false;
|
| - if (op == SLA) {
|
| - isOF = CheckOverflowForShiftLeft(r1_val, shiftBits);
|
| - alu_out = r1_val << shiftBits;
|
| - } else if (op == SRA) {
|
| - alu_out = r1_val >> shiftBits;
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - }
|
| - case LLHR: {
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| - case LLGHR: {
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| - case L:
|
| - case LA:
|
| - case LD:
|
| - case LE: {
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int b2 = rxinst->B2Value();
|
| - int x2 = rxinst->X2Value();
|
| - int32_t r1 = rxinst->R1Value();
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - intptr_t addr = b2_val + x2_val + d2_val;
|
| - if (op == L) {
|
| - int32_t mem_val = ReadW(addr, instr);
|
| - set_low_register(r1, mem_val);
|
| - } else if (op == LA) {
|
| - set_register(r1, addr);
|
| - } else if (op == LD) {
|
| - int64_t dbl_val = *reinterpret_cast<int64_t*>(addr);
|
| - set_d_register(r1, dbl_val);
|
| - } else if (op == LE) {
|
| - float float_val = *reinterpret_cast<float*>(addr);
|
| - set_d_register_from_float32(r1, float_val);
|
| - }
|
| - break;
|
| - }
|
| - case C:
|
| - case CL: {
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int b2 = rxinst->B2Value();
|
| - int x2 = rxinst->X2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(rxinst->R1Value());
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - intptr_t addr = b2_val + x2_val + d2_val;
|
| - int32_t mem_val = ReadW(addr, instr);
|
| - if (C == op)
|
| - SetS390ConditionCode<int32_t>(r1_val, mem_val);
|
| - else if (CL == op)
|
| - SetS390ConditionCode<uint32_t>(r1_val, mem_val);
|
| - break;
|
| - }
|
| - case CLI: {
|
| - // Compare Immediate (Mem - Imm) (8)
|
| - int b1 = siInstr->B1Value();
|
| - int64_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
| - intptr_t d1_val = siInstr->D1Value();
|
| - intptr_t addr = b1_val + d1_val;
|
| - uint8_t mem_val = ReadB(addr);
|
| - uint8_t imm_val = siInstr->I2Value();
|
| - SetS390ConditionCode<uint8_t>(mem_val, imm_val);
|
| - break;
|
| - }
|
| - case TM: {
|
| - // Test Under Mask (Mem - Imm) (8)
|
| - int b1 = siInstr->B1Value();
|
| - int64_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
| - intptr_t d1_val = siInstr->D1Value();
|
| - intptr_t addr = b1_val + d1_val;
|
| - uint8_t mem_val = ReadB(addr);
|
| - uint8_t imm_val = siInstr->I2Value();
|
| - uint8_t selected_bits = mem_val & imm_val;
|
| - // CC0: Selected bits are zero
|
| - // CC1: Selected bits mixed zeros and ones
|
| - // CC3: Selected bits all ones
|
| - if (0 == selected_bits) {
|
| - condition_reg_ = CC_EQ; // CC0
|
| - } else if (selected_bits == imm_val) {
|
| - condition_reg_ = 0x1; // CC3
|
| - } else {
|
| - condition_reg_ = 0x4; // CC1
|
| - }
|
| - break;
|
| - }
|
| - case ST:
|
| - case STE:
|
| - case STD: {
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int b2 = rxinst->B2Value();
|
| - int x2 = rxinst->X2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(rxinst->R1Value());
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - intptr_t addr = b2_val + x2_val + d2_val;
|
| - if (op == ST) {
|
| - WriteW(addr, r1_val, instr);
|
| - } else if (op == STD) {
|
| - int64_t frs_val = get_d_register(rxinst->R1Value());
|
| - WriteDW(addr, frs_val);
|
| - } else if (op == STE) {
|
| - int64_t frs_val = get_d_register(rxinst->R1Value()) >> 32;
|
| - WriteW(addr, static_cast<int32_t>(frs_val), instr);
|
| - }
|
| - break;
|
| - }
|
| - case LTGFR:
|
| - case LGFR: {
|
| - // Load and Test Register (64 <- 32) (Sign Extends 32-bit val)
|
| - // Load Register (64 <- 32) (Sign Extends 32-bit val)
|
| - RREInstruction* rreInstr = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreInstr->R1Value();
|
| - int r2 = rreInstr->R2Value();
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - int64_t result = static_cast<int64_t>(r2_val);
|
| - set_register(r1, result);
|
| -
|
| - if (LTGFR == op) SetS390ConditionCode<int64_t>(result, 0);
|
| - break;
|
| - }
|
| - case LNGR: {
|
| - // Load Negative (64)
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - int64_t r2_val = get_register(r2);
|
| - r2_val = (r2_val >= 0) ? -r2_val : r2_val; // If pos, then negate it.
|
| - set_register(r1, r2_val);
|
| - condition_reg_ = (r2_val == 0) ? CC_EQ : CC_LT; // CC0 - result is zero
|
| - // CC1 - result is negative
|
| - break;
|
| - }
|
| - case TRAP4: {
|
| - // whack the space of the caller allocated stack
|
| - int64_t sp_addr = get_register(sp);
|
| - for (int i = 0; i < kCalleeRegisterSaveAreaSize / kPointerSize; ++i) {
|
| - // we dont want to whack the RA (r14)
|
| - if (i != 14) (reinterpret_cast<intptr_t*>(sp_addr))[i] = 0xdeadbabe;
|
| - }
|
| - SoftwareInterrupt(instr);
|
| - break;
|
| - }
|
| - case STC: {
|
| - // Store Character/Byte
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int b2 = rxinst->B2Value();
|
| - int x2 = rxinst->X2Value();
|
| - uint8_t r1_val = get_low_register<int32_t>(rxinst->R1Value());
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - intptr_t mem_addr = b2_val + x2_val + d2_val;
|
| - WriteB(mem_addr, r1_val);
|
| - break;
|
| - }
|
| - case STH: {
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int b2 = rxinst->B2Value();
|
| - int x2 = rxinst->X2Value();
|
| - int16_t r1_val = get_low_register<int32_t>(rxinst->R1Value());
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - intptr_t mem_addr = b2_val + x2_val + d2_val;
|
| - WriteH(mem_addr, r1_val, instr);
|
| - break;
|
| - }
|
| -#if V8_TARGET_ARCH_S390X
|
| - case LCGR: {
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - int64_t r2_val = get_register(r2);
|
| - r2_val = ~r2_val;
|
| - r2_val = r2_val + 1;
|
| - set_register(r1, r2_val);
|
| - SetS390ConditionCode<int64_t>(r2_val, 0);
|
| - // if the input is INT_MIN, loading its compliment would be overflowing
|
| - if (r2_val < 0 && (r2_val + 1) > 0) {
|
| - SetS390OverflowCode(true);
|
| - }
|
| - break;
|
| - }
|
| -#endif
|
| - case SRDA: {
|
| - RSInstruction* rsInstr = reinterpret_cast<RSInstruction*>(instr);
|
| - int r1 = rsInstr->R1Value();
|
| - DCHECK(r1 % 2 == 0); // must be a reg pair
|
| - int b2 = rsInstr->B2Value();
|
| - intptr_t d2 = rsInstr->D2Value();
|
| - // only takes rightmost 6bits
|
| - int64_t b2_val = b2 == 0 ? 0 : get_register(b2);
|
| - int shiftBits = (b2_val + d2) & 0x3F;
|
| - int64_t opnd1 = static_cast<int64_t>(get_low_register<int32_t>(r1)) << 32;
|
| - int64_t opnd2 = static_cast<uint64_t>(get_low_register<uint32_t>(r1 + 1));
|
| - int64_t r1_val = opnd1 + opnd2;
|
| - int64_t alu_out = r1_val >> shiftBits;
|
| - set_low_register(r1, alu_out >> 32);
|
| - set_low_register(r1 + 1, alu_out & 0x00000000FFFFFFFF);
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - break;
|
| - }
|
| - case SRDL: {
|
| - RSInstruction* rsInstr = reinterpret_cast<RSInstruction*>(instr);
|
| - int r1 = rsInstr->R1Value();
|
| - DCHECK(r1 % 2 == 0); // must be a reg pair
|
| - int b2 = rsInstr->B2Value();
|
| - intptr_t d2 = rsInstr->D2Value();
|
| - // only takes rightmost 6bits
|
| - int64_t b2_val = b2 == 0 ? 0 : get_register(b2);
|
| - int shiftBits = (b2_val + d2) & 0x3F;
|
| - uint64_t opnd1 = static_cast<uint64_t>(get_low_register<uint32_t>(r1))
|
| - << 32;
|
| - uint64_t opnd2 =
|
| - static_cast<uint64_t>(get_low_register<uint32_t>(r1 + 1));
|
| - uint64_t r1_val = opnd1 | opnd2;
|
| - uint64_t alu_out = r1_val >> shiftBits;
|
| - set_low_register(r1, alu_out >> 32);
|
| - set_low_register(r1 + 1, alu_out & 0x00000000FFFFFFFF);
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - break;
|
| - }
|
| - default: { return DecodeFourByteArithmetic(instr); }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -bool Simulator::DecodeFourByteArithmetic64Bit(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| -
|
| - RRFInstruction* rrfInst = reinterpret_cast<RRFInstruction*>(instr);
|
| - RREInstruction* rreInst = reinterpret_cast<RREInstruction*>(instr);
|
| -
|
| - switch (op) {
|
| - case AGR:
|
| - case SGR:
|
| - case OGR:
|
| - case NGR:
|
| - case XGR: {
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - int64_t r1_val = get_register(r1);
|
| - int64_t r2_val = get_register(r2);
|
| - bool isOF = false;
|
| - switch (op) {
|
| - case AGR:
|
| - isOF = CheckOverflowForIntAdd(r1_val, r2_val, int64_t);
|
| - r1_val += r2_val;
|
| - SetS390ConditionCode<int64_t>(r1_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - case SGR:
|
| - isOF = CheckOverflowForIntSub(r1_val, r2_val, int64_t);
|
| - r1_val -= r2_val;
|
| - SetS390ConditionCode<int64_t>(r1_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - case OGR:
|
| - r1_val |= r2_val;
|
| - SetS390BitWiseConditionCode<uint64_t>(r1_val);
|
| - break;
|
| - case NGR:
|
| - r1_val &= r2_val;
|
| - SetS390BitWiseConditionCode<uint64_t>(r1_val);
|
| - break;
|
| - case XGR:
|
| - r1_val ^= r2_val;
|
| - SetS390BitWiseConditionCode<uint64_t>(r1_val);
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - break;
|
| - }
|
| - set_register(r1, r1_val);
|
| - break;
|
| - }
|
| - case AGFR: {
|
| - // Add Register (64 <- 32) (Sign Extends 32-bit val)
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - int64_t r1_val = get_register(r1);
|
| - int64_t r2_val = static_cast<int64_t>(get_low_register<int32_t>(r2));
|
| - bool isOF = CheckOverflowForIntAdd(r1_val, r2_val, int64_t);
|
| - r1_val += r2_val;
|
| - SetS390ConditionCode<int64_t>(r1_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_register(r1, r1_val);
|
| - break;
|
| - }
|
| - case SGFR: {
|
| - // Sub Reg (64 <- 32)
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - int64_t r1_val = get_register(r1);
|
| - int64_t r2_val = static_cast<int64_t>(get_low_register<int32_t>(r2));
|
| - bool isOF = false;
|
| - isOF = CheckOverflowForIntSub(r1_val, r2_val, int64_t);
|
| - r1_val -= r2_val;
|
| - SetS390ConditionCode<int64_t>(r1_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_register(r1, r1_val);
|
| - break;
|
| - }
|
| - case AGRK:
|
| - case SGRK:
|
| - case NGRK:
|
| - case OGRK:
|
| - case XGRK: {
|
| - // 64-bit Non-clobbering arithmetics / bitwise ops.
|
| - int r1 = rrfInst->R1Value();
|
| - int r2 = rrfInst->R2Value();
|
| - int r3 = rrfInst->R3Value();
|
| - int64_t r2_val = get_register(r2);
|
| - int64_t r3_val = get_register(r3);
|
| - if (AGRK == op) {
|
| - bool isOF = CheckOverflowForIntAdd(r2_val, r3_val, int64_t);
|
| - SetS390ConditionCode<int64_t>(r2_val + r3_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_register(r1, r2_val + r3_val);
|
| - } else if (SGRK == op) {
|
| - bool isOF = CheckOverflowForIntSub(r2_val, r3_val, int64_t);
|
| - SetS390ConditionCode<int64_t>(r2_val - r3_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_register(r1, r2_val - r3_val);
|
| - } else {
|
| - // Assume bitwise operation here
|
| - uint64_t bitwise_result = 0;
|
| - if (NGRK == op) {
|
| - bitwise_result = r2_val & r3_val;
|
| - } else if (OGRK == op) {
|
| - bitwise_result = r2_val | r3_val;
|
| - } else if (XGRK == op) {
|
| - bitwise_result = r2_val ^ r3_val;
|
| - }
|
| - SetS390BitWiseConditionCode<uint64_t>(bitwise_result);
|
| - set_register(r1, bitwise_result);
|
| - }
|
| - break;
|
| - }
|
| - case ALGRK:
|
| - case SLGRK: {
|
| - // 64-bit Non-clobbering unsigned arithmetics
|
| - int r1 = rrfInst->R1Value();
|
| - int r2 = rrfInst->R2Value();
|
| - int r3 = rrfInst->R3Value();
|
| - uint64_t r2_val = get_register(r2);
|
| - uint64_t r3_val = get_register(r3);
|
| - if (ALGRK == op) {
|
| - bool isOF = CheckOverflowForUIntAdd(r2_val, r3_val);
|
| - SetS390ConditionCode<uint64_t>(r2_val + r3_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_register(r1, r2_val + r3_val);
|
| - } else if (SLGRK == op) {
|
| - bool isOF = CheckOverflowForUIntSub(r2_val, r3_val);
|
| - SetS390ConditionCode<uint64_t>(r2_val - r3_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_register(r1, r2_val - r3_val);
|
| - }
|
| - break;
|
| - }
|
| - case AGHI:
|
| - case MGHI: {
|
| - RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
| - int32_t r1 = riinst->R1Value();
|
| - int64_t i = static_cast<int64_t>(riinst->I2Value());
|
| - int64_t r1_val = get_register(r1);
|
| - bool isOF = false;
|
| - switch (op) {
|
| - case AGHI:
|
| - isOF = CheckOverflowForIntAdd(r1_val, i, int64_t);
|
| - r1_val += i;
|
| - break;
|
| - case MGHI:
|
| - isOF = CheckOverflowForMul(r1_val, i);
|
| - r1_val *= i;
|
| - break; // no overflow indication is given
|
| - default:
|
| - break;
|
| - }
|
| - set_register(r1, r1_val);
|
| - SetS390ConditionCode<int32_t>(r1_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -/**
|
| - * Decodes and simulates four byte arithmetic instructions
|
| - */
|
| -bool Simulator::DecodeFourByteArithmetic(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| -
|
| - // Pre-cast instruction to various types
|
| - RRFInstruction* rrfInst = reinterpret_cast<RRFInstruction*>(instr);
|
| -
|
| - switch (op) {
|
| - case AGR:
|
| - case SGR:
|
| - case OGR:
|
| - case NGR:
|
| - case XGR:
|
| - case AGFR:
|
| - case SGFR: {
|
| - DecodeFourByteArithmetic64Bit(instr);
|
| - break;
|
| - }
|
| - case ARK:
|
| - case SRK:
|
| - case NRK:
|
| - case ORK:
|
| - case XRK: {
|
| - // 32-bit Non-clobbering arithmetics / bitwise ops
|
| - int r1 = rrfInst->R1Value();
|
| - int r2 = rrfInst->R2Value();
|
| - int r3 = rrfInst->R3Value();
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - int32_t r3_val = get_low_register<int32_t>(r3);
|
| - if (ARK == op) {
|
| - bool isOF = CheckOverflowForIntAdd(r2_val, r3_val, int32_t);
|
| - SetS390ConditionCode<int32_t>(r2_val + r3_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_low_register(r1, r2_val + r3_val);
|
| - } else if (SRK == op) {
|
| - bool isOF = CheckOverflowForIntSub(r2_val, r3_val, int32_t);
|
| - SetS390ConditionCode<int32_t>(r2_val - r3_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_low_register(r1, r2_val - r3_val);
|
| - } else {
|
| - // Assume bitwise operation here
|
| - uint32_t bitwise_result = 0;
|
| - if (NRK == op) {
|
| - bitwise_result = r2_val & r3_val;
|
| - } else if (ORK == op) {
|
| - bitwise_result = r2_val | r3_val;
|
| - } else if (XRK == op) {
|
| - bitwise_result = r2_val ^ r3_val;
|
| - }
|
| - SetS390BitWiseConditionCode<uint32_t>(bitwise_result);
|
| - set_low_register(r1, bitwise_result);
|
| - }
|
| - break;
|
| - }
|
| - case ALRK:
|
| - case SLRK: {
|
| - // 32-bit Non-clobbering unsigned arithmetics
|
| - int r1 = rrfInst->R1Value();
|
| - int r2 = rrfInst->R2Value();
|
| - int r3 = rrfInst->R3Value();
|
| - uint32_t r2_val = get_low_register<uint32_t>(r2);
|
| - uint32_t r3_val = get_low_register<uint32_t>(r3);
|
| - if (ALRK == op) {
|
| - bool isOF = CheckOverflowForUIntAdd(r2_val, r3_val);
|
| - SetS390ConditionCode<uint32_t>(r2_val + r3_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_low_register(r1, r2_val + r3_val);
|
| - } else if (SLRK == op) {
|
| - bool isOF = CheckOverflowForUIntSub(r2_val, r3_val);
|
| - SetS390ConditionCode<uint32_t>(r2_val - r3_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - set_low_register(r1, r2_val - r3_val);
|
| - }
|
| - break;
|
| - }
|
| - case AGRK:
|
| - case SGRK:
|
| - case NGRK:
|
| - case OGRK:
|
| - case XGRK: {
|
| - DecodeFourByteArithmetic64Bit(instr);
|
| - break;
|
| - }
|
| - case ALGRK:
|
| - case SLGRK: {
|
| - DecodeFourByteArithmetic64Bit(instr);
|
| - break;
|
| - }
|
| - case AHI:
|
| - case MHI: {
|
| - RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
| - int32_t r1 = riinst->R1Value();
|
| - int32_t i = riinst->I2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - bool isOF = false;
|
| - switch (op) {
|
| - case AHI:
|
| - isOF = CheckOverflowForIntAdd(r1_val, i, int32_t);
|
| - r1_val += i;
|
| - break;
|
| - case MHI:
|
| - isOF = CheckOverflowForMul(r1_val, i);
|
| - r1_val *= i;
|
| - break; // no overflow indication is given
|
| - default:
|
| - break;
|
| - }
|
| - set_low_register(r1, r1_val);
|
| - SetS390ConditionCode<int32_t>(r1_val, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - }
|
| - case AGHI:
|
| - case MGHI: {
|
| - DecodeFourByteArithmetic64Bit(instr);
|
| - break;
|
| - }
|
| - case MLR: {
|
| - RREInstruction* rreinst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreinst->R1Value();
|
| - int r2 = rreinst->R2Value();
|
| - DCHECK(r1 % 2 == 0);
|
| -
|
| - uint32_t r1_val = get_low_register<uint32_t>(r1 + 1);
|
| - uint32_t r2_val = get_low_register<uint32_t>(r2);
|
| - uint64_t product =
|
| - static_cast<uint64_t>(r1_val) * static_cast<uint64_t>(r2_val);
|
| - int32_t high_bits = product >> 32;
|
| - int32_t low_bits = product & 0x00000000FFFFFFFF;
|
| - set_low_register(r1, high_bits);
|
| - set_low_register(r1 + 1, low_bits);
|
| - break;
|
| - }
|
| - case DLGR: {
|
| -#ifdef V8_TARGET_ARCH_S390X
|
| - RREInstruction* rreinst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreinst->R1Value();
|
| - int r2 = rreinst->R2Value();
|
| - uint64_t r1_val = get_register(r1);
|
| - uint64_t r2_val = get_register(r2);
|
| - DCHECK(r1 % 2 == 0);
|
| - unsigned __int128 dividend = static_cast<unsigned __int128>(r1_val) << 64;
|
| - dividend += get_register(r1 + 1);
|
| - uint64_t remainder = dividend % r2_val;
|
| - uint64_t quotient = dividend / r2_val;
|
| - r1_val = remainder;
|
| - set_register(r1, remainder);
|
| - set_register(r1 + 1, quotient);
|
| -#else
|
| - UNREACHABLE();
|
| -#endif
|
| - break;
|
| - }
|
| - case DLR: {
|
| - RREInstruction* rreinst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreinst->R1Value();
|
| - int r2 = rreinst->R2Value();
|
| - uint32_t r1_val = get_low_register<uint32_t>(r1);
|
| - uint32_t r2_val = get_low_register<uint32_t>(r2);
|
| - DCHECK(r1 % 2 == 0);
|
| - uint64_t dividend = static_cast<uint64_t>(r1_val) << 32;
|
| - dividend += get_low_register<uint32_t>(r1 + 1);
|
| - uint32_t remainder = dividend % r2_val;
|
| - uint32_t quotient = dividend / r2_val;
|
| - r1_val = remainder;
|
| - set_low_register(r1, remainder);
|
| - set_low_register(r1 + 1, quotient);
|
| - break;
|
| - }
|
| - case A:
|
| - case S:
|
| - case M:
|
| - case D:
|
| - case O:
|
| - case N:
|
| - case X: {
|
| - // 32-bit Reg-Mem instructions
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int b2 = rxinst->B2Value();
|
| - int x2 = rxinst->X2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(rxinst->R1Value());
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - int32_t mem_val = ReadW(b2_val + x2_val + d2_val, instr);
|
| - int32_t alu_out = 0;
|
| - bool isOF = false;
|
| - switch (op) {
|
| - case A:
|
| - isOF = CheckOverflowForIntAdd(r1_val, mem_val, int32_t);
|
| - alu_out = r1_val + mem_val;
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - case S:
|
| - isOF = CheckOverflowForIntSub(r1_val, mem_val, int32_t);
|
| - alu_out = r1_val - mem_val;
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - case M:
|
| - case D:
|
| - UNIMPLEMENTED();
|
| - break;
|
| - case O:
|
| - alu_out = r1_val | mem_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - break;
|
| - case N:
|
| - alu_out = r1_val & mem_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - break;
|
| - case X:
|
| - alu_out = r1_val ^ mem_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - break;
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - break;
|
| - }
|
| - case OILL:
|
| - case OIHL: {
|
| - RIInstruction* riInst = reinterpret_cast<RIInstruction*>(instr);
|
| - int r1 = riInst->R1Value();
|
| - int i = riInst->I2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - if (OILL == op) {
|
| - // CC is set based on the 16 bits that are AND'd
|
| - SetS390BitWiseConditionCode<uint16_t>(r1_val | i);
|
| - } else if (OILH == op) {
|
| - // CC is set based on the 16 bits that are AND'd
|
| - SetS390BitWiseConditionCode<uint16_t>((r1_val >> 16) | i);
|
| - i = i << 16;
|
| - } else {
|
| - UNIMPLEMENTED();
|
| - }
|
| - set_low_register(r1, r1_val | i);
|
| - break;
|
| - }
|
| - case NILL:
|
| - case NILH: {
|
| - RIInstruction* riInst = reinterpret_cast<RIInstruction*>(instr);
|
| - int r1 = riInst->R1Value();
|
| - int i = riInst->I2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - if (NILL == op) {
|
| - // CC is set based on the 16 bits that are AND'd
|
| - SetS390BitWiseConditionCode<uint16_t>(r1_val & i);
|
| - i |= 0xFFFF0000;
|
| - } else if (NILH == op) {
|
| - // CC is set based on the 16 bits that are AND'd
|
| - SetS390BitWiseConditionCode<uint16_t>((r1_val >> 16) & i);
|
| - i = (i << 16) | 0x0000FFFF;
|
| - } else {
|
| - UNIMPLEMENTED();
|
| - }
|
| - set_low_register(r1, r1_val & i);
|
| - break;
|
| - }
|
| - case AH:
|
| - case SH:
|
| - case MH: {
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int b2 = rxinst->B2Value();
|
| - int x2 = rxinst->X2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(rxinst->R1Value());
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - intptr_t addr = b2_val + x2_val + d2_val;
|
| - int32_t mem_val = static_cast<int32_t>(ReadH(addr, instr));
|
| - int32_t alu_out = 0;
|
| - bool isOF = false;
|
| - if (AH == op) {
|
| - isOF = CheckOverflowForIntAdd(r1_val, mem_val, int32_t);
|
| - alu_out = r1_val + mem_val;
|
| - } else if (SH == op) {
|
| - isOF = CheckOverflowForIntSub(r1_val, mem_val, int32_t);
|
| - alu_out = r1_val - mem_val;
|
| - } else if (MH == op) {
|
| - alu_out = r1_val * mem_val;
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - if (MH != op) { // MH does not change condition code
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - }
|
| - break;
|
| - }
|
| - case DSGR: {
|
| - RREInstruction* rreInst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| -
|
| - DCHECK(r1 % 2 == 0);
|
| -
|
| - int64_t dividend = get_register(r1 + 1);
|
| - int64_t divisor = get_register(r2);
|
| - set_register(r1, dividend % divisor);
|
| - set_register(r1 + 1, dividend / divisor);
|
| -
|
| - break;
|
| - }
|
| - case FLOGR: {
|
| - RREInstruction* rreInst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| -
|
| - DCHECK(r1 % 2 == 0);
|
| -
|
| - int64_t r2_val = get_register(r2);
|
| -
|
| - int i = 0;
|
| - for (; i < 64; i++) {
|
| - if (r2_val < 0) break;
|
| - r2_val <<= 1;
|
| - }
|
| -
|
| - r2_val = get_register(r2);
|
| -
|
| - int64_t mask = ~(1 << (63 - i));
|
| - set_register(r1, i);
|
| - set_register(r1 + 1, r2_val & mask);
|
| -
|
| - break;
|
| - }
|
| - case MSR:
|
| - case MSGR: { // they do not set overflow code
|
| - RREInstruction* rreInst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - if (op == MSR) {
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - set_low_register(r1, r1_val * r2_val);
|
| - } else if (op == MSGR) {
|
| - int64_t r1_val = get_register(r1);
|
| - int64_t r2_val = get_register(r2);
|
| - set_register(r1, r1_val * r2_val);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - }
|
| - case MS: {
|
| - RXInstruction* rxinst = reinterpret_cast<RXInstruction*>(instr);
|
| - int r1 = rxinst->R1Value();
|
| - int b2 = rxinst->B2Value();
|
| - int x2 = rxinst->X2Value();
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - intptr_t d2_val = rxinst->D2Value();
|
| - int32_t mem_val = ReadW(b2_val + x2_val + d2_val, instr);
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - set_low_register(r1, r1_val * mem_val);
|
| - break;
|
| - }
|
| - case LGBR:
|
| - case LBR: {
|
| - RREInstruction* rrinst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - if (op == LGBR) {
|
| - int64_t r2_val = get_low_register<int64_t>(r2);
|
| - r2_val <<= 56;
|
| - r2_val >>= 56;
|
| - set_register(r1, r2_val);
|
| - } else if (op == LBR) {
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - r2_val <<= 24;
|
| - r2_val >>= 24;
|
| - set_low_register(r1, r2_val);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - }
|
| - case LGHR:
|
| - case LHR: {
|
| - RREInstruction* rrinst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - if (op == LGHR) {
|
| - int64_t r2_val = get_low_register<int64_t>(r2);
|
| - r2_val <<= 48;
|
| - r2_val >>= 48;
|
| - set_register(r1, r2_val);
|
| - } else if (op == LHR) {
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - r2_val <<= 16;
|
| - r2_val >>= 16;
|
| - set_low_register(r1, r2_val);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - }
|
| - case ALCR: {
|
| - RREInstruction* rrinst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - uint32_t r1_val = get_low_register<uint32_t>(r1);
|
| - uint32_t r2_val = get_low_register<uint32_t>(r2);
|
| - uint32_t alu_out = 0;
|
| - bool isOF = false;
|
| -
|
| - alu_out = r1_val + r2_val;
|
| - bool isOF_original = CheckOverflowForUIntAdd(r1_val, r2_val);
|
| - if (TestConditionCode((Condition)2) || TestConditionCode((Condition)3)) {
|
| - alu_out = alu_out + 1;
|
| - isOF = isOF_original || CheckOverflowForUIntAdd(alu_out, 1);
|
| - } else {
|
| - isOF = isOF_original;
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - SetS390ConditionCodeCarry<uint32_t>(alu_out, isOF);
|
| - break;
|
| - }
|
| - case SLBR: {
|
| - RREInstruction* rrinst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rrinst->R1Value();
|
| - int r2 = rrinst->R2Value();
|
| - uint32_t r1_val = get_low_register<uint32_t>(r1);
|
| - uint32_t r2_val = get_low_register<uint32_t>(r2);
|
| - uint32_t alu_out = 0;
|
| - bool isOF = false;
|
| -
|
| - alu_out = r1_val - r2_val;
|
| - bool isOF_original = CheckOverflowForUIntSub(r1_val, r2_val);
|
| - if (TestConditionCode((Condition)2) || TestConditionCode((Condition)3)) {
|
| - alu_out = alu_out - 1;
|
| - isOF = isOF_original || CheckOverflowForUIntSub(alu_out, 1);
|
| - } else {
|
| - isOF = isOF_original;
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - SetS390ConditionCodeCarry<uint32_t>(alu_out, isOF);
|
| - break;
|
| - }
|
| - default: { return DecodeFourByteFloatingPoint(instr); }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void Simulator::DecodeFourByteFloatingPointIntConversion(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| - switch (op) {
|
| - case CDLFBR:
|
| - case CDLGBR:
|
| - case CELGBR:
|
| - case CLFDBR:
|
| - case CLGDBR:
|
| - case CELFBR:
|
| - case CLGEBR:
|
| - case CLFEBR: {
|
| - RREInstruction* rreInstr = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreInstr->R1Value();
|
| - int r2 = rreInstr->R2Value();
|
| - if (op == CDLFBR) {
|
| - uint32_t r2_val = get_low_register<uint32_t>(r2);
|
| - double r1_val = static_cast<double>(r2_val);
|
| - set_d_register_from_double(r1, r1_val);
|
| - } else if (op == CELFBR) {
|
| - uint32_t r2_val = get_low_register<uint32_t>(r2);
|
| - float r1_val = static_cast<float>(r2_val);
|
| - set_d_register_from_float32(r1, r1_val);
|
| - } else if (op == CDLGBR) {
|
| - uint64_t r2_val = get_register(r2);
|
| - double r1_val = static_cast<double>(r2_val);
|
| - set_d_register_from_double(r1, r1_val);
|
| - } else if (op == CELGBR) {
|
| - uint64_t r2_val = get_register(r2);
|
| - float r1_val = static_cast<float>(r2_val);
|
| - set_d_register_from_float32(r1, r1_val);
|
| - } else if (op == CLFDBR) {
|
| - double r2_val = get_double_from_d_register(r2);
|
| - uint32_t r1_val = static_cast<uint32_t>(r2_val);
|
| - set_low_register(r1, r1_val);
|
| - SetS390ConvertConditionCode<double>(r2_val, r1_val, UINT32_MAX);
|
| - } else if (op == CLFEBR) {
|
| - float r2_val = get_float32_from_d_register(r2);
|
| - uint32_t r1_val = static_cast<uint32_t>(r2_val);
|
| - set_low_register(r1, r1_val);
|
| - SetS390ConvertConditionCode<double>(r2_val, r1_val, UINT32_MAX);
|
| - } else if (op == CLGDBR) {
|
| - double r2_val = get_double_from_d_register(r2);
|
| - uint64_t r1_val = static_cast<uint64_t>(r2_val);
|
| - set_register(r1, r1_val);
|
| - SetS390ConvertConditionCode<double>(r2_val, r1_val, UINT64_MAX);
|
| - } else if (op == CLGEBR) {
|
| - float r2_val = get_float32_from_d_register(r2);
|
| - uint64_t r1_val = static_cast<uint64_t>(r2_val);
|
| - set_register(r1, r1_val);
|
| - SetS390ConvertConditionCode<double>(r2_val, r1_val, UINT64_MAX);
|
| - }
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -void Simulator::DecodeFourByteFloatingPointRound(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| - RREInstruction* rreInstr = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreInstr->R1Value();
|
| - int r2 = rreInstr->R2Value();
|
| - double r2_val = get_double_from_d_register(r2);
|
| - float r2_fval = get_float32_from_d_register(r2);
|
| -
|
| - switch (op) {
|
| - case CFDBR: {
|
| - int mask_val = rreInstr->M3Value();
|
| - int32_t r1_val = 0;
|
| -
|
| - SetS390RoundConditionCode(r2_val, INT32_MAX, INT32_MIN);
|
| -
|
| - switch (mask_val) {
|
| - case CURRENT_ROUNDING_MODE:
|
| - case ROUND_TO_PREPARE_FOR_SHORTER_PRECISION: {
|
| - r1_val = static_cast<int32_t>(r2_val);
|
| - break;
|
| - }
|
| - case ROUND_TO_NEAREST_WITH_TIES_AWAY_FROM_0: {
|
| - double ceil_val = std::ceil(r2_val);
|
| - double floor_val = std::floor(r2_val);
|
| - double sub_val1 = std::fabs(r2_val - floor_val);
|
| - double sub_val2 = std::fabs(r2_val - ceil_val);
|
| - if (sub_val1 > sub_val2) {
|
| - r1_val = static_cast<int32_t>(ceil_val);
|
| - } else if (sub_val1 < sub_val2) {
|
| - r1_val = static_cast<int32_t>(floor_val);
|
| - } else { // round away from zero:
|
| - if (r2_val > 0.0) {
|
| - r1_val = static_cast<int32_t>(ceil_val);
|
| - } else {
|
| - r1_val = static_cast<int32_t>(floor_val);
|
| - }
|
| - }
|
| - break;
|
| - }
|
| - case ROUND_TO_NEAREST_WITH_TIES_TO_EVEN: {
|
| - double ceil_val = std::ceil(r2_val);
|
| - double floor_val = std::floor(r2_val);
|
| - double sub_val1 = std::fabs(r2_val - floor_val);
|
| - double sub_val2 = std::fabs(r2_val - ceil_val);
|
| - if (sub_val1 > sub_val2) {
|
| - r1_val = static_cast<int32_t>(ceil_val);
|
| - } else if (sub_val1 < sub_val2) {
|
| - r1_val = static_cast<int32_t>(floor_val);
|
| - } else { // check which one is even:
|
| - int32_t c_v = static_cast<int32_t>(ceil_val);
|
| - int32_t f_v = static_cast<int32_t>(floor_val);
|
| - if (f_v % 2 == 0)
|
| - r1_val = f_v;
|
| - else
|
| - r1_val = c_v;
|
| - }
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_0: {
|
| - // check for overflow, cast r2_val to 64bit integer
|
| - // then check value within the range of INT_MIN and INT_MAX
|
| - // and set condition code accordingly
|
| - int64_t temp = static_cast<int64_t>(r2_val);
|
| - if (temp < INT_MIN || temp > INT_MAX) {
|
| - condition_reg_ = CC_OF;
|
| - }
|
| - r1_val = static_cast<int32_t>(r2_val);
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_PLUS_INFINITE: {
|
| - r1_val = static_cast<int32_t>(std::ceil(r2_val));
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_MINUS_INFINITE: {
|
| - // check for overflow, cast r2_val to 64bit integer
|
| - // then check value within the range of INT_MIN and INT_MAX
|
| - // and set condition code accordingly
|
| - int64_t temp = static_cast<int64_t>(std::floor(r2_val));
|
| - if (temp < INT_MIN || temp > INT_MAX) {
|
| - condition_reg_ = CC_OF;
|
| - }
|
| - r1_val = static_cast<int32_t>(std::floor(r2_val));
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - set_low_register(r1, r1_val);
|
| - break;
|
| - }
|
| - case CGDBR: {
|
| - int mask_val = rreInstr->M3Value();
|
| - int64_t r1_val = 0;
|
| -
|
| - SetS390RoundConditionCode(r2_val, INT64_MAX, INT64_MIN);
|
| -
|
| - switch (mask_val) {
|
| - case CURRENT_ROUNDING_MODE:
|
| - case ROUND_TO_NEAREST_WITH_TIES_AWAY_FROM_0:
|
| - case ROUND_TO_PREPARE_FOR_SHORTER_PRECISION: {
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| - case ROUND_TO_NEAREST_WITH_TIES_TO_EVEN: {
|
| - double ceil_val = std::ceil(r2_val);
|
| - double floor_val = std::floor(r2_val);
|
| - if (std::abs(r2_val - floor_val) > std::abs(r2_val - ceil_val)) {
|
| - r1_val = static_cast<int64_t>(ceil_val);
|
| - } else if (std::abs(r2_val - floor_val) <
|
| - std::abs(r2_val - ceil_val)) {
|
| - r1_val = static_cast<int64_t>(floor_val);
|
| - } else { // check which one is even:
|
| - int64_t c_v = static_cast<int64_t>(ceil_val);
|
| - int64_t f_v = static_cast<int64_t>(floor_val);
|
| - if (f_v % 2 == 0)
|
| - r1_val = f_v;
|
| - else
|
| - r1_val = c_v;
|
| - }
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_0: {
|
| - r1_val = static_cast<int64_t>(r2_val);
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_PLUS_INFINITE: {
|
| - r1_val = static_cast<int64_t>(std::ceil(r2_val));
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_MINUS_INFINITE: {
|
| - r1_val = static_cast<int64_t>(std::floor(r2_val));
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - set_register(r1, r1_val);
|
| - break;
|
| - }
|
| - case CGEBR: {
|
| - int mask_val = rreInstr->M3Value();
|
| - int64_t r1_val = 0;
|
| -
|
| - SetS390RoundConditionCode(r2_fval, INT64_MAX, INT64_MIN);
|
| -
|
| - switch (mask_val) {
|
| - case CURRENT_ROUNDING_MODE:
|
| - case ROUND_TO_NEAREST_WITH_TIES_AWAY_FROM_0:
|
| - case ROUND_TO_PREPARE_FOR_SHORTER_PRECISION: {
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| - case ROUND_TO_NEAREST_WITH_TIES_TO_EVEN: {
|
| - float ceil_val = std::ceil(r2_fval);
|
| - float floor_val = std::floor(r2_fval);
|
| - if (std::abs(r2_fval - floor_val) > std::abs(r2_fval - ceil_val)) {
|
| - r1_val = static_cast<int64_t>(ceil_val);
|
| - } else if (std::abs(r2_fval - floor_val) <
|
| - std::abs(r2_fval - ceil_val)) {
|
| - r1_val = static_cast<int64_t>(floor_val);
|
| - } else { // check which one is even:
|
| - int64_t c_v = static_cast<int64_t>(ceil_val);
|
| - int64_t f_v = static_cast<int64_t>(floor_val);
|
| - if (f_v % 2 == 0)
|
| - r1_val = f_v;
|
| - else
|
| - r1_val = c_v;
|
| - }
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_0: {
|
| - r1_val = static_cast<int64_t>(r2_fval);
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_PLUS_INFINITE: {
|
| - r1_val = static_cast<int64_t>(std::ceil(r2_fval));
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_MINUS_INFINITE: {
|
| - r1_val = static_cast<int64_t>(std::floor(r2_fval));
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - set_register(r1, r1_val);
|
| - break;
|
| - }
|
| - case CFEBR: {
|
| - int mask_val = rreInstr->M3Value();
|
| - int32_t r1_val = 0;
|
| -
|
| - SetS390RoundConditionCode(r2_fval, INT32_MAX, INT32_MIN);
|
| -
|
| - switch (mask_val) {
|
| - case CURRENT_ROUNDING_MODE:
|
| - case ROUND_TO_PREPARE_FOR_SHORTER_PRECISION: {
|
| - r1_val = static_cast<int32_t>(r2_fval);
|
| - break;
|
| - }
|
| - case ROUND_TO_NEAREST_WITH_TIES_AWAY_FROM_0: {
|
| - float ceil_val = std::ceil(r2_fval);
|
| - float floor_val = std::floor(r2_fval);
|
| - float sub_val1 = std::fabs(r2_fval - floor_val);
|
| - float sub_val2 = std::fabs(r2_fval - ceil_val);
|
| - if (sub_val1 > sub_val2) {
|
| - r1_val = static_cast<int32_t>(ceil_val);
|
| - } else if (sub_val1 < sub_val2) {
|
| - r1_val = static_cast<int32_t>(floor_val);
|
| - } else { // round away from zero:
|
| - if (r2_fval > 0.0) {
|
| - r1_val = static_cast<int32_t>(ceil_val);
|
| - } else {
|
| - r1_val = static_cast<int32_t>(floor_val);
|
| - }
|
| - }
|
| - break;
|
| - }
|
| - case ROUND_TO_NEAREST_WITH_TIES_TO_EVEN: {
|
| - float ceil_val = std::ceil(r2_fval);
|
| - float floor_val = std::floor(r2_fval);
|
| - float sub_val1 = std::fabs(r2_fval - floor_val);
|
| - float sub_val2 = std::fabs(r2_fval - ceil_val);
|
| - if (sub_val1 > sub_val2) {
|
| - r1_val = static_cast<int32_t>(ceil_val);
|
| - } else if (sub_val1 < sub_val2) {
|
| - r1_val = static_cast<int32_t>(floor_val);
|
| - } else { // check which one is even:
|
| - int32_t c_v = static_cast<int32_t>(ceil_val);
|
| - int32_t f_v = static_cast<int32_t>(floor_val);
|
| - if (f_v % 2 == 0)
|
| - r1_val = f_v;
|
| - else
|
| - r1_val = c_v;
|
| - }
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_0: {
|
| - // check for overflow, cast r2_fval to 64bit integer
|
| - // then check value within the range of INT_MIN and INT_MAX
|
| - // and set condition code accordingly
|
| - int64_t temp = static_cast<int64_t>(r2_fval);
|
| - if (temp < INT_MIN || temp > INT_MAX) {
|
| - condition_reg_ = CC_OF;
|
| - }
|
| - r1_val = static_cast<int32_t>(r2_fval);
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_PLUS_INFINITE: {
|
| - r1_val = static_cast<int32_t>(std::ceil(r2_fval));
|
| - break;
|
| - }
|
| - case ROUND_TOWARD_MINUS_INFINITE: {
|
| - // check for overflow, cast r2_fval to 64bit integer
|
| - // then check value within the range of INT_MIN and INT_MAX
|
| - // and set condition code accordingly
|
| - int64_t temp = static_cast<int64_t>(std::floor(r2_fval));
|
| - if (temp < INT_MIN || temp > INT_MAX) {
|
| - condition_reg_ = CC_OF;
|
| - }
|
| - r1_val = static_cast<int32_t>(std::floor(r2_fval));
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| - set_low_register(r1, r1_val);
|
| -
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Decodes and simulates four byte floating point instructions
|
| - */
|
| -bool Simulator::DecodeFourByteFloatingPoint(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| -
|
| - switch (op) {
|
| - case ADBR:
|
| - case AEBR:
|
| - case SDBR:
|
| - case SEBR:
|
| - case MDBR:
|
| - case MEEBR:
|
| - case MADBR:
|
| - case DDBR:
|
| - case DEBR:
|
| - case CDBR:
|
| - case CEBR:
|
| - case CDFBR:
|
| - case CDGBR:
|
| - case CEGBR:
|
| - case CGEBR:
|
| - case CFDBR:
|
| - case CGDBR:
|
| - case SQDBR:
|
| - case SQEBR:
|
| - case CFEBR:
|
| - case CEFBR:
|
| - case LCDBR:
|
| - case LCEBR:
|
| - case LPDBR:
|
| - case LPEBR: {
|
| - RREInstruction* rreInstr = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreInstr->R1Value();
|
| - int r2 = rreInstr->R2Value();
|
| - double r1_val = get_double_from_d_register(r1);
|
| - double r2_val = get_double_from_d_register(r2);
|
| - float fr1_val = get_float32_from_d_register(r1);
|
| - float fr2_val = get_float32_from_d_register(r2);
|
| - if (op == ADBR) {
|
| - r1_val += r2_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - SetS390ConditionCode<double>(r1_val, 0);
|
| - } else if (op == AEBR) {
|
| - fr1_val += fr2_val;
|
| - set_d_register_from_float32(r1, fr1_val);
|
| - SetS390ConditionCode<float>(fr1_val, 0);
|
| - } else if (op == SDBR) {
|
| - r1_val -= r2_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - SetS390ConditionCode<double>(r1_val, 0);
|
| - } else if (op == SEBR) {
|
| - fr1_val -= fr2_val;
|
| - set_d_register_from_float32(r1, fr1_val);
|
| - SetS390ConditionCode<float>(fr1_val, 0);
|
| - } else if (op == MDBR) {
|
| - r1_val *= r2_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - SetS390ConditionCode<double>(r1_val, 0);
|
| - } else if (op == MEEBR) {
|
| - fr1_val *= fr2_val;
|
| - set_d_register_from_float32(r1, fr1_val);
|
| - SetS390ConditionCode<float>(fr1_val, 0);
|
| - } else if (op == MADBR) {
|
| - RRDInstruction* rrdInstr = reinterpret_cast<RRDInstruction*>(instr);
|
| - int r1 = rrdInstr->R1Value();
|
| - int r2 = rrdInstr->R2Value();
|
| - int r3 = rrdInstr->R3Value();
|
| - double r1_val = get_double_from_d_register(r1);
|
| - double r2_val = get_double_from_d_register(r2);
|
| - double r3_val = get_double_from_d_register(r3);
|
| - r1_val += r2_val * r3_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - SetS390ConditionCode<double>(r1_val, 0);
|
| - } else if (op == DDBR) {
|
| - r1_val /= r2_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - SetS390ConditionCode<double>(r1_val, 0);
|
| - } else if (op == DEBR) {
|
| - fr1_val /= fr2_val;
|
| - set_d_register_from_float32(r1, fr1_val);
|
| - SetS390ConditionCode<float>(fr1_val, 0);
|
| - } else if (op == CDBR) {
|
| - if (isNaN(r1_val) || isNaN(r2_val)) {
|
| - condition_reg_ = CC_OF;
|
| - } else {
|
| - SetS390ConditionCode<double>(r1_val, r2_val);
|
| - }
|
| - } else if (op == CEBR) {
|
| - if (isNaN(fr1_val) || isNaN(fr2_val)) {
|
| - condition_reg_ = CC_OF;
|
| - } else {
|
| - SetS390ConditionCode<float>(fr1_val, fr2_val);
|
| - }
|
| - } else if (op == CDGBR) {
|
| - int64_t r2_val = get_register(r2);
|
| - double r1_val = static_cast<double>(r2_val);
|
| - set_d_register_from_double(r1, r1_val);
|
| - } else if (op == CEGBR) {
|
| - int64_t fr2_val = get_register(r2);
|
| - float fr1_val = static_cast<float>(fr2_val);
|
| - set_d_register_from_float32(r1, fr1_val);
|
| - } else if (op == CDFBR) {
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - double r1_val = static_cast<double>(r2_val);
|
| - set_d_register_from_double(r1, r1_val);
|
| - } else if (op == CEFBR) {
|
| - int32_t fr2_val = get_low_register<int32_t>(r2);
|
| - float fr1_val = static_cast<float>(fr2_val);
|
| - set_d_register_from_float32(r1, fr1_val);
|
| - } else if (op == CFDBR) {
|
| - DecodeFourByteFloatingPointRound(instr);
|
| - } else if (op == CGDBR) {
|
| - DecodeFourByteFloatingPointRound(instr);
|
| - } else if (op == CGEBR) {
|
| - DecodeFourByteFloatingPointRound(instr);
|
| - } else if (op == SQDBR) {
|
| - r1_val = std::sqrt(r2_val);
|
| - set_d_register_from_double(r1, r1_val);
|
| - } else if (op == SQEBR) {
|
| - fr1_val = std::sqrt(fr2_val);
|
| - set_d_register_from_float32(r1, fr1_val);
|
| - } else if (op == CFEBR) {
|
| - DecodeFourByteFloatingPointRound(instr);
|
| - } else if (op == LCDBR) {
|
| - r1_val = -r2_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - if (r2_val != r2_val) { // input is NaN
|
| - condition_reg_ = CC_OF;
|
| - } else if (r2_val == 0) {
|
| - condition_reg_ = CC_EQ;
|
| - } else if (r2_val < 0) {
|
| - condition_reg_ = CC_LT;
|
| - } else if (r2_val > 0) {
|
| - condition_reg_ = CC_GT;
|
| - }
|
| - } else if (op == LCEBR) {
|
| - fr1_val = -fr2_val;
|
| - set_d_register_from_float32(r1, fr1_val);
|
| - if (fr2_val != fr2_val) { // input is NaN
|
| - condition_reg_ = CC_OF;
|
| - } else if (fr2_val == 0) {
|
| - condition_reg_ = CC_EQ;
|
| - } else if (fr2_val < 0) {
|
| - condition_reg_ = CC_LT;
|
| - } else if (fr2_val > 0) {
|
| - condition_reg_ = CC_GT;
|
| - }
|
| - } else if (op == LPDBR) {
|
| - r1_val = std::fabs(r2_val);
|
| - set_d_register_from_double(r1, r1_val);
|
| - if (r2_val != r2_val) { // input is NaN
|
| - condition_reg_ = CC_OF;
|
| - } else if (r2_val == 0) {
|
| - condition_reg_ = CC_EQ;
|
| - } else {
|
| - condition_reg_ = CC_GT;
|
| - }
|
| - } else if (op == LPEBR) {
|
| - fr1_val = std::fabs(fr2_val);
|
| - set_d_register_from_float32(r1, fr1_val);
|
| - if (fr2_val != fr2_val) { // input is NaN
|
| - condition_reg_ = CC_OF;
|
| - } else if (fr2_val == 0) {
|
| - condition_reg_ = CC_EQ;
|
| - } else {
|
| - condition_reg_ = CC_GT;
|
| - }
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - }
|
| - case CDLFBR:
|
| - case CDLGBR:
|
| - case CELGBR:
|
| - case CLFDBR:
|
| - case CELFBR:
|
| - case CLGDBR:
|
| - case CLGEBR:
|
| - case CLFEBR: {
|
| - DecodeFourByteFloatingPointIntConversion(instr);
|
| - break;
|
| - }
|
| - case TMLL: {
|
| - RIInstruction* riinst = reinterpret_cast<RIInstruction*>(instr);
|
| - int r1 = riinst->R1Value();
|
| - int mask = riinst->I2Value() & 0x0000FFFF;
|
| - if (mask == 0) {
|
| - condition_reg_ = 0x0;
|
| - break;
|
| - }
|
| - uint32_t r1_val = get_low_register<uint32_t>(r1);
|
| - r1_val = r1_val & 0x0000FFFF; // uses only the last 16bits
|
| -
|
| - // Test if all selected bits are Zero
|
| - bool allSelectedBitsAreZeros = true;
|
| - for (int i = 0; i < 15; i++) {
|
| - if (mask & (1 << i)) {
|
| - if (r1_val & (1 << i)) {
|
| - allSelectedBitsAreZeros = false;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - if (allSelectedBitsAreZeros) {
|
| - condition_reg_ = 0x8;
|
| - break; // Done!
|
| - }
|
| -
|
| - // Test if all selected bits are one
|
| - bool allSelectedBitsAreOnes = true;
|
| - for (int i = 0; i < 15; i++) {
|
| - if (mask & (1 << i)) {
|
| - if (!(r1_val & (1 << i))) {
|
| - allSelectedBitsAreOnes = false;
|
| - break;
|
| - }
|
| - }
|
| - }
|
| - if (allSelectedBitsAreOnes) {
|
| - condition_reg_ = 0x1;
|
| - break; // Done!
|
| - }
|
| -
|
| - // Now we know selected bits mixed zeros and ones
|
| - // Test if the leftmost bit is zero or one
|
| - for (int i = 14; i >= 0; i--) {
|
| - if (mask & (1 << i)) {
|
| - if (r1_val & (1 << i)) {
|
| - // leftmost bit is one
|
| - condition_reg_ = 0x2;
|
| - } else {
|
| - // leftmost bit is zero
|
| - condition_reg_ = 0x4;
|
| - }
|
| - break; // Done!
|
| - }
|
| - }
|
| - break;
|
| - }
|
| - case LEDBR: {
|
| - RREInstruction* rreInst = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreInst->R1Value();
|
| - int r2 = rreInst->R2Value();
|
| - double r2_val = get_double_from_d_register(r2);
|
| - set_d_register_from_float32(r1, static_cast<float>(r2_val));
|
| - break;
|
| - }
|
| - case FIDBRA: {
|
| - RRFInstruction* rrfInst = reinterpret_cast<RRFInstruction*>(instr);
|
| - int r1 = rrfInst->R1Value();
|
| - int r2 = rrfInst->R2Value();
|
| - int m3 = rrfInst->M3Value();
|
| - double r2_val = get_double_from_d_register(r2);
|
| - DCHECK(rrfInst->M4Value() == 0);
|
| - switch (m3) {
|
| - case Assembler::FIDBRA_ROUND_TO_NEAREST_AWAY_FROM_0:
|
| - set_d_register_from_double(r1, round(r2_val));
|
| - break;
|
| - case Assembler::FIDBRA_ROUND_TOWARD_0:
|
| - set_d_register_from_double(r1, trunc(r2_val));
|
| - break;
|
| - case Assembler::FIDBRA_ROUND_TOWARD_POS_INF:
|
| - set_d_register_from_double(r1, std::ceil(r2_val));
|
| - break;
|
| - case Assembler::FIDBRA_ROUND_TOWARD_NEG_INF:
|
| - set_d_register_from_double(r1, std::floor(r2_val));
|
| - break;
|
| - default:
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| - break;
|
| - }
|
| - case FIEBRA: {
|
| - RRFInstruction* rrfInst = reinterpret_cast<RRFInstruction*>(instr);
|
| - int r1 = rrfInst->R1Value();
|
| - int r2 = rrfInst->R2Value();
|
| - int m3 = rrfInst->M3Value();
|
| - float r2_val = get_float32_from_d_register(r2);
|
| - DCHECK(rrfInst->M4Value() == 0);
|
| - switch (m3) {
|
| - case Assembler::FIDBRA_ROUND_TO_NEAREST_AWAY_FROM_0:
|
| - set_d_register_from_float32(r1, round(r2_val));
|
| - break;
|
| - case Assembler::FIDBRA_ROUND_TOWARD_0:
|
| - set_d_register_from_float32(r1, trunc(r2_val));
|
| - break;
|
| - case Assembler::FIDBRA_ROUND_TOWARD_POS_INF:
|
| - set_d_register_from_float32(r1, std::ceil(r2_val));
|
| - break;
|
| - case Assembler::FIDBRA_ROUND_TOWARD_NEG_INF:
|
| - set_d_register_from_float32(r1, std::floor(r2_val));
|
| - break;
|
| - default:
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| - break;
|
| - }
|
| - case MSDBR: {
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| - case LDEBR: {
|
| - RREInstruction* rreInstr = reinterpret_cast<RREInstruction*>(instr);
|
| - int r1 = rreInstr->R1Value();
|
| - int r2 = rreInstr->R2Value();
|
| - float fp_val = get_float32_from_d_register(r2);
|
| - double db_val = static_cast<double>(fp_val);
|
| - set_d_register_from_double(r1, db_val);
|
| - break;
|
| - }
|
| - default: {
|
| - UNREACHABLE();
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// Decode routine for six-byte instructions
|
| -bool Simulator::DecodeSixByte(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| -
|
| - // Pre-cast instruction to various types
|
| - RIEInstruction* rieInstr = reinterpret_cast<RIEInstruction*>(instr);
|
| - RILInstruction* rilInstr = reinterpret_cast<RILInstruction*>(instr);
|
| - RSYInstruction* rsyInstr = reinterpret_cast<RSYInstruction*>(instr);
|
| - RXEInstruction* rxeInstr = reinterpret_cast<RXEInstruction*>(instr);
|
| - RXYInstruction* rxyInstr = reinterpret_cast<RXYInstruction*>(instr);
|
| - SIYInstruction* siyInstr = reinterpret_cast<SIYInstruction*>(instr);
|
| - SILInstruction* silInstr = reinterpret_cast<SILInstruction*>(instr);
|
| - SSInstruction* ssInstr = reinterpret_cast<SSInstruction*>(instr);
|
| -
|
| - switch (op) {
|
| - case CLIY: {
|
| - // Compare Immediate (Mem - Imm) (8)
|
| - int b1 = siyInstr->B1Value();
|
| - int64_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
| - intptr_t d1_val = siyInstr->D1Value();
|
| - intptr_t addr = b1_val + d1_val;
|
| - uint8_t mem_val = ReadB(addr);
|
| - uint8_t imm_val = siyInstr->I2Value();
|
| - SetS390ConditionCode<uint8_t>(mem_val, imm_val);
|
| - break;
|
| - }
|
| - case TMY: {
|
| - // Test Under Mask (Mem - Imm) (8)
|
| - int b1 = siyInstr->B1Value();
|
| - int64_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
| - intptr_t d1_val = siyInstr->D1Value();
|
| - intptr_t addr = b1_val + d1_val;
|
| - uint8_t mem_val = ReadB(addr);
|
| - uint8_t imm_val = siyInstr->I2Value();
|
| - uint8_t selected_bits = mem_val & imm_val;
|
| - // CC0: Selected bits are zero
|
| - // CC1: Selected bits mixed zeros and ones
|
| - // CC3: Selected bits all ones
|
| - if (0 == selected_bits) {
|
| - condition_reg_ = CC_EQ; // CC0
|
| - } else if (selected_bits == imm_val) {
|
| - condition_reg_ = 0x1; // CC3
|
| - } else {
|
| - condition_reg_ = 0x4; // CC1
|
| - }
|
| - break;
|
| - }
|
| - case LDEB: {
|
| - // Load Float
|
| - int r1 = rxeInstr->R1Value();
|
| - int rb = rxeInstr->B2Value();
|
| - int rx = rxeInstr->X2Value();
|
| - int offset = rxeInstr->D2Value();
|
| - int64_t rb_val = (rb == 0) ? 0 : get_register(rb);
|
| - int64_t rx_val = (rx == 0) ? 0 : get_register(rx);
|
| - double ret = static_cast<double>(
|
| - *reinterpret_cast<float*>(rx_val + rb_val + offset));
|
| - set_d_register_from_double(r1, ret);
|
| - break;
|
| - }
|
| - case LAY: {
|
| - // Load Address
|
| - int r1 = rxyInstr->R1Value();
|
| - int rb = rxyInstr->B2Value();
|
| - int rx = rxyInstr->X2Value();
|
| - int offset = rxyInstr->D2Value();
|
| - int64_t rb_val = (rb == 0) ? 0 : get_register(rb);
|
| - int64_t rx_val = (rx == 0) ? 0 : get_register(rx);
|
| - set_register(r1, rx_val + rb_val + offset);
|
| - break;
|
| - }
|
| - case LARL: {
|
| - // Load Addresss Relative Long
|
| - int r1 = rilInstr->R1Value();
|
| - intptr_t offset = rilInstr->I2Value() * 2;
|
| - set_register(r1, get_pc() + offset);
|
| - break;
|
| - }
|
| - case LLILF: {
|
| - // Load Logical into lower 32-bits (zero extend upper 32-bits)
|
| - int r1 = rilInstr->R1Value();
|
| - uint64_t imm = static_cast<uint64_t>(rilInstr->I2UnsignedValue());
|
| - set_register(r1, imm);
|
| - break;
|
| - }
|
| - case LLIHF: {
|
| - // Load Logical Immediate into high word
|
| - int r1 = rilInstr->R1Value();
|
| - uint64_t imm = static_cast<uint64_t>(rilInstr->I2UnsignedValue());
|
| - set_register(r1, imm << 32);
|
| - break;
|
| - }
|
| - case OILF:
|
| - case NILF:
|
| - case IILF: {
|
| - // Bitwise Op on lower 32-bits
|
| - int r1 = rilInstr->R1Value();
|
| - uint32_t imm = rilInstr->I2UnsignedValue();
|
| - uint32_t alu_out = get_low_register<uint32_t>(r1);
|
| - if (NILF == op) {
|
| - alu_out &= imm;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - } else if (OILF == op) {
|
| - alu_out |= imm;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - } else if (op == IILF) {
|
| - alu_out = imm;
|
| - } else {
|
| - DCHECK(false);
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - break;
|
| - }
|
| - case OIHF:
|
| - case NIHF:
|
| - case IIHF: {
|
| - // Bitwise Op on upper 32-bits
|
| - int r1 = rilInstr->R1Value();
|
| - uint32_t imm = rilInstr->I2Value();
|
| - uint32_t alu_out = get_high_register<uint32_t>(r1);
|
| - if (op == NIHF) {
|
| - alu_out &= imm;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - } else if (op == OIHF) {
|
| - alu_out |= imm;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - } else if (op == IIHF) {
|
| - alu_out = imm;
|
| - } else {
|
| - DCHECK(false);
|
| - }
|
| - set_high_register(r1, alu_out);
|
| - break;
|
| - }
|
| - case CLFI: {
|
| - // Compare Logical with Immediate (32)
|
| - int r1 = rilInstr->R1Value();
|
| - uint32_t imm = rilInstr->I2UnsignedValue();
|
| - SetS390ConditionCode<uint32_t>(get_low_register<uint32_t>(r1), imm);
|
| - break;
|
| - }
|
| - case CFI: {
|
| - // Compare with Immediate (32)
|
| - int r1 = rilInstr->R1Value();
|
| - int32_t imm = rilInstr->I2Value();
|
| - SetS390ConditionCode<int32_t>(get_low_register<int32_t>(r1), imm);
|
| - break;
|
| - }
|
| - case CLGFI: {
|
| - // Compare Logical with Immediate (64)
|
| - int r1 = rilInstr->R1Value();
|
| - uint64_t imm = static_cast<uint64_t>(rilInstr->I2UnsignedValue());
|
| - SetS390ConditionCode<uint64_t>(get_register(r1), imm);
|
| - break;
|
| - }
|
| - case CGFI: {
|
| - // Compare with Immediate (64)
|
| - int r1 = rilInstr->R1Value();
|
| - int64_t imm = static_cast<int64_t>(rilInstr->I2Value());
|
| - SetS390ConditionCode<int64_t>(get_register(r1), imm);
|
| - break;
|
| - }
|
| - case BRASL: {
|
| - // Branch and Save Relative Long
|
| - int r1 = rilInstr->R1Value();
|
| - intptr_t d2 = rilInstr->I2Value();
|
| - intptr_t pc = get_pc();
|
| - set_register(r1, pc + 6); // save next instruction to register
|
| - set_pc(pc + d2 * 2); // update register
|
| - break;
|
| - }
|
| - case BRCL: {
|
| - // Branch on Condition Relative Long
|
| - Condition m1 = (Condition)rilInstr->R1Value();
|
| - if (TestConditionCode((Condition)m1)) {
|
| - intptr_t offset = rilInstr->I2Value() * 2;
|
| - set_pc(get_pc() + offset);
|
| - }
|
| - break;
|
| - }
|
| - case LMG:
|
| - case STMG: {
|
| - // Store Multiple 64-bits.
|
| - int r1 = rsyInstr->R1Value();
|
| - int r3 = rsyInstr->R3Value();
|
| - int rb = rsyInstr->B2Value();
|
| - int offset = rsyInstr->D2Value();
|
| -
|
| - // Regs roll around if r3 is less than r1.
|
| - // Artifically increase r3 by 16 so we can calculate
|
| - // the number of regs stored properly.
|
| - if (r3 < r1) r3 += 16;
|
| -
|
| - int64_t rb_val = (rb == 0) ? 0 : get_register(rb);
|
| -
|
| - // Store each register in ascending order.
|
| - for (int i = 0; i <= r3 - r1; i++) {
|
| - if (op == LMG) {
|
| - int64_t value = ReadDW(rb_val + offset + 8 * i);
|
| - set_register((r1 + i) % 16, value);
|
| - } else if (op == STMG) {
|
| - int64_t value = get_register((r1 + i) % 16);
|
| - WriteDW(rb_val + offset + 8 * i, value);
|
| - } else {
|
| - DCHECK(false);
|
| - }
|
| - }
|
| - break;
|
| - }
|
| - case SLLK:
|
| - case RLL:
|
| - case SRLK:
|
| - case SLLG:
|
| - case RLLG:
|
| - case SRLG: {
|
| - DecodeSixByteBitShift(instr);
|
| - break;
|
| - }
|
| - case SLAK:
|
| - case SRAK: {
|
| - // 32-bit non-clobbering shift-left/right arithmetic
|
| - int r1 = rsyInstr->R1Value();
|
| - int r3 = rsyInstr->R3Value();
|
| - int b2 = rsyInstr->B2Value();
|
| - intptr_t d2 = rsyInstr->D2Value();
|
| - // only takes rightmost 6 bits
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int shiftBits = (b2_val + d2) & 0x3F;
|
| - int32_t r3_val = get_low_register<int32_t>(r3);
|
| - int32_t alu_out = 0;
|
| - bool isOF = false;
|
| - if (op == SLAK) {
|
| - isOF = CheckOverflowForShiftLeft(r3_val, shiftBits);
|
| - alu_out = r3_val << shiftBits;
|
| - } else if (op == SRAK) {
|
| - alu_out = r3_val >> shiftBits;
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - }
|
| - case SLAG:
|
| - case SRAG: {
|
| - // 64-bit non-clobbering shift-left/right arithmetic
|
| - int r1 = rsyInstr->R1Value();
|
| - int r3 = rsyInstr->R3Value();
|
| - int b2 = rsyInstr->B2Value();
|
| - intptr_t d2 = rsyInstr->D2Value();
|
| - // only takes rightmost 6 bits
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int shiftBits = (b2_val + d2) & 0x3F;
|
| - int64_t r3_val = get_register(r3);
|
| - intptr_t alu_out = 0;
|
| - bool isOF = false;
|
| - if (op == SLAG) {
|
| - isOF = CheckOverflowForShiftLeft(r3_val, shiftBits);
|
| - alu_out = r3_val << shiftBits;
|
| - } else if (op == SRAG) {
|
| - alu_out = r3_val >> shiftBits;
|
| - }
|
| - set_register(r1, alu_out);
|
| - SetS390ConditionCode<intptr_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - }
|
| - case LMY:
|
| - case STMY: {
|
| - RSYInstruction* rsyInstr = reinterpret_cast<RSYInstruction*>(instr);
|
| - // Load/Store Multiple (32)
|
| - int r1 = rsyInstr->R1Value();
|
| - int r3 = rsyInstr->R3Value();
|
| - int b2 = rsyInstr->B2Value();
|
| - int offset = rsyInstr->D2Value();
|
| -
|
| - // Regs roll around if r3 is less than r1.
|
| - // Artifically increase r3 by 16 so we can calculate
|
| - // the number of regs stored properly.
|
| - if (r3 < r1) r3 += 16;
|
| -
|
| - int32_t b2_val = (b2 == 0) ? 0 : get_low_register<int32_t>(b2);
|
| -
|
| - // Store each register in ascending order.
|
| - for (int i = 0; i <= r3 - r1; i++) {
|
| - if (op == LMY) {
|
| - int32_t value = ReadW(b2_val + offset + 4 * i, instr);
|
| - set_low_register((r1 + i) % 16, value);
|
| - } else {
|
| - int32_t value = get_low_register<int32_t>((r1 + i) % 16);
|
| - WriteW(b2_val + offset + 4 * i, value, instr);
|
| - }
|
| - }
|
| - break;
|
| - }
|
| - case LT:
|
| - case LTG: {
|
| - // Load and Test (32/64)
|
| - int r1 = rxyInstr->R1Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int b2 = rxyInstr->B2Value();
|
| - int d2 = rxyInstr->D2Value();
|
| -
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - intptr_t addr = x2_val + b2_val + d2;
|
| -
|
| - if (op == LT) {
|
| - int32_t value = ReadW(addr, instr);
|
| - set_low_register(r1, value);
|
| - SetS390ConditionCode<int32_t>(value, 0);
|
| - } else if (op == LTG) {
|
| - int64_t value = ReadDW(addr);
|
| - set_register(r1, value);
|
| - SetS390ConditionCode<int64_t>(value, 0);
|
| - }
|
| - break;
|
| - }
|
| - case LY:
|
| - case LB:
|
| - case LGB:
|
| - case LG:
|
| - case LGF:
|
| - case LGH:
|
| - case LLGF:
|
| - case STG:
|
| - case STY:
|
| - case STCY:
|
| - case STHY:
|
| - case STEY:
|
| - case LDY:
|
| - case LHY:
|
| - case STDY:
|
| - case LEY: {
|
| - // Miscellaneous Loads and Stores
|
| - int r1 = rxyInstr->R1Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int b2 = rxyInstr->B2Value();
|
| - int d2 = rxyInstr->D2Value();
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - intptr_t addr = x2_val + b2_val + d2;
|
| - if (op == LY) {
|
| - uint32_t mem_val = ReadWU(addr, instr);
|
| - set_low_register(r1, mem_val);
|
| - } else if (op == LB) {
|
| - int32_t mem_val = ReadB(addr);
|
| - set_low_register(r1, mem_val);
|
| - } else if (op == LGB) {
|
| - int64_t mem_val = ReadB(addr);
|
| - set_register(r1, mem_val);
|
| - } else if (op == LG) {
|
| - int64_t mem_val = ReadDW(addr);
|
| - set_register(r1, mem_val);
|
| - } else if (op == LGF) {
|
| - int64_t mem_val = static_cast<int64_t>(ReadW(addr, instr));
|
| - set_register(r1, mem_val);
|
| - } else if (op == LGH) {
|
| - int64_t mem_val = static_cast<int64_t>(ReadH(addr, instr));
|
| - set_register(r1, mem_val);
|
| - } else if (op == LLGF) {
|
| - // int r1 = rreInst->R1Value();
|
| - // int r2 = rreInst->R2Value();
|
| - // int32_t r2_val = get_low_register<int32_t>(r2);
|
| - // uint64_t r2_finalval = (static_cast<uint64_t>(r2_val)
|
| - // & 0x00000000ffffffff);
|
| - // set_register(r1, r2_finalval);
|
| - // break;
|
| - uint64_t mem_val = static_cast<uint64_t>(ReadWU(addr, instr));
|
| - set_register(r1, mem_val);
|
| - } else if (op == LDY) {
|
| - uint64_t dbl_val = *reinterpret_cast<uint64_t*>(addr);
|
| - set_d_register(r1, dbl_val);
|
| - } else if (op == STEY) {
|
| - int64_t frs_val = get_d_register(r1) >> 32;
|
| - WriteW(addr, static_cast<int32_t>(frs_val), instr);
|
| - } else if (op == LEY) {
|
| - float float_val = *reinterpret_cast<float*>(addr);
|
| - set_d_register_from_float32(r1, float_val);
|
| - } else if (op == STY) {
|
| - uint32_t value = get_low_register<uint32_t>(r1);
|
| - WriteW(addr, value, instr);
|
| - } else if (op == STG) {
|
| - uint64_t value = get_register(r1);
|
| - WriteDW(addr, value);
|
| - } else if (op == STDY) {
|
| - int64_t frs_val = get_d_register(r1);
|
| - WriteDW(addr, frs_val);
|
| - } else if (op == STCY) {
|
| - uint8_t value = get_low_register<uint32_t>(r1);
|
| - WriteB(addr, value);
|
| - } else if (op == STHY) {
|
| - uint16_t value = get_low_register<uint32_t>(r1);
|
| - WriteH(addr, value, instr);
|
| - } else if (op == LHY) {
|
| - int32_t result = static_cast<int32_t>(ReadH(addr, instr));
|
| - set_low_register(r1, result);
|
| - }
|
| - break;
|
| - }
|
| - case MVC: {
|
| - // Move Character
|
| - int b1 = ssInstr->B1Value();
|
| - intptr_t d1 = ssInstr->D1Value();
|
| - int b2 = ssInstr->B2Value();
|
| - intptr_t d2 = ssInstr->D2Value();
|
| - int length = ssInstr->Length();
|
| - int64_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - intptr_t src_addr = b2_val + d2;
|
| - intptr_t dst_addr = b1_val + d1;
|
| - // remember that the length is the actual length - 1
|
| - for (int i = 0; i < length + 1; ++i) {
|
| - WriteB(dst_addr++, ReadB(src_addr++));
|
| - }
|
| - break;
|
| - }
|
| - case MVHI: {
|
| - // Move Integer (32)
|
| - int b1 = silInstr->B1Value();
|
| - intptr_t d1 = silInstr->D1Value();
|
| - int16_t i2 = silInstr->I2Value();
|
| - int64_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
| - intptr_t src_addr = b1_val + d1;
|
| - WriteW(src_addr, i2, instr);
|
| - break;
|
| - }
|
| - case MVGHI: {
|
| - // Move Integer (64)
|
| - int b1 = silInstr->B1Value();
|
| - intptr_t d1 = silInstr->D1Value();
|
| - int16_t i2 = silInstr->I2Value();
|
| - int64_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
| - intptr_t src_addr = b1_val + d1;
|
| - WriteDW(src_addr, i2);
|
| - break;
|
| - }
|
| - case LLH:
|
| - case LLGH: {
|
| - // Load Logical Halfworld
|
| - int r1 = rxyInstr->R1Value();
|
| - int b2 = rxyInstr->B2Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxyInstr->D2Value();
|
| - uint16_t mem_val = ReadHU(b2_val + d2_val + x2_val, instr);
|
| - if (op == LLH) {
|
| - set_low_register(r1, mem_val);
|
| - } else if (op == LLGH) {
|
| - set_register(r1, mem_val);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - }
|
| - case LLC:
|
| - case LLGC: {
|
| - // Load Logical Character - loads a byte and zero extends.
|
| - int r1 = rxyInstr->R1Value();
|
| - int b2 = rxyInstr->B2Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxyInstr->D2Value();
|
| - uint8_t mem_val = ReadBU(b2_val + d2_val + x2_val);
|
| - if (op == LLC) {
|
| - set_low_register(r1, static_cast<uint32_t>(mem_val));
|
| - } else if (op == LLGC) {
|
| - set_register(r1, static_cast<uint64_t>(mem_val));
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - }
|
| - case XIHF:
|
| - case XILF: {
|
| - int r1 = rilInstr->R1Value();
|
| - uint32_t imm = rilInstr->I2UnsignedValue();
|
| - uint32_t alu_out = 0;
|
| - if (op == XILF) {
|
| - alu_out = get_low_register<uint32_t>(r1);
|
| - alu_out = alu_out ^ imm;
|
| - set_low_register(r1, alu_out);
|
| - } else if (op == XIHF) {
|
| - alu_out = get_high_register<uint32_t>(r1);
|
| - alu_out = alu_out ^ imm;
|
| - set_high_register(r1, alu_out);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - break;
|
| - }
|
| - case RISBG: {
|
| - // Rotate then insert selected bits
|
| - int r1 = rieInstr->R1Value();
|
| - int r2 = rieInstr->R2Value();
|
| - // Starting Bit Position is Bits 2-7 of I3 field
|
| - uint32_t start_bit = rieInstr->I3Value() & 0x3F;
|
| - // Ending Bit Position is Bits 2-7 of I4 field
|
| - uint32_t end_bit = rieInstr->I4Value() & 0x3F;
|
| - // Shift Amount is Bits 2-7 of I5 field
|
| - uint32_t shift_amount = rieInstr->I5Value() & 0x3F;
|
| - // Zero out Remaining (unslected) bits if Bit 0 of I4 is 1.
|
| - bool zero_remaining = (0 != (rieInstr->I4Value() & 0x80));
|
| -
|
| - uint64_t src_val = get_register(r2);
|
| -
|
| - // Rotate Left by Shift Amount first
|
| - uint64_t rotated_val =
|
| - (src_val << shift_amount) | (src_val >> (64 - shift_amount));
|
| - int32_t width = end_bit - start_bit + 1;
|
| -
|
| - uint64_t selection_mask = 0;
|
| - if (width < 64) {
|
| - selection_mask = (static_cast<uint64_t>(1) << width) - 1;
|
| - } else {
|
| - selection_mask = static_cast<uint64_t>(static_cast<int64_t>(-1));
|
| - }
|
| - selection_mask = selection_mask << (63 - end_bit);
|
| -
|
| - uint64_t selected_val = rotated_val & selection_mask;
|
| -
|
| - if (!zero_remaining) {
|
| - // Merged the unselected bits from the original value
|
| - selected_val = (src_val & ~selection_mask) | selected_val;
|
| - }
|
| -
|
| - // Condition code is set by treating result as 64-bit signed int
|
| - SetS390ConditionCode<int64_t>(selected_val, 0);
|
| - set_register(r1, selected_val);
|
| - break;
|
| - }
|
| - default:
|
| - return DecodeSixByteArithmetic(instr);
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -void Simulator::DecodeSixByteBitShift(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| -
|
| - // Pre-cast instruction to various types
|
| -
|
| - RSYInstruction* rsyInstr = reinterpret_cast<RSYInstruction*>(instr);
|
| -
|
| - switch (op) {
|
| - case SLLK:
|
| - case RLL:
|
| - case SRLK: {
|
| - // For SLLK/SRLL, the 32-bit third operand is shifted the number
|
| - // of bits specified by the second-operand address, and the result is
|
| - // placed at the first-operand location. Except for when the R1 and R3
|
| - // fields designate the same register, the third operand remains
|
| - // unchanged in general register R3.
|
| - int r1 = rsyInstr->R1Value();
|
| - int r3 = rsyInstr->R3Value();
|
| - int b2 = rsyInstr->B2Value();
|
| - intptr_t d2 = rsyInstr->D2Value();
|
| - // only takes rightmost 6 bits
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int shiftBits = (b2_val + d2) & 0x3F;
|
| - // unsigned
|
| - uint32_t r3_val = get_low_register<uint32_t>(r3);
|
| - uint32_t alu_out = 0;
|
| - if (SLLK == op) {
|
| - alu_out = r3_val << shiftBits;
|
| - } else if (SRLK == op) {
|
| - alu_out = r3_val >> shiftBits;
|
| - } else if (RLL == op) {
|
| - uint32_t rotateBits = r3_val >> (32 - shiftBits);
|
| - alu_out = (r3_val << shiftBits) | (rotateBits);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - break;
|
| - }
|
| - case SLLG:
|
| - case RLLG:
|
| - case SRLG: {
|
| - // For SLLG/SRLG, the 64-bit third operand is shifted the number
|
| - // of bits specified by the second-operand address, and the result is
|
| - // placed at the first-operand location. Except for when the R1 and R3
|
| - // fields designate the same register, the third operand remains
|
| - // unchanged in general register R3.
|
| - int r1 = rsyInstr->R1Value();
|
| - int r3 = rsyInstr->R3Value();
|
| - int b2 = rsyInstr->B2Value();
|
| - intptr_t d2 = rsyInstr->D2Value();
|
| - // only takes rightmost 6 bits
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int shiftBits = (b2_val + d2) & 0x3F;
|
| - // unsigned
|
| - uint64_t r3_val = get_register(r3);
|
| - uint64_t alu_out = 0;
|
| - if (op == SLLG) {
|
| - alu_out = r3_val << shiftBits;
|
| - } else if (op == SRLG) {
|
| - alu_out = r3_val >> shiftBits;
|
| - } else if (op == RLLG) {
|
| - uint64_t rotateBits = r3_val >> (64 - shiftBits);
|
| - alu_out = (r3_val << shiftBits) | (rotateBits);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - set_register(r1, alu_out);
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Decodes and simulates six byte arithmetic instructions
|
| - */
|
| -bool Simulator::DecodeSixByteArithmetic(Instruction* instr) {
|
| - Opcode op = instr->S390OpcodeValue();
|
| -
|
| - // Pre-cast instruction to various types
|
| - SIYInstruction* siyInstr = reinterpret_cast<SIYInstruction*>(instr);
|
| -
|
| - switch (op) {
|
| - case CDB:
|
| - case ADB:
|
| - case SDB:
|
| - case MDB:
|
| - case DDB:
|
| - case SQDB: {
|
| - RXEInstruction* rxeInstr = reinterpret_cast<RXEInstruction*>(instr);
|
| - int b2 = rxeInstr->B2Value();
|
| - int x2 = rxeInstr->X2Value();
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxeInstr->D2Value();
|
| - double r1_val = get_double_from_d_register(rxeInstr->R1Value());
|
| - double dbl_val = ReadDouble(b2_val + x2_val + d2_val);
|
| -
|
| - switch (op) {
|
| - case CDB:
|
| - SetS390ConditionCode<double>(r1_val, dbl_val);
|
| - break;
|
| - case ADB:
|
| - r1_val += dbl_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - SetS390ConditionCode<double>(r1_val, 0);
|
| - break;
|
| - case SDB:
|
| - r1_val -= dbl_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - SetS390ConditionCode<double>(r1_val, 0);
|
| - break;
|
| - case MDB:
|
| - r1_val *= dbl_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - SetS390ConditionCode<double>(r1_val, 0);
|
| - break;
|
| - case DDB:
|
| - r1_val /= dbl_val;
|
| - set_d_register_from_double(r1, r1_val);
|
| - SetS390ConditionCode<double>(r1_val, 0);
|
| - break;
|
| - case SQDB:
|
| - r1_val = std::sqrt(dbl_val);
|
| - set_d_register_from_double(r1, r1_val);
|
| - default:
|
| - UNREACHABLE();
|
| - break;
|
| - }
|
| - break;
|
| - }
|
| - case LRV:
|
| - case LRVH:
|
| - case STRV:
|
| - case STRVH: {
|
| - RXYInstruction* rxyInstr = reinterpret_cast<RXYInstruction*>(instr);
|
| - int r1 = rxyInstr->R1Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int b2 = rxyInstr->B2Value();
|
| - int d2 = rxyInstr->D2Value();
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - intptr_t mem_addr = b2_val + x2_val + d2;
|
| -
|
| - if (op == LRVH) {
|
| - int16_t mem_val = ReadH(mem_addr, instr);
|
| - int32_t result = ByteReverse(mem_val) & 0x0000ffff;
|
| - result |= r1_val & 0xffff0000;
|
| - set_low_register(r1, result);
|
| - } else if (op == LRV) {
|
| - int32_t mem_val = ReadW(mem_addr, instr);
|
| - set_low_register(r1, ByteReverse(mem_val));
|
| - } else if (op == STRVH) {
|
| - int16_t result = static_cast<int16_t>(r1_val >> 16);
|
| - WriteH(mem_addr, ByteReverse(result), instr);
|
| - } else if (op == STRV) {
|
| - WriteW(mem_addr, ByteReverse(r1_val), instr);
|
| - }
|
| -
|
| - break;
|
| - }
|
| - case AHIK:
|
| - case AGHIK: {
|
| - // Non-clobbering Add Halfword Immediate
|
| - RIEInstruction* rieInst = reinterpret_cast<RIEInstruction*>(instr);
|
| - int r1 = rieInst->R1Value();
|
| - int r2 = rieInst->R2Value();
|
| - bool isOF = false;
|
| - if (AHIK == op) {
|
| - // 32-bit Add
|
| - int32_t r2_val = get_low_register<int32_t>(r2);
|
| - int32_t imm = rieInst->I6Value();
|
| - isOF = CheckOverflowForIntAdd(r2_val, imm, int32_t);
|
| - set_low_register(r1, r2_val + imm);
|
| - SetS390ConditionCode<int32_t>(r2_val + imm, 0);
|
| - } else if (AGHIK == op) {
|
| - // 64-bit Add
|
| - int64_t r2_val = get_register(r2);
|
| - int64_t imm = static_cast<int64_t>(rieInst->I6Value());
|
| - isOF = CheckOverflowForIntAdd(r2_val, imm, int64_t);
|
| - set_register(r1, r2_val + imm);
|
| - SetS390ConditionCode<int64_t>(r2_val + imm, 0);
|
| - }
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - }
|
| - case ALFI:
|
| - case SLFI: {
|
| - RILInstruction* rilInstr = reinterpret_cast<RILInstruction*>(instr);
|
| - int r1 = rilInstr->R1Value();
|
| - uint32_t imm = rilInstr->I2UnsignedValue();
|
| - uint32_t alu_out = get_low_register<uint32_t>(r1);
|
| - if (op == ALFI) {
|
| - alu_out += imm;
|
| - } else if (op == SLFI) {
|
| - alu_out -= imm;
|
| - }
|
| - SetS390ConditionCode<uint32_t>(alu_out, 0);
|
| - set_low_register(r1, alu_out);
|
| - break;
|
| - }
|
| - case ML: {
|
| - UNIMPLEMENTED();
|
| - break;
|
| - }
|
| - case AY:
|
| - case SY:
|
| - case NY:
|
| - case OY:
|
| - case XY:
|
| - case CY: {
|
| - RXYInstruction* rxyInstr = reinterpret_cast<RXYInstruction*>(instr);
|
| - int r1 = rxyInstr->R1Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int b2 = rxyInstr->B2Value();
|
| - int d2 = rxyInstr->D2Value();
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int32_t alu_out = get_low_register<int32_t>(r1);
|
| - int32_t mem_val = ReadW(b2_val + x2_val + d2, instr);
|
| - bool isOF = false;
|
| - if (op == AY) {
|
| - isOF = CheckOverflowForIntAdd(alu_out, mem_val, int32_t);
|
| - alu_out += mem_val;
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - } else if (op == SY) {
|
| - isOF = CheckOverflowForIntSub(alu_out, mem_val, int32_t);
|
| - alu_out -= mem_val;
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - } else if (op == NY) {
|
| - alu_out &= mem_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - } else if (op == OY) {
|
| - alu_out |= mem_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - } else if (op == XY) {
|
| - alu_out ^= mem_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - } else if (op == CY) {
|
| - SetS390ConditionCode<int32_t>(alu_out, mem_val);
|
| - }
|
| - if (op != CY) {
|
| - set_low_register(r1, alu_out);
|
| - }
|
| - break;
|
| - }
|
| - case AHY:
|
| - case SHY: {
|
| - RXYInstruction* rxyInstr = reinterpret_cast<RXYInstruction*>(instr);
|
| - int32_t r1_val = get_low_register<int32_t>(rxyInstr->R1Value());
|
| - int b2 = rxyInstr->B2Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxyInstr->D2Value();
|
| - int32_t mem_val =
|
| - static_cast<int32_t>(ReadH(b2_val + d2_val + x2_val, instr));
|
| - int32_t alu_out = 0;
|
| - bool isOF = false;
|
| - switch (op) {
|
| - case AHY:
|
| - alu_out = r1_val + mem_val;
|
| - isOF = CheckOverflowForIntAdd(r1_val, mem_val, int32_t);
|
| - break;
|
| - case SHY:
|
| - alu_out = r1_val - mem_val;
|
| - isOF = CheckOverflowForIntSub(r1_val, mem_val, int64_t);
|
| - break;
|
| - default:
|
| - UNREACHABLE();
|
| - break;
|
| - }
|
| - set_low_register(r1, alu_out);
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - }
|
| - case AG:
|
| - case SG:
|
| - case NG:
|
| - case OG:
|
| - case XG:
|
| - case CG:
|
| - case CLG: {
|
| - RXYInstruction* rxyInstr = reinterpret_cast<RXYInstruction*>(instr);
|
| - int r1 = rxyInstr->R1Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int b2 = rxyInstr->B2Value();
|
| - int d2 = rxyInstr->D2Value();
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t alu_out = get_register(r1);
|
| - int64_t mem_val = ReadDW(b2_val + x2_val + d2);
|
| -
|
| - switch (op) {
|
| - case AG: {
|
| - alu_out += mem_val;
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - break;
|
| - }
|
| - case SG: {
|
| - alu_out -= mem_val;
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - break;
|
| - }
|
| - case NG: {
|
| - alu_out &= mem_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - break;
|
| - }
|
| - case OG: {
|
| - alu_out |= mem_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - break;
|
| - }
|
| - case XG: {
|
| - alu_out ^= mem_val;
|
| - SetS390BitWiseConditionCode<uint32_t>(alu_out);
|
| - break;
|
| - }
|
| - case CG: {
|
| - SetS390ConditionCode<int64_t>(alu_out, mem_val);
|
| - break;
|
| - }
|
| - case CLG: {
|
| - SetS390ConditionCode<uint64_t>(alu_out, mem_val);
|
| - break;
|
| - }
|
| - default: {
|
| - DCHECK(false);
|
| - break;
|
| - }
|
| - }
|
| -
|
| - if (op != CG) {
|
| - set_register(r1, alu_out);
|
| - }
|
| - break;
|
| - }
|
| - case ALY:
|
| - case SLY:
|
| - case CLY: {
|
| - RXYInstruction* rxyInstr = reinterpret_cast<RXYInstruction*>(instr);
|
| - int r1 = rxyInstr->R1Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int b2 = rxyInstr->B2Value();
|
| - int d2 = rxyInstr->D2Value();
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - uint32_t alu_out = get_low_register<uint32_t>(r1);
|
| - uint32_t mem_val = ReadWU(b2_val + x2_val + d2, instr);
|
| -
|
| - if (op == ALY) {
|
| - alu_out += mem_val;
|
| - set_low_register(r1, alu_out);
|
| - SetS390ConditionCode<uint32_t>(alu_out, 0);
|
| - } else if (op == SLY) {
|
| - alu_out -= mem_val;
|
| - set_low_register(r1, alu_out);
|
| - SetS390ConditionCode<uint32_t>(alu_out, 0);
|
| - } else if (op == CLY) {
|
| - SetS390ConditionCode<uint32_t>(alu_out, mem_val);
|
| - }
|
| - break;
|
| - }
|
| - case AGFI:
|
| - case AFI: {
|
| - // Clobbering Add Word Immediate
|
| - RILInstruction* rilInstr = reinterpret_cast<RILInstruction*>(instr);
|
| - int32_t r1 = rilInstr->R1Value();
|
| - bool isOF = false;
|
| - if (AFI == op) {
|
| - // 32-bit Add (Register + 32-bit Immediate)
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - int32_t i2 = rilInstr->I2Value();
|
| - isOF = CheckOverflowForIntAdd(r1_val, i2, int32_t);
|
| - int32_t alu_out = r1_val + i2;
|
| - set_low_register(r1, alu_out);
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - } else if (AGFI == op) {
|
| - // 64-bit Add (Register + 32-bit Imm)
|
| - int64_t r1_val = get_register(r1);
|
| - int64_t i2 = static_cast<int64_t>(rilInstr->I2Value());
|
| - isOF = CheckOverflowForIntAdd(r1_val, i2, int64_t);
|
| - int64_t alu_out = r1_val + i2;
|
| - set_register(r1, alu_out);
|
| - SetS390ConditionCode<int64_t>(alu_out, 0);
|
| - }
|
| - SetS390OverflowCode(isOF);
|
| - break;
|
| - }
|
| - case ASI: {
|
| - // TODO(bcleung): Change all fooInstr->I2Value() to template functions.
|
| - // The below static cast to 8 bit and then to 32 bit is necessary
|
| - // because siyInstr->I2Value() returns a uint8_t, which a direct
|
| - // cast to int32_t could incorrectly interpret.
|
| - int8_t i2_8bit = static_cast<int8_t>(siyInstr->I2Value());
|
| - int32_t i2 = static_cast<int32_t>(i2_8bit);
|
| - int b1 = siyInstr->B1Value();
|
| - intptr_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
| -
|
| - int d1_val = siyInstr->D1Value();
|
| - intptr_t addr = b1_val + d1_val;
|
| -
|
| - int32_t mem_val = ReadW(addr, instr);
|
| - bool isOF = CheckOverflowForIntAdd(mem_val, i2, int32_t);
|
| - int32_t alu_out = mem_val + i2;
|
| - SetS390ConditionCode<int32_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - WriteW(addr, alu_out, instr);
|
| - break;
|
| - }
|
| - case AGSI: {
|
| - // TODO(bcleung): Change all fooInstr->I2Value() to template functions.
|
| - // The below static cast to 8 bit and then to 32 bit is necessary
|
| - // because siyInstr->I2Value() returns a uint8_t, which a direct
|
| - // cast to int32_t could incorrectly interpret.
|
| - int8_t i2_8bit = static_cast<int8_t>(siyInstr->I2Value());
|
| - int64_t i2 = static_cast<int64_t>(i2_8bit);
|
| - int b1 = siyInstr->B1Value();
|
| - intptr_t b1_val = (b1 == 0) ? 0 : get_register(b1);
|
| -
|
| - int d1_val = siyInstr->D1Value();
|
| - intptr_t addr = b1_val + d1_val;
|
| -
|
| - int64_t mem_val = ReadDW(addr);
|
| - int isOF = CheckOverflowForIntAdd(mem_val, i2, int64_t);
|
| - int64_t alu_out = mem_val + i2;
|
| - SetS390ConditionCode<uint64_t>(alu_out, 0);
|
| - SetS390OverflowCode(isOF);
|
| - WriteDW(addr, alu_out);
|
| - break;
|
| - }
|
| - case AGF:
|
| - case SGF:
|
| - case ALG:
|
| - case SLG: {
|
| -#ifndef V8_TARGET_ARCH_S390X
|
| - DCHECK(false);
|
| -#endif
|
| - RXYInstruction* rxyInstr = reinterpret_cast<RXYInstruction*>(instr);
|
| - int r1 = rxyInstr->R1Value();
|
| - uint64_t r1_val = get_register(rxyInstr->R1Value());
|
| - int b2 = rxyInstr->B2Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxyInstr->D2Value();
|
| - uint64_t alu_out = r1_val;
|
| - if (op == ALG) {
|
| - uint64_t mem_val =
|
| - static_cast<uint64_t>(ReadDW(b2_val + d2_val + x2_val));
|
| - alu_out += mem_val;
|
| - SetS390ConditionCode<uint64_t>(alu_out, 0);
|
| - } else if (op == SLG) {
|
| - uint64_t mem_val =
|
| - static_cast<uint64_t>(ReadDW(b2_val + d2_val + x2_val));
|
| - alu_out -= mem_val;
|
| - SetS390ConditionCode<uint64_t>(alu_out, 0);
|
| - } else if (op == AGF) {
|
| - uint32_t mem_val = ReadW(b2_val + d2_val + x2_val, instr);
|
| - alu_out += mem_val;
|
| - SetS390ConditionCode<int64_t>(alu_out, 0);
|
| - } else if (op == SGF) {
|
| - uint32_t mem_val = ReadW(b2_val + d2_val + x2_val, instr);
|
| - alu_out -= mem_val;
|
| - SetS390ConditionCode<int64_t>(alu_out, 0);
|
| - } else {
|
| - DCHECK(false);
|
| - }
|
| - set_register(r1, alu_out);
|
| - break;
|
| - }
|
| - case ALGFI:
|
| - case SLGFI: {
|
| -#ifndef V8_TARGET_ARCH_S390X
|
| - // should only be called on 64bit
|
| - DCHECK(false);
|
| -#endif
|
| - RILInstruction* rilInstr = reinterpret_cast<RILInstruction*>(instr);
|
| - int r1 = rilInstr->R1Value();
|
| - uint32_t i2 = rilInstr->I2UnsignedValue();
|
| - uint64_t r1_val = (uint64_t)(get_register(r1));
|
| - uint64_t alu_out;
|
| - if (op == ALGFI)
|
| - alu_out = r1_val + i2;
|
| - else
|
| - alu_out = r1_val - i2;
|
| - set_register(r1, (intptr_t)alu_out);
|
| - SetS390ConditionCode<uint64_t>(alu_out, 0);
|
| - break;
|
| - }
|
| - case MSY:
|
| - case MSG: {
|
| - RXYInstruction* rxyInstr = reinterpret_cast<RXYInstruction*>(instr);
|
| - int r1 = rxyInstr->R1Value();
|
| - int b2 = rxyInstr->B2Value();
|
| - int x2 = rxyInstr->X2Value();
|
| - int64_t b2_val = (b2 == 0) ? 0 : get_register(b2);
|
| - int64_t x2_val = (x2 == 0) ? 0 : get_register(x2);
|
| - intptr_t d2_val = rxyInstr->D2Value();
|
| - if (op == MSY) {
|
| - int32_t mem_val = ReadW(b2_val + d2_val + x2_val, instr);
|
| - int32_t r1_val = get_low_register<int32_t>(r1);
|
| - set_low_register(r1, mem_val * r1_val);
|
| - } else if (op == MSG) {
|
| - int64_t mem_val = ReadDW(b2_val + d2_val + x2_val);
|
| - int64_t r1_val = get_register(r1);
|
| - set_register(r1, mem_val * r1_val);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - }
|
| - case MSFI:
|
| - case MSGFI: {
|
| - RILInstruction* rilinst = reinterpret_cast<RILInstruction*>(instr);
|
| - int r1 = rilinst->R1Value();
|
| - int32_t i2 = rilinst->I2Value();
|
| - if (op == MSFI) {
|
| - int32_t alu_out = get_low_register<int32_t>(r1);
|
| - alu_out = alu_out * i2;
|
| - set_low_register(r1, alu_out);
|
| - } else if (op == MSGFI) {
|
| - int64_t alu_out = get_register(r1);
|
| - alu_out = alu_out * i2;
|
| - set_register(r1, alu_out);
|
| - } else {
|
| - UNREACHABLE();
|
| - }
|
| - break;
|
| - }
|
| - default:
|
| - UNREACHABLE();
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| int16_t Simulator::ByteReverse(int16_t hword) {
|
| #if defined(__GNUC__)
|
| return __builtin_bswap16(hword);
|
| @@ -5583,18 +2440,6 @@ int64_t Simulator::ByteReverse(int64_t dword) {
|
| #endif
|
| }
|
|
|
| -int Simulator::DecodeInstructionOriginal(Instruction* instr) {
|
| - int instrLength = instr->InstructionLength();
|
| - bool processed = true;
|
| - if (instrLength == 2)
|
| - processed = DecodeTwoByte(instr);
|
| - else if (instrLength == 4)
|
| - processed = DecodeFourByte(instr);
|
| - else if (instrLength == 6)
|
| - processed = DecodeSixByte(instr);
|
| - return instrLength;
|
| -}
|
| -
|
| int Simulator::DecodeInstruction(Instruction* instr) {
|
| Opcode op = instr->S390OpcodeValue();
|
| DCHECK(EvalTable[op] != NULL);
|
|
|