| Index: src/arm64/simulator-arm64.cc
|
| diff --git a/src/arm64/simulator-arm64.cc b/src/arm64/simulator-arm64.cc
|
| index 2e43dfc2219336d03c85c1dbe0866c5caac28ac5..e798beb61dc9731e8763a3bd6c48a836f18a8d00 100644
|
| --- a/src/arm64/simulator-arm64.cc
|
| +++ b/src/arm64/simulator-arm64.cc
|
| @@ -30,30 +30,28 @@ namespace internal {
|
|
|
|
|
| // Helpers for colors.
|
| -// Depending on your terminal configuration, the colour names may not match the
|
| -// observed colours.
|
| -#define COLOUR(colour_code) "\033[" colour_code "m"
|
| -#define BOLD(colour_code) "1;" colour_code
|
| -#define NORMAL ""
|
| -#define GREY "30"
|
| -#define GREEN "32"
|
| -#define ORANGE "33"
|
| -#define BLUE "34"
|
| -#define PURPLE "35"
|
| -#define INDIGO "36"
|
| -#define WHITE "37"
|
| +#define COLOUR(colour_code) "\033[0;" colour_code "m"
|
| +#define COLOUR_BOLD(colour_code) "\033[1;" colour_code "m"
|
| +#define NORMAL ""
|
| +#define GREY "30"
|
| +#define RED "31"
|
| +#define GREEN "32"
|
| +#define YELLOW "33"
|
| +#define BLUE "34"
|
| +#define MAGENTA "35"
|
| +#define CYAN "36"
|
| +#define WHITE "37"
|
| typedef char const * const TEXT_COLOUR;
|
| TEXT_COLOUR clr_normal = FLAG_log_colour ? COLOUR(NORMAL) : "";
|
| -TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR(BOLD(GREY)) : "";
|
| -TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(BOLD(WHITE)) : "";
|
| -TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR(BOLD(BLUE)) : "";
|
| -TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(BOLD(INDIGO)) : "";
|
| -TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR(BOLD(ORANGE)) : "";
|
| -TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(BOLD(PURPLE)) : "";
|
| -TEXT_COLOUR clr_memory_value = FLAG_log_colour ? COLOUR(BOLD(GREEN)) : "";
|
| -TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR(GREEN) : "";
|
| -TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR(BOLD(ORANGE)) : "";
|
| -TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(ORANGE) : "";
|
| +TEXT_COLOUR clr_flag_name = FLAG_log_colour ? COLOUR_BOLD(WHITE) : "";
|
| +TEXT_COLOUR clr_flag_value = FLAG_log_colour ? COLOUR(NORMAL) : "";
|
| +TEXT_COLOUR clr_reg_name = FLAG_log_colour ? COLOUR_BOLD(CYAN) : "";
|
| +TEXT_COLOUR clr_reg_value = FLAG_log_colour ? COLOUR(CYAN) : "";
|
| +TEXT_COLOUR clr_fpreg_name = FLAG_log_colour ? COLOUR_BOLD(MAGENTA) : "";
|
| +TEXT_COLOUR clr_fpreg_value = FLAG_log_colour ? COLOUR(MAGENTA) : "";
|
| +TEXT_COLOUR clr_memory_address = FLAG_log_colour ? COLOUR_BOLD(BLUE) : "";
|
| +TEXT_COLOUR clr_debug_number = FLAG_log_colour ? COLOUR_BOLD(YELLOW) : "";
|
| +TEXT_COLOUR clr_debug_message = FLAG_log_colour ? COLOUR(YELLOW) : "";
|
| TEXT_COLOUR clr_printf = FLAG_log_colour ? COLOUR(GREEN) : "";
|
|
|
|
|
| @@ -337,7 +335,7 @@ uintptr_t Simulator::PopAddress() {
|
| uintptr_t Simulator::StackLimit() const {
|
| // Leave a safety margin of 1024 bytes to prevent overrunning the stack when
|
| // pushing values.
|
| - return reinterpret_cast<uintptr_t>(stack_limit_) + 1024;
|
| + return stack_limit_ + 1024;
|
| }
|
|
|
|
|
| @@ -380,11 +378,11 @@ void Simulator::Init(FILE* stream) {
|
|
|
| // Allocate and setup the simulator stack.
|
| stack_size_ = (FLAG_sim_stack_size * KB) + (2 * stack_protection_size_);
|
| - stack_ = new byte[stack_size_];
|
| + stack_ = reinterpret_cast<uintptr_t>(new byte[stack_size_]);
|
| stack_limit_ = stack_ + stack_protection_size_;
|
| - byte* tos = stack_ + stack_size_ - stack_protection_size_;
|
| - // The stack pointer must be 16 bytes aligned.
|
| - set_sp(reinterpret_cast<int64_t>(tos) & ~0xfUL);
|
| + uintptr_t tos = stack_ + stack_size_ - stack_protection_size_;
|
| + // The stack pointer must be 16-byte aligned.
|
| + set_sp(tos & ~0xfUL);
|
|
|
| stream_ = stream;
|
| print_disasm_ = new PrintDisassembler(stream_);
|
| @@ -420,7 +418,7 @@ void Simulator::ResetState() {
|
|
|
|
|
| Simulator::~Simulator() {
|
| - delete[] stack_;
|
| + delete[] reinterpret_cast<byte*>(stack_);
|
| if (FLAG_log_instruction_stats) {
|
| delete instrument_;
|
| }
|
| @@ -734,15 +732,15 @@ void* Simulator::RedirectExternalReference(void* external_function,
|
|
|
|
|
| const char* Simulator::xreg_names[] = {
|
| -"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
| -"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
| -"ip0", "ip1", "x18", "x19", "x20", "x21", "x22", "x23",
|
| -"x24", "x25", "x26", "cp", "jssp", "fp", "lr", "xzr", "csp"};
|
| +"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",
|
| +"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",
|
| +"ip0", "ip1", "x18", "x19", "x20", "x21", "x22", "x23",
|
| +"x24", "x25", "x26", "cp", "jssp", "fp", "lr", "xzr", "csp"};
|
|
|
| const char* Simulator::wreg_names[] = {
|
| -"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
|
| -"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
|
| -"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
|
| +"w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
|
| +"w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
|
| +"w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
|
| "w24", "w25", "w26", "wcp", "wjssp", "wfp", "wlr", "wzr", "wcsp"};
|
|
|
| const char* Simulator::sreg_names[] = {
|
| @@ -765,40 +763,47 @@ const char* Simulator::vreg_names[] = {
|
|
|
|
|
| const char* Simulator::WRegNameForCode(unsigned code, Reg31Mode mode) {
|
| + STATIC_ASSERT(arraysize(Simulator::wreg_names) == (kNumberOfRegisters + 1));
|
| DCHECK(code < kNumberOfRegisters);
|
| // If the code represents the stack pointer, index the name after zr.
|
| if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
|
| code = kZeroRegCode + 1;
|
| }
|
| - return wreg_names[code];
|
| + // Using basic pointer arithmetic (instead of an array index) avoids an
|
| + // erroneous GCC warning about an out-of-bounds array index.
|
| + return *(wreg_names + code);
|
| }
|
|
|
|
|
| const char* Simulator::XRegNameForCode(unsigned code, Reg31Mode mode) {
|
| + STATIC_ASSERT(arraysize(Simulator::xreg_names) == (kNumberOfRegisters + 1));
|
| DCHECK(code < kNumberOfRegisters);
|
| // If the code represents the stack pointer, index the name after zr.
|
| if ((code == kZeroRegCode) && (mode == Reg31IsStackPointer)) {
|
| code = kZeroRegCode + 1;
|
| }
|
| - return xreg_names[code];
|
| + return *(xreg_names + code);
|
| }
|
|
|
|
|
| const char* Simulator::SRegNameForCode(unsigned code) {
|
| + STATIC_ASSERT(arraysize(Simulator::sreg_names) == kNumberOfFPRegisters);
|
| DCHECK(code < kNumberOfFPRegisters);
|
| - return sreg_names[code];
|
| + return *(sreg_names + code);
|
| }
|
|
|
|
|
| const char* Simulator::DRegNameForCode(unsigned code) {
|
| + STATIC_ASSERT(arraysize(Simulator::dreg_names) == kNumberOfFPRegisters);
|
| DCHECK(code < kNumberOfFPRegisters);
|
| - return dreg_names[code];
|
| + return *(dreg_names + code);
|
| }
|
|
|
|
|
| const char* Simulator::VRegNameForCode(unsigned code) {
|
| + STATIC_ASSERT(arraysize(Simulator::vreg_names) == kNumberOfFPRegisters);
|
| DCHECK(code < kNumberOfFPRegisters);
|
| - return vreg_names[code];
|
| + return *(vreg_names + code);
|
| }
|
|
|
|
|
| @@ -855,6 +860,7 @@ T Simulator::AddWithCarry(bool set_flags,
|
| nzcv().SetZ(Z);
|
| nzcv().SetC(C);
|
| nzcv().SetV(V);
|
| + LogSystemRegister(NZCV);
|
| }
|
| return result;
|
| }
|
| @@ -978,6 +984,7 @@ void Simulator::FPCompare(double val0, double val1) {
|
| } else {
|
| UNREACHABLE();
|
| }
|
| + LogSystemRegister(NZCV);
|
| }
|
|
|
|
|
| @@ -1044,117 +1051,206 @@ void Simulator::PrintInstructionsAt(Instruction* start, uint64_t count) {
|
| }
|
|
|
|
|
| -void Simulator::PrintSystemRegisters(bool print_all) {
|
| - static bool first_run = true;
|
| -
|
| - static SimSystemRegister last_nzcv;
|
| - if (print_all || first_run || (last_nzcv.RawValue() != nzcv().RawValue())) {
|
| - fprintf(stream_, "# %sFLAGS: %sN:%d Z:%d C:%d V:%d%s\n",
|
| - clr_flag_name,
|
| - clr_flag_value,
|
| - nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(),
|
| - clr_normal);
|
| - }
|
| - last_nzcv = nzcv();
|
| -
|
| - static SimSystemRegister last_fpcr;
|
| - if (print_all || first_run || (last_fpcr.RawValue() != fpcr().RawValue())) {
|
| - static const char * rmode[] = {
|
| - "0b00 (Round to Nearest)",
|
| - "0b01 (Round towards Plus Infinity)",
|
| - "0b10 (Round towards Minus Infinity)",
|
| - "0b11 (Round towards Zero)"
|
| - };
|
| - DCHECK(fpcr().RMode() < arraysize(rmode));
|
| - fprintf(stream_, "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
|
| - clr_flag_name,
|
| - clr_flag_value,
|
| - fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()],
|
| - clr_normal);
|
| - }
|
| - last_fpcr = fpcr();
|
| -
|
| - first_run = false;
|
| +void Simulator::PrintSystemRegisters() {
|
| + PrintSystemRegister(NZCV);
|
| + PrintSystemRegister(FPCR);
|
| }
|
|
|
|
|
| -void Simulator::PrintRegisters(bool print_all_regs) {
|
| - static bool first_run = true;
|
| - static int64_t last_regs[kNumberOfRegisters];
|
| -
|
| +void Simulator::PrintRegisters() {
|
| for (unsigned i = 0; i < kNumberOfRegisters; i++) {
|
| - if (print_all_regs || first_run ||
|
| - (last_regs[i] != xreg(i, Reg31IsStackPointer))) {
|
| - fprintf(stream_,
|
| - "# %s%4s:%s 0x%016" PRIx64 "%s\n",
|
| - clr_reg_name,
|
| - XRegNameForCode(i, Reg31IsStackPointer),
|
| - clr_reg_value,
|
| - xreg(i, Reg31IsStackPointer),
|
| - clr_normal);
|
| - }
|
| - // Cache the new register value so the next run can detect any changes.
|
| - last_regs[i] = xreg(i, Reg31IsStackPointer);
|
| + PrintRegister(i);
|
| }
|
| - first_run = false;
|
| }
|
|
|
|
|
| -void Simulator::PrintFPRegisters(bool print_all_regs) {
|
| - static bool first_run = true;
|
| - static uint64_t last_regs[kNumberOfFPRegisters];
|
| -
|
| - // Print as many rows of registers as necessary, keeping each individual
|
| - // register in the same column each time (to make it easy to visually scan
|
| - // for changes).
|
| +void Simulator::PrintFPRegisters() {
|
| for (unsigned i = 0; i < kNumberOfFPRegisters; i++) {
|
| - if (print_all_regs || first_run || (last_regs[i] != dreg_bits(i))) {
|
| + PrintFPRegister(i);
|
| + }
|
| +}
|
| +
|
| +
|
| +void Simulator::PrintRegister(unsigned code, Reg31Mode r31mode) {
|
| + // Don't print writes into xzr.
|
| + if ((code == kZeroRegCode) && (r31mode == Reg31IsZeroRegister)) {
|
| + return;
|
| + }
|
| +
|
| + // The template is "# x<code>:value".
|
| + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s\n",
|
| + clr_reg_name, XRegNameForCode(code, r31mode),
|
| + clr_reg_value, reg<uint64_t>(code, r31mode), clr_normal);
|
| +}
|
| +
|
| +
|
| +void Simulator::PrintFPRegister(unsigned code, PrintFPRegisterSizes sizes) {
|
| + // The template is "# v<code>:bits (d<code>:value, ...)".
|
| +
|
| + DCHECK(sizes != 0);
|
| + DCHECK((sizes & kPrintAllFPRegValues) == sizes);
|
| +
|
| + // Print the raw bits.
|
| + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (",
|
| + clr_fpreg_name, VRegNameForCode(code),
|
| + clr_fpreg_value, fpreg<uint64_t>(code), clr_normal);
|
| +
|
| + // Print all requested value interpretations.
|
| + bool need_separator = false;
|
| + if (sizes & kPrintDRegValue) {
|
| + fprintf(stream_, "%s%s%s: %s%g%s",
|
| + need_separator ? ", " : "",
|
| + clr_fpreg_name, DRegNameForCode(code),
|
| + clr_fpreg_value, fpreg<double>(code), clr_normal);
|
| + need_separator = true;
|
| + }
|
| +
|
| + if (sizes & kPrintSRegValue) {
|
| + fprintf(stream_, "%s%s%s: %s%g%s",
|
| + need_separator ? ", " : "",
|
| + clr_fpreg_name, SRegNameForCode(code),
|
| + clr_fpreg_value, fpreg<float>(code), clr_normal);
|
| + need_separator = true;
|
| + }
|
| +
|
| + // End the value list.
|
| + fprintf(stream_, ")\n");
|
| +}
|
| +
|
| +
|
| +void Simulator::PrintSystemRegister(SystemRegister id) {
|
| + switch (id) {
|
| + case NZCV:
|
| + fprintf(stream_, "# %sNZCV: %sN:%d Z:%d C:%d V:%d%s\n",
|
| + clr_flag_name, clr_flag_value,
|
| + nzcv().N(), nzcv().Z(), nzcv().C(), nzcv().V(),
|
| + clr_normal);
|
| + break;
|
| + case FPCR: {
|
| + static const char * rmode[] = {
|
| + "0b00 (Round to Nearest)",
|
| + "0b01 (Round towards Plus Infinity)",
|
| + "0b10 (Round towards Minus Infinity)",
|
| + "0b11 (Round towards Zero)"
|
| + };
|
| + DCHECK(fpcr().RMode() < arraysize(rmode));
|
| fprintf(stream_,
|
| - "# %s %4s:%s 0x%016" PRIx64 "%s (%s%s:%s %g%s %s:%s %g%s)\n",
|
| - clr_fpreg_name,
|
| - VRegNameForCode(i),
|
| - clr_fpreg_value,
|
| - dreg_bits(i),
|
| - clr_normal,
|
| - clr_fpreg_name,
|
| - DRegNameForCode(i),
|
| - clr_fpreg_value,
|
| - dreg(i),
|
| - clr_fpreg_name,
|
| - SRegNameForCode(i),
|
| - clr_fpreg_value,
|
| - sreg(i),
|
| + "# %sFPCR: %sAHP:%d DN:%d FZ:%d RMode:%s%s\n",
|
| + clr_flag_name, clr_flag_value,
|
| + fpcr().AHP(), fpcr().DN(), fpcr().FZ(), rmode[fpcr().RMode()],
|
| clr_normal);
|
| + break;
|
| }
|
| - // Cache the new register value so the next run can detect any changes.
|
| - last_regs[i] = dreg_bits(i);
|
| + default:
|
| + UNREACHABLE();
|
| }
|
| - first_run = false;
|
| }
|
|
|
|
|
| -void Simulator::PrintProcessorState() {
|
| - PrintSystemRegisters();
|
| - PrintRegisters();
|
| - PrintFPRegisters();
|
| +void Simulator::PrintRead(uintptr_t address,
|
| + size_t size,
|
| + unsigned reg_code) {
|
| + USE(size); // Size is unused here.
|
| +
|
| + // The template is "# x<code>:value <- address".
|
| + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s",
|
| + clr_reg_name, XRegNameForCode(reg_code),
|
| + clr_reg_value, reg<uint64_t>(reg_code), clr_normal);
|
| +
|
| + fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
|
| + clr_memory_address, address, clr_normal);
|
| +}
|
| +
|
| +
|
| +void Simulator::PrintReadFP(uintptr_t address,
|
| + size_t size,
|
| + unsigned reg_code) {
|
| + // The template is "# reg:bits (reg:value) <- address".
|
| + switch (size) {
|
| + case kSRegSize:
|
| + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%gf%s)",
|
| + clr_fpreg_name, VRegNameForCode(reg_code),
|
| + clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
|
| + clr_fpreg_name, SRegNameForCode(reg_code),
|
| + clr_fpreg_value, fpreg<float>(reg_code), clr_normal);
|
| + break;
|
| + case kDRegSize:
|
| + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)",
|
| + clr_fpreg_name, VRegNameForCode(reg_code),
|
| + clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
|
| + clr_fpreg_name, DRegNameForCode(reg_code),
|
| + clr_fpreg_value, fpreg<double>(reg_code), clr_normal);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + fprintf(stream_, " <- %s0x%016" PRIxPTR "%s\n",
|
| + clr_memory_address, address, clr_normal);
|
| }
|
|
|
|
|
| -void Simulator::PrintWrite(uintptr_t address, uint64_t value,
|
| - unsigned num_bytes) {
|
| - // The template is "# value -> address". The format string is not used
|
| - // directly in the printf because some compilers struggle with the
|
| - // parametrized width field (%0*).
|
| - const char* format = "# %s0x%0*" PRIx64 "%s -> %s0x%016" PRIxPTR "%s\n";
|
| - fprintf(stream_,
|
| - format,
|
| - clr_memory_value,
|
| - num_bytes * 2, // The width in hexadecimal characters.
|
| - value,
|
| - clr_normal,
|
| - clr_memory_address,
|
| - address,
|
| - clr_normal);
|
| +void Simulator::PrintWrite(uintptr_t address,
|
| + size_t size,
|
| + unsigned reg_code) {
|
| + // The template is "# reg:value -> address". To keep the trace tidy and
|
| + // readable, the value is aligned with the values in the register trace.
|
| + switch (size) {
|
| + case kByteSizeInBytes:
|
| + fprintf(stream_, "# %s%5s<7:0>: %s0x%02" PRIx8 "%s",
|
| + clr_reg_name, WRegNameForCode(reg_code),
|
| + clr_reg_value, reg<uint8_t>(reg_code), clr_normal);
|
| + break;
|
| + case kHalfWordSizeInBytes:
|
| + fprintf(stream_, "# %s%5s<15:0>: %s0x%04" PRIx16 "%s",
|
| + clr_reg_name, WRegNameForCode(reg_code),
|
| + clr_reg_value, reg<uint16_t>(reg_code), clr_normal);
|
| + break;
|
| + case kWRegSize:
|
| + fprintf(stream_, "# %s%5s: %s0x%08" PRIx32 "%s",
|
| + clr_reg_name, WRegNameForCode(reg_code),
|
| + clr_reg_value, reg<uint32_t>(reg_code), clr_normal);
|
| + break;
|
| + case kXRegSize:
|
| + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s",
|
| + clr_reg_name, XRegNameForCode(reg_code),
|
| + clr_reg_value, reg<uint64_t>(reg_code), clr_normal);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
|
| + clr_memory_address, address, clr_normal);
|
| +}
|
| +
|
| +
|
| +void Simulator::PrintWriteFP(uintptr_t address,
|
| + size_t size,
|
| + unsigned reg_code) {
|
| + // The template is "# reg:bits (reg:value) -> address". To keep the trace tidy
|
| + // and readable, the value is aligned with the values in the register trace.
|
| + switch (size) {
|
| + case kSRegSize:
|
| + fprintf(stream_, "# %s%5s<31:0>: %s0x%08" PRIx32 "%s (%s%s: %s%gf%s)",
|
| + clr_fpreg_name, VRegNameForCode(reg_code),
|
| + clr_fpreg_value, fpreg<uint32_t>(reg_code), clr_normal,
|
| + clr_fpreg_name, SRegNameForCode(reg_code),
|
| + clr_fpreg_value, fpreg<float>(reg_code), clr_normal);
|
| + break;
|
| + case kDRegSize:
|
| + fprintf(stream_, "# %s%5s: %s0x%016" PRIx64 "%s (%s%s: %s%g%s)",
|
| + clr_fpreg_name, VRegNameForCode(reg_code),
|
| + clr_fpreg_value, fpreg<uint64_t>(reg_code), clr_normal,
|
| + clr_fpreg_name, DRegNameForCode(reg_code),
|
| + clr_fpreg_value, fpreg<double>(reg_code), clr_normal);
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +
|
| + fprintf(stream_, " -> %s0x%016" PRIxPTR "%s\n",
|
| + clr_memory_address, address, clr_normal);
|
| }
|
|
|
|
|
| @@ -1383,6 +1479,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 +1520,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 +1561,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 +1576,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 +1605,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 +1629,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 +1665,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 +1683,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 +1693,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 +1779,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 +1791,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 +1833,7 @@ uint8_t* Simulator::LoadStoreAddress(unsigned addr_reg,
|
| address += offset;
|
| }
|
|
|
| - return reinterpret_cast<uint8_t*>(address);
|
| + return address;
|
| }
|
|
|
|
|
| @@ -1685,12 +1848,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 +2408,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 +3191,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 +3409,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 +3614,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 +3622,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 +3649,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:
|
|
|