Reland r23732: ARM64: Fix and improve --trace-sim register trace.
authorJacob.Bramley@arm.com <Jacob.Bramley@arm.com>
Tue, 9 Sep 2014 12:43:43 +0000 (12:43 +0000)
committerJacob.Bramley@arm.com <Jacob.Bramley@arm.com>
Tue, 9 Sep 2014 12:43:43 +0000 (12:43 +0000)
- Use standard names (except that our GREY is the standard BLACK).
- Make non-bold colours explicit, otherwise the boldness can carry over
  into subsequent colour declarations.
- I've moved some colours around to make them consistent. Register value
  updates (which are very common) now stand out less than they did,
  making the less-common (and arguably more important) debug
  announcements appear brighter.
  - FP registers and values are now magenta.
  - Integer registers and values are now cyan.
  - Memory accesses are now blue.
- LOG_WRITE prints the source register for stores.
- Loads are logged with a format similar to that used for stores.
  Specifically, the memory address is printed alongside the new register
  value.
- Updates to D registers print the raw bits as well as the double value.
  Updates to S registers print the raw bits as well as the float value.
  (Previously, we printed both double and float interpretations of the
  bits, which was a bit cluttered.)

BUG=
R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/551823004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23802 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/arm64/disasm-arm64.cc
src/arm64/instructions-arm64.h
src/arm64/simulator-arm64.cc
src/arm64/simulator-arm64.h

index b8b1d5d..ac7cb37 100644 (file)
@@ -1517,7 +1517,9 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
     case LDR_w_lit:
     case LDR_x_lit:
     case LDR_s_lit:
-    case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
+    case LDR_d_lit:
+      AppendToOutput("(addr 0x%016" PRIxPTR ")", instr->LiteralAddress());
+      break;
     default: UNREACHABLE();
   }
 
index bd4e753..9f3c20f 100644 (file)
@@ -352,9 +352,9 @@ class Instruction {
   // Patch a literal load instruction to load from 'source'.
   void SetImmLLiteral(Instruction* source);
 
-  uint8_t* LiteralAddress() {
+  uintptr_t LiteralAddress() {
     int offset = ImmLLiteral() << kLoadLiteralScaleLog2;
-    return reinterpret_cast<uint8_t*>(this) + offset;
+    return reinterpret_cast<uintptr_t>(this) + offset;
   }
 
   enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT };
index 2e43dfc..277275c 100644 (file)
@@ -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;
+void Simulator::PrintSystemRegisters() {
+  PrintSystemRegister(NZCV);
+  PrintSystemRegister(FPCR);
+}
+
+
+void Simulator::PrintRegisters() {
+  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
+    PrintRegister(i);
+  }
+}
 
-  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);
+
+void Simulator::PrintFPRegisters() {
+  for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
+    PrintFPRegister(i);
   }
-  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);
+void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) {
+  // Don't print writes into xzr.
+  if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
+    return;
   }
-  last_fpcr = fpcr();
 
-  first_run = false;
+  // 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::PrintRegisters(bool print_all_regs) {
-  static bool first_run = true;
-  static int64_t last_regs[kNumberOfRegisters];
+void Simulator::PrintFPRegister(unsigned code, PrintFPRegisterSizes sizes) {
+  // The template is "# v<code>:bits (d<code>:value, ...)".
 
-  for (unsigned i = 0; i < kNumberOfRegisters; i++) {
-    if (print_all_regs || first_run ||
-        (last_regs[i] != xreg(i, Reg31IsStackPointer))) {
+  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\n",
-              clr_reg_name,
-              XRegNameForCode(i, Reg31IsStackPointer),
-              clr_reg_value,
-              xreg(i, Reg31IsStackPointer),
+              "# %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] = xreg(i, Reg31IsStackPointer);
+    default:
+      UNREACHABLE();
   }
-  first_run = false;
 }
 
 
-void Simulator::PrintFPRegisters(bool print_all_regs) {
-  static bool first_run = true;
-  static uint64_t last_regs[kNumberOfFPRegisters];
+void Simulator::PrintRead(uintptr_t address,
+                          size_t size,
+                          unsigned reg_code) {
+  USE(size);  // Size is unused here.
 
-  // 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).
-  for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
-    if (print_all_regs || first_run || (last_regs[i] != dreg_bits(i))) {
-      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),
-              clr_normal);
-    }
-    // Cache the new register value so the next run can detect any changes.
-    last_regs[i] = dreg_bits(i);
+  // 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();
   }
-  first_run = false;
+
+  fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
+          clr_memory_address, address, clr_normal);
 }
 
 
-void Simulator::PrintProcessorState() {
-  PrintSystemRegisters();
-  PrintRegisters();
-  PrintFPRegisters();
+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::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::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:
index a9f2e09..108f6f2 100644 (file)
@@ -312,7 +312,6 @@ class Simulator : public DecoderVisitor {
     DCHECK(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstructionSize));
     CheckBreakNext();
     Decode(pc_);
-    LogProcessorState();
     increment_pc();
     CheckBreakpoints();
   }
@@ -348,16 +347,13 @@ class Simulator : public DecoderVisitor {
     return reg<int64_t>(code, r31mode);
   }
 
-  // Write 'size' bits of 'value' into an integer register. The value is
-  // zero-extended. This behaviour matches AArch64 register writes.
-
-  // Like set_reg(), but infer the access size from the template type.
+  // Write 'value' into an integer register. The value is zero-extended. This
+  // behaviour matches AArch64 register writes.
   template<typename T>
   void set_reg(unsigned code, T value,
                Reg31Mode r31mode = Reg31IsZeroRegister) {
-    DCHECK(code < kNumberOfRegisters);
-    if (!IsZeroRegister(code, r31mode))
-      registers_[code].Set(value);
+    set_reg_no_log(code, value, r31mode);
+    LogRegister(code, r31mode);
   }
 
   // Common specialized accessors for the set_reg() template.
@@ -371,6 +367,26 @@ class Simulator : public DecoderVisitor {
     set_reg(code, value, r31mode);
   }
 
+  // As above, but don't automatically log the register update.
+  template <typename T>
+  void set_reg_no_log(unsigned code, T value,
+                      Reg31Mode r31mode = Reg31IsZeroRegister) {
+    DCHECK(code < kNumberOfRegisters);
+    if (!IsZeroRegister(code, r31mode)) {
+      registers_[code].Set(value);
+    }
+  }
+
+  void set_wreg_no_log(unsigned code, int32_t value,
+                       Reg31Mode r31mode = Reg31IsZeroRegister) {
+    set_reg_no_log(code, value, r31mode);
+  }
+
+  void set_xreg_no_log(unsigned code, int64_t value,
+                       Reg31Mode r31mode = Reg31IsZeroRegister) {
+    set_reg_no_log(code, value, r31mode);
+  }
+
   // Commonly-used special cases.
   template<typename T>
   void set_lr(T value) {
@@ -430,9 +446,13 @@ class Simulator : public DecoderVisitor {
   // This behaviour matches AArch64 register writes.
   template<typename T>
   void set_fpreg(unsigned code, T value) {
-    DCHECK((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize));
-    DCHECK(code < kNumberOfFPRegisters);
-    fpregisters_[code].Set(value);
+    set_fpreg_no_log(code, value);
+
+    if (sizeof(value) <= kSRegSize) {
+      LogFPRegister(code, kPrintSRegValue);
+    } else {
+      LogFPRegister(code, kPrintDRegValue);
+    }
   }
 
   // Common specialized accessors for the set_fpreg() template.
@@ -452,6 +472,22 @@ class Simulator : public DecoderVisitor {
     set_fpreg(code, value);
   }
 
+  // As above, but don't automatically log the register update.
+  template <typename T>
+  void set_fpreg_no_log(unsigned code, T value) {
+    DCHECK((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize));
+    DCHECK(code < kNumberOfFPRegisters);
+    fpregisters_[code].Set(value);
+  }
+
+  void set_sreg_no_log(unsigned code, float value) {
+    set_fpreg_no_log(code, value);
+  }
+
+  void set_dreg_no_log(unsigned code, double value) {
+    set_fpreg_no_log(code, value);
+  }
+
   SimSystemRegister& nzcv() { return nzcv_; }
   SimSystemRegister& fpcr() { return fpcr_; }
 
@@ -478,33 +514,68 @@ class Simulator : public DecoderVisitor {
   // Disassemble instruction at the given address.
   void PrintInstructionsAt(Instruction* pc, uint64_t count);
 
-  void PrintSystemRegisters(bool print_all = false);
-  void PrintRegisters(bool print_all_regs = false);
-  void PrintFPRegisters(bool print_all_regs = false);
-  void PrintProcessorState();
-  void PrintWrite(uintptr_t address, uint64_t value, unsigned num_bytes);
+  // Print all registers of the specified types.
+  void PrintRegisters();
+  void PrintFPRegisters();
+  void PrintSystemRegisters();
+
+  // Like Print* (above), but respect log_parameters().
   void LogSystemRegisters() {
-    if (log_parameters_ & LOG_SYS_REGS) PrintSystemRegisters();
+    if (log_parameters() & LOG_SYS_REGS) PrintSystemRegisters();
   }
   void LogRegisters() {
-    if (log_parameters_ & LOG_REGS) PrintRegisters();
+    if (log_parameters() & LOG_REGS) PrintRegisters();
   }
   void LogFPRegisters() {
-    if (log_parameters_ & LOG_FP_REGS) PrintFPRegisters();
+    if (log_parameters() & LOG_FP_REGS) PrintFPRegisters();
+  }
+
+  // Specify relevant register sizes, for PrintFPRegister.
+  //
+  // These values are bit masks; they can be combined in case multiple views of
+  // a machine register are interesting.
+  enum PrintFPRegisterSizes {
+    kPrintDRegValue = 1 << kDRegSize,
+    kPrintSRegValue = 1 << kSRegSize,
+    kPrintAllFPRegValues = kPrintDRegValue | kPrintSRegValue
+  };
+
+  // Print individual register values (after update).
+  void PrintRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer);
+  void PrintFPRegister(unsigned code,
+                       PrintFPRegisterSizes sizes = kPrintAllFPRegValues);
+  void PrintSystemRegister(SystemRegister id);
+
+  // Like Print* (above), but respect log_parameters().
+  void LogRegister(unsigned code, Reg31Mode r31mode = Reg31IsStackPointer) {
+    if (log_parameters() & LOG_REGS) PrintRegister(code, r31mode);
   }
-  void LogProcessorState() {
-    LogSystemRegisters();
-    LogRegisters();
-    LogFPRegisters();
+  void LogFPRegister(unsigned code,
+                     PrintFPRegisterSizes sizes = kPrintAllFPRegValues) {
+    if (log_parameters() & LOG_FP_REGS) PrintFPRegister(code, sizes);
   }
-  template <typename T>
-  void LogWrite(uintptr_t address, T value) {
-    uint64_t raw_value = 0;
-    DCHECK(sizeof(value) <= sizeof(raw_value));
-    if (log_parameters_ & LOG_WRITE) {
-      memcpy(&raw_value, &value, sizeof(value));
-      PrintWrite(address, raw_value, sizeof(value));
-    }
+  void LogSystemRegister(SystemRegister id) {
+    if (log_parameters() & LOG_SYS_REGS) PrintSystemRegister(id);
+  }
+
+  // Print memory accesses.
+  void PrintRead(uintptr_t address, size_t size, unsigned reg_code);
+  void PrintReadFP(uintptr_t address, size_t size, unsigned reg_code);
+  void PrintWrite(uintptr_t address, size_t size, unsigned reg_code);
+  void PrintWriteFP(uintptr_t address, size_t size, unsigned reg_code);
+
+  // Like Print* (above), but respect log_parameters().
+  void LogRead(uintptr_t address, size_t size, unsigned reg_code) {
+    if (log_parameters() & LOG_REGS) PrintRead(address, size, reg_code);
+  }
+  void LogReadFP(uintptr_t address, size_t size, unsigned reg_code) {
+    if (log_parameters() & LOG_FP_REGS) PrintReadFP(address, size, reg_code);
+  }
+  void LogWrite(uintptr_t address, size_t size, unsigned reg_code) {
+    if (log_parameters() & LOG_WRITE) PrintWrite(address, size, reg_code);
+  }
+  void LogWriteFP(uintptr_t address, size_t size, unsigned reg_code) {
+    if (log_parameters() & LOG_WRITE) PrintWriteFP(address, size, reg_code);
   }
 
   int log_parameters() { return log_parameters_; }
@@ -595,14 +666,14 @@ class Simulator : public DecoderVisitor {
                        int64_t offset,
                        AddrMode addrmode);
   void LoadStorePairHelper(Instruction* instr, AddrMode addrmode);
-  uint8_t* LoadStoreAddress(unsigned addr_reg,
-                            int64_t offset,
-                            AddrMode addrmode);
+  uintptr_t LoadStoreAddress(unsigned addr_reg, int64_t offset,
+                             AddrMode addrmode);
   void LoadStoreWriteBack(unsigned addr_reg,
                           int64_t offset,
                           AddrMode addrmode);
-  void CheckMemoryAccess(uint8_t* address, uint8_t* stack);
+  void CheckMemoryAccess(uintptr_t address, uintptr_t stack);
 
+  // Memory read helpers.
   template <typename T, typename A>
   T MemoryRead(A address) {
     T value;
@@ -612,11 +683,11 @@ class Simulator : public DecoderVisitor {
     return value;
   }
 
+  // Memory write helpers.
   template <typename T, typename A>
   void MemoryWrite(A address, T value) {
     STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
                   (sizeof(value) == 4) || (sizeof(value) == 8));
-    LogWrite(reinterpret_cast<uintptr_t>(address), value);
     memcpy(reinterpret_cast<void*>(address), &value, sizeof(value));
   }
 
@@ -771,10 +842,10 @@ class Simulator : public DecoderVisitor {
   static const uint32_t kConditionFlagsMask = 0xf0000000;
 
   // Stack
-  byte* stack_;
-  static const intptr_t stack_protection_size_ = KB;
-  intptr_t stack_size_;
-  byte* stack_limit_;
+  uintptr_t stack_;
+  static const size_t stack_protection_size_ = KB;
+  size_t stack_size_;
+  uintptr_t stack_limit_;
 
   Decoder<DispatchingDecoderVisitor>* decoder_;
   Decoder<DispatchingDecoderVisitor>* disassembler_decoder_;