blob: 10d6a9412a9b47fe4aa73f7618f9aa25f853d547 [file] [log] [blame]
#include "uhdmastreport.h"
#include "frontends/ast/ast.h"
#include <fstream>
#include <sys/stat.h>
#include <uhdm/BaseClass.h>
#include <unordered_set>
namespace systemverilog_plugin
{
using namespace ::Yosys;
void UhdmAstReport::mark_handled(const UHDM::BaseClass *object)
{
handled_count_per_file.insert(std::make_pair(object->VpiFile(), 0));
auto it = unhandled.find(object);
if (it != unhandled.end()) {
unhandled.erase(it);
handled_count_per_file.at(std::string(object->VpiFile()))++;
}
}
void UhdmAstReport::mark_handled(const vpiHandle obj_h)
{
auto handle = reinterpret_cast<const uhdm_handle *>(obj_h);
mark_handled(reinterpret_cast<const UHDM::BaseClass *>(handle->object));
}
static std::string replace_in_string(std::string str, const std::string &to_find, const std::string &to_replace_with)
{
size_t pos = str.find(to_find);
while (pos != std::string::npos) {
str.replace(pos, to_find.length(), to_replace_with);
pos += to_replace_with.length();
pos = str.find(to_find, pos);
}
return str;
}
void UhdmAstReport::write(const std::string &directory)
{
std::unordered_map<std::string, std::unordered_set<unsigned>> unhandled_per_file;
for (auto object : unhandled) {
if (!object->VpiFile().empty() && object->VpiFile() != AST::current_filename) {
unhandled_per_file.insert(std::make_pair(object->VpiFile(), std::unordered_set<unsigned>()));
unhandled_per_file.at(std::string(object->VpiFile())).insert(object->VpiLineNo());
handled_count_per_file.insert(std::make_pair(object->VpiFile(), 0));
}
}
unsigned total_handled = 0;
for (auto &hc : handled_count_per_file) {
if (!hc.first.empty() && hc.first != AST::current_filename) {
unhandled_per_file.insert(std::make_pair(hc.first, std::unordered_set<unsigned>()));
total_handled += hc.second;
}
}
float coverage = total_handled * 100.f / (total_handled + unhandled.size());
mkdir(directory.c_str(), 0777);
std::ofstream index_file(directory + "/index.html");
index_file << "<!DOCTYPE html>\n<html>\n<head>\n<style>h3{margin:0;padding:10}</style>\n</head><body>" << std::endl;
index_file << "<h2>Overall coverage: " << coverage << "%</h2>" << std::endl;
for (auto &unhandled_in_file : unhandled_per_file) {
// Calculate coverage in file
unsigned handled_count = handled_count_per_file.at(unhandled_in_file.first);
unsigned unhandled_count = unhandled_in_file.second.size();
float coverage = handled_count * 100.f / (handled_count + unhandled_count);
// Add to the index file
std::string report_filename = replace_in_string(unhandled_in_file.first, "/", ".") + ".html";
index_file << "<h3>Cov: " << coverage << "%<a href=\"" << report_filename << "\">" << unhandled_in_file.first << "</a></h3><br>" << std::endl;
// Write the report file
std::ofstream report_file(directory + '/' + report_filename);
report_file << "<!DOCTYPE html>\n<html>\n<head>\n<style>\nbody{font-size:12px;}pre{display:inline}</style>\n</head><body>" << std::endl;
report_file << "<h2>" << unhandled_in_file.first << " | Coverage: " << coverage << "%</h2>" << std::endl;
std::ifstream source_file(unhandled_in_file.first); // Read the source code
unsigned line_number = 1;
std::string line;
while (std::getline(source_file, line)) {
if (unhandled_in_file.second.find(line_number) == unhandled_in_file.second.end()) {
report_file << line_number << "<pre> " << line << "</pre><br>" << std::endl;
} else {
report_file << line_number << "<pre style=\"background-color: #FFB6C1;\"> " << line << "</pre><br>" << std::endl;
}
++line_number;
}
report_file << "</body>\n</html>" << std::endl;
}
index_file << "</body>\n</html>" << std::endl;
}
} // namespace systemverilog_plugin