Commit 3dbb3c39 authored by Jacob.Bramley@arm.com's avatar Jacob.Bramley@arm.com

Reland r23732: ARM64: Fix and improve --trace-sim register trace.

- 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
parent f3e03388
...@@ -1517,7 +1517,9 @@ int Disassembler::SubstituteLiteralField(Instruction* instr, ...@@ -1517,7 +1517,9 @@ int Disassembler::SubstituteLiteralField(Instruction* instr,
case LDR_w_lit: case LDR_w_lit:
case LDR_x_lit: case LDR_x_lit:
case LDR_s_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(); default: UNREACHABLE();
} }
......
...@@ -352,9 +352,9 @@ class Instruction { ...@@ -352,9 +352,9 @@ class Instruction {
// Patch a literal load instruction to load from 'source'. // Patch a literal load instruction to load from 'source'.
void SetImmLLiteral(Instruction* source); void SetImmLLiteral(Instruction* source);
uint8_t* LiteralAddress() { uintptr_t LiteralAddress() {
int offset = ImmLLiteral() << kLoadLiteralScaleLog2; int offset = ImmLLiteral() << kLoadLiteralScaleLog2;
return reinterpret_cast<uint8_t*>(this) + offset; return reinterpret_cast<uintptr_t>(this) + offset;
} }
enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT }; enum CheckAlignment { NO_CHECK, CHECK_ALIGNMENT };
......
...@@ -30,30 +30,28 @@ namespace internal { ...@@ -30,30 +30,28 @@ namespace internal {
// Helpers for colors. // Helpers for colors.
// Depending on your terminal configuration, the colour names may not match the #define COLOUR(colour_code) "\033[0;" colour_code "m"
// observed colours. #define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m"
#define COLOUR(colour_code) "\033[" colour_code "m" #define NORMAL ""
#define BOLD(colour_code) "1;" colour_code #define GREY "30"
#define NORMAL "" #define RED "31"
#define GREY "30" #define GREEN "32"
#define GREEN "32" #define YELLOW "33"
#define ORANGE "33" #define BLUE "34"
#define BLUE "34" #define MAGENTA "35"
#define PURPLE "35" #define CYAN "36"
#define INDIGO "36" #define WHITE "37"
#define WHITE "37"
typedef char const * const TEXT_COLOUR; typedef char const * const TEXT_COLOUR;
TEXT_COLOUR clr_normal = FLAG_log_colour ? COLOUR(NORMAL) : ""; TEXT_COLOUR clr_normal = FLAG_log_colour ? COLOUR(NORMAL) : "";
TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR(BOLD(GREY)) : ""; TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR_BOLD(WHITE) : "";
TEXT_COLOUR clr_flag_value = 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(BLUE)) : ""; TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) : "";
TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(BOLD(INDIGO)) : ""; TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) : "";
TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR(BOLD(ORANGE)) : ""; TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : "";
TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(BOLD(PURPLE)) : ""; TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : "";
TEXT_COLOUR clr_memory_value = FLAG_log_colour ? COLOUR(BOLD(GREEN)) : ""; TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) : "";
TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR(GREEN) : ""; TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) : "";
TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR(BOLD(ORANGE)) : ""; TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) : "";
TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(ORANGE) : "";
TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : ""; TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : "";
...@@ -337,7 +335,7 @@ uintptr_t Simulator::PopAddress() { ...@@ -337,7 +335,7 @@ uintptr_t Simulator::PopAddress() {
uintptr_t Simulator::StackLimit() const { uintptr_t Simulator::StackLimit() const {
// Leave a safety margin of 1024 bytes to prevent overrunning the stack when // Leave a safety margin of 1024 bytes to prevent overrunning the stack when
// pushing values. // pushing values.
return reinterpret_cast<uintptr_t>(stack_limit_) + 1024; return stack_limit_ + 1024;
} }
...@@ -380,11 +378,11 @@ void Simulator::Init(FILE* stream) { ...@@ -380,11 +378,11 @@ void Simulator::Init(FILE* stream) {
// Allocate and setup the simulator stack. // Allocate and setup the simulator stack.
stack_size_ = (FLAG_sim_stack_size * KB) + (2 * stack_protection_size_); 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_; stack_limit_ = stack_ + stack_protection_size_;
byte* tos = stack_ + stack_size_ - stack_protection_size_; uintptr_t tos = stack_ + stack_size_ - stack_protection_size_;
// The stack pointer must be 16 bytes aligned. // The stack pointer must be 16-byte aligned.
set_sp(reinterpret_cast<int64_t>(tos) & ~0xfUL); set_sp(tos & ~0xfUL);
stream_ = stream; stream_ = stream;
print_disasm_ = new PrintDisassembler(stream_); print_disasm_ = new PrintDisassembler(stream_);
...@@ -420,7 +418,7 @@ void Simulator::ResetState() { ...@@ -420,7 +418,7 @@ void Simulator::ResetState() {
Simulator::~Simulator() { Simulator::~Simulator() {
delete[] stack_; delete[] reinterpret_cast<byte*>(stack_);
if (FLAG_log_instruction_stats) { if (FLAG_log_instruction_stats) {
delete instrument_; delete instrument_;
} }
...@@ -734,15 +732,15 @@ void* Simulator::RedirectExternalReference(void* external_function, ...@@ -734,15 +732,15 @@ void* Simulator::RedirectExternalReference(void* external_function,
const char* Simulator::xreg_names[] = { const char* Simulator::xreg_names[] = {
"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
"ip0", "ip1", "x18", "x19", "x20", "x21", "x22", "x23", "ip0", "ip1", "x18", "x19", "x20", "x21", "x22", "x23",
"x24", "x25", "x26", "cp", "jssp", "fp", "lr", "xzr", "csp"}; "x24", "x25", "x26", "cp", "jssp", "fp", "lr", "xzr", "csp"};
const char* Simulator::wreg_names[] = { const char* Simulator::wreg_names[] = {
"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7", "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23", "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
"w24", "w25", "w26", "wcp", "wjssp", "wfp", "wlr", "wzr", "wcsp"}; "w24", "w25", "w26", "wcp", "wjssp", "wfp", "wlr", "wzr", "wcsp"};
const char* Simulator::sreg_names[] = { const char* Simulator::sreg_names[] = {
...@@ -765,7 +763,12 @@ const char* Simulator::vreg_names[] = { ...@@ -765,7 +763,12 @@ const char* Simulator::vreg_names[] = {
const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) { const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
STATIC_ASSERT(arraysize(Simulator::wreg_names) == (kNumberOfRegisters + 1));
DCHECK(code < kNumberOfRegisters); 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 the code represents the stack pointer, index the name after zr.
if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
code = kZeroRegCode + 1; code = kZeroRegCode + 1;
...@@ -775,7 +778,10 @@ const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) { ...@@ -775,7 +778,10 @@ const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) { const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
STATIC_ASSERT(arraysize(Simulator::xreg_names) == (kNumberOfRegisters + 1));
DCHECK(code < kNumberOfRegisters); DCHECK(code < kNumberOfRegisters);
code %= kNumberOfRegisters;
// If the code represents the stack pointer, index the name after zr. // If the code represents the stack pointer, index the name after zr.
if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) { if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
code = kZeroRegCode + 1; code = kZeroRegCode + 1;
...@@ -785,20 +791,23 @@ const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) { ...@@ -785,20 +791,23 @@ const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
const char* Simulator::SRegNameForCode(unsigned code) { const char* Simulator::SRegNameForCode(unsigned code) {
STATIC_ASSERT(arraysize(Simulator::sreg_names) == kNumberOfFPRegisters);
DCHECK(code < kNumberOfFPRegisters); DCHECK(code < kNumberOfFPRegisters);
return sreg_names[code]; return sreg_names[code % kNumberOfFPRegisters];
} }
const char* Simulator::DRegNameForCode(unsigned code) { const char* Simulator::DRegNameForCode(unsigned code) {
STATIC_ASSERT(arraysize(Simulator::dreg_names) == kNumberOfFPRegisters);
DCHECK(code < kNumberOfFPRegisters); DCHECK(code < kNumberOfFPRegisters);
return dreg_names[code]; return dreg_names[code % kNumberOfFPRegisters];
} }
const char* Simulator::VRegNameForCode(unsigned code) { const char* Simulator::VRegNameForCode(unsigned code) {
STATIC_ASSERT(arraysize(Simulator::vreg_names) == kNumberOfFPRegisters);
DCHECK(code < kNumberOfFPRegisters); DCHECK(code < kNumberOfFPRegisters);
return vreg_names[code]; return vreg_names[code % kNumberOfFPRegisters];
} }
...@@ -855,6 +864,7 @@ T Simulator::AddWithCarry(bool set_flags, ...@@ -855,6 +864,7 @@ T Simulator::AddWithCarry(bool set_flags,
nzcv().SetZ(Z); nzcv().SetZ(Z);
nzcv().SetC(C); nzcv().SetC(C);
nzcv().SetV(V); nzcv().SetV(V);
LogSystemRegister(NZCV);
} }
return result; return result;
} }
...@@ -978,6 +988,7 @@ void Simulator::FPCompare(double val0, double val1) { ...@@ -978,6 +988,7 @@ void Simulator::FPCompare(double val0, double val1) {
} else { } else {
UNREACHABLE(); UNREACHABLE();
} }
LogSystemRegister(NZCV);
} }
...@@ -1044,117 +1055,206 @@ void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) { ...@@ -1044,117 +1055,206 @@ void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) {
} }
void Simulator::PrintSystemRegisters(bool print_all) { void Simulator::PrintSystemRegisters() {
static bool first_run = true; 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())) { void Simulator::PrintFPRegisters() {
fprintf(stream_, "# %sFLAGS: %sN:%d Z:%d C:%d V:%d%s\n", for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
clr_flag_name, PrintFPRegister(i);
clr_flag_value,
nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(),
clr_normal);
} }
last_nzcv = nzcv(); }
static SimSystemRegister last_fpcr; void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) {
if (print_all || first_run || (last_fpcr.RawValue() != fpcr().RawValue())) { // Don't print writes into xzr.
static const char * rmode[] = { if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
"0b00 (Round to Nearest)", return;
"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; // 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) { void Simulator::PrintFPRegister(unsigned code, PrintFPRegisterSizes sizes) {
static bool first_run = true; // The template is "# v<code>:bits (d<code>:value, ...)".
static int64_t last_regs[kNumberOfRegisters];
for (unsigned i = 0; i < kNumberOfRegisters; i++) { DCHECK(sizes != 0);
if (print_all_regs || first_run || DCHECK((sizes & kPrintAllFPRegValues) == sizes);
(last_regs[i] != xreg(i, Reg31IsStackPointer))) {
// 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_, fprintf(stream_,
"# %s%4s:%s 0x%016" PRIx64 "%s\n", "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
clr_reg_name, clr_flag_name, clr_flag_value,
XRegNameForCode(i, Reg31IsStackPointer), fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()],
clr_reg_value,
xreg(i, Reg31IsStackPointer),
clr_normal); clr_normal);
break;
} }
// Cache the new register value so the next run can detect any changes. default:
last_regs[i] = xreg(i, Reg31IsStackPointer); UNREACHABLE();
} }
first_run = false;
} }
void Simulator::PrintFPRegisters(bool print_all_regs) { void Simulator::PrintRead(uintptr_t address,
static bool first_run = true; size_t size,
static uint64_t last_regs[kNumberOfFPRegisters]; unsigned reg_code) {
USE(size); // Size is unused here.
// Print as many rows of registers as necessary, keeping each individual // The template is "# x<code>:value <- address".
// register in the same column each time (to make it easy to visually scan fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s",
// for changes). clr_reg_name, XRegNameForCode(reg_code),
for (unsigned i = 0; i < kNumberOfFPRegisters; i++) { clr_reg_value, reg<uint64_t>(reg_code), clr_normal);
if (print_all_regs || first_run || (last_regs[i] != dreg_bits(i))) {
fprintf(stream_, fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
"# %s %4s:%s 0x%016" PRIx64 "%s (%s%s:%s %g%s %s:%s %g%s)\n", clr_memory_address, address, clr_normal);
clr_fpreg_name, }
VRegNameForCode(i),
clr_fpreg_value,
dreg_bits(i), void Simulator::PrintReadFP(uintptr_t address,
clr_normal, size_t size,
clr_fpreg_name, unsigned reg_code) {
DRegNameForCode(i), // The template is "# reg:bits (reg:value) <- address".
clr_fpreg_value, switch (size) {
dreg(i), case kSRegSize:
clr_fpreg_name, fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%gf%s)",
SRegNameForCode(i), clr_fpreg_name, VRegNameForCode(reg_code),
clr_fpreg_value, clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
sreg(i), clr_fpreg_name, SRegNameForCode(reg_code),
clr_normal); clr_fpreg_value, fpreg<float>(reg_code), clr_normal);
} break;
// Cache the new register value so the next run can detect any changes. case kDRegSize:
last_regs[i] = dreg_bits(i); 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() { void Simulator::PrintWrite(uintptr_t address,
PrintSystemRegisters(); size_t size,
PrintRegisters(); unsigned reg_code) {
PrintFPRegisters(); // 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, void Simulator::PrintWriteFP(uintptr_t address,
unsigned num_bytes) { size_t size,
// The template is "# value -> address". The format string is not used unsigned reg_code) {
// directly in the printf because some compilers struggle with the // The template is "# reg:bits (reg:value) -> address". To keep the trace tidy
// parametrized width field (%0*). // and readable, the value is aligned with the values in the register trace.
const char* format = "# %s0x%0*" PRIx64 "%s -> %s0x%016" PRIxPTR "%s\n"; switch (size) {
fprintf(stream_, case kSRegSize:
format, fprintf(stream_, "# %s%5s<31:0>: %s0x%08" PRIx32 "%s (%s%s: %s%gf%s)",
clr_memory_value, clr_fpreg_name, VRegNameForCode(reg_code),
num_bytes * 2, // The width in hexadecimal characters. clr_fpreg_value, fpreg<uint32_t>(reg_code), clr_normal,
value, clr_fpreg_name, SRegNameForCode(reg_code),
clr_normal, clr_fpreg_value, fpreg<float>(reg_code), clr_normal);
clr_memory_address, break;
address, case kDRegSize:
clr_normal); 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) { ...@@ -1383,6 +1483,7 @@ void Simulator::LogicalHelper(Instruction* instr, T op2) {
nzcv().SetZ(CalcZFlag(result)); nzcv().SetZ(CalcZFlag(result));
nzcv().SetC(0); nzcv().SetC(0);
nzcv().SetV(0); nzcv().SetV(0);
LogSystemRegister(NZCV);
} }
set_reg<T>(instr->Rd(), result, instr->RdMode()); set_reg<T>(instr->Rd(), result, instr->RdMode());
...@@ -1423,6 +1524,7 @@ void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) { ...@@ -1423,6 +1524,7 @@ void Simulator::ConditionalCompareHelper(Instruction* instr, T op2) {
} else { } else {
// If the condition fails, set the status flags to the nzcv immediate. // If the condition fails, set the status flags to the nzcv immediate.
nzcv().SetFlags(instr->Nzcv()); nzcv().SetFlags(instr->Nzcv());
LogSystemRegister(NZCV);
} }
} }
...@@ -1463,8 +1565,8 @@ void Simulator::LoadStoreHelper(Instruction* instr, ...@@ -1463,8 +1565,8 @@ void Simulator::LoadStoreHelper(Instruction* instr,
AddrMode addrmode) { AddrMode addrmode) {
unsigned srcdst = instr->Rt(); unsigned srcdst = instr->Rt();
unsigned addr_reg = instr->Rn(); unsigned addr_reg = instr->Rn();
uint8_t* address = LoadStoreAddress(addr_reg, offset, addrmode); uintptr_t address = LoadStoreAddress(addr_reg, offset, addrmode);
uint8_t* stack = NULL; uintptr_t stack = 0;
// Handle the writeback for stores before the store. On a CPU the writeback // 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 // and the store are atomic, but when running on the simulator it is possible
...@@ -1478,22 +1580,24 @@ void Simulator::LoadStoreHelper(Instruction* instr, ...@@ -1478,22 +1580,24 @@ void Simulator::LoadStoreHelper(Instruction* instr,
// For store the address post writeback is used to check access below the // For store the address post writeback is used to check access below the
// stack. // stack.
stack = reinterpret_cast<uint8_t*>(sp()); stack = sp();
} }
LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreOpMask)); LoadStoreOp op = static_cast<LoadStoreOp>(instr->Mask(LoadStoreOpMask));
switch (op) { switch (op) {
case LDRB_w: set_wreg(srcdst, MemoryRead<uint8_t>(address)); break; // Use _no_log variants to suppress the register trace (LOG_REGS,
case LDRH_w: set_wreg(srcdst, MemoryRead<uint16_t>(address)); break; // LOG_FP_REGS). We will print a more detailed log.
case LDR_w: set_wreg(srcdst, MemoryRead<uint32_t>(address)); break; case LDRB_w: set_wreg_no_log(srcdst, MemoryRead<uint8_t>(address)); break;
case LDR_x: set_xreg(srcdst, MemoryRead<uint64_t>(address)); break; case LDRH_w: set_wreg_no_log(srcdst, MemoryRead<uint16_t>(address)); break;
case LDRSB_w: set_wreg(srcdst, MemoryRead<int8_t>(address)); break; case LDR_w: set_wreg_no_log(srcdst, MemoryRead<uint32_t>(address)); break;
case LDRSH_w: set_wreg(srcdst, MemoryRead<int16_t>(address)); break; case LDR_x: set_xreg_no_log(srcdst, MemoryRead<uint64_t>(address)); break;
case LDRSB_x: set_xreg(srcdst, MemoryRead<int8_t>(address)); break; case LDRSB_w: set_wreg_no_log(srcdst, MemoryRead<int8_t>(address)); break;
case LDRSH_x: set_xreg(srcdst, MemoryRead<int16_t>(address)); break; case LDRSH_w: set_wreg_no_log(srcdst, MemoryRead<int16_t>(address)); break;
case LDRSW_x: set_xreg(srcdst, MemoryRead<int32_t>(address)); break; case LDRSB_x: set_xreg_no_log(srcdst, MemoryRead<int8_t>(address)); break;
case LDR_s: set_sreg(srcdst, MemoryRead<float>(address)); break; case LDRSH_x: set_xreg_no_log(srcdst, MemoryRead<int16_t>(address)); break;
case LDR_d: set_dreg(srcdst, MemoryRead<double>(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 STRB_w: MemoryWrite<uint8_t>(address, wreg(srcdst)); break;
case STRH_w: MemoryWrite<uint16_t>(address, wreg(srcdst)); break; case STRH_w: MemoryWrite<uint16_t>(address, wreg(srcdst)); break;
...@@ -1505,6 +1609,23 @@ void Simulator::LoadStoreHelper(Instruction* instr, ...@@ -1505,6 +1609,23 @@ void Simulator::LoadStoreHelper(Instruction* instr,
default: UNIMPLEMENTED(); 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 // Handle the writeback for loads after the load to ensure safe pop
// operation even when interrupted in the middle of it. The stack pointer // 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 // is only updated after the load so pop(fp) will never break the invariant
...@@ -1512,7 +1633,7 @@ void Simulator::LoadStoreHelper(Instruction* instr, ...@@ -1512,7 +1633,7 @@ void Simulator::LoadStoreHelper(Instruction* instr,
if (instr->IsLoad()) { if (instr->IsLoad()) {
// For loads the address pre writeback is used to check access below the // For loads the address pre writeback is used to check access below the
// stack. // stack.
stack = reinterpret_cast<uint8_t*>(sp()); stack = sp();
LoadStoreWriteBack(addr_reg, offset, addrmode); LoadStoreWriteBack(addr_reg, offset, addrmode);
} }
...@@ -1548,9 +1669,11 @@ void Simulator::LoadStorePairHelper(Instruction* instr, ...@@ -1548,9 +1669,11 @@ void Simulator::LoadStorePairHelper(Instruction* instr,
unsigned rt = instr->Rt(); unsigned rt = instr->Rt();
unsigned rt2 = instr->Rt2(); unsigned rt2 = instr->Rt2();
unsigned addr_reg = instr->Rn(); unsigned addr_reg = instr->Rn();
int offset = instr->ImmLSPair() << instr->SizeLSPair(); size_t access_size = 1 << instr->SizeLSPair();
uint8_t* address = LoadStoreAddress(addr_reg, offset, addrmode); int64_t offset = instr->ImmLSPair() * access_size;
uint8_t* stack = NULL; 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 // 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 // and the store are atomic, but when running on the simulator it is possible
...@@ -1564,7 +1687,7 @@ void Simulator::LoadStorePairHelper(Instruction* instr, ...@@ -1564,7 +1687,7 @@ void Simulator::LoadStorePairHelper(Instruction* instr,
// For store the address post writeback is used to check access below the // For store the address post writeback is used to check access below the
// stack. // stack.
stack = reinterpret_cast<uint8_t*>(sp()); stack = sp();
} }
LoadStorePairOp op = LoadStorePairOp op =
...@@ -1574,54 +1697,85 @@ void Simulator::LoadStorePairHelper(Instruction* instr, ...@@ -1574,54 +1697,85 @@ void Simulator::LoadStorePairHelper(Instruction* instr,
DCHECK(((op & LoadStorePairLBit) == 0) || (rt != rt2)); DCHECK(((op & LoadStorePairLBit) == 0) || (rt != rt2));
switch (op) { 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: { case LDP_w: {
set_wreg(rt, MemoryRead<uint32_t>(address)); DCHECK(access_size == kWRegSize);
set_wreg(rt2, MemoryRead<uint32_t>(address + kWRegSize)); set_wreg_no_log(rt, MemoryRead<uint32_t>(address));
set_wreg_no_log(rt2, MemoryRead<uint32_t>(address2));
break; break;
} }
case LDP_s: { case LDP_s: {
set_sreg(rt, MemoryRead<float>(address)); DCHECK(access_size == kSRegSize);
set_sreg(rt2, MemoryRead<float>(address + kSRegSize)); set_sreg_no_log(rt, MemoryRead<float>(address));
set_sreg_no_log(rt2, MemoryRead<float>(address2));
break; break;
} }
case LDP_x: { case LDP_x: {
set_xreg(rt, MemoryRead<uint64_t>(address)); DCHECK(access_size == kXRegSize);
set_xreg(rt2, MemoryRead<uint64_t>(address + kXRegSize)); set_xreg_no_log(rt, MemoryRead<uint64_t>(address));
set_xreg_no_log(rt2, MemoryRead<uint64_t>(address2));
break; break;
} }
case LDP_d: { case LDP_d: {
set_dreg(rt, MemoryRead<double>(address)); DCHECK(access_size == kDRegSize);
set_dreg(rt2, MemoryRead<double>(address + kDRegSize)); set_dreg_no_log(rt, MemoryRead<double>(address));
set_dreg_no_log(rt2, MemoryRead<double>(address2));
break; break;
} }
case LDPSW_x: { case LDPSW_x: {
set_xreg(rt, MemoryRead<int32_t>(address)); DCHECK(access_size == kWRegSize);
set_xreg(rt2, MemoryRead<int32_t>(address + kWRegSize)); set_xreg_no_log(rt, MemoryRead<int32_t>(address));
set_xreg_no_log(rt2, MemoryRead<int32_t>(address2));
break; break;
} }
case STP_w: { case STP_w: {
DCHECK(access_size == kWRegSize);
MemoryWrite<uint32_t>(address, wreg(rt)); MemoryWrite<uint32_t>(address, wreg(rt));
MemoryWrite<uint32_t>(address + kWRegSize, wreg(rt2)); MemoryWrite<uint32_t>(address2, wreg(rt2));
break; break;
} }
case STP_s: { case STP_s: {
DCHECK(access_size == kSRegSize);
MemoryWrite<float>(address, sreg(rt)); MemoryWrite<float>(address, sreg(rt));
MemoryWrite<float>(address + kSRegSize, sreg(rt2)); MemoryWrite<float>(address2, sreg(rt2));
break; break;
} }
case STP_x: { case STP_x: {
DCHECK(access_size == kXRegSize);
MemoryWrite<uint64_t>(address, xreg(rt)); MemoryWrite<uint64_t>(address, xreg(rt));
MemoryWrite<uint64_t>(address + kXRegSize, xreg(rt2)); MemoryWrite<uint64_t>(address2, xreg(rt2));
break; break;
} }
case STP_d: { case STP_d: {
DCHECK(access_size == kDRegSize);
MemoryWrite<double>(address, dreg(rt)); MemoryWrite<double>(address, dreg(rt));
MemoryWrite<double>(address + kDRegSize, dreg(rt2)); MemoryWrite<double>(address2, dreg(rt2));
break; break;
} }
default: UNREACHABLE(); 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 // Handle the writeback for loads after the load to ensure safe pop
// operation even when interrupted in the middle of it. The stack pointer // 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 // is only updated after the load so pop(fp) will never break the invariant
...@@ -1629,7 +1783,7 @@ void Simulator::LoadStorePairHelper(Instruction* instr, ...@@ -1629,7 +1783,7 @@ void Simulator::LoadStorePairHelper(Instruction* instr,
if (instr->IsLoad()) { if (instr->IsLoad()) {
// For loads the address pre writeback is used to check access below the // For loads the address pre writeback is used to check access below the
// stack. // stack.
stack = reinterpret_cast<uint8_t*>(sp()); stack = sp();
LoadStoreWriteBack(addr_reg, offset, addrmode); LoadStoreWriteBack(addr_reg, offset, addrmode);
} }
...@@ -1641,24 +1795,37 @@ void Simulator::LoadStorePairHelper(Instruction* instr, ...@@ -1641,24 +1795,37 @@ void Simulator::LoadStorePairHelper(Instruction* instr,
void Simulator::VisitLoadLiteral(Instruction* instr) { void Simulator::VisitLoadLiteral(Instruction* instr) {
uint8_t* address = instr->LiteralAddress(); uintptr_t address = instr->LiteralAddress();
unsigned rt = instr->Rt(); unsigned rt = instr->Rt();
switch (instr->Mask(LoadLiteralMask)) { switch (instr->Mask(LoadLiteralMask)) {
case LDR_w_lit: set_wreg(rt, MemoryRead<uint32_t>(address)); break; // Use _no_log variants to suppress the register trace (LOG_REGS,
case LDR_x_lit: set_xreg(rt, MemoryRead<uint64_t>(address)); break; // LOG_FP_REGS), then print a more detailed log.
case LDR_s_lit: set_sreg(rt, MemoryRead<float>(address)); break; case LDR_w_lit:
case LDR_d_lit: set_dreg(rt, MemoryRead<double>(address)); break; 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(); default: UNREACHABLE();
} }
} }
uint8_t* Simulator::LoadStoreAddress(unsigned addr_reg, uintptr_t Simulator::LoadStoreAddress(unsigned addr_reg, int64_t offset,
int64_t offset, AddrMode addrmode) {
AddrMode addrmode) {
const unsigned kSPRegCode = kSPRegInternalCode & kRegCodeMask; 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)) { if ((addr_reg == kSPRegCode) && ((address % 16) != 0)) {
// When the base register is SP the stack pointer is required to be // When the base register is SP the stack pointer is required to be
// quadword aligned prior to the address calculation and write-backs. // quadword aligned prior to the address calculation and write-backs.
...@@ -1670,7 +1837,7 @@ uint8_t* Simulator::LoadStoreAddress(unsigned addr_reg, ...@@ -1670,7 +1837,7 @@ uint8_t* Simulator::LoadStoreAddress(unsigned addr_reg,
address += offset; address += offset;
} }
return reinterpret_cast<uint8_t*>(address); return address;
} }
...@@ -1685,12 +1852,12 @@ void Simulator::LoadStoreWriteBack(unsigned addr_reg, ...@@ -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)) { if ((address >= stack_limit_) && (address < stack)) {
fprintf(stream_, "ACCESS BELOW STACK POINTER:\n"); fprintf(stream_, "ACCESS BELOW STACK POINTER:\n");
fprintf(stream_, " sp is here: 0x%16p\n", stack); fprintf(stream_, " sp is here: 0x%016" PRIx64 "\n", stack);
fprintf(stream_, " access was here: 0x%16p\n", address); fprintf(stream_, " access was here: 0x%016" PRIx64 "\n", address);
fprintf(stream_, " stack limit is here: 0x%16p\n", stack_limit_); fprintf(stream_, " stack limit is here: 0x%016" PRIx64 "\n", stack_limit_);
fprintf(stream_, "\n"); fprintf(stream_, "\n");
FATAL("ACCESS BELOW STACK POINTER"); FATAL("ACCESS BELOW STACK POINTER");
} }
...@@ -2245,6 +2412,7 @@ void Simulator::VisitFPConditionalCompare(Instruction* instr) { ...@@ -2245,6 +2412,7 @@ void Simulator::VisitFPConditionalCompare(Instruction* instr) {
} else { } else {
// If the condition fails, set the status flags to the nzcv immediate. // If the condition fails, set the status flags to the nzcv immediate.
nzcv().SetFlags(instr->Nzcv()); nzcv().SetFlags(instr->Nzcv());
LogSystemRegister(NZCV);
} }
break; break;
} }
...@@ -3027,8 +3195,14 @@ void Simulator::VisitSystem(Instruction* instr) { ...@@ -3027,8 +3195,14 @@ void Simulator::VisitSystem(Instruction* instr) {
} }
case MSR: { case MSR: {
switch (instr->ImmSystemRegister()) { switch (instr->ImmSystemRegister()) {
case NZCV: nzcv().SetRawValue(xreg(instr->Rt())); break; case NZCV:
case FPCR: fpcr().SetRawValue(xreg(instr->Rt())); break; nzcv().SetRawValue(xreg(instr->Rt()));
LogSystemRegister(NZCV);
break;
case FPCR:
fpcr().SetRawValue(xreg(instr->Rt()));
LogSystemRegister(FPCR);
break;
default: UNIMPLEMENTED(); default: UNIMPLEMENTED();
} }
break; break;
...@@ -3239,8 +3413,8 @@ void Simulator::Debug() { ...@@ -3239,8 +3413,8 @@ void Simulator::Debug() {
} else if ((strcmp(cmd, "print") == 0) || (strcmp(cmd, "p") == 0)) { } else if ((strcmp(cmd, "print") == 0) || (strcmp(cmd, "p") == 0)) {
if (argc == 2) { if (argc == 2) {
if (strcmp(arg1, "all") == 0) { if (strcmp(arg1, "all") == 0) {
PrintRegisters(true); PrintRegisters();
PrintFPRegisters(true); PrintFPRegisters();
} else { } else {
if (!PrintValue(arg1)) { if (!PrintValue(arg1)) {
PrintF("%s unrecognized\n", arg1); PrintF("%s unrecognized\n", arg1);
...@@ -3444,7 +3618,7 @@ void Simulator::VisitException(Instruction* instr) { ...@@ -3444,7 +3618,7 @@ void Simulator::VisitException(Instruction* instr) {
if (FLAG_trace_sim_messages || FLAG_trace_sim || (parameters & BREAK)) { if (FLAG_trace_sim_messages || FLAG_trace_sim || (parameters & BREAK)) {
if (message != NULL) { if (message != NULL) {
PrintF(stream_, PrintF(stream_,
"%sDebugger hit %d: %s%s%s\n", "# %sDebugger hit %d: %s%s%s\n",
clr_debug_number, clr_debug_number,
code, code,
clr_debug_message, clr_debug_message,
...@@ -3452,7 +3626,7 @@ void Simulator::VisitException(Instruction* instr) { ...@@ -3452,7 +3626,7 @@ void Simulator::VisitException(Instruction* instr) {
clr_normal); clr_normal);
} else { } else {
PrintF(stream_, PrintF(stream_,
"%sDebugger hit %d.%s\n", "# %sDebugger hit %d.%s\n",
clr_debug_number, clr_debug_number,
code, code,
clr_normal); clr_normal);
...@@ -3479,9 +3653,9 @@ void Simulator::VisitException(Instruction* instr) { ...@@ -3479,9 +3653,9 @@ void Simulator::VisitException(Instruction* instr) {
// Don't print information that is already being traced. // Don't print information that is already being traced.
parameters &= ~log_parameters(); parameters &= ~log_parameters();
// Print the requested information. // Print the requested information.
if (parameters & LOG_SYS_REGS) PrintSystemRegisters(true); if (parameters & LOG_SYS_REGS) PrintSystemRegisters();
if (parameters & LOG_REGS) PrintRegisters(true); if (parameters & LOG_REGS) PrintRegisters();
if (parameters & LOG_FP_REGS) PrintFPRegisters(true); if (parameters & LOG_FP_REGS) PrintFPRegisters();
} }
// The stop parameters are inlined in the code. Skip them: // The stop parameters are inlined in the code. Skip them:
......
...@@ -312,7 +312,6 @@ class Simulator : public DecoderVisitor { ...@@ -312,7 +312,6 @@ class Simulator : public DecoderVisitor {
DCHECK(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstructionSize)); DCHECK(IsAligned(reinterpret_cast<uintptr_t>(pc_), kInstructionSize));
CheckBreakNext(); CheckBreakNext();
Decode(pc_); Decode(pc_);
LogProcessorState();
increment_pc(); increment_pc();
CheckBreakpoints(); CheckBreakpoints();
} }
...@@ -348,16 +347,13 @@ class Simulator : public DecoderVisitor { ...@@ -348,16 +347,13 @@ class Simulator : public DecoderVisitor {
return reg<int64_t>(code, r31mode); return reg<int64_t>(code, r31mode);
} }
// Write 'size' bits of 'value' into an integer register. The value is // Write 'value' into an integer register. The value is zero-extended. This
// zero-extended. This behaviour matches AArch64 register writes. // behaviour matches AArch64 register writes.
// Like set_reg(), but infer the access size from the template type.
template<typename T> template<typename T>
void set_reg(unsigned code, T value, void set_reg(unsigned code, T value,
Reg31Mode r31mode = Reg31IsZeroRegister) { Reg31Mode r31mode = Reg31IsZeroRegister) {
DCHECK(code < kNumberOfRegisters); set_reg_no_log(code, value, r31mode);
if (!IsZeroRegister(code, r31mode)) LogRegister(code, r31mode);
registers_[code].Set(value);
} }
// Common specialized accessors for the set_reg() template. // Common specialized accessors for the set_reg() template.
...@@ -371,6 +367,26 @@ class Simulator : public DecoderVisitor { ...@@ -371,6 +367,26 @@ class Simulator : public DecoderVisitor {
set_reg(code, value, r31mode); 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. // Commonly-used special cases.
template<typename T> template<typename T>
void set_lr(T value) { void set_lr(T value) {
...@@ -430,9 +446,13 @@ class Simulator : public DecoderVisitor { ...@@ -430,9 +446,13 @@ class Simulator : public DecoderVisitor {
// This behaviour matches AArch64 register writes. // This behaviour matches AArch64 register writes.
template<typename T> template<typename T>
void set_fpreg(unsigned code, T value) { void set_fpreg(unsigned code, T value) {
DCHECK((sizeof(value) == kDRegSize) || (sizeof(value) == kSRegSize)); set_fpreg_no_log(code, value);
DCHECK(code < kNumberOfFPRegisters);
fpregisters_[code].Set(value); if (sizeof(value) <= kSRegSize) {
LogFPRegister(code, kPrintSRegValue);
} else {
LogFPRegister(code, kPrintDRegValue);
}
} }
// Common specialized accessors for the set_fpreg() template. // Common specialized accessors for the set_fpreg() template.
...@@ -452,6 +472,22 @@ class Simulator : public DecoderVisitor { ...@@ -452,6 +472,22 @@ class Simulator : public DecoderVisitor {
set_fpreg(code, value); 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& nzcv() { return nzcv_; }
SimSystemRegister& fpcr() { return fpcr_; } SimSystemRegister& fpcr() { return fpcr_; }
...@@ -478,33 +514,68 @@ class Simulator : public DecoderVisitor { ...@@ -478,33 +514,68 @@ class Simulator : public DecoderVisitor {
// Disassemble instruction at the given address. // Disassemble instruction at the given address.
void PrintInstructionsAt(Instruction* pc, uint64_t count); void PrintInstructionsAt(Instruction* pc, uint64_t count);
void PrintSystemRegisters(bool print_all = false); // Print all registers of the specified types.
void PrintRegisters(bool print_all_regs = false); void PrintRegisters();
void PrintFPRegisters(bool print_all_regs = false); void PrintFPRegisters();
void PrintProcessorState(); void PrintSystemRegisters();
void PrintWrite(uintptr_t address, uint64_t value, unsigned num_bytes);
// Like Print* (above), but respect log_parameters().
void LogSystemRegisters() { void LogSystemRegisters() {
if (log_parameters_ & LOG_SYS_REGS) PrintSystemRegisters(); if (log_parameters() & LOG_SYS_REGS) PrintSystemRegisters();
} }
void LogRegisters() { void LogRegisters() {
if (log_parameters_ & LOG_REGS) PrintRegisters(); if (log_parameters() & LOG_REGS) PrintRegisters();
} }
void LogFPRegisters() { 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() { void LogFPRegister(unsigned code,
LogSystemRegisters(); PrintFPRegisterSizes sizes = kPrintAllFPRegValues) {
LogRegisters(); if (log_parameters() & LOG_FP_REGS) PrintFPRegister(code, sizes);
LogFPRegisters();
} }
template <typename T> void LogSystemRegister(SystemRegister id) {
void LogWrite(uintptr_t address, T value) { if (log_parameters() & LOG_SYS_REGS) PrintSystemRegister(id);
uint64_t raw_value = 0; }
DCHECK(sizeof(value) <= sizeof(raw_value));
if (log_parameters_ & LOG_WRITE) { // Print memory accesses.
memcpy(&raw_value, &value, sizeof(value)); void PrintRead(uintptr_t address, size_t size, unsigned reg_code);
PrintWrite(address, raw_value, sizeof(value)); 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_; } int log_parameters() { return log_parameters_; }
...@@ -595,14 +666,14 @@ class Simulator : public DecoderVisitor { ...@@ -595,14 +666,14 @@ class Simulator : public DecoderVisitor {
int64_t offset, int64_t offset,
AddrMode addrmode); AddrMode addrmode);
void LoadStorePairHelper(Instruction* instr, AddrMode addrmode); void LoadStorePairHelper(Instruction* instr, AddrMode addrmode);
uint8_t* LoadStoreAddress(unsigned addr_reg, uintptr_t LoadStoreAddress(unsigned addr_reg, int64_t offset,
int64_t offset, AddrMode addrmode);
AddrMode addrmode);
void LoadStoreWriteBack(unsigned addr_reg, void LoadStoreWriteBack(unsigned addr_reg,
int64_t offset, int64_t offset,
AddrMode addrmode); 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> template <typename T, typename A>
T MemoryRead(A address) { T MemoryRead(A address) {
T value; T value;
...@@ -612,11 +683,11 @@ class Simulator : public DecoderVisitor { ...@@ -612,11 +683,11 @@ class Simulator : public DecoderVisitor {
return value; return value;
} }
// Memory write helpers.
template <typename T, typename A> template <typename T, typename A>
void MemoryWrite(A address, T value) { void MemoryWrite(A address, T value) {
STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) || STATIC_ASSERT((sizeof(value) == 1) || (sizeof(value) == 2) ||
(sizeof(value) == 4) || (sizeof(value) == 8)); (sizeof(value) == 4) || (sizeof(value) == 8));
LogWrite(reinterpret_cast<uintptr_t>(address), value);
memcpy(reinterpret_cast<void*>(address), &value, sizeof(value)); memcpy(reinterpret_cast<void*>(address), &value, sizeof(value));
} }
...@@ -771,10 +842,10 @@ class Simulator : public DecoderVisitor { ...@@ -771,10 +842,10 @@ class Simulator : public DecoderVisitor {
static const uint32_t kConditionFlagsMask = 0xf0000000; static const uint32_t kConditionFlagsMask = 0xf0000000;
// Stack // Stack
byte* stack_; uintptr_t stack_;
static const intptr_t stack_protection_size_ = KB; static const size_t stack_protection_size_ = KB;
intptr_t stack_size_; size_t stack_size_;
byte* stack_limit_; uintptr_t stack_limit_;
Decoder<DispatchingDecoderVisitor>* decoder_; Decoder<DispatchingDecoderVisitor>* decoder_;
Decoder<DispatchingDecoderVisitor>* disassembler_decoder_; Decoder<DispatchingDecoderVisitor>* disassembler_decoder_;
......
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