Commit 21228278 authored by ager@chromium.org's avatar ager@chromium.org

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
parent c964e478
......@@ -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<Instr>(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);
}
......
......@@ -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
......
......@@ -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<SoftwareInterruptCodes>(Bits(23, 0));
}
......
......@@ -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"
......
......@@ -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<int32_t*>(instr + Instr::kInstrSize),
*reinterpret_cast<char**>(instr + Instr::kInstrSize),
*reinterpret_cast<char**>(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.
......
This diff is collapsed.
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment