| Index: src/arm/simulator-arm.cc
|
| ===================================================================
|
| --- src/arm/simulator-arm.cc (revision 4001)
|
| +++ src/arm/simulator-arm.cc (working copy)
|
| @@ -240,10 +240,10 @@
|
| "%" XSTR(ARG_SIZE) "s",
|
| cmd, arg1, arg2);
|
| if ((strcmp(cmd, "si") == 0) || (strcmp(cmd, "stepi") == 0)) {
|
| - sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
|
| + sim_->InstructionDecode(sim_->get_pc());
|
| } else if ((strcmp(cmd, "c") == 0) || (strcmp(cmd, "cont") == 0)) {
|
| // Execute the one instruction we broke at with breakpoints disabled.
|
| - sim_->InstructionDecode(reinterpret_cast<Instr*>(sim_->get_pc()));
|
| + sim_->InstructionDecode(sim_->get_pc());
|
| // Leave the debugger shell.
|
| done = true;
|
| } else if ((strcmp(cmd, "p") == 0) || (strcmp(cmd, "print") == 0)) {
|
| @@ -404,6 +404,142 @@
|
| }
|
|
|
|
|
| +
|
| +InstrThumb2::InstrThumb2(byte* pc)
|
| + : pc_(pc) {
|
| + instr0_ = *reinterpret_cast<uint16_t*>(Address());
|
| + if (instr0_ > kMax16BitThumbOpcode) {
|
| + instr1_ = *reinterpret_cast<uint16_t*>(
|
| + reinterpret_cast<uint32_t>(Address() + 2));
|
| + size_ = 4;
|
| + Decode32();
|
| + } else {
|
| + size_ = 2;
|
| + Decode16();
|
| + }
|
| +}
|
| +
|
| +void InstrThumb2::Decode16() {
|
| + switch (instr0_ & 0xff80) { // bits 15 - 11
|
| + case B13:
|
| + Decode16_Rdn3Imm8(OP_CMP, VARIANT_IMMEDIATE);
|
| + break;
|
| + case B13 | B12:
|
| + Decode16_Rdn3Imm8(OP_ADD, VARIANT_IMMEDIATE);
|
| + break;
|
| + case B15 | B13 | B11:
|
| + Decode16_Rdn3Imm8(OP_ADD, VARIANT_SP_PLUS_IMMEDIATE);
|
| + break;
|
| + case B15 | B14 | B13:
|
| + Decode16_Imm11(OP_B, VARIANT_REGISTER);
|
| + break;
|
| + case B15 | B14 | B13 | B12 | B11:
|
| + Decode16_Imm11(OP_BL, VARIANT_IMMEDIATE);
|
| + break;
|
| + default:
|
| + UnsupportedInstruction();
|
| + }
|
| +}
|
| +
|
| +void InstrThumb2::Decode32() {
|
| + switch (instr0_ & (0xff * B5)) {
|
| + case B11 | B9: // 01010000 * B5
|
| + Decode32_SRn4XImm3Rd4Imm2Type2Rm4(OP_AND, VARIANT_REGISTER);
|
| + DecodeImmShift();
|
| + break;
|
| + case B11 | B9 | B8: // 01011000 * B5
|
| + Decode32_SRn4XImm3Rd4Imm2Type2Rm4(OP_ADD, VARIANT_REGISTER);
|
| + DecodeImmShift();
|
| + break;
|
| + case B12 | B8 | B7 | B5: // 10x01101 * B5;
|
| + case B12 | B10 | B8 | B7 | B5: // B10 is part of Imm.
|
| + Decode32_ImmX5SRn4XImm3Rd4Imm8(OP_SUB, VARIANT_IMMEDIATE);
|
| + ThumbExpandImm();
|
| + break;
|
| +
|
| + default:
|
| + UnsupportedInstruction();
|
| + }
|
| +}
|
| +
|
| +void InstrThumb2::UnsupportedInstruction() {
|
| + if (size_ == 2) {
|
| + PrintF("Unsupported 16bit instruction %x\n", instr0_);
|
| + } else {
|
| + PrintF("Unsupported 32bit instruction %x:%x\n", instr0_, instr1_);
|
| + }
|
| + op_ = OP_UNSUPPORTED;
|
| +}
|
| +
|
| +void InstrThumb2::Decode16_Rdn3Imm8(Operation op, OpVariant variant) {
|
| + op_ = op;
|
| + variant_ = variant;
|
| + s_ = AUTO;
|
| +
|
| + imm_ = Bits0(7, 0);
|
| + rd_ = rn_ = Bits0(10, 8);
|
| +}
|
| +
|
| +void InstrThumb2::Decode16_Imm11(Operation op, OpVariant variant) {
|
| + op_ = op;
|
| + variant_ = variant;
|
| + s_ = AUTO;
|
| +
|
| + imm_ = Bits0(10, 0);
|
| +}
|
| +
|
| +void InstrThumb2::Decode32_SRn4XImm3Rd4Imm2Type2Rm4(Operation op,
|
| + OpVariant variant) {
|
| + op_ = op;
|
| + variant_ = variant;
|
| +
|
| + s_ = Bit0(4);
|
| + rn_ = Bits0(3, 0);
|
| + imm_ = Bits1(14, 12) * B2 | Bits1(7, 6);
|
| + rd_ = Bits1(11, 8);
|
| + type_ = Bits1(5, 4);
|
| + rm_ = Bits1(3, 0);
|
| +}
|
| +
|
| +void InstrThumb2::Decode32_ImmX5SRn4XImm3Rd4Imm8(Operation op,
|
| + OpVariant variant) {
|
| + op_ = op;
|
| + variant_ = variant;
|
| +
|
| + s_ = Bit0(4);
|
| + imm_ = Bit0(10) * B11 | Bits1(14, 12) * B8 | Bits1(7, 0);
|
| + rn_ = Bits0(3, 0);
|
| + rd_ = Bits1(11, 8);
|
| +}
|
| +
|
| +void InstrThumb2::DecodeImmShift() {
|
| + if (imm_ == 0) {
|
| + switch (type_) {
|
| + case LSL:
|
| + type_ = no_shift;
|
| + break;
|
| + case ASR:
|
| + case LSR:
|
| + imm_ = 32;
|
| + break;
|
| + case ROR:
|
| + type_ = RRX;
|
| + imm_ = 1;
|
| + break;
|
| + default:
|
| + UnsupportedInstruction();
|
| + }
|
| + }
|
| +}
|
| +
|
| +void InstrThumb2::ThumbExpandImm() {
|
| + if (imm_ > 255) {
|
| + // TODO(haustein) Support thumb2 immediate shift here..
|
| + UnsupportedInstruction();
|
| + }
|
| +}
|
| +
|
| +
|
| // Create one simulator per thread and keep it in thread local storage.
|
| static v8::internal::Thread::LocalStorageKey simulator_key;
|
|
|
| @@ -466,6 +602,7 @@
|
| // access violation if the simulator ever tries to execute it.
|
| registers_[pc] = bad_lr;
|
| registers_[lr] = bad_lr;
|
| +
|
| InitializeCoverage();
|
| }
|
|
|
| @@ -557,7 +694,11 @@
|
| // the special case of accessing the PC register.
|
| int32_t Simulator::get_register(int reg) const {
|
| ASSERT((reg >= 0) && (reg < num_registers));
|
| - return registers_[reg] + ((reg == pc) ? Instr::kPCReadOffset : 0);
|
| + if (reg == pc) {
|
| + return registers_[reg] + (InThumbMode() ? Instr::kPCReadOffsetThumb
|
| + : Instr::kPCReadOffset);
|
| + }
|
| + return registers_[reg];
|
| }
|
|
|
|
|
| @@ -2110,18 +2251,139 @@
|
| }
|
|
|
|
|
| -// Executes the current instruction.
|
| -void Simulator::InstructionDecode(Instr* instr) {
|
| - pc_modified_ = false;
|
| +void Simulator::InstructionDecode(int32_t adr) {
|
| if (::v8::internal::FLAG_trace_sim) {
|
| disasm::NameConverter converter;
|
| disasm::Disassembler dasm(converter);
|
| // use a reasonably large buffer
|
| v8::internal::EmbeddedVector<char, 256> buffer;
|
| dasm.InstructionDecode(buffer,
|
| - reinterpret_cast<byte*>(instr));
|
| - PrintF(" 0x%08x %s\n", instr, buffer.start());
|
| + reinterpret_cast<byte*>(adr));
|
| + PrintF(" 0x%08x %s\n", adr, buffer.start());
|
| }
|
| + if ((adr & 1) == 1) {
|
| + InstructionDecodeThumb2(reinterpret_cast<byte*>(adr));
|
| + } else {
|
| + InstructionDecodeArm(reinterpret_cast<Instr*>(adr));
|
| + }
|
| +}
|
| +
|
| +int32_t Simulator::GetOperand2(const InstrThumb2& instr, bool* carry_out) {
|
| + switch (instr.Variant()) {
|
| + case VARIANT_IMMEDIATE:
|
| + return instr.Imm();
|
| +
|
| + case VARIANT_REGISTER:
|
| + return GetRmShiftImm(instr, carry_out);
|
| +
|
| + default:
|
| + UNIMPLEMENTED();
|
| + return -1;
|
| + }
|
| +}
|
| +
|
| +int32_t Simulator::GetRmShiftImm(const InstrThumb2& instr, bool* carry_out) {
|
| + Shift shift = (Shift) instr.Type();
|
| + int shift_amount = instr.Imm();
|
| + int32_t result = get_register(instr.Rm());
|
| +
|
| + switch (shift) {
|
| + case no_shift:
|
| + break;
|
| +
|
| + case ASR: {
|
| + ASSERT(shift_amount > 0);
|
| + result >>= (shift_amount - 1);
|
| + *carry_out = (result & 1) == 1;
|
| + result >>= 1;
|
| + break;
|
| + }
|
| +
|
| + case LSL: {
|
| + ASSERT(shift_amount > 0);
|
| + result <<= (shift_amount - 1);
|
| + *carry_out = (result < 0);
|
| + result <<= 1;
|
| + break;
|
| + }
|
| +
|
| + case LSR: {
|
| + uint32_t uresult = static_cast<uint32_t>(result);
|
| + ASSERT(shift_amount > 0);
|
| + uresult >>= (shift_amount - 1);
|
| + *carry_out = (uresult & 1) == 1;
|
| + uresult >>= 1;
|
| + result = static_cast<int32_t>(uresult);
|
| + break;
|
| + }
|
| +
|
| + case RRX:
|
| + case ROR: {
|
| + UNIMPLEMENTED();
|
| + break;
|
| + }
|
| +
|
| + default: {
|
| + UNREACHABLE();
|
| + break;
|
| + }
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +
|
| +
|
| +void Simulator::InstructionDecodeThumb2(byte* adr) {
|
| + pc_modified_ = false;
|
| + InstrThumb2 instr(adr);
|
| + bool shifter_carry_out = 0;
|
| + int32_t alu_out;
|
| + int32_t operand2;
|
| +
|
| + int32_t rn_val = get_register(instr.Rn());
|
| + switch (instr.Op()) {
|
| + case OP_AND:
|
| + alu_out = rn_val & GetOperand2(instr, &shifter_carry_out);
|
| + set_register(instr.Rd(), alu_out);
|
| + if (instr.HasS()) {
|
| + SetNZFlags(alu_out);
|
| + SetCFlag(shifter_carry_out);
|
| + }
|
| + break;
|
| + case OP_ADD:
|
| + operand2 = GetOperand2(instr, &shifter_carry_out);
|
| + alu_out = rn_val + operand2;
|
| + set_register(instr.Rd(), alu_out);
|
| + if (instr.HasS()) {
|
| + SetNZFlags(alu_out);
|
| + SetCFlag(CarryFrom(rn_val, operand2));
|
| + SetVFlag(OverflowFrom(alu_out, rn_val, operand2, true));
|
| + }
|
| + break;
|
| +
|
| + case OP_SUB:
|
| + operand2 = GetOperand2(instr, &shifter_carry_out);
|
| + alu_out = rn_val - operand2;
|
| + set_register(instr.Rd(), alu_out);
|
| + if (instr.HasS()) {
|
| + SetNZFlags(alu_out);
|
| + SetCFlag(!BorrowFrom(rn_val, operand2));
|
| + SetVFlag(OverflowFrom(alu_out, rn_val, operand2, false));
|
| + }
|
| + break;
|
| +
|
| + default:
|
| + PrintF("Unrecogized Thumb Instruction");
|
| + UNIMPLEMENTED();
|
| + }
|
| + if (!pc_modified_) {
|
| + set_register(pc, reinterpret_cast<int32_t>(adr) + instr.Size());
|
| + }
|
| +}
|
| +
|
| +// Executes the current instruction.
|
| +void Simulator::InstructionDecodeArm(Instr* instr) {
|
| + pc_modified_ = false;
|
| if (instr->ConditionField() == special_condition) {
|
| DecodeUnconditional(instr);
|
| } else if (ConditionallyExecute(instr)) {
|
| @@ -2176,22 +2438,20 @@
|
| // Fast version of the dispatch loop without checking whether the simulator
|
| // should be stopping at a particular executed instruction.
|
| while (program_counter != end_sim_pc) {
|
| - Instr* instr = reinterpret_cast<Instr*>(program_counter);
|
| icount_++;
|
| - InstructionDecode(instr);
|
| + InstructionDecode(program_counter);
|
| program_counter = get_pc();
|
| }
|
| } else {
|
| // FLAG_stop_sim_at is at the non-default value. Stop in the debugger when
|
| // we reach the particular instuction count.
|
| while (program_counter != end_sim_pc) {
|
| - Instr* instr = reinterpret_cast<Instr*>(program_counter);
|
| icount_++;
|
| if (icount_ == ::v8::internal::FLAG_stop_sim_at) {
|
| Debugger dbg(this);
|
| dbg.Debug();
|
| } else {
|
| - InstructionDecode(instr);
|
| + InstructionDecode(program_counter);
|
| }
|
| program_counter = get_pc();
|
| }
|
|
|