11 Commits

13 changed files with 761 additions and 613 deletions

View File

@@ -83,6 +83,10 @@ elseif(TARGET elfio::elfio)
else() else()
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing") message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
endif() endif()
if(TARGET lz4::lz4)
target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_LZ4)
target_link_libraries(${PROJECT_NAME} PUBLIC lz4::lz4)
endif()
if(TARGET RapidJSON) if(TARGET RapidJSON)
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON) target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
endif() endif()

View File

@@ -163,13 +163,13 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
uint${byteSize(reg.size)}_t ${reg.name} = 0;<% uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
}}%> }}%>
} reg; } reg;
#pragma pack(pop)
uint32_t trap_state = 0, pending_trap = 0; uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0; uint64_t icount = 0;
uint64_t cycle = 0; uint64_t cycle = 0;
uint64_t instret = 0; uint64_t instret = 0;
uint32_t instruction = 0; uint32_t instruction = 0;
uint32_t last_branch = 0; uint32_t last_branch = 0;
#pragma pack(pop)
std::array<address_type, 4> addr_mode; std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0; uint64_t interrupt_sim=0;

View File

@@ -314,11 +314,9 @@ typename vm_base<ARCH>::virt_addr_t vm_impl<ARCH>::execute_inst(finish_cond_e co
<%}}%>// calculate next pc value <%}}%>// calculate next pc value
*NEXT_PC = *PC + ${instr.length/8}; *NEXT_PC = *PC + ${instr.length/8};
// execute instruction // execute instruction
try {
<%instr.behavior.eachLine{%>${it} <%instr.behavior.eachLine{%>${it}
<%}%>} catch(...){} <%}%>TRAP_${instr.name}:break;
} }// @suppress("No break at end of case")<%}%>
break;<%}%>
default: { default: {
*NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2); *NEXT_PC = *PC + ((instr & 3) == 3 ? 4 : 2);
raise(0, 2); raise(0, 2);

View File

@@ -567,22 +567,22 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
try { try {
switch (space) { switch (space) {
case traits<BASE>::MEM: { case traits<BASE>::MEM: {
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) { auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
fault_data = addr; fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr); if (is_debug(access)) throw trap_access(0, addr);
this->trap_state = (1 << 31); // issue trap 0 this->trap_state = (1 << 31); // issue trap 0
return iss::Err; return iss::Err;
} }
try { try {
auto alignment = access == iss::access_type::FETCH? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length; if(!is_debug(access) && (addr&(alignment-1))){
if(alignment>1 && (addr&(alignment-1))){
this->trap_state = 1<<31 | 4<<16; this->trap_state = 1<<31 | 4<<16;
fault_data=addr; fault_data=addr;
return iss::Err; return iss::Err;
} }
auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr}); auto phys_addr = type==iss::address_type::PHYSICAL?phys_addr_t{access, space, addr}:BASE::v2p(iss::addr_t{access, type, space, addr});
auto res = iss::Err; auto res = iss::Err;
if(access != access_type::FETCH && memfn_range.size()){ if(!is_fetch(access) && memfn_range.size()){
auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){ auto it = std::find_if(std::begin(memfn_range), std::end(memfn_range), [phys_addr](std::tuple<uint64_t, uint64_t> const& a){
return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val; return std::get<0>(a)<=phys_addr.val && (std::get<0>(a)+std::get<1>(a))>phys_addr.val;
}); });

View File

@@ -611,13 +611,19 @@ iss::status riscv_hart_msu_vp<BASE>::read(const address_type type, const access_
try { try {
switch (space) { switch (space) {
case traits<BASE>::MEM: { case traits<BASE>::MEM: {
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) { auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
fault_data = addr; fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr); if (access && iss::access_type::DEBUG) throw trap_access(0, addr);
this->trap_state = (1 << 31); // issue trap 0 this->trap_state = (1 << 31); // issue trap 0
return iss::Err; return iss::Err;
} }
try { try {
if(!is_debug(access) && (addr&(alignment-1))){
this->trap_state = 1<<31 | 4<<16;
fault_data=addr;
return iss::Err;
}
if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary if (unlikely((addr & ~PGMASK) != ((addr + length - 1) & ~PGMASK))) { // we may cross a page boundary
vm_info vm = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp); vm_info vm = hart_state_type::decode_vm_info(this->reg.PRIV, state.satp);
if (vm.levels != 0) { // VM is active if (vm.levels != 0) { // VM is active

View File

@@ -705,22 +705,22 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
switch (space) { switch (space) {
case traits<BASE>::MEM: { case traits<BASE>::MEM: {
if(FEAT & FEAT_PMP){ if(FEAT & FEAT_PMP){
if(!pmp_check(access, addr, length) && (access&access_type::DEBUG) != access_type::DEBUG) { if(!pmp_check(access, addr, length) && !is_debug(access)) {
fault_data = addr; fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr); if (is_debug(access)) throw trap_access(0, addr);
this->trap_state = (1 << 31) | ((access==access_type::FETCH?1:5) << 16); // issue trap 1 this->trap_state = (1 << 31) | ((access==access_type::FETCH?1:5) << 16); // issue trap 1
return iss::Err; return iss::Err;
} }
} }
if (unlikely((access == iss::access_type::FETCH || access == iss::access_type::DEBUG_FETCH) && (addr & 0x1) == 1)) { auto alignment = is_fetch(access)? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length;
if (unlikely(is_fetch(access) && (addr&(alignment-1)))) {
fault_data = addr; fault_data = addr;
if (access && iss::access_type::DEBUG) throw trap_access(0, addr); if (is_debug(access)) throw trap_access(0, addr);
this->trap_state = (1 << 31); // issue trap 0 this->trap_state = (1 << 31); // issue trap 0
return iss::Err; return iss::Err;
} }
try { try {
auto alignment = access == iss::access_type::FETCH? (traits<BASE>::MISA_VAL&0x100? 2 : 4) : length; if(!is_debug(access) && (addr&(alignment-1))){
if(alignment>1 && (addr&(alignment-1))){
this->trap_state = 1<<31 | 4<<16; this->trap_state = 1<<31 | 4<<16;
fault_data=addr; fault_data=addr;
return iss::Err; return iss::Err;

View File

@@ -252,13 +252,13 @@ struct tgc_c: public arch_if {
uint8_t PRIV = 0; uint8_t PRIV = 0;
uint32_t DPC = 0; uint32_t DPC = 0;
} reg; } reg;
#pragma pack(pop)
uint32_t trap_state = 0, pending_trap = 0; uint32_t trap_state = 0, pending_trap = 0;
uint64_t icount = 0; uint64_t icount = 0;
uint64_t cycle = 0; uint64_t cycle = 0;
uint64_t instret = 0; uint64_t instret = 0;
uint32_t instruction = 0; uint32_t instruction = 0;
uint32_t last_branch = 0; uint32_t last_branch = 0;
#pragma pack(pop)
std::array<address_type, 4> addr_mode; std::array<address_type, 4> addr_mode;
uint64_t interrupt_sim=0; uint64_t interrupt_sim=0;

View File

@@ -81,7 +81,7 @@ public:
void callback(instr_info_t instr_info, exec_info const&) override; void callback(instr_info_t instr_info, exec_info const&) override;
private: private:
iss::instrumentation_if *arch_instr; iss::instrumentation_if *instr_if;
std::vector<instr_desc> delays; std::vector<instr_desc> delays;
struct pair_hash { struct pair_hash {
size_t operator()(const std::pair<uint64_t, uint64_t> &p) const { size_t operator()(const std::pair<uint64_t, uint64_t> &p) const {

View File

@@ -44,7 +44,7 @@
namespace iss { namespace iss {
namespace plugin { namespace plugin {
class lz4compress_steambuf;
class cov : public iss::vm_plugin { class cov : public iss::vm_plugin {
struct instr_delay { struct instr_delay {
std::string instr_name; std::string instr_name;
@@ -88,10 +88,13 @@ public:
private: private:
iss::instrumentation_if *instr_if {nullptr}; iss::instrumentation_if *instr_if {nullptr};
std::ofstream output; std::ofstream output;
#ifdef WITH_LZ4
std::unique_ptr<lz4compress_steambuf> strbuf;
std::ostream ostr;
#endif
std::string filename; std::string filename;
std::vector<instr_desc> delays; std::vector<instr_desc> delays;
bool jumped, first; bool jumped{false}, first{true};
}; };
} }
} }

View File

@@ -60,13 +60,13 @@ int main(int argc, char *argv[]) {
desc.add_options() desc.add_options()
("help,h", "Print help message") ("help,h", "Print help message")
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity") ("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
("logfile,f", po::value<std::string>(), "Sets default log file.") ("logfile,l", po::value<std::string>(), "Sets default log file.")
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly") ("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use") ("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate") ("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
("reset,r", po::value<std::string>(), "reset address") ("reset,r", po::value<std::string>(), "reset address")
("dump-ir", "dump the intermediate representation") ("dump-ir", "dump the intermediate representation")
("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load") ("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
("mem,m", po::value<std::string>(), "the memory input file") ("mem,m", po::value<std::string>(), "the memory input file")
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate") ("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
("backend", po::value<std::string>()->default_value("interp"), "the memory input file") ("backend", po::value<std::string>()->default_value("interp"), "the memory input file")

View File

@@ -48,7 +48,7 @@ using namespace rapidjson;
using namespace std; using namespace std;
iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name) iss::plugin::cycle_estimate::cycle_estimate(string const& config_file_name)
: arch_instr(nullptr) : instr_if(nullptr)
, config_file_name(config_file_name) , config_file_name(config_file_name)
{ {
} }
@@ -57,9 +57,9 @@ iss::plugin::cycle_estimate::~cycle_estimate() {
} }
bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) { bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if& vm) {
arch_instr = vm.get_arch()->get_instrumentation_if(); instr_if = vm.get_arch()->get_instrumentation_if();
if(!arch_instr) return false; if(!instr_if) return false;
const string core_name = arch_instr->core_type_name(); const string core_name = instr_if->core_type_name();
if (config_file_name.length() > 0) { if (config_file_name.length() > 0) {
ifstream is(config_file_name); ifstream is(config_file_name);
if (is.is_open()) { if (is.is_open()) {
@@ -108,11 +108,11 @@ bool iss::plugin::cycle_estimate::registration(const char* const version, vm_if&
} }
void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const& exc_info) { void iss::plugin::cycle_estimate::callback(instr_info_t instr_info, exec_info const& exc_info) {
assert(arch_instr && "No instrumentation interface available but callback executed"); assert(instr_if && "No instrumentation interface available but callback executed");
auto entry = delays[instr_info.instr_id]; auto entry = delays[instr_info.instr_id];
bool taken = exc_info.branch_taken; bool taken = exc_info.branch_taken;
if (exc_info.branch_taken && (entry.taken > 1)) if (exc_info.branch_taken && (entry.taken > 1))
arch_instr->set_curr_instr_cycles(entry.taken); instr_if->set_curr_instr_cycles(entry.taken);
else if (entry.not_taken > 1) else if (entry.not_taken > 1)
arch_instr->set_curr_instr_cycles(entry.not_taken); instr_if->set_curr_instr_cycles(entry.not_taken);
} }

View File

@@ -9,27 +9,99 @@
#include <rapidjson/ostreamwrapper.h> #include <rapidjson/ostreamwrapper.h>
#include <rapidjson/error/en.h> #include <rapidjson/error/en.h>
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#ifdef WITH_LZ4
#include <lz4frame.h>
#endif
namespace iss {
namespace plugin {
using namespace rapidjson; using namespace rapidjson;
using namespace std; using namespace std;
iss::plugin::cov::cov(std::string const &filename) #ifdef WITH_LZ4
: instr_if(nullptr) class lz4compress_steambuf: public std::streambuf {
, filename(filename) public:
{ lz4compress_steambuf(const lz4compress_steambuf&) = delete;
output.open("output.trc"); lz4compress_steambuf& operator=(const lz4compress_steambuf&) = delete;
jumped = false; lz4compress_steambuf(std::ostream &sink, size_t buf_size)
first = true; : sink(sink)
} , src_buf(buf_size)
, dest_buf(LZ4F_compressBound(buf_size, nullptr))
{
auto errCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
if (LZ4F_isError(errCode) != 0)
throw std::runtime_error(std::string("Failed to create LZ4 context: ") + LZ4F_getErrorName(errCode));
size_t ret = LZ4F_compressBegin(ctx, &dest_buf.front(), dest_buf.capacity(), nullptr);
if (LZ4F_isError(ret) != 0)
throw std::runtime_error(std::string("Failed to start LZ4 compression: ") + LZ4F_getErrorName(ret));
setp(src_buf.data(), src_buf.data() + src_buf.size() - 1);
sink.write(dest_buf.data(), ret);
}
iss::plugin::cov::~cov() { ~lz4compress_steambuf() {
output.close(); close();
} }
bool iss::plugin::cov::registration(const char *const version, vm_if& vm) { void close() {
if (closed)
return;
sync();
auto ret = LZ4F_compressEnd(ctx, dest_buf.data(), dest_buf.capacity(), nullptr);
if (LZ4F_isError(ret) != 0)
throw std::runtime_error(std::string("Failed to finish LZ4 compression: ") + LZ4F_getErrorName(ret));
sink.write(dest_buf.data(), ret);
LZ4F_freeCompressionContext(ctx);
closed = true;
}
private:
int_type overflow(int_type ch) override {
compress_and_write();
*pptr() = static_cast<char_type>(ch);
pbump(1);
return ch;
}
int_type sync() override {
compress_and_write();
return 0;
}
void compress_and_write() {
if (closed)
throw std::runtime_error("Cannot write to closed stream");
if(auto orig_size = pptr() - pbase()){
auto ret = LZ4F_compressUpdate(ctx, dest_buf.data(), dest_buf.capacity(), pbase(), orig_size, nullptr);
if (LZ4F_isError(ret) != 0)
throw std::runtime_error(std::string("LZ4 compression failed: ") + LZ4F_getErrorName(ret));
if(ret) sink.write(dest_buf.data(), ret);
pbump(-orig_size);
}
}
std::ostream &sink;
std::vector<char> src_buf;
std::vector<char> dest_buf;
LZ4F_compressionContext_t ctx{ nullptr };
bool closed{ false };
};
#endif
cov::cov(std::string const &filename)
: instr_if(nullptr)
, filename(filename)
, output("output.trc")
#ifdef WITH_LZ4
, strbuf(new lz4compress_steambuf(output, 4096))
, ostr(strbuf.get())
#endif
{ }
cov::~cov() { }
bool cov::registration(const char *const version, vm_if& vm) {
instr_if = vm.get_arch()->get_instrumentation_if(); instr_if = vm.get_arch()->get_instrumentation_if();
if(!instr_if) return false; if(!instr_if) return false;
const string core_name = instr_if->core_type_name(); const string core_name = instr_if->core_type_name();
@@ -78,60 +150,31 @@ bool iss::plugin::cov::registration(const char *const version, vm_if& vm) {
} }
} }
return true; return true;
} }
inline string formatPC(uint64_t pc) { void cov::callback(instr_info_t iinfo, const exec_info& einfo) {
stringstream stream;
stream << "0x" << std::hex << pc;
return stream.str();
}
void iss::plugin::cov::callback(instr_info_t iinfo, const exec_info& einfo) {
// auto delay = 0;
// auto entry = delays[iinfo.instr_id];
// bool taken = einfo.branch_taken;
// if (einfo.branch_taken)
// delay = entry.taken;
// else
// delay = entry.not_taken;
//
// if (first){
// output << formatPC(instr_if->get_pc()) << "," << delay;
// first = false;
// }
// if(instr_if->get_next_pc()-instr_if->get_pc() != delays[iinfo.instr_id].size/8){
// //The goal is to keep the output in start-target pairs, so after a jump the target address needs to get written
// //to the output. If the target happens to also be a start, we keep the pairing by adding a 0-delay entry.
// if (jumped)
// output <<"\n" <<formatPC(instr_if->get_pc()) << "," << 0;
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
// jumped = true;
// }
// else{
// if (jumped){
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
// jumped = false;
// }
// else if(delay!=1){
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay;
// output <<"\n" << formatPC(instr_if->get_pc()) << "," << 0;
// }
//
// }
//source code for the full output
auto delay = 0; auto delay = 0;
size_t id = iinfo.instr_id; size_t id = iinfo.instr_id;
auto entry = delays[id]; auto entry = delays[id];
auto instr = instr_if->get_instr_word(); auto instr = instr_if->get_instr_word();
auto call = (id==2 || id==3) && bit_sub<7,5>(instr)!=0; auto call = id==65 || id ==86 || ((id==2 || id==3) && bit_sub<7,5>(instr)!=0) ;//not taking care of tail calls (jalr with loading x6)
bool taken = einfo.branch_taken; bool taken = einfo.branch_taken;
if (einfo.branch_taken) bool compressed = (instr&0x3)!=0x3;
if (einfo.branch_taken) {
delay = entry.taken; delay = entry.taken;
else if(entry.taken > 1)
instr_if->set_curr_instr_cycles(entry.taken);
} else {
delay = entry.not_taken; delay = entry.not_taken;
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay << "\n"; if (entry.not_taken > 1)
instr_if->set_curr_instr_cycles(entry.not_taken);
}
#ifndef WITH_LZ4
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
#else
auto rdbuf=ostr.rdbuf();
ostr<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
#endif
}
}
} }

File diff suppressed because it is too large Load Diff