From 21228278931cea4c8dd7cb3b90fffaa9f090e82b Mon Sep 17 00:00:00 2001 From: "ager@chromium.org" Date: Thu, 28 Oct 2010 07:35:07 +0000 Subject: [PATCH] Landing for Rodolph Perfetta. Fix the ARM simulator, the ARM disassembler and extend the stop feature. The stop feature in the simulator now support enabling, disabling and counting. BUG=None TEST=None git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5723 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/assembler-arm.cc | 26 +++- src/arm/assembler-arm.h | 7 +- src/arm/constants-arm.h | 10 +- src/arm/cpu-arm.cc | 10 +- src/arm/disasm-arm.cc | 113 +++++---------- src/arm/simulator-arm.cc | 299 ++++++++++++++++++++++++++------------- src/arm/simulator-arm.h | 27 +++- 7 files changed, 304 insertions(+), 188 deletions(-) diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc index 7d368bf415..ebbd9b1138 100644 --- a/src/arm/assembler-arm.cc +++ b/src/arm/assembler-arm.cc @@ -1004,7 +1004,7 @@ void Assembler::blx(int branch_offset) { // v5 and above int h = ((branch_offset & 2) >> 1)*B24; int imm24 = branch_offset >> 2; ASSERT(is_int24(imm24)); - emit(15 << 28 | B27 | B25 | h | (imm24 & Imm24Mask)); + emit(nv | B27 | B25 | h | (imm24 & Imm24Mask)); } @@ -1634,15 +1634,29 @@ void Assembler::stm(BlockAddrMode am, // Exception-generating instructions and debugging support. -void Assembler::stop(const char* msg) { +// Stops with a non-negative code less than kNumOfWatchedStops support +// enabling/disabling and a counter feature. See simulator-arm.h . +void Assembler::stop(const char* msg, Condition cond, int32_t code) { #ifndef __arm__ - // The simulator handles these special instructions and stops execution. - emit(15 << 28 | ((intptr_t) msg)); + // See constants-arm.h SoftwareInterruptCodes. Unluckily the Assembler and + // Simulator do not share constants declaration. + ASSERT(code >= kDefaultStopCode); + static const uint32_t kStopInterruptCode = 1 << 23; + static const uint32_t kMaxStopCode = kStopInterruptCode - 1; + // The Simulator will handle the stop instruction and get the message address. + // It expects to find the address just after the svc instruction. + BlockConstPoolFor(2); + if (code >= 0) { + svc(kStopInterruptCode + code, cond); + } else { + svc(kStopInterruptCode + kMaxStopCode, cond); + } + emit(reinterpret_cast(msg)); #else // def __arm__ #ifdef CAN_USE_ARMV5_INSTRUCTIONS bkpt(0); #else // ndef CAN_USE_ARMV5_INSTRUCTIONS - swi(0x9f0001); + svc(0x9f0001); #endif // ndef CAN_USE_ARMV5_INSTRUCTIONS #endif // def __arm__ } @@ -1654,7 +1668,7 @@ void Assembler::bkpt(uint32_t imm16) { // v5 and above } -void Assembler::swi(uint32_t imm24, Condition cond) { +void Assembler::svc(uint32_t imm24, Condition cond) { ASSERT(is_uint24(imm24)); emit(cond | 15*B24 | imm24); } diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h index 1c4fd6094d..5b647a7537 100644 --- a/src/arm/assembler-arm.h +++ b/src/arm/assembler-arm.h @@ -904,10 +904,13 @@ class Assembler : public Malloced { void stm(BlockAddrMode am, Register base, RegList src, Condition cond = al); // Exception-generating instructions and debugging support - void stop(const char* msg); + static const int kDefaultStopCode = -1; + void stop(const char* msg, + Condition cond = al, + int32_t code = kDefaultStopCode); void bkpt(uint32_t imm16); // v5 and above - void swi(uint32_t imm24, Condition cond = al); + void svc(uint32_t imm24, Condition cond = al); // Coprocessor instructions diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h index b2b5cb56b0..123c5e7972 100644 --- a/src/arm/constants-arm.h +++ b/src/arm/constants-arm.h @@ -186,12 +186,18 @@ enum Shift { // Special Software Interrupt codes when used in the presence of the ARM // simulator. +// svc (formerly swi) provides a 24bit immediate value. Use bits 22:0 for +// standard SoftwareInterrupCode. Bit 23 is reserved for the stop feature. enum SoftwareInterruptCodes { // transition to C code call_rt_redirected = 0x10, // break point - break_point = 0x20 + break_point = 0x20, + // stop + stop = 1 << 23 }; +static const int32_t kStopCodeMask = stop - 1; +static const uint32_t kMaxStopCode = stop - 1; // Type of VFP register. Determines register encoding. @@ -325,7 +331,7 @@ class Instr { inline int SImmed24Field() const { return ((InstructionBits() << 8) >> 8); } // Fields used in Software interrupt instructions - inline SoftwareInterruptCodes SwiField() const { + inline SoftwareInterruptCodes SvcField() const { return static_cast(Bits(23, 0)); } diff --git a/src/arm/cpu-arm.cc b/src/arm/cpu-arm.cc index a3bf48328d..e998b6f596 100644 --- a/src/arm/cpu-arm.cc +++ b/src/arm/cpu-arm.cc @@ -70,7 +70,7 @@ void CPU::FlushICache(void* start, size_t size) { // __arm__ may be defined in thumb mode. register uint32_t scno asm("r7") = __ARM_NR_cacheflush; asm volatile( - "swi 0x0" + "svc 0x0" : "=r" (beg) : "0" (beg), "r" (end), "r" (flg), "r" (scno)); #else @@ -83,7 +83,7 @@ void CPU::FlushICache(void* start, size_t size) { ".ARM \n" "1: push {r7} \n\t" "mov r7, %4 \n\t" - "swi 0x0 \n\t" + "svc 0x0 \n\t" "pop {r7} \n\t" "@ Enter THUMB Mode\n\t" "adr r3, 2f+1 \n\t" @@ -98,20 +98,20 @@ void CPU::FlushICache(void* start, size_t size) { #if defined (__arm__) && !defined(__thumb__) // __arm__ may be defined in thumb mode. asm volatile( - "swi %1" + "svc %1" : "=r" (beg) : "i" (__ARM_NR_cacheflush), "0" (beg), "r" (end), "r" (flg)); #else // Do not use the value of __ARM_NR_cacheflush in the inline assembly // below, because the thumb mode value would be used, which would be - // wrong, since we switch to ARM mode before executing the swi instruction + // wrong, since we switch to ARM mode before executing the svc instruction asm volatile( "@ Enter ARM Mode \n\t" "adr r3, 1f \n\t" "bx r3 \n\t" ".ALIGN 4 \n\t" ".ARM \n" - "1: swi 0x9f0002 \n" + "1: svc 0x9f0002 \n" "@ Enter THUMB Mode\n\t" "adr r3, 2f+1 \n\t" "bx r3 \n\t" diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc index 5122f437b9..4e7580f868 100644 --- a/src/arm/disasm-arm.cc +++ b/src/arm/disasm-arm.cc @@ -108,7 +108,7 @@ class Decoder { void PrintShiftImm(Instr* instr); void PrintShiftSat(Instr* instr); void PrintPU(Instr* instr); - void PrintSoftwareInterrupt(SoftwareInterruptCodes swi); + void PrintSoftwareInterrupt(SoftwareInterruptCodes svc); // Handle formatting of instructions and their options. int FormatRegister(Instr* instr, const char* option); @@ -126,8 +126,8 @@ class Decoder { void DecodeType4(Instr* instr); void DecodeType5(Instr* instr); void DecodeType6(Instr* instr); - void DecodeType7(Instr* instr); - void DecodeUnconditional(Instr* instr); + // Type 7 includes special Debugger instructions. + int DecodeType7(Instr* instr); // For VFP support. void DecodeTypeVFP(Instr* instr); void DecodeType6CoprocessorIns(Instr* instr); @@ -290,8 +290,8 @@ void Decoder::PrintPU(Instr* instr) { // Print SoftwareInterrupt codes. Factoring this out reduces the complexity of // the FormatOption method. -void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) { - switch (swi) { +void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes svc) { + switch (svc) { case call_rt_redirected: Print("call_rt_redirected"); return; @@ -299,9 +299,16 @@ void Decoder::PrintSoftwareInterrupt(SoftwareInterruptCodes swi) { Print("break_point"); return; default: - out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, - "%d", - swi); + if (svc >= stop) { + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d - 0x%x", + svc & kStopCodeMask, + svc & kStopCodeMask); + } else { + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "%d", + svc); + } return; } } @@ -553,9 +560,9 @@ int Decoder::FormatOption(Instr* instr, const char* format) { PrintShiftRm(instr); return 8; } - } else if (format[1] == 'w') { // 'swi - ASSERT(STRING_STARTS_WITH(format, "swi")); - PrintSoftwareInterrupt(instr->SwiField()); + } else if (format[1] == 'v') { // 'svc + ASSERT(STRING_STARTS_WITH(format, "svc")); + PrintSoftwareInterrupt(instr->SvcField()); return 3; } else if (format[1] == 'i') { // 'sign: signed extra loads and stores ASSERT(STRING_STARTS_WITH(format, "sign")); @@ -1004,72 +1011,27 @@ void Decoder::DecodeType6(Instr* instr) { } -void Decoder::DecodeType7(Instr* instr) { +int Decoder::DecodeType7(Instr* instr) { if (instr->Bit(24) == 1) { - Format(instr, "swi'cond 'swi"); + if (instr->SvcField() >= stop) { + Format(instr, "stop'cond 'svc"); + // Also print the stop message. Its address is encoded + // in the following 4 bytes. + out_buffer_pos_ += + v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, + "\n %p %08x stop message: %s", + reinterpret_cast(instr + Instr::kInstrSize), + *reinterpret_cast(instr + Instr::kInstrSize), + *reinterpret_cast(instr + Instr::kInstrSize)); + // We have decoded 2 * Instr::kInstrSize bytes. + return 2 * Instr::kInstrSize; + } else { + Format(instr, "svc'cond 'svc"); + } } else { DecodeTypeVFP(instr); } -} - -void Decoder::DecodeUnconditional(Instr* instr) { - if (instr->Bits(7, 4) == 0xB && instr->Bits(27, 25) == 0 && instr->HasL()) { - Format(instr, "'memop'h'pu 'rd, "); - bool immediate = instr->HasB(); - switch (instr->PUField()) { - case 0: { - // Post index, negative. - if (instr->HasW()) { - Unknown(instr); - break; - } - if (immediate) { - Format(instr, "['rn], #-'imm12"); - } else { - Format(instr, "['rn], -'rm"); - } - break; - } - case 1: { - // Post index, positive. - if (instr->HasW()) { - Unknown(instr); - break; - } - if (immediate) { - Format(instr, "['rn], #+'imm12"); - } else { - Format(instr, "['rn], +'rm"); - } - break; - } - case 2: { - // Pre index or offset, negative. - if (immediate) { - Format(instr, "['rn, #-'imm12]'w"); - } else { - Format(instr, "['rn, -'rm]'w"); - } - break; - } - case 3: { - // Pre index or offset, positive. - if (immediate) { - Format(instr, "['rn, #+'imm12]'w"); - } else { - Format(instr, "['rn, +'rm]'w"); - } - break; - } - default: { - // The PU field is a 2-bit field. - UNREACHABLE(); - break; - } - } - return; - } - Format(instr, "break 'msg"); + return Instr::kInstrSize; } @@ -1332,7 +1294,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) { "%08x ", instr->InstructionBits()); if (instr->ConditionField() == special_condition) { - DecodeUnconditional(instr); + UNIMPLEMENTED(); return Instr::kInstrSize; } switch (instr->TypeField()) { @@ -1362,8 +1324,7 @@ int Decoder::InstructionDecode(byte* instr_ptr) { break; } case 7: { - DecodeType7(instr); - break; + return DecodeType7(instr); } default: { // The type field is 3-bits in the ARM encoding. diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc index 534e394af1..cb91520f3a 100644 --- a/src/arm/simulator-arm.cc +++ b/src/arm/simulator-arm.cc @@ -112,15 +112,29 @@ static void InitializeCoverage() { void Debugger::Stop(Instr* instr) { - char* str = reinterpret_cast(instr->InstructionBits() & 0x0fffffff); - if (strlen(str) > 0) { + // Get the stop code. + uint32_t code = instr->SvcField() & kStopCodeMask; + // Retrieve the encoded address, which comes just after this stop. + char** msg_address = + reinterpret_cast(sim_->get_pc() + Instr::kInstrSize); + char* msg = *msg_address; + ASSERT(msg != NULL); + + // Update this stop description. + if (isWatchedStop(code) && !watched_stops[code].desc) { + watched_stops[code].desc = msg; + } + + if (strlen(msg) > 0) { if (coverage_log != NULL) { - fprintf(coverage_log, "%s\n", str); + fprintf(coverage_log, "%s\n", msg); fflush(coverage_log); } - instr->SetInstructionBits(0xe1a00000); // Overwrite with nop. + // Overwrite the instruction and address with nops. + instr->SetInstructionBits(kNopInstr); + reinterpret_cast(msg_address)->SetInstructionBits(kNopInstr); } - sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); + sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize); } #else // ndef GENERATED_CODE_COVERAGE @@ -130,9 +144,16 @@ static void InitializeCoverage() { void Debugger::Stop(Instr* instr) { - const char* str = (const char*)(instr->InstructionBits() & 0x0fffffff); - PrintF("Simulator hit %s\n", str); - sim_->set_pc(sim_->get_pc() + Instr::kInstrSize); + // Get the stop code. + uint32_t code = instr->SvcField() & kStopCodeMask; + // Retrieve the encoded address, which comes just after this stop. + char* msg = *reinterpret_cast(sim_->get_pc() + Instr::kInstrSize); + // Update this stop description. + if (sim_->isWatchedStop(code) && !sim_->watched_stops[code].desc) { + sim_->watched_stops[code].desc = msg; + } + PrintF("Simulator hit %s\n", msg); + sim_->set_pc(sim_->get_pc() + 2 * Instr::kInstrSize); Debug(); } #endif @@ -359,6 +380,7 @@ void Debugger::Debug() { // use a reasonably large buffer v8::internal::EmbeddedVector buffer; + byte* prev = NULL; byte* cur = NULL; byte* end = NULL; @@ -368,9 +390,9 @@ void Debugger::Debug() { } else if (argc == 2) { int32_t value; if (GetValue(arg1, &value)) { - cur = reinterpret_cast(value); - // no length parameter passed, assume 10 instructions - end = cur + (10 * Instr::kInstrSize); + cur = reinterpret_cast(sim_->get_pc()); + // Disassemble instructions. + end = cur + (value * Instr::kInstrSize); } } else { int32_t value1; @@ -382,10 +404,10 @@ void Debugger::Debug() { } while (cur < end) { - dasm.InstructionDecode(buffer, cur); + prev = cur; + cur += dasm.InstructionDecode(buffer, cur); PrintF(" 0x%08x %s\n", - reinterpret_cast(cur), buffer.start()); - cur += Instr::kInstrSize; + reinterpret_cast(prev), buffer.start()); } } else if (strcmp(cmd, "gdb") == 0) { PrintF("relinquishing control to gdb\n"); @@ -418,13 +440,58 @@ void Debugger::Debug() { PrintF("OVERFLOW flag: %d; ", sim_->overflow_vfp_flag_); PrintF("UNDERFLOW flag: %d; ", sim_->underflow_vfp_flag_); PrintF("INEXACT flag: %d; ", sim_->inexact_vfp_flag_); - } else if (strcmp(cmd, "unstop") == 0) { - intptr_t stop_pc = sim_->get_pc() - Instr::kInstrSize; + } else if (strcmp(cmd, "stop") == 0) { + int32_t value; + intptr_t stop_pc = sim_->get_pc() - 2 * Instr::kInstrSize; Instr* stop_instr = reinterpret_cast(stop_pc); - if (stop_instr->ConditionField() == special_condition) { - stop_instr->SetInstructionBits(kNopInstr); + Instr* msg_address = + reinterpret_cast(stop_pc + Instr::kInstrSize); + if ((argc == 2) && (strcmp(arg1, "unstop") == 0)) { + // Remove the current stop. + if (sim_->isStopInstruction(stop_instr)) { + stop_instr->SetInstructionBits(kNopInstr); + msg_address->SetInstructionBits(kNopInstr); + } else { + PrintF("Not at debugger stop.\n"); + } + } else if (argc == 3) { + // Print information about all/the specified breakpoint(s). + if (strcmp(arg1, "info") == 0) { + if (strcmp(arg2, "all") == 0) { + PrintF("Stop information:\n"); + for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) { + sim_->PrintStopInfo(i); + } + } else if (GetValue(arg2, &value)) { + sim_->PrintStopInfo(value); + } else { + PrintF("Unrecognized argument.\n"); + } + } else if (strcmp(arg1, "enable") == 0) { + // Enable all/the specified breakpoint(s). + if (strcmp(arg2, "all") == 0) { + for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) { + sim_->EnableStop(i); + } + } else if (GetValue(arg2, &value)) { + sim_->EnableStop(value); + } else { + PrintF("Unrecognized argument.\n"); + } + } else if (strcmp(arg1, "disable") == 0) { + // Disable all/the specified breakpoint(s). + if (strcmp(arg2, "all") == 0) { + for (uint32_t i = 0; i < sim_->kNumOfWatchedStops; i++) { + sim_->DisableStop(i); + } + } else if (GetValue(arg2, &value)) { + sim_->DisableStop(value); + } else { + PrintF("Unrecognized argument.\n"); + } + } } else { - PrintF("Not at debugger stop."); + PrintF("Wrong usage. Use help command for more information.\n"); } } else if ((strcmp(cmd, "t") == 0) || strcmp(cmd, "trace") == 0) { ::v8::internal::FLAG_trace_sim = !::v8::internal::FLAG_trace_sim; @@ -455,11 +522,29 @@ void Debugger::Debug() { PrintF(" set a break point on the address\n"); PrintF("del\n"); PrintF(" delete the breakpoint\n"); - PrintF("unstop\n"); - PrintF(" ignore the stop instruction at the current location"); - PrintF(" from now on\n"); PrintF("trace (alias 't')\n"); PrintF(" toogle the tracing of all executed statements\n"); + PrintF("stop feature:\n"); + PrintF(" Description:\n"); + PrintF(" Stops are debug instructions inserted by\n"); + PrintF(" the Assembler::stop() function.\n"); + PrintF(" When hitting a stop, the Simulator will\n"); + PrintF(" stop and and give control to the Debugger.\n"); + PrintF(" The first %d stop codes are watched:\n", + Simulator::kNumOfWatchedStops); + PrintF(" - They can be enabled / disabled: the Simulator\n"); + PrintF(" will / won't stop when hitting them.\n"); + PrintF(" - The Simulator keeps track of how many times they \n"); + PrintF(" are met. (See the info command.) Going over a\n"); + PrintF(" disabled stop still increases its counter. \n"); + PrintF(" Commands:\n"); + PrintF(" stop info all/ : print infos about number \n"); + PrintF(" or all stop(s).\n"); + PrintF(" stop enable/disable all/ : enables / disables\n"); + PrintF(" all or number stop(s)\n"); + PrintF(" stop unstop\n"); + PrintF(" ignore the stop instruction at the current location\n"); + PrintF(" from now on\n"); } else { PrintF("Unknown command: %s\n", cmd); } @@ -643,9 +728,9 @@ Simulator::Simulator() { // the simulator. The external reference will be a function compiled for the // host architecture. We need to call that function instead of trying to // execute it with the simulator. We do that by redirecting the external -// reference to a swi (software-interrupt) instruction that is handled by +// reference to a svc (Supervisor Call) instruction that is handled by // the simulator. We write the original destination of the jump just at a known -// offset from the swi instruction so the simulator knows what to call. +// offset from the svc instruction so the simulator knows what to call. class Redirection { public: Redirection(void* external_function, bool fp_return) @@ -1434,8 +1519,8 @@ typedef double (*SimulatorRuntimeFPCall)(int32_t arg0, // Software interrupt instructions are used by the simulator to call into the // C-based V8 runtime. void Simulator::SoftwareInterrupt(Instr* instr) { - int swi = instr->SwiField(); - switch (swi) { + int svc = instr->SvcField(); + switch (svc) { case call_rt_redirected: { // Check if stack is aligned. Error if not aligned is reported below to // include information on the function called. @@ -1505,9 +1590,98 @@ void Simulator::SoftwareInterrupt(Instr* instr) { dbg.Debug(); break; } + // stop uses all codes greater than 1 << 23. default: { - UNREACHABLE(); - break; + if (svc >= (1 << 23)) { + uint32_t code = svc & kStopCodeMask; + if (isWatchedStop(code)) { + IncreaseStopCounter(code); + } + // Stop if it is enabled, otherwise go on jumping over the stop + // and the message address. + if (isEnabledStop(code)) { + Debugger dbg(this); + dbg.Stop(instr); + } else { + set_pc(get_pc() + 2 * Instr::kInstrSize); + } + } else { + // This is not a valid svc code. + UNREACHABLE(); + break; + } + } + } +} + + +// Stop helper functions. +bool Simulator::isStopInstruction(Instr* instr) { + return (instr->Bits(27, 24) == 0xF) && (instr->SvcField() >= stop); +} + + +bool Simulator::isWatchedStop(uint32_t code) { + ASSERT(code <= kMaxStopCode); + return code < kNumOfWatchedStops; +} + + +bool Simulator::isEnabledStop(uint32_t code) { + ASSERT(code <= kMaxStopCode); + // Unwatched stops are always enabled. + return !isWatchedStop(code) || + !(watched_stops[code].count & kStopDisabledBit); +} + + +void Simulator::EnableStop(uint32_t code) { + ASSERT(isWatchedStop(code)); + if (!isEnabledStop(code)) { + watched_stops[code].count &= ~kStopDisabledBit; + } +} + + +void Simulator::DisableStop(uint32_t code) { + ASSERT(isWatchedStop(code)); + if (isEnabledStop(code)) { + watched_stops[code].count |= kStopDisabledBit; + } +} + + +void Simulator::IncreaseStopCounter(uint32_t code) { + ASSERT(code <= kMaxStopCode); + ASSERT(isWatchedStop(code)); + if ((watched_stops[code].count & ~(1 << 31)) == 0x7fffffff) { + PrintF("Stop counter for code %i has overflowed.\n" + "Enabling this code and reseting the counter to 0.\n", code); + watched_stops[code].count = 0; + EnableStop(code); + } else { + watched_stops[code].count++; + } +} + + +// Print a stop status. +void Simulator::PrintStopInfo(uint32_t code) { + ASSERT(code <= kMaxStopCode); + if (!isWatchedStop(code)) { + PrintF("Stop not watched."); + } else { + const char* state = isEnabledStop(code) ? "Enabled" : "Disabled"; + int32_t count = watched_stops[code].count & ~kStopDisabledBit; + // Don't print the state of unused breakpoints. + if (count != 0) { + if (watched_stops[code].desc) { + PrintF("stop %i - 0x%x: \t%s, \tcounter = %i, \t%s\n", + code, code, state, count, watched_stops[code].desc); + } else { + PrintF("stop %i - 0x%x: \t%s, \tcounter = %i\n", + code, code, state, count); + } } } } @@ -2216,73 +2390,6 @@ void Simulator::DecodeType7(Instr* instr) { } -void Simulator::DecodeUnconditional(Instr* instr) { - if (instr->Bits(7, 4) == 0x0B && instr->Bits(27, 25) == 0 && instr->HasL()) { - // Load halfword instruction, either register or immediate offset. - int rd = instr->RdField(); - int rn = instr->RnField(); - int32_t rn_val = get_register(rn); - int32_t addr = 0; - int32_t offset; - if (instr->Bit(22) == 0) { - // Register offset. - int rm = instr->RmField(); - offset = get_register(rm); - } else { - // Immediate offset - offset = instr->Bits(3, 0) + (instr->Bits(11, 8) << 4); - } - switch (instr->PUField()) { - case 0: { - // Post index, negative. - ASSERT(!instr->HasW()); - addr = rn_val; - rn_val -= offset; - set_register(rn, rn_val); - break; - } - case 1: { - // Post index, positive. - ASSERT(!instr->HasW()); - addr = rn_val; - rn_val += offset; - set_register(rn, rn_val); - break; - } - case 2: { - // Pre index or offset, negative. - rn_val -= offset; - addr = rn_val; - if (instr->HasW()) { - set_register(rn, rn_val); - } - break; - } - case 3: { - // Pre index or offset, positive. - rn_val += offset; - addr = rn_val; - if (instr->HasW()) { - set_register(rn, rn_val); - } - break; - } - default: { - // The PU field is a 2-bit field. - UNREACHABLE(); - break; - } - } - // Not sign extending, so load as unsigned. - uint16_t halfword = ReadH(addr, instr); - set_register(rd, halfword); - } else { - Debugger dbg(this); - dbg.Stop(instr); - } -} - - // void Simulator::DecodeTypeVFP(Instr* instr) // The Following ARMv7 VFPv instructions are currently supported. // vmov :Sn = Rt @@ -2655,7 +2762,7 @@ void Simulator::InstructionDecode(Instr* instr) { PrintF(" 0x%08x %s\n", reinterpret_cast(instr), buffer.start()); } if (instr->ConditionField() == special_condition) { - DecodeUnconditional(instr); + UNIMPLEMENTED(); } else if (ConditionallyExecute(instr)) { switch (instr->TypeField()) { case 0: diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h index e0658fc997..3e023489ee 100644 --- a/src/arm/simulator-arm.h +++ b/src/arm/simulator-arm.h @@ -226,6 +226,15 @@ class Simulator { void HandleRList(Instr* instr, bool load); void SoftwareInterrupt(Instr* instr); + // Stop helper functions. + inline bool isStopInstruction(Instr* instr); + inline bool isWatchedStop(uint32_t bkpt_code); + inline bool isEnabledStop(uint32_t bkpt_code); + inline void EnableStop(uint32_t bkpt_code); + inline void DisableStop(uint32_t bkpt_code); + inline void IncreaseStopCounter(uint32_t bkpt_code); + void PrintStopInfo(uint32_t code); + // Read and write memory. inline uint8_t ReadBU(int32_t addr); inline int8_t ReadB(int32_t addr); @@ -252,7 +261,6 @@ class Simulator { void DecodeType5(Instr* instr); void DecodeType6(Instr* instr); void DecodeType7(Instr* instr); - void DecodeUnconditional(Instr* instr); // Support for VFP. void DecodeTypeVFP(Instr* instr); @@ -317,6 +325,23 @@ class Simulator { // Registered breakpoints. Instr* break_pc_; instr_t break_instr_; + + // A stop is watched if its code is less than kNumOfWatchedStops. + // Only watched stops support enabling/disabling and the counter feature. + static const uint32_t kNumOfWatchedStops = 256; + + // Breakpoint is disabled if bit 31 is set. + static const uint32_t kStopDisabledBit = 1 << 31; + + // A stop is enabled, meaning the simulator will stop when meeting the + // instruction, if bit 31 of watched_stops[code].count is unset. + // The value watched_stops[code].count & ~(1 << 31) indicates how many times + // the breakpoint was hit or gone through. + struct StopCoundAndDesc { + uint32_t count; + char* desc; + }; + StopCoundAndDesc watched_stops[kNumOfWatchedStops]; }; } } // namespace assembler::arm