Index: src/arm64/simulator-arm64.cc |
diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc |
index 2e43dfc2219336d03c85c1dbe0866c5caac28ac5..277275c87d5e85f66d3730bc513af48459370322 100644 |
--- a/src/arm64/simulator-arm64.cc |
+++ b/src/arm64/simulator-arm64.cc |
@@ -30,30 +30,28 @@ namespace internal { |
// Helpers for colors. |
-// Depending on your terminal configuration, the colour names may not match the |
-// observed colours. |
-#define COLOUR(colour_code) "\033[" colour_code "m" |
-#define BOLD(colour_code) "1;" colour_code |
-#define NORMAL "" |
-#define GREY "30" |
-#define GREEN "32" |
-#define ORANGE "33" |
-#define BLUE "34" |
-#define PURPLE "35" |
-#define INDIGO "36" |
-#define WHITE "37" |
+#define COLOUR(colour_code) "\033[0;" colour_code "m" |
+#define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m" |
+#define NORMAL "" |
+#define GREY "30" |
+#define RED "31" |
+#define GREEN "32" |
+#define YELLOW "33" |
+#define BLUE "34" |
+#define MAGENTA "35" |
+#define CYAN "36" |
+#define WHITE "37" |
typedef char const * const TEXT_COLOUR; |
TEXT_COLOUR clr_normal = FLAG_log_colour ? COLOUR(NORMAL) : ""; |
-TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR(BOLD(GREY)) : ""; |
-TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(BOLD(WHITE)) : ""; |
-TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR(BOLD(BLUE)) : ""; |
-TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(BOLD(INDIGO)) : ""; |
-TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR(BOLD(ORANGE)) : ""; |
-TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(BOLD(PURPLE)) : ""; |
-TEXT_COLOUR clr_memory_value = FLAG_log_colour ? COLOUR(BOLD(GREEN)) : ""; |
-TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR(GREEN) : ""; |
-TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR(BOLD(ORANGE)) : ""; |
-TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(ORANGE) : ""; |
+TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR_BOLD(WHITE) : ""; |
+TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(NORMAL) : ""; |
+TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) : ""; |
+TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) : ""; |
+TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : ""; |
+TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : ""; |
+TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) : ""; |
+TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) : ""; |
+TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) : ""; |
TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : ""; |
@@ -337,7 +335,7 @@ uintptr_t Simulator::PopAddress() { |
uintptr_t Simulator::StackLimit() const { |
// Leave a safety margin of 1024 bytes to prevent overrunning the stack when |
// pushing values. |
- return reinterpret_cast<uintptr_t>(stack_limit_) + 1024; |
+ return stack_limit_ + 1024; |
} |
@@ -380,11 +378,11 @@ void Simulator::Init(FILE* stream) { |
// Allocate and setup the simulator stack. |
stack_size_ = (FLAG_sim_stack_size * KB) + (2 * stack_protection_size_); |
- stack_ = new byte[stack_size_]; |
+ stack_ = reinterpret_cast<uintptr_t>(new byte[stack_size_]); |
stack_limit_ = stack_ + stack_protection_size_; |
- byte* tos = stack_ + stack_size_ - stack_protection_size_; |
- // The stack pointer must be 16 bytes aligned. |
- set_sp(reinterpret_cast<int64_t>(tos) & ~0xfUL); |
+ uintptr_t tos = stack_ + stack_size_ - stack_protection_size_; |
+ // The stack pointer must be 16-byte aligned. |
+ set_sp(tos & ~0xfUL); |
stream_ = stream; |
print_disasm_ = new PrintDisassembler(stream_); |
@@ -420,7 +418,7 @@ void Simulator::ResetState() { |
Simulator::~Simulator() { |
- delete[] stack_; |
+ delete[] reinterpret_cast<byte*>(stack_); |
if (FLAG_log_instruction_stats) { |
delete instrument_; |
} |
@@ -734,15 +732,15 @@ void* Simulator::RedirectExternalReference(void* external_function, |
const char* Simulator::xreg_names[] = { |
-"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", |
-"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", |
-"ip0", "ip1", "x18", "x19", "x20", "x21", "x22", "x23", |
-"x24", "x25", "x26", "cp", "jssp", "fp", "lr", "xzr", "csp"}; |
+"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", |
+"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", |
+"ip0", "ip1", "x18", "x19", "x20", "x21", "x22", "x23", |
+"x24", "x25", "x26", "cp", "jssp", "fp", "lr", "xzr", "csp"}; |
const char* Simulator::wreg_names[] = { |
-"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", |
-"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", |
-"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", |
+"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", |
+"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", |
+"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", |
"w24", "w25", "w26", "wcp", "wjssp", "wfp", "wlr", "wzr", "wcsp"}; |
const char* Simulator::sreg_names[] = { |
@@ -765,7 +763,12 @@ const char* Simulator::vreg_names[] = { |
const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) { |
+ STATIC_ASSERT(arraysize(Simulator::wreg_names) == (kNumberOfRegisters + 1)); |
DCHECK(code < kNumberOfRegisters); |
+ // The modulo operator has no effect here, but it silences a broken GCC |
+ // warning about out-of-bounds array accesses. |
+ code %= kNumberOfRegisters; |
+ |
// If the code represents the stack pointer, index the name after zr. |
if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { |
code = kZeroRegCode + 1; |
@@ -775,7 +778,10 @@ const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) { |
const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) { |
+ STATIC_ASSERT(arraysize(Simulator::xreg_names) == (kNumberOfRegisters + 1)); |
DCHECK(code < kNumberOfRegisters); |
+ code %= kNumberOfRegisters; |
+ |
// If the code represents the stack pointer, index the name after zr. |
if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { |
code = kZeroRegCode + 1; |
@@ -785,20 +791,23 @@ const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) { |
const char* Simulator::SRegNameForCode(unsigned code) { |
+ STATIC_ASSERT(arraysize(Simulator::sreg_names) == kNumberOfFPRegisters); |
DCHECK(code < kNumberOfFPRegisters); |
- return sreg_names[code]; |
+ return sreg_names[code % kNumberOfFPRegisters]; |
} |
const char* Simulator::DRegNameForCode(unsigned code) { |
+ STATIC_ASSERT(arraysize(Simulator::dreg_names) == kNumberOfFPRegisters); |
DCHECK(code < kNumberOfFPRegisters); |
- return dreg_names[code]; |
+ return dreg_names[code % kNumberOfFPRegisters]; |
} |
const char* Simulator::VRegNameForCode(unsigned code) { |
+ STATIC_ASSERT(arraysize(Simulator::vreg_names) == kNumberOfFPRegisters); |
DCHECK(code < kNumberOfFPRegisters); |
- return vreg_names[code]; |
+ return vreg_names[code % kNumberOfFPRegisters]; |
} |
@@ -855,6 +864,7 @@ T Simulator::AddWithCarry(bool set_flags, |
nzcv().SetZ(Z); |
nzcv().SetC(C); |
nzcv().SetV(V); |
+ LogSystemRegister(NZCV); |
} |
return result; |
} |
@@ -978,6 +988,7 @@ void Simulator::FPCompare(double val0, double val1) { |
} else { |
UNREACHABLE(); |
} |
+ LogSystemRegister(NZCV); |
} |
@@ -1044,117 +1055,206 @@ void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) { |
} |
-void Simulator::PrintSystemRegisters(bool print_all) { |
- static bool first_run = true; |
- |
- static SimSystemRegister last_nzcv; |
- if (print_all || first_run || (last_nzcv.RawValue() != nzcv().RawValue())) { |
- fprintf(stream_, "# %sFLAGS: %sN:%d Z:%d C:%d V:%d%s\n", |
- clr_flag_name, |
- clr_flag_value, |
- nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(), |
- clr_normal); |
- } |
- last_nzcv = nzcv(); |
- |
- static SimSystemRegister last_fpcr; |
- if (print_all || first_run || (last_fpcr.RawValue() != fpcr().RawValue())) { |
- static const char * rmode[] = { |
- "0b00 (Round to Nearest)", |
- "0b01 (Round towards Plus Infinity)", |
- "0b10 (Round towards Minus Infinity)", |
- "0b11 (Round towards Zero)" |
- }; |
- DCHECK(fpcr().RMode() < arraysize(rmode)); |
- fprintf(stream_, "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n", |
- clr_flag_name, |
- clr_flag_value, |
- fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()], |
- clr_normal); |
- } |
- last_fpcr = fpcr(); |
- |
- first_run = false; |
+void Simulator::PrintSystemRegisters() { |
+ PrintSystemRegister(NZCV); |
+ PrintSystemRegister(FPCR); |
} |
-void Simulator::PrintRegisters(bool print_all_regs) { |
- static bool first_run = true; |
- static int64_t last_regs[kNumberOfRegisters]; |
- |
+void Simulator::PrintRegisters() { |
for (unsigned i = 0; i < kNumberOfRegisters; i++) { |
- if (print_all_regs || first_run || |
- (last_regs[i] != xreg(i, Reg31IsStackPointer))) { |
- fprintf(stream_, |
- "# %s%4s:%s 0x%016" PRIx64 "%s\n", |
- clr_reg_name, |
- XRegNameForCode(i, Reg31IsStackPointer), |
- clr_reg_value, |
- xreg(i, Reg31IsStackPointer), |
- clr_normal); |
- } |
- // Cache the new register value so the next run can detect any changes. |
- last_regs[i] = xreg(i, Reg31IsStackPointer); |
+ PrintRegister(i); |
} |
- first_run = false; |
} |
-void Simulator::PrintFPRegisters(bool print_all_regs) { |
- static bool first_run = true; |
- static uint64_t last_regs[kNumberOfFPRegisters]; |
- |
- // Print as many rows of registers as necessary, keeping each individual |
- // register in the same column each time (to make it easy to visually scan |
- // for changes). |
+void Simulator::PrintFPRegisters() { |
for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { |
- if (print_all_regs || first_run || (last_regs[i] != dreg_bits(i))) { |
+ PrintFPRegister(i); |
+ } |
+} |
+ |
+ |
+void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) { |
+ // Don't print writes into xzr. |
+ if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) { |
+ return; |
+ } |
+ |
+ // The template is "# x<code>:value". |
+ fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s\n", |
+ clr_reg_name, XRegNameForCode(code, r31mode), |
+ clr_reg_value, reg<uint64_t>(code, r31mode), clr_normal); |
+} |
+ |
+ |
+void Simulator::PrintFPRegister(unsigned code, PrintFPRegisterSizes sizes) { |
+ // The template is "# v<code>:bits (d<code>:value, ...)". |
+ |
+ DCHECK(sizes != 0); |
+ DCHECK((sizes & kPrintAllFPRegValues) == sizes); |
+ |
+ // Print the raw bits. |
+ fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (", |
+ clr_fpreg_name, VRegNameForCode(code), |
+ clr_fpreg_value, fpreg<uint64_t>(code), clr_normal); |
+ |
+ // Print all requested value interpretations. |
+ bool need_separator = false; |
+ if (sizes & kPrintDRegValue) { |
+ fprintf(stream_, "%s%s%s: %s%g%s", |
+ need_separator ? ", " : "", |
+ clr_fpreg_name, DRegNameForCode(code), |
+ clr_fpreg_value, fpreg<double>(code), clr_normal); |
+ need_separator = true; |
+ } |
+ |
+ if (sizes & kPrintSRegValue) { |
+ fprintf(stream_, "%s%s%s: %s%g%s", |
+ need_separator ? ", " : "", |
+ clr_fpreg_name, SRegNameForCode(code), |
+ clr_fpreg_value, fpreg<float>(code), clr_normal); |
+ need_separator = true; |
+ } |
+ |
+ // End the value list. |
+ fprintf(stream_, ")\n"); |
+} |
+ |
+ |
+void Simulator::PrintSystemRegister(SystemRegister id) { |
+ switch (id) { |
+ case NZCV: |
+ fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n", |
+ clr_flag_name, clr_flag_value, |
+ nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(), |
+ clr_normal); |
+ break; |
+ case FPCR: { |
+ static const char * rmode[] = { |
+ "0b00 (Round to Nearest)", |
+ "0b01 (Round towards Plus Infinity)", |
+ "0b10 (Round towards Minus Infinity)", |
+ "0b11 (Round towards Zero)" |
+ }; |
+ DCHECK(fpcr().RMode() < arraysize(rmode)); |
fprintf(stream_, |
- "# %s %4s:%s 0x%016" PRIx64 "%s (%s%s:%s %g%s %s:%s %g%s)\n", |
- clr_fpreg_name, |
- VRegNameForCode(i), |
- clr_fpreg_value, |
- dreg_bits(i), |
- clr_normal, |
- clr_fpreg_name, |
- DRegNameForCode(i), |
- clr_fpreg_value, |
- dreg(i), |
- clr_fpreg_name, |
- SRegNameForCode(i), |
- clr_fpreg_value, |
- sreg(i), |
+ "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n", |
+ clr_flag_name, clr_flag_value, |
+ fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()], |
clr_normal); |
+ break; |
} |
- // Cache the new register value so the next run can detect any changes. |
- last_regs[i] = dreg_bits(i); |
+ default: |
+ UNREACHABLE(); |
} |
- first_run = false; |
} |
-void Simulator::PrintProcessorState() { |
- PrintSystemRegisters(); |
- PrintRegisters(); |
- PrintFPRegisters(); |
+void Simulator::PrintRead(uintptr_t address, |
+ size_t size, |
+ unsigned reg_code) { |
+ USE(size); // Size is unused here. |
+ |
+ // The template is "# x<code>:value <- address". |
+ fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s", |
+ clr_reg_name, XRegNameForCode(reg_code), |
+ clr_reg_value, reg<uint64_t>(reg_code), clr_normal); |
+ |
+ fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", |
+ clr_memory_address, address, clr_normal); |
+} |
+ |
+ |
+void Simulator::PrintReadFP(uintptr_t address, |
+ size_t size, |
+ unsigned reg_code) { |
+ // The template is "# reg:bits (reg:value) <- address". |
+ switch (size) { |
+ case kSRegSize: |
+ fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%gf%s)", |
+ clr_fpreg_name, VRegNameForCode(reg_code), |
+ clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal, |
+ clr_fpreg_name, SRegNameForCode(reg_code), |
+ clr_fpreg_value, fpreg<float>(reg_code), clr_normal); |
+ break; |
+ case kDRegSize: |
+ fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)", |
+ clr_fpreg_name, VRegNameForCode(reg_code), |
+ clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal, |
+ clr_fpreg_name, DRegNameForCode(reg_code), |
+ clr_fpreg_value, fpreg<double>(reg_code), clr_normal); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ |
+ fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n", |
+ clr_memory_address, address, clr_normal); |
} |
-void Simulator::PrintWrite(uintptr_t address, uint64_t value, |
- unsigned num_bytes) { |
- // The template is "# value -> address". The format string is not used |
- // directly in the printf because some compilers struggle with the |
- // parametrized width field (%0*). |
- const char* format = "# %s0x%0*" PRIx64 "%s -> %s0x%016" PRIxPTR "%s\n"; |
- fprintf(stream_, |
- format, |
- clr_memory_value, |
- num_bytes * 2, // The width in hexadecimal characters. |
- value, |
- clr_normal, |
- clr_memory_address, |
- address, |
- clr_normal); |
+void Simulator::PrintWrite(uintptr_t address, |
+ size_t size, |
+ unsigned reg_code) { |
+ // The template is "# reg:value -> address". To keep the trace tidy and |
+ // readable, the value is aligned with the values in the register trace. |
+ switch (size) { |
+ case kByteSizeInBytes: |
+ fprintf(stream_, "# %s%5s<7:0>: %s0x%02" PRIx8 "%s", |
+ clr_reg_name, WRegNameForCode(reg_code), |
+ clr_reg_value, reg<uint8_t>(reg_code), clr_normal); |
+ break; |
+ case kHalfWordSizeInBytes: |
+ fprintf(stream_, "# %s%5s<15:0>: %s0x%04" PRIx16 "%s", |
+ clr_reg_name, WRegNameForCode(reg_code), |
+ clr_reg_value, reg<uint16_t>(reg_code), clr_normal); |
+ break; |
+ case kWRegSize: |
+ fprintf(stream_, "# %s%5s: %s0x%08" PRIx32 "%s", |
+ clr_reg_name, WRegNameForCode(reg_code), |
+ clr_reg_value, reg<uint32_t>(reg_code), clr_normal); |
+ break; |
+ case kXRegSize: |
+ fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s", |
+ clr_reg_name, XRegNameForCode(reg_code), |
+ clr_reg_value, reg<uint64_t>(reg_code), clr_normal); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ |
+ fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", |
+ clr_memory_address, address, clr_normal); |
+} |
+ |
+ |
+void Simulator::PrintWriteFP(uintptr_t address, |
+ size_t size, |
+ unsigned reg_code) { |
+ // The template is "# reg:bits (reg:value) -> address". To keep the trace tidy |
+ // and readable, the value is aligned with the values in the register trace. |
+ switch (size) { |
+ case kSRegSize: |
+ fprintf(stream_, "# %s%5s<31:0>: %s0x%08" PRIx32 "%s (%s%s: %s%gf%s)", |
+ clr_fpreg_name, VRegNameForCode(reg_code), |
+ clr_fpreg_value, fpreg<uint32_t>(reg_code), clr_normal, |
+ clr_fpreg_name, SRegNameForCode(reg_code), |
+ clr_fpreg_value, fpreg<float>(reg_code), clr_normal); |
+ break; |
+ case kDRegSize: |
+ fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)", |
+ clr_fpreg_name, VRegNameForCode(reg_code), |
+ clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal, |
+ clr_fpreg_name, DRegNameForCode(reg_code), |
+ clr_fpreg_value, fpreg<double>(reg_code), clr_normal); |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ |
+ fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n", |
+ clr_memory_address, address, clr_normal); |
} |
@@ -1383,6 +1483,7 @@ void Simulator::LogicalHelper(Instruction* instr, T op2) { |
nzcv().SetZ(CalcZFlag(result)); |
nzcv().SetC(0); |
nzcv().SetV(0); |
+ LogSystemRegister(NZCV); |
} |
set_reg<T>(instr->Rd(), result, instr->RdMode()); |
@@ -1423,6 +1524,7 @@ void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) { |
} else { |
// If the condition fails, set the status flags to the nzcv immediate. |
nzcv().SetFlags(instr->Nzcv()); |
+ LogSystemRegister(NZCV); |
} |
} |
@@ -1463,8 +1565,8 @@ void Simulator::LoadStoreHelper(Instruction* instr, |
AddrMode addrmode) { |
unsigned srcdst = instr->Rt(); |
unsigned addr_reg = instr->Rn(); |
- uint8_t* address = LoadStoreAddress(addr_reg, offset, addrmode); |
- uint8_t* stack = NULL; |
+ uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode); |
+ uintptr_t stack = 0; |
// Handle the writeback for stores before the store. On a CPU the writeback |
// and the store are atomic, but when running on the simulator it is possible |
@@ -1478,22 +1580,24 @@ void Simulator::LoadStoreHelper(Instruction* instr, |
// For store the address post writeback is used to check access below the |
// stack. |
- stack = reinterpret_cast<uint8_t*>(sp()); |
+ stack = sp(); |
} |
LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreOpMask)); |
switch (op) { |
- case LDRB_w: set_wreg(srcdst, MemoryRead<uint8_t>(address)); break; |
- case LDRH_w: set_wreg(srcdst, MemoryRead<uint16_t>(address)); break; |
- case LDR_w: set_wreg(srcdst, MemoryRead<uint32_t>(address)); break; |
- case LDR_x: set_xreg(srcdst, MemoryRead<uint64_t>(address)); break; |
- case LDRSB_w: set_wreg(srcdst, MemoryRead<int8_t>(address)); break; |
- case LDRSH_w: set_wreg(srcdst, MemoryRead<int16_t>(address)); break; |
- case LDRSB_x: set_xreg(srcdst, MemoryRead<int8_t>(address)); break; |
- case LDRSH_x: set_xreg(srcdst, MemoryRead<int16_t>(address)); break; |
- case LDRSW_x: set_xreg(srcdst, MemoryRead<int32_t>(address)); break; |
- case LDR_s: set_sreg(srcdst, MemoryRead<float>(address)); break; |
- case LDR_d: set_dreg(srcdst, MemoryRead<double>(address)); break; |
+ // Use _no_log variants to suppress the register trace (LOG_REGS, |
+ // LOG_FP_REGS). We will print a more detailed log. |
+ case LDRB_w: set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address)); break; |
+ case LDRH_w: set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address)); break; |
+ case LDR_w: set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address)); break; |
+ case LDR_x: set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address)); break; |
+ case LDRSB_w: set_wreg_no_log(srcdst, MemoryRead<int8_t>(address)); break; |
+ case LDRSH_w: set_wreg_no_log(srcdst, MemoryRead<int16_t>(address)); break; |
+ case LDRSB_x: set_xreg_no_log(srcdst, MemoryRead<int8_t>(address)); break; |
+ case LDRSH_x: set_xreg_no_log(srcdst, MemoryRead<int16_t>(address)); break; |
+ case LDRSW_x: set_xreg_no_log(srcdst, MemoryRead<int32_t>(address)); break; |
+ case LDR_s: set_sreg_no_log(srcdst, MemoryRead<float>(address)); break; |
+ case LDR_d: set_dreg_no_log(srcdst, MemoryRead<double>(address)); break; |
case STRB_w: MemoryWrite<uint8_t>(address, wreg(srcdst)); break; |
case STRH_w: MemoryWrite<uint16_t>(address, wreg(srcdst)); break; |
@@ -1505,6 +1609,23 @@ void Simulator::LoadStoreHelper(Instruction* instr, |
default: UNIMPLEMENTED(); |
} |
+ // Print a detailed trace (including the memory address) instead of the basic |
+ // register:value trace generated by set_*reg(). |
+ size_t access_size = 1 << instr->SizeLS(); |
+ if (instr->IsLoad()) { |
+ if ((op == LDR_s) || (op == LDR_d)) { |
+ LogReadFP(address, access_size, srcdst); |
+ } else { |
+ LogRead(address, access_size, srcdst); |
+ } |
+ } else { |
+ if ((op == STR_s) || (op == STR_d)) { |
+ LogWriteFP(address, access_size, srcdst); |
+ } else { |
+ LogWrite(address, access_size, srcdst); |
+ } |
+ } |
+ |
// Handle the writeback for loads after the load to ensure safe pop |
// operation even when interrupted in the middle of it. The stack pointer |
// is only updated after the load so pop(fp) will never break the invariant |
@@ -1512,7 +1633,7 @@ void Simulator::LoadStoreHelper(Instruction* instr, |
if (instr->IsLoad()) { |
// For loads the address pre writeback is used to check access below the |
// stack. |
- stack = reinterpret_cast<uint8_t*>(sp()); |
+ stack = sp(); |
LoadStoreWriteBack(addr_reg, offset, addrmode); |
} |
@@ -1548,9 +1669,11 @@ void Simulator::LoadStorePairHelper(Instruction* instr, |
unsigned rt = instr->Rt(); |
unsigned rt2 = instr->Rt2(); |
unsigned addr_reg = instr->Rn(); |
- int offset = instr->ImmLSPair() << instr->SizeLSPair(); |
- uint8_t* address = LoadStoreAddress(addr_reg, offset, addrmode); |
- uint8_t* stack = NULL; |
+ size_t access_size = 1 << instr->SizeLSPair(); |
+ int64_t offset = instr->ImmLSPair() * access_size; |
+ uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode); |
+ uintptr_t address2 = address + access_size; |
+ uintptr_t stack = 0; |
// Handle the writeback for stores before the store. On a CPU the writeback |
// and the store are atomic, but when running on the simulator it is possible |
@@ -1564,7 +1687,7 @@ void Simulator::LoadStorePairHelper(Instruction* instr, |
// For store the address post writeback is used to check access below the |
// stack. |
- stack = reinterpret_cast<uint8_t*>(sp()); |
+ stack = sp(); |
} |
LoadStorePairOp op = |
@@ -1574,54 +1697,85 @@ void Simulator::LoadStorePairHelper(Instruction* instr, |
DCHECK(((op & LoadStorePairLBit) == 0) || (rt != rt2)); |
switch (op) { |
+ // Use _no_log variants to suppress the register trace (LOG_REGS, |
+ // LOG_FP_REGS). We will print a more detailed log. |
case LDP_w: { |
- set_wreg(rt, MemoryRead<uint32_t>(address)); |
- set_wreg(rt2, MemoryRead<uint32_t>(address + kWRegSize)); |
+ DCHECK(access_size == kWRegSize); |
+ set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); |
+ set_wreg_no_log(rt2, MemoryRead<uint32_t>(address2)); |
break; |
} |
case LDP_s: { |
- set_sreg(rt, MemoryRead<float>(address)); |
- set_sreg(rt2, MemoryRead<float>(address + kSRegSize)); |
+ DCHECK(access_size == kSRegSize); |
+ set_sreg_no_log(rt, MemoryRead<float>(address)); |
+ set_sreg_no_log(rt2, MemoryRead<float>(address2)); |
break; |
} |
case LDP_x: { |
- set_xreg(rt, MemoryRead<uint64_t>(address)); |
- set_xreg(rt2, MemoryRead<uint64_t>(address + kXRegSize)); |
+ DCHECK(access_size == kXRegSize); |
+ set_xreg_no_log(rt, MemoryRead<uint64_t>(address)); |
+ set_xreg_no_log(rt2, MemoryRead<uint64_t>(address2)); |
break; |
} |
case LDP_d: { |
- set_dreg(rt, MemoryRead<double>(address)); |
- set_dreg(rt2, MemoryRead<double>(address + kDRegSize)); |
+ DCHECK(access_size == kDRegSize); |
+ set_dreg_no_log(rt, MemoryRead<double>(address)); |
+ set_dreg_no_log(rt2, MemoryRead<double>(address2)); |
break; |
} |
case LDPSW_x: { |
- set_xreg(rt, MemoryRead<int32_t>(address)); |
- set_xreg(rt2, MemoryRead<int32_t>(address + kWRegSize)); |
+ DCHECK(access_size == kWRegSize); |
+ set_xreg_no_log(rt, MemoryRead<int32_t>(address)); |
+ set_xreg_no_log(rt2, MemoryRead<int32_t>(address2)); |
break; |
} |
case STP_w: { |
+ DCHECK(access_size == kWRegSize); |
MemoryWrite<uint32_t>(address, wreg(rt)); |
- MemoryWrite<uint32_t>(address + kWRegSize, wreg(rt2)); |
+ MemoryWrite<uint32_t>(address2, wreg(rt2)); |
break; |
} |
case STP_s: { |
+ DCHECK(access_size == kSRegSize); |
MemoryWrite<float>(address, sreg(rt)); |
- MemoryWrite<float>(address + kSRegSize, sreg(rt2)); |
+ MemoryWrite<float>(address2, sreg(rt2)); |
break; |
} |
case STP_x: { |
+ DCHECK(access_size == kXRegSize); |
MemoryWrite<uint64_t>(address, xreg(rt)); |
- MemoryWrite<uint64_t>(address + kXRegSize, xreg(rt2)); |
+ MemoryWrite<uint64_t>(address2, xreg(rt2)); |
break; |
} |
case STP_d: { |
+ DCHECK(access_size == kDRegSize); |
MemoryWrite<double>(address, dreg(rt)); |
- MemoryWrite<double>(address + kDRegSize, dreg(rt2)); |
+ MemoryWrite<double>(address2, dreg(rt2)); |
break; |
} |
default: UNREACHABLE(); |
} |
+ // Print a detailed trace (including the memory address) instead of the basic |
+ // register:value trace generated by set_*reg(). |
+ if (instr->IsLoad()) { |
+ if ((op == LDP_s) || (op == LDP_d)) { |
+ LogReadFP(address, access_size, rt); |
+ LogReadFP(address2, access_size, rt2); |
+ } else { |
+ LogRead(address, access_size, rt); |
+ LogRead(address2, access_size, rt2); |
+ } |
+ } else { |
+ if ((op == STP_s) || (op == STP_d)) { |
+ LogWriteFP(address, access_size, rt); |
+ LogWriteFP(address2, access_size, rt2); |
+ } else { |
+ LogWrite(address, access_size, rt); |
+ LogWrite(address2, access_size, rt2); |
+ } |
+ } |
+ |
// Handle the writeback for loads after the load to ensure safe pop |
// operation even when interrupted in the middle of it. The stack pointer |
// is only updated after the load so pop(fp) will never break the invariant |
@@ -1629,7 +1783,7 @@ void Simulator::LoadStorePairHelper(Instruction* instr, |
if (instr->IsLoad()) { |
// For loads the address pre writeback is used to check access below the |
// stack. |
- stack = reinterpret_cast<uint8_t*>(sp()); |
+ stack = sp(); |
LoadStoreWriteBack(addr_reg, offset, addrmode); |
} |
@@ -1641,24 +1795,37 @@ void Simulator::LoadStorePairHelper(Instruction* instr, |
void Simulator::VisitLoadLiteral(Instruction* instr) { |
- uint8_t* address = instr->LiteralAddress(); |
+ uintptr_t address = instr->LiteralAddress(); |
unsigned rt = instr->Rt(); |
switch (instr->Mask(LoadLiteralMask)) { |
- case LDR_w_lit: set_wreg(rt, MemoryRead<uint32_t>(address)); break; |
- case LDR_x_lit: set_xreg(rt, MemoryRead<uint64_t>(address)); break; |
- case LDR_s_lit: set_sreg(rt, MemoryRead<float>(address)); break; |
- case LDR_d_lit: set_dreg(rt, MemoryRead<double>(address)); break; |
+ // Use _no_log variants to suppress the register trace (LOG_REGS, |
+ // LOG_FP_REGS), then print a more detailed log. |
+ case LDR_w_lit: |
+ set_wreg_no_log(rt, MemoryRead<uint32_t>(address)); |
+ LogRead(address, kWRegSize, rt); |
+ break; |
+ case LDR_x_lit: |
+ set_xreg_no_log(rt, MemoryRead<uint64_t>(address)); |
+ LogRead(address, kXRegSize, rt); |
+ break; |
+ case LDR_s_lit: |
+ set_sreg_no_log(rt, MemoryRead<float>(address)); |
+ LogReadFP(address, kSRegSize, rt); |
+ break; |
+ case LDR_d_lit: |
+ set_dreg_no_log(rt, MemoryRead<double>(address)); |
+ LogReadFP(address, kDRegSize, rt); |
+ break; |
default: UNREACHABLE(); |
} |
} |
-uint8_t* Simulator::LoadStoreAddress(unsigned addr_reg, |
- int64_t offset, |
- AddrMode addrmode) { |
+uintptr_t Simulator::LoadStoreAddress(unsigned addr_reg, int64_t offset, |
+ AddrMode addrmode) { |
const unsigned kSPRegCode = kSPRegInternalCode & kRegCodeMask; |
- int64_t address = xreg(addr_reg, Reg31IsStackPointer); |
+ uint64_t address = xreg(addr_reg, Reg31IsStackPointer); |
if ((addr_reg == kSPRegCode) && ((address % 16) != 0)) { |
// When the base register is SP the stack pointer is required to be |
// quadword aligned prior to the address calculation and write-backs. |
@@ -1670,7 +1837,7 @@ uint8_t* Simulator::LoadStoreAddress(unsigned addr_reg, |
address += offset; |
} |
- return reinterpret_cast<uint8_t*>(address); |
+ return address; |
} |
@@ -1685,12 +1852,12 @@ void Simulator::LoadStoreWriteBack(unsigned addr_reg, |
} |
-void Simulator::CheckMemoryAccess(uint8_t* address, uint8_t* stack) { |
+void Simulator::CheckMemoryAccess(uintptr_t address, uintptr_t stack) { |
if ((address >= stack_limit_) && (address < stack)) { |
fprintf(stream_, "ACCESS BELOW STACK POINTER:\n"); |
- fprintf(stream_, " sp is here: 0x%16p\n", stack); |
- fprintf(stream_, " access was here: 0x%16p\n", address); |
- fprintf(stream_, " stack limit is here: 0x%16p\n", stack_limit_); |
+ fprintf(stream_, " sp is here: 0x%016" PRIx64 "\n", stack); |
+ fprintf(stream_, " access was here: 0x%016" PRIx64 "\n", address); |
+ fprintf(stream_, " stack limit is here: 0x%016" PRIx64 "\n", stack_limit_); |
fprintf(stream_, "\n"); |
FATAL("ACCESS BELOW STACK POINTER"); |
} |
@@ -2245,6 +2412,7 @@ void Simulator::VisitFPConditionalCompare(Instruction* instr) { |
} else { |
// If the condition fails, set the status flags to the nzcv immediate. |
nzcv().SetFlags(instr->Nzcv()); |
+ LogSystemRegister(NZCV); |
} |
break; |
} |
@@ -3027,8 +3195,14 @@ void Simulator::VisitSystem(Instruction* instr) { |
} |
case MSR: { |
switch (instr->ImmSystemRegister()) { |
- case NZCV: nzcv().SetRawValue(xreg(instr->Rt())); break; |
- case FPCR: fpcr().SetRawValue(xreg(instr->Rt())); break; |
+ case NZCV: |
+ nzcv().SetRawValue(xreg(instr->Rt())); |
+ LogSystemRegister(NZCV); |
+ break; |
+ case FPCR: |
+ fpcr().SetRawValue(xreg(instr->Rt())); |
+ LogSystemRegister(FPCR); |
+ break; |
default: UNIMPLEMENTED(); |
} |
break; |
@@ -3239,8 +3413,8 @@ void Simulator::Debug() { |
} else if ((strcmp(cmd, "print") == 0) || (strcmp(cmd, "p") == 0)) { |
if (argc == 2) { |
if (strcmp(arg1, "all") == 0) { |
- PrintRegisters(true); |
- PrintFPRegisters(true); |
+ PrintRegisters(); |
+ PrintFPRegisters(); |
} else { |
if (!PrintValue(arg1)) { |
PrintF("%s unrecognized\n", arg1); |
@@ -3444,7 +3618,7 @@ void Simulator::VisitException(Instruction* instr) { |
if (FLAG_trace_sim_messages || FLAG_trace_sim || (parameters & BREAK)) { |
if (message != NULL) { |
PrintF(stream_, |
- "%sDebugger hit %d: %s%s%s\n", |
+ "# %sDebugger hit %d: %s%s%s\n", |
clr_debug_number, |
code, |
clr_debug_message, |
@@ -3452,7 +3626,7 @@ void Simulator::VisitException(Instruction* instr) { |
clr_normal); |
} else { |
PrintF(stream_, |
- "%sDebugger hit %d.%s\n", |
+ "# %sDebugger hit %d.%s\n", |
clr_debug_number, |
code, |
clr_normal); |
@@ -3479,9 +3653,9 @@ void Simulator::VisitException(Instruction* instr) { |
// Don't print information that is already being traced. |
parameters &= ~log_parameters(); |
// Print the requested information. |
- if (parameters & LOG_SYS_REGS) PrintSystemRegisters(true); |
- if (parameters & LOG_REGS) PrintRegisters(true); |
- if (parameters & LOG_FP_REGS) PrintFPRegisters(true); |
+ if (parameters & LOG_SYS_REGS) PrintSystemRegisters(); |
+ if (parameters & LOG_REGS) PrintRegisters(); |
+ if (parameters & LOG_FP_REGS) PrintFPRegisters(); |
} |
// The stop parameters are inlined in the code. Skip them: |