Revert "Merge pull request #1917 from YosysHQ/eddie/abc9_delay_check"
[yosys.git] / passes / cmds / cover.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2014 Clifford Wolf <clifford@clifford.at>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include <sys/types.h>
22
23 #ifndef _WIN32
24 # include <unistd.h>
25 #else
26 # include <io.h>
27 #endif
28
29 #include "kernel/register.h"
30 #include "kernel/rtlil.h"
31 #include "kernel/log.h"
32
33 USING_YOSYS_NAMESPACE
34 PRIVATE_NAMESPACE_BEGIN
35
36 struct CoverPass : public Pass {
37 CoverPass() : Pass("cover", "print code coverage counters") { }
38 void help() YS_OVERRIDE
39 {
40 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
41 log("\n");
42 log(" cover [options] [pattern]\n");
43 log("\n");
44 log("Print the code coverage counters collected using the cover() macro in the Yosys\n");
45 log("C++ code. This is useful to figure out what parts of Yosys are utilized by a\n");
46 log("test bench.\n");
47 log("\n");
48 log(" -q\n");
49 log(" Do not print output to the normal destination (console and/or log file)\n");
50 log("\n");
51 log(" -o file\n");
52 log(" Write output to this file, truncate if exists.\n");
53 log("\n");
54 log(" -a file\n");
55 log(" Write output to this file, append if exists.\n");
56 log("\n");
57 log(" -d dir\n");
58 log(" Write output to a newly created file in the specified directory.\n");
59 log("\n");
60 log("When one or more pattern (shell wildcards) are specified, then only counters\n");
61 log("matching at least one pattern are printed.\n");
62 log("\n");
63 log("\n");
64 log("It is also possible to instruct Yosys to print the coverage counters on program\n");
65 log("exit to a file using environment variables:\n");
66 log("\n");
67 log(" YOSYS_COVER_DIR=\"{dir-name}\" yosys {args}\n");
68 log("\n");
69 log(" This will create a file (with an auto-generated name) in this\n");
70 log(" directory and write the coverage counters to it.\n");
71 log("\n");
72 log(" YOSYS_COVER_FILE=\"{file-name}\" yosys {args}\n");
73 log("\n");
74 log(" This will append the coverage counters to the specified file.\n");
75 log("\n");
76 log("\n");
77 log("Hint: Use the following AWK command to consolidate Yosys coverage files:\n");
78 log("\n");
79 log(" gawk '{ p[$3] = $1; c[$3] += $2; } END { for (i in p)\n");
80 log(" printf \"%%-60s %%10d %%s\\n\", p[i], c[i], i; }' {files} | sort -k3\n");
81 log("\n");
82 log("\n");
83 log("Coverage counters are only available in Yosys for Linux.\n");
84 log("\n");
85 }
86 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
87 {
88 std::vector<FILE*> out_files;
89 std::vector<std::string> patterns;
90 bool do_log = true;
91
92 size_t argidx;
93 for (argidx = 1; argidx < args.size(); argidx++)
94 {
95 if (args[argidx] == "-q") {
96 do_log = false;
97 continue;
98 }
99 if ((args[argidx] == "-o" || args[argidx] == "-a" || args[argidx] == "-d") && argidx+1 < args.size()) {
100 const char *open_mode = args[argidx] == "-a" ? "a+" : "w";
101 const std::string &filename = args[++argidx];
102 FILE *f = nullptr;
103 if (args[argidx-1] == "-d") {
104 #if defined(_WIN32) || defined(__wasm)
105 log_cmd_error("The 'cover -d' option is not supported on this platform.\n");
106 #else
107 char filename_buffer[4096];
108 snprintf(filename_buffer, 4096, "%s/yosys_cover_%d_XXXXXX.txt", filename.c_str(), getpid());
109 f = fdopen(mkstemps(filename_buffer, 4), "w");
110 #endif
111 } else {
112 f = fopen(filename.c_str(), open_mode);
113 }
114 if (f == NULL) {
115 for (auto f : out_files)
116 fclose(f);
117 log_cmd_error("Can't create file %s%s.\n", args[argidx-1] == "-d" ? "in directory " : "", args[argidx].c_str());
118 }
119 out_files.push_back(f);
120 continue;
121 }
122 break;
123 }
124 while (argidx < args.size() && args[argidx].compare(0, 1, "-") != 0)
125 patterns.push_back(args[argidx++]);
126 extra_args(args, argidx, design);
127
128 if (do_log) {
129 log_header(design, "Printing code coverage counters.\n");
130 log("\n");
131 }
132
133 #if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
134 for (auto &it : get_coverage_data()) {
135 if (!patterns.empty()) {
136 for (auto &p : patterns)
137 if (patmatch(p.c_str(), it.first.c_str()))
138 goto pattern_match;
139 continue;
140 }
141 pattern_match:
142 for (auto f : out_files)
143 fprintf(f, "%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
144 if (do_log)
145 log("%-60s %10d %s\n", it.second.first.c_str(), it.second.second, it.first.c_str());
146 }
147 #else
148 for (auto f : out_files)
149 fclose(f);
150
151 log_cmd_error("This version of Yosys was not built with support for code coverage counters.\n");
152 #endif
153
154 for (auto f : out_files)
155 fclose(f);
156 }
157 } CoverPass;
158
159 PRIVATE_NAMESPACE_END