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