| #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 |