Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1068)

Unified Diff: src/s390/simulator-s390.cc

Issue 2741053004: s390: cleanup old instruction decode routines (Closed)
Patch Set: Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/s390/simulator-s390.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « src/s390/simulator-s390.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698