Skip to content

Support label-based sideband commands for printing register contents #2024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions fesvr/htif.cc
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,22 @@ htif_t::~htif_t()
{
for (auto d : dynamic_devices)
delete d;

if (intrinsic_label_log_stream) {
intrinsic_label_log_stream->close();
delete intrinsic_label_log_stream;
}
}

std::ostream &htif_t::log_label_intrinsic_output(void) {
if (intrinsic_label_log_stream)
return *intrinsic_label_log_stream;

if (intrinsic_label_log_file.empty())
return std::cout;

intrinsic_label_log_stream = new std::ofstream(intrinsic_label_log_file);
return *intrinsic_label_log_stream;
}

void htif_t::start()
Expand Down Expand Up @@ -183,11 +199,8 @@ void htif_t::load_symbols(std::map<std::string, uint64_t>& symbols)
fprintf(stderr, "warning: tohost and fromhost symbols not in ELF; can't communicate with target\n");
}

for (auto i : symbols) {
auto it = addr2symbol.find(i.second);
if ( it == addr2symbol.end())
addr2symbol[i.second] = i.first;
}
for (auto i : symbols)
addr2symbol[i.second].push_back(i.first);
}

void htif_t::load_program()
Expand All @@ -211,7 +224,20 @@ const char* htif_t::get_symbol(uint64_t addr)
if(it == addr2symbol.end())
return nullptr;

return it->second.c_str();
if (it->second.empty())
return nullptr;

return it->second[0].c_str();
}

std::vector<std::string> htif_t::get_all_symbols(uint64_t addr)
{
auto it = addr2symbol.find(addr);

if(it == addr2symbol.end())
return std::vector<std::string>();

return it->second;
}

bool htif_t::should_exit() const {
Expand Down Expand Up @@ -362,6 +388,9 @@ void htif_t::parse_arguments(int argc, char ** argv)
case HTIF_LONG_OPTIONS_OPTIND + 7:
symbol_elfs.push_back(optarg);
break;
case HTIF_LONG_OPTIONS_OPTIND + 8:
intrinsic_label_log_file = optarg;
break;
case '?':
if (!opterr)
break;
Expand Down Expand Up @@ -408,6 +437,10 @@ void htif_t::parse_arguments(int argc, char ** argv)
c = HTIF_LONG_OPTIONS_OPTIND + 7;
optarg = optarg + 12;
}
else if (arg.find("+intrinsic-label-log=") == 0) {
c = HTIF_LONG_OPTIONS_OPTIND + 8;
optarg = optarg + 21;
}
else if (arg.find("+permissive-off") == 0) {
if (opterr)
throw std::invalid_argument("Found +permissive-off when not parsing permissively");
Expand Down
11 changes: 10 additions & 1 deletion fesvr/htif.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ class htif_t : public chunked_memif_t

// Given an address, return symbol from addr2symbol map
const char* get_symbol(uint64_t addr);
std::vector<std::string> get_all_symbols(uint64_t addr);

std::ostream &log_label_intrinsic_output(void);

// Return true if the simulation should exit due to a signal,
// or end-of-test from HTIF, or an instruction limit.
Expand Down Expand Up @@ -112,7 +115,10 @@ class htif_t : public chunked_memif_t
std::vector<std::string> payloads;

std::vector<std::string> symbol_elfs;
std::map<uint64_t, std::string> addr2symbol;
std::map<uint64_t, std::vector<std::string>> addr2symbol;

std::string intrinsic_label_log_file;
std::ofstream *intrinsic_label_log_stream = nullptr;

friend class memif_t;
friend class syscall_t;
Expand Down Expand Up @@ -142,6 +148,8 @@ class htif_t : public chunked_memif_t
+payload=PATH\n\
--symbol-elf=PATH Populate the symbol table with the ELF file at PATH\n\
+symbol-elf=PATH\n\
--intrinsic-label-log=PATH File for output caused by intrinsic labels\n\
+intrinsic-label-log=PATH\n\
\n\
HOST OPTIONS (currently unsupported)\n\
--disk=DISK Add DISK device. Use a ramdisk since this isn't\n\
Expand All @@ -162,6 +170,7 @@ TARGET (RISC-V BINARY) OPTIONS\n\
{"signature-granularity", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 5 }, \
{"target-argument", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 6 }, \
{"symbol-elf", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 7 }, \
{"intrinsic-label-log", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 8 }, \
{0, 0, 0, 0}

#endif // __HTIF_H
8 changes: 8 additions & 0 deletions riscv/execute.cc
Original file line number Diff line number Diff line change
Expand Up @@ -289,13 +289,17 @@ void processor_t::step(size_t n)
throw wait_for_interrupt_t();
}

sim->process_intrinsic_labels_pre_addr(state, state.pc);

in_wfi = false;
insn_fetch_t fetch = mmu->load_insn(pc);
if (debug && !state.serialized)
disasm(fetch.insn);
pc = execute_insn_logged(this, pc, fetch);
advance_pc();

sim->process_intrinsic_labels_post_addr(state, state.pc);

// Resume from debug mode in critical error
if (state.critical_error && !state.debug_mode) {
if (state.dcsr->read() & DCSR_CETRIG) {
Expand All @@ -310,6 +314,8 @@ void processor_t::step(size_t n)
}
else while (instret < n)
{
sim->process_intrinsic_labels_pre_addr(state, state.pc);

// Main simulation loop, fast path.
for (auto ic_entry = _mmu->access_icache(pc); ; ) {
auto fetch = ic_entry->data;
Expand All @@ -324,6 +330,8 @@ void processor_t::step(size_t n)
}

advance_pc();

sim->process_intrinsic_labels_post_addr(state, state.pc);
}
}
catch(trap_t& t)
Expand Down
40 changes: 40 additions & 0 deletions riscv/sim.cc
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,46 @@ const char* sim_t::get_symbol(uint64_t paddr)
return htif_t::get_symbol(paddr);
}

std::vector<std::string> sim_t::get_all_symbols(uint64_t paddr)
{
return htif_t::get_all_symbols(paddr);
}

void sim_t::process_label_intrinsic(const state_t &state, const std::string &sym) {
size_t dot_pos = sym.find('.');
auto prefix = sym.substr(0, dot_pos);
if (prefix == "printreg")
process_print_register_label_intrinsic(state, sym.substr(dot_pos + 1));
}

void sim_t::process_print_register_label_intrinsic(const state_t &state, const std::string &sym) {
size_t dot_pos = sym.find('.');
if (dot_pos != std::string::npos) {
std::string reg_str = sym.substr(1, dot_pos - 1);
std::string id_str = sym.substr(dot_pos + 1, std::string::npos - dot_pos - 1);

int reg_num = std::stoi(reg_str);
if (reg_num >= 0 && reg_num < 32)
htif_t::log_label_intrinsic_output() << id_str << "=0x" << std::hex << state.XPR[reg_num] << std::endl;
}
}

void sim_t::process_intrinsic_labels_pre_addr(const state_t &state, uint64_t addr) {
for (const std::string &sym : get_all_symbols(addr)) {
std::string prefix("spike.pre.");
if (sym.substr(0, prefix.size()) == prefix)
process_label_intrinsic(state, sym.substr(prefix.size()));
}
}

void sim_t::process_intrinsic_labels_post_addr(const state_t &state, uint64_t addr) {
for (const std::string &sym : get_all_symbols(addr)) {
std::string prefix("spike.post.");
if (sym.substr(0, prefix.size()) == prefix)
process_label_intrinsic(state, sym.substr(prefix.size()));
}
}

// htif

void sim_t::reset()
Expand Down
9 changes: 9 additions & 0 deletions riscv/sim.h
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ class sim_t : public htif_t, public simif_t
void set_rom();

virtual const char* get_symbol(uint64_t paddr) override;
virtual std::vector<std::string> get_all_symbols(uint64_t paddr) override;

virtual void process_intrinsic_labels_pre_addr(const state_t &state, uint64_t addr) override;
virtual void process_intrinsic_labels_post_addr(const state_t &state, uint64_t addr) override;

// presents a prompt for introspection into the simulation
void interactive();
Expand Down Expand Up @@ -157,6 +161,11 @@ class sim_t : public htif_t, public simif_t
virtual size_t chunk_max_size() override { return 8; }
virtual endianness_t get_target_endianness() const override;

private:
// label intrinsic handling
void process_label_intrinsic(const state_t &state, const std::string &sym);
void process_print_register_label_intrinsic(const state_t &state, const std::string &sym);

public:
// Initialize this after procs, because in debug_module_t::reset() we
// enumerate processors, which segfaults if procs hasn't been initialized
Expand Down
6 changes: 6 additions & 0 deletions riscv/simif.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "cfg.h"

class processor_t;
struct state_t;
class mmu_t;

// this is the interface to the simulator used by the processors and memory
Expand All @@ -24,10 +25,15 @@ class simif_t
// Callback for processors to let the simulation know they were reset.
virtual void proc_reset(unsigned id) = 0;

// used to process intrinsic labels
virtual void process_intrinsic_labels_pre_addr(const state_t &state, uint64_t addr) = 0;
virtual void process_intrinsic_labels_post_addr(const state_t &state, uint64_t addr) = 0;

virtual const cfg_t &get_cfg() const = 0;
virtual const std::map<size_t, processor_t*>& get_harts() const = 0;

virtual const char* get_symbol(uint64_t paddr) = 0;
virtual std::vector<std::string> get_all_symbols(uint64_t paddr) = 0;

virtual ~simif_t() = default;

Expand Down