diff options
Diffstat (limited to 'deps/v8/src/s390/simulator-s390.cc')
-rw-r--r-- | deps/v8/src/s390/simulator-s390.cc | 3368 |
1 files changed, 175 insertions, 3193 deletions
diff --git a/deps/v8/src/s390/simulator-s390.cc b/deps/v8/src/s390/simulator-s390.cc index c5d3a1c3bb..b0fa0917ad 100644 --- a/deps/v8/src/s390/simulator-s390.cc +++ b/deps/v8/src/s390/simulator-s390.cc @@ -842,6 +842,7 @@ void Simulator::EvalTableInit() { EvalTable[OI] = &Simulator::Evaluate_OI; EvalTable[XI] = &Simulator::Evaluate_XI; EvalTable[LM] = &Simulator::Evaluate_LM; + EvalTable[CS] = &Simulator::Evaluate_CS; EvalTable[MVCLE] = &Simulator::Evaluate_MVCLE; EvalTable[CLCLE] = &Simulator::Evaluate_CLCLE; EvalTable[MC] = &Simulator::Evaluate_MC; @@ -1299,6 +1300,7 @@ void Simulator::EvalTableInit() { EvalTable[BCTG] = &Simulator::Evaluate_BCTG; EvalTable[STY] = &Simulator::Evaluate_STY; EvalTable[MSY] = &Simulator::Evaluate_MSY; + EvalTable[MSC] = &Simulator::Evaluate_MSC; EvalTable[NY] = &Simulator::Evaluate_NY; EvalTable[CLY] = &Simulator::Evaluate_CLY; EvalTable[OY] = &Simulator::Evaluate_OY; @@ -2411,3149 +2413,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); @@ -5582,18 +2441,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); @@ -6446,7 +3293,7 @@ EVALUATE(RISBG) { if (!zero_remaining) { // Merged the unselected bits from the original value - selected_val = (src_val & ~selection_mask) | selected_val; + selected_val = (get_register(r1) & ~selection_mask) | selected_val; } // Condition code is set by treating result as 64-bit signed int @@ -7811,10 +4658,10 @@ EVALUATE(TMLL) { mask = 0x80000000u >> leadingZeros; if (mask & r1_val) { // leftmost bit is one - condition_reg_ = 0x4; + condition_reg_ = 0x2; } else { // leftmost bit is zero - condition_reg_ = 0x2; + condition_reg_ = 0x4; } return length; // Done! #else @@ -8770,8 +5617,6 @@ EVALUATE(DEBR) { float fr2_val = get_float32_from_d_register(r2); fr1_val /= fr2_val; set_d_register_from_float32(r1, fr1_val); - SetS390ConditionCode<float>(fr1_val, 0); - return length; } @@ -8871,7 +5716,6 @@ EVALUATE(MEEBR) { float fr2_val = get_float32_from_d_register(r2); fr1_val *= fr2_val; set_d_register_from_float32(r1, fr1_val); - SetS390ConditionCode<float>(fr1_val, 0); return length; } @@ -8923,7 +5767,6 @@ EVALUATE(MDBR) { double r2_val = get_double_from_d_register(r2); r1_val *= r2_val; set_d_register_from_double(r1, r1_val); - SetS390ConditionCode<double>(r1_val, 0); return length; } @@ -8934,7 +5777,6 @@ EVALUATE(DDBR) { double r2_val = get_double_from_d_register(r2); r1_val /= r2_val; set_d_register_from_double(r1, r1_val); - SetS390ConditionCode<double>(r1_val, 0); return length; } @@ -9424,10 +6266,21 @@ EVALUATE(CLFEBR) { EVALUATE(CLFDBR) { DCHECK_OPCODE(CLFDBR); DECODE_RRE_INSTRUCTION(r1, r2); - double r2_val = get_double_from_d_register(r2); - uint32_t r1_val = static_cast<uint32_t>(r2_val); + double a = get_double_from_d_register(r2); + double n = std::round(a); + uint32_t r1_val = static_cast<uint32_t>(n); set_low_register(r1, r1_val); - SetS390ConvertConditionCode<double>(r2_val, r1_val, UINT32_MAX); + if (std::isfinite(a) && a < 0.0) { + DCHECK(n <= 0.0 && std::isfinite(n)); + condition_reg_ = (n < 0.0) ? 0x1 : 0x4; + } else if (a == 0.0) { + condition_reg_ = 0x8; + } else if (std::isfinite(a) && a > 0.0) { + DCHECK(n >= 0.0 && std::isfinite(n)); + condition_reg_ = (n <= static_cast<double>(UINT32_MAX)) ? 0x2 : 0x1; + } else { + condition_reg_ = 0x1; + } return length; } @@ -10440,12 +7293,14 @@ EVALUATE(DLGR) { 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); return length; #else + // 32 bit arch doesn't support __int128 type + USE(instr); UNREACHABLE(); + return 0; #endif } @@ -10502,9 +7357,13 @@ EVALUATE(LLCR) { } EVALUATE(LLHR) { - UNIMPLEMENTED(); - USE(instr); - return 0; + DCHECK_OPCODE(LLHR); + DECODE_RRE_INSTRUCTION(r1, r2); + uint32_t r2_val = get_low_register<uint32_t>(r2); + r2_val <<= 16; + r2_val >>= 16; + set_low_register(r1, r2_val); + return length; } EVALUATE(MLR) { @@ -10931,8 +7790,10 @@ EVALUATE(AG) { 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); + bool isOF = CheckOverflowForIntAdd(alu_out, mem_val, int64_t); alu_out += mem_val; - SetS390ConditionCode<int32_t>(alu_out, 0); + SetS390ConditionCode<int64_t>(alu_out, 0); + SetS390OverflowCode(isOF); set_register(r1, alu_out); return length; } @@ -10944,8 +7805,10 @@ EVALUATE(SG) { 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); + bool isOF = CheckOverflowForIntSub(alu_out, mem_val, int64_t); alu_out -= mem_val; SetS390ConditionCode<int32_t>(alu_out, 0); + SetS390OverflowCode(isOF); set_register(r1, alu_out); return length; } @@ -10999,9 +7862,19 @@ EVALUATE(MSG) { } EVALUATE(DSG) { - UNIMPLEMENTED(); - USE(instr); - return 0; + DCHECK_OPCODE(DSG); + DECODE_RXY_A_INSTRUCTION(r1, x2, b2, d2); + DCHECK(r1 % 2 == 0); + int64_t b2_val = (b2 == 0) ? 0 : get_register(b2); + int64_t x2_val = (x2 == 0) ? 0 : get_register(x2); + intptr_t d2_val = d2; + int64_t mem_val = ReadDW(b2_val + d2_val + x2_val); + int64_t r1_val = get_register(r1 + 1); + int64_t quotient = r1_val / mem_val; + int64_t remainder = r1_val % mem_val; + set_register(r1, remainder); + set_register(r1 + 1, quotient); + return length; } EVALUATE(CVBG) { @@ -11285,6 +8158,25 @@ EVALUATE(MSY) { return length; } +EVALUATE(MSC) { + DCHECK_OPCODE(MSC); + DECODE_RXY_A_INSTRUCTION(r1, x2, b2, d2); + int64_t b2_val = (b2 == 0) ? 0 : get_register(b2); + int64_t x2_val = (x2 == 0) ? 0 : get_register(x2); + intptr_t d2_val = d2; + int32_t mem_val = ReadW(b2_val + d2_val + x2_val, instr); + int32_t r1_val = get_low_register<int32_t>(r1); + int64_t result64 = + static_cast<int64_t>(r1_val) * static_cast<int64_t>(mem_val); + int32_t result32 = static_cast<int32_t>(result64); + bool isOF = (static_cast<int64_t>(result32) != result64); + SetS390ConditionCode<int32_t>(result32, 0); + SetS390OverflowCode(isOF); + set_low_register(r1, result32); + set_low_register(r1, mem_val * r1_val); + return length; +} + EVALUATE(NY) { DCHECK_OPCODE(NY); DECODE_RXY_A_INSTRUCTION(r1, x2, b2, d2); @@ -11609,9 +8501,27 @@ EVALUATE(MLG) { } EVALUATE(DLG) { - UNIMPLEMENTED(); + DCHECK_OPCODE(DLG); +#ifdef V8_TARGET_ARCH_S390X + DECODE_RXY_A_INSTRUCTION(r1, x2, b2, d2); + uint64_t r1_val = get_register(r1); + int64_t x2_val = (x2 == 0) ? 0 : get_register(x2); + int64_t b2_val = (b2 == 0) ? 0 : get_register(b2); + DCHECK(r1 % 2 == 0); + unsigned __int128 dividend = static_cast<unsigned __int128>(r1_val) << 64; + dividend += get_register(r1 + 1); + int64_t mem_val = ReadDW(b2_val + x2_val + d2); + uint64_t remainder = dividend % mem_val; + uint64_t quotient = dividend / mem_val; + set_register(r1, remainder); + set_register(r1 + 1, quotient); + return length; +#else + // 32 bit arch doesn't support __int128 type USE(instr); + UNREACHABLE(); return 0; +#endif } EVALUATE(ALCG) { @@ -11950,7 +8860,53 @@ EVALUATE(SLLG) { return length; } +EVALUATE(CS) { + DCHECK_OPCODE(CS); + DECODE_RS_A_INSTRUCTION(r1, r3, rb, d2); + int32_t offset = d2; + int64_t rb_val = (rb == 0) ? 0 : get_register(rb); + intptr_t target_addr = static_cast<intptr_t>(rb_val) + offset; + + int32_t r1_val = get_low_register<int32_t>(r1); + int32_t r3_val = get_low_register<int32_t>(r3); + + DCHECK((target_addr & 0x3) == 0); + bool is_success = __atomic_compare_exchange_n( + reinterpret_cast<int32_t*>(target_addr), &r1_val, r3_val, true, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + if (!is_success) { + set_low_register(r1, r1_val); + condition_reg_ = 0x4; + } else { + condition_reg_ = 0x8; + } + return length; +} + EVALUATE(CSY) { + DCHECK_OPCODE(CSY); + DECODE_RSY_A_INSTRUCTION(r1, r3, b2, d2); + int32_t offset = d2; + int64_t b2_val = (b2 == 0) ? 0 : get_register(b2); + intptr_t target_addr = static_cast<intptr_t>(b2_val) + offset; + + int32_t r1_val = get_low_register<int32_t>(r1); + int32_t r3_val = get_low_register<int32_t>(r3); + + DCHECK((target_addr & 0x3) == 0); + bool is_success = __atomic_compare_exchange_n( + reinterpret_cast<int32_t*>(target_addr), &r1_val, r3_val, true, + __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); + if (!is_success) { + set_low_register(r1, r1_val); + condition_reg_ = 0x4; + } else { + condition_reg_ = 0x8; + } + return length; +} + +EVALUATE(CSG) { UNIMPLEMENTED(); USE(instr); return 0; @@ -12514,16 +9470,14 @@ EVALUATE(CIB) { EVALUATE(LDEB) { DCHECK_OPCODE(LDEB); - // Load Float DECODE_RXE_INSTRUCTION(r1, b2, x2, d2); int rb = b2; int rx = x2; int offset = d2; 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); + float fval = ReadFloat(rx_val + rb_val + offset); + set_d_register_from_double(r1, static_cast<double>(fval)); return length; } @@ -12565,15 +9519,31 @@ EVALUATE(CEB) { } EVALUATE(AEB) { - UNIMPLEMENTED(); - USE(instr); - return 0; + DCHECK_OPCODE(AEB); + DECODE_RXE_INSTRUCTION(r1, b2, x2, d2); + int64_t b2_val = (b2 == 0) ? 0 : get_register(b2); + int64_t x2_val = (x2 == 0) ? 0 : get_register(x2); + intptr_t d2_val = d2; + float r1_val = get_float32_from_d_register(r1); + float fval = ReadFloat(b2_val + x2_val + d2_val); + r1_val += fval; + set_d_register_from_float32(r1, r1_val); + SetS390ConditionCode<float>(r1_val, 0); + return length; } EVALUATE(SEB) { - UNIMPLEMENTED(); - USE(instr); - return 0; + DCHECK_OPCODE(SEB); + DECODE_RXE_INSTRUCTION(r1, b2, x2, d2); + int64_t b2_val = (b2 == 0) ? 0 : get_register(b2); + int64_t x2_val = (x2 == 0) ? 0 : get_register(x2); + intptr_t d2_val = d2; + float r1_val = get_float32_from_d_register(r1); + float fval = ReadFloat(b2_val + x2_val + d2_val); + r1_val -= fval; + set_d_register_from_float32(r1, r1_val); + SetS390ConditionCode<float>(r1_val, 0); + return length; } EVALUATE(MDEB) { @@ -12583,9 +9553,16 @@ EVALUATE(MDEB) { } EVALUATE(DEB) { - UNIMPLEMENTED(); - USE(instr); - return 0; + DCHECK_OPCODE(DEB); + DECODE_RXE_INSTRUCTION(r1, b2, x2, d2); + int64_t b2_val = (b2 == 0) ? 0 : get_register(b2); + int64_t x2_val = (x2 == 0) ? 0 : get_register(x2); + intptr_t d2_val = d2; + float r1_val = get_float32_from_d_register(r1); + float fval = ReadFloat(b2_val + x2_val + d2_val); + r1_val /= fval; + set_d_register_from_float32(r1, r1_val); + return length; } EVALUATE(MAEB) { @@ -12638,9 +9615,16 @@ EVALUATE(SQDB) { } EVALUATE(MEEB) { - UNIMPLEMENTED(); - USE(instr); - return 0; + DCHECK_OPCODE(MEEB); + DECODE_RXE_INSTRUCTION(r1, b2, x2, d2); + int64_t b2_val = (b2 == 0) ? 0 : get_register(b2); + int64_t x2_val = (x2 == 0) ? 0 : get_register(x2); + intptr_t d2_val = d2; + float r1_val = get_float32_from_d_register(r1); + float fval = ReadFloat(b2_val + x2_val + d2_val); + r1_val *= fval; + set_d_register_from_float32(r1, r1_val); + return length; } EVALUATE(KDB) { @@ -12701,7 +9685,6 @@ EVALUATE(MDB) { double dbl_val = ReadDouble(b2_val + x2_val + d2_val); r1_val *= dbl_val; set_d_register_from_double(r1, r1_val); - SetS390ConditionCode<double>(r1_val, 0); return length; } @@ -12715,7 +9698,6 @@ EVALUATE(DDB) { double dbl_val = ReadDouble(b2_val + x2_val + d2_val); r1_val /= dbl_val; set_d_register_from_double(r1, r1_val); - SetS390ConditionCode<double>(r1_val, 0); return length; } |