2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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.
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.
20 #include "kernel/yosys.h"
21 #include "libs/sha1/sha1.h"
22 #include "backends/rtlil/rtlil_backend.h"
24 #if !defined(_WIN32) || defined(__MINGW32__)
25 # include <sys/time.h>
28 #if defined(__linux__) || defined(__FreeBSD__)
41 std::vector
<FILE*> log_files
;
42 std::vector
<std::ostream
*> log_streams
;
43 std::map
<std::string
, std::set
<std::string
>> log_hdump
;
44 std::vector
<YS_REGEX_TYPE
> log_warn_regexes
, log_nowarn_regexes
, log_werror_regexes
;
45 dict
<std::string
, LogExpectedItem
> log_expect_log
, log_expect_warning
, log_expect_error
;
46 std::set
<std::string
> log_warnings
, log_experimentals
, log_experimentals_ignored
;
47 int log_warnings_count
= 0;
48 int log_warnings_count_noexpect
= 0;
49 bool log_expect_no_warnings
= false;
50 bool log_hdump_all
= false;
51 FILE *log_errfile
= NULL
;
52 SHA1
*log_hasher
= NULL
;
54 bool log_time
= false;
55 bool log_error_stderr
= false;
56 bool log_cmd_error_throw
= false;
57 bool log_quiet_warnings
= false;
58 int log_verbose_level
;
59 string log_last_error
;
60 void (*log_error_atexit
)() = NULL
;
62 int log_make_debug
= 0;
63 int log_force_debug
= 0;
64 int log_debug_suppressed
= 0;
66 vector
<int> header_count
;
67 vector
<char*> log_id_cache
;
68 vector
<shared_str
> string_buf
;
69 int string_buf_index
= -1;
71 static struct timeval initial_tv
= { 0, 0 };
72 static bool next_print_log
= false;
73 static int log_newline_count
= 0;
75 static void log_id_cache_clear()
77 for (auto p
: log_id_cache
)
82 #if defined(_WIN32) && !defined(__MINGW32__)
83 // this will get time information and return it in timeval, simulating gettimeofday()
84 int gettimeofday(struct timeval
*tv
, struct timezone
*tz
)
86 LARGE_INTEGER counter
;
89 QueryPerformanceFrequency(&freq
);
90 QueryPerformanceCounter(&counter
);
92 counter
.QuadPart
*= 1000000;
93 counter
.QuadPart
/= freq
.QuadPart
;
95 tv
->tv_sec
= long(counter
.QuadPart
/ 1000000);
96 tv
->tv_usec
= counter
.QuadPart
% 1000000;
102 void logv(const char *format
, va_list ap
)
104 while (format
[0] == '\n' && format
[1] != 0) {
109 if (log_make_debug
&& !ys_debug(1))
112 std::string str
= vstringf(format
, ap
);
117 size_t nnl_pos
= str
.find_last_not_of('\n');
118 if (nnl_pos
== std::string::npos
)
119 log_newline_count
+= GetSize(str
);
121 log_newline_count
= GetSize(str
) - nnl_pos
- 1;
124 log_hasher
->update(str
);
128 std::string time_str
;
130 if (next_print_log
|| initial_tv
.tv_sec
== 0) {
131 next_print_log
= false;
133 gettimeofday(&tv
, NULL
);
134 if (initial_tv
.tv_sec
== 0)
136 if (tv
.tv_usec
< initial_tv
.tv_usec
) {
138 tv
.tv_usec
+= 1000000;
140 tv
.tv_sec
-= initial_tv
.tv_sec
;
141 tv
.tv_usec
-= initial_tv
.tv_usec
;
142 time_str
+= stringf("[%05d.%06d] ", int(tv
.tv_sec
), int(tv
.tv_usec
));
145 if (format
[0] && format
[strlen(format
)-1] == '\n')
146 next_print_log
= true;
148 for (auto f
: log_files
)
149 fputs(time_str
.c_str(), f
);
151 for (auto f
: log_streams
)
155 for (auto f
: log_files
)
156 fputs(str
.c_str(), f
);
158 for (auto f
: log_streams
)
161 static std::string linebuffer
;
162 static bool log_warn_regex_recusion_guard
= false;
164 if (!log_warn_regex_recusion_guard
)
166 log_warn_regex_recusion_guard
= true;
168 if (log_warn_regexes
.empty() && log_expect_log
.empty())
176 if (!linebuffer
.empty() && linebuffer
.back() == '\n') {
177 for (auto &re
: log_warn_regexes
)
178 if (YS_REGEX_NS::regex_search(linebuffer
, re
))
179 log_warning("Found log message matching -W regex:\n%s", str
.c_str());
181 for (auto &item
: log_expect_log
)
182 if (YS_REGEX_NS::regex_search(linebuffer
, item
.second
.pattern
))
183 item
.second
.current_count
++;
189 log_warn_regex_recusion_guard
= false;
193 void logv_header(RTLIL::Design
*design
, const char *format
, va_list ap
)
195 bool pop_errfile
= false;
198 if (header_count
.size() > 0)
199 header_count
.back()++;
201 if (int(header_count
.size()) <= log_verbose_level
&& log_errfile
!= NULL
) {
202 log_files
.push_back(log_errfile
);
206 std::string header_id
;
208 for (int c
: header_count
)
209 header_id
+= stringf("%s%d", header_id
.empty() ? "" : ".", c
);
211 log("%s. ", header_id
.c_str());
216 log_hdump
[header_id
].insert("yosys_dump_" + header_id
+ ".il");
218 if (log_hdump
.count(header_id
) && design
!= nullptr)
219 for (auto &filename
: log_hdump
.at(header_id
)) {
220 log("Dumping current design to '%s'.\n", filename
.c_str());
222 IdString::xtrace_db_dump();
223 Pass::call(design
, {"dump", "-o", filename
});
225 log("#X# -- end of dump --\n");
229 log_files
.pop_back();
232 static void logv_warning_with_prefix(const char *prefix
,
233 const char *format
, va_list ap
)
235 std::string message
= vstringf(format
, ap
);
236 bool suppressed
= false;
238 for (auto &re
: log_nowarn_regexes
)
239 if (YS_REGEX_NS::regex_search(message
, re
))
244 log("Suppressed %s%s", prefix
, message
.c_str());
248 int bak_log_make_debug
= log_make_debug
;
251 for (auto &re
: log_werror_regexes
)
252 if (YS_REGEX_NS::regex_search(message
, re
))
253 log_error("%s", message
.c_str());
255 bool warning_match
= false;
256 for (auto &item
: log_expect_warning
)
257 if (YS_REGEX_NS::regex_search(message
, item
.second
.pattern
)) {
258 item
.second
.current_count
++;
259 warning_match
= true;
262 if (log_warnings
.count(message
))
264 log("%s%s", prefix
, message
.c_str());
269 if (log_errfile
!= NULL
&& !log_quiet_warnings
)
270 log_files
.push_back(log_errfile
);
272 log("%s%s", prefix
, message
.c_str());
275 if (log_errfile
!= NULL
&& !log_quiet_warnings
)
276 log_files
.pop_back();
278 log_warnings
.insert(message
);
282 log_warnings_count_noexpect
++;
283 log_warnings_count
++;
284 log_make_debug
= bak_log_make_debug
;
288 void logv_warning(const char *format
, va_list ap
)
290 logv_warning_with_prefix("Warning: ", format
, ap
);
293 void logv_warning_noprefix(const char *format
, va_list ap
)
295 logv_warning_with_prefix("", format
, ap
);
298 void log_file_warning(const std::string
&filename
, int lineno
,
299 const char *format
, ...)
302 va_start(ap
, format
);
303 std::string prefix
= stringf("%s:%d: Warning: ",
304 filename
.c_str(), lineno
);
305 logv_warning_with_prefix(prefix
.c_str(), format
, ap
);
309 void log_file_info(const std::string
&filename
, int lineno
,
310 const char *format
, ...)
313 va_start(ap
, format
);
314 std::string fmt
= stringf("%s:%d: Info: %s",
315 filename
.c_str(), lineno
, format
);
316 logv(fmt
.c_str(), ap
);
321 static void logv_error_with_prefix(const char *prefix
,
322 const char *format
, va_list ap
)
325 auto backup_log_files
= log_files
;
327 int bak_log_make_debug
= log_make_debug
;
331 if (log_errfile
!= NULL
)
332 log_files
.push_back(log_errfile
);
334 if (log_error_stderr
)
335 for (auto &f
: log_files
)
339 log_last_error
= vstringf(format
, ap
);
340 log("%s%s", prefix
, log_last_error
.c_str());
343 log_make_debug
= bak_log_make_debug
;
345 for (auto &item
: log_expect_error
)
346 if (YS_REGEX_NS::regex_search(log_last_error
, item
.second
.pattern
))
347 item
.second
.current_count
++;
349 log_check_expected();
351 if (log_error_atexit
)
354 YS_DEBUGTRAP_IF_DEBUGGING
;
357 log_files
= backup_log_files
;
359 #elif defined(_MSC_VER)
366 void logv_error(const char *format
, va_list ap
)
368 logv_error_with_prefix("ERROR: ", format
, ap
);
371 void log_file_error(const string
&filename
, int lineno
,
372 const char *format
, ...)
375 va_start(ap
, format
);
376 std::string prefix
= stringf("%s:%d: ERROR: ",
377 filename
.c_str(), lineno
);
378 logv_error_with_prefix(prefix
.c_str(), format
, ap
);
381 void log(const char *format
, ...)
384 va_start(ap
, format
);
389 void log_header(RTLIL::Design
*design
, const char *format
, ...)
392 va_start(ap
, format
);
393 logv_header(design
, format
, ap
);
397 void log_warning(const char *format
, ...)
400 va_start(ap
, format
);
401 logv_warning(format
, ap
);
405 void log_experimental(const char *format
, ...)
408 va_start(ap
, format
);
409 string s
= vstringf(format
, ap
);
412 if (log_experimentals_ignored
.count(s
) == 0 && log_experimentals
.count(s
) == 0) {
413 log_warning("Feature '%s' is experimental.\n", s
.c_str());
414 log_experimentals
.insert(s
);
418 void log_warning_noprefix(const char *format
, ...)
421 va_start(ap
, format
);
422 logv_warning_noprefix(format
, ap
);
426 void log_error(const char *format
, ...)
429 va_start(ap
, format
);
430 logv_error(format
, ap
);
433 void log_cmd_error(const char *format
, ...)
436 va_start(ap
, format
);
438 if (log_cmd_error_throw
) {
439 log_last_error
= vstringf(format
, ap
);
440 log("ERROR: %s", log_last_error
.c_str());
442 throw log_cmd_error_exception();
445 logv_error(format
, ap
);
450 if (log_newline_count
< 2) log("\n");
451 if (log_newline_count
< 2) log("\n");
456 header_count
.push_back(0);
461 header_count
.pop_back();
462 log_id_cache_clear();
464 string_buf_index
= -1;
468 #if (defined(__linux__) || defined(__FreeBSD__)) && defined(YOSYS_ENABLE_PLUGINS)
469 void log_backtrace(const char *prefix
, int levels
)
471 if (levels
<= 0) return;
476 if ((p
= __builtin_extract_return_addr(__builtin_return_address(0))) && dladdr(p
, &dli
)) {
477 log("%sframe #1: %p %s(%p) %s(%p)\n", prefix
, p
, dli
.dli_fname
, dli
.dli_fbase
, dli
.dli_sname
, dli
.dli_saddr
);
479 log("%sframe #1: ---\n", prefix
);
483 if (levels
<= 1) return;
486 log("%sframe #2: [build Yosys with ENABLE_DEBUG for deeper backtraces]\n", prefix
);
488 if ((p
= __builtin_extract_return_addr(__builtin_return_address(1))) && dladdr(p
, &dli
)) {
489 log("%sframe #2: %p %s(%p) %s(%p)\n", prefix
, p
, dli
.dli_fname
, dli
.dli_fbase
, dli
.dli_sname
, dli
.dli_saddr
);
491 log("%sframe #2: ---\n", prefix
);
495 if (levels
<= 2) return;
497 if ((p
= __builtin_extract_return_addr(__builtin_return_address(2))) && dladdr(p
, &dli
)) {
498 log("%sframe #3: %p %s(%p) %s(%p)\n", prefix
, p
, dli
.dli_fname
, dli
.dli_fbase
, dli
.dli_sname
, dli
.dli_saddr
);
500 log("%sframe #3: ---\n", prefix
);
504 if (levels
<= 3) return;
506 if ((p
= __builtin_extract_return_addr(__builtin_return_address(3))) && dladdr(p
, &dli
)) {
507 log("%sframe #4: %p %s(%p) %s(%p)\n", prefix
, p
, dli
.dli_fname
, dli
.dli_fbase
, dli
.dli_sname
, dli
.dli_saddr
);
509 log("%sframe #4: ---\n", prefix
);
513 if (levels
<= 4) return;
515 if ((p
= __builtin_extract_return_addr(__builtin_return_address(4))) && dladdr(p
, &dli
)) {
516 log("%sframe #5: %p %s(%p) %s(%p)\n", prefix
, p
, dli
.dli_fname
, dli
.dli_fbase
, dli
.dli_sname
, dli
.dli_saddr
);
518 log("%sframe #5: ---\n", prefix
);
522 if (levels
<= 5) return;
524 if ((p
= __builtin_extract_return_addr(__builtin_return_address(5))) && dladdr(p
, &dli
)) {
525 log("%sframe #6: %p %s(%p) %s(%p)\n", prefix
, p
, dli
.dli_fname
, dli
.dli_fbase
, dli
.dli_sname
, dli
.dli_saddr
);
527 log("%sframe #6: ---\n", prefix
);
531 if (levels
<= 6) return;
533 if ((p
= __builtin_extract_return_addr(__builtin_return_address(6))) && dladdr(p
, &dli
)) {
534 log("%sframe #7: %p %s(%p) %s(%p)\n", prefix
, p
, dli
.dli_fname
, dli
.dli_fbase
, dli
.dli_sname
, dli
.dli_saddr
);
536 log("%sframe #7: ---\n", prefix
);
540 if (levels
<= 7) return;
542 if ((p
= __builtin_extract_return_addr(__builtin_return_address(7))) && dladdr(p
, &dli
)) {
543 log("%sframe #8: %p %s(%p) %s(%p)\n", prefix
, p
, dli
.dli_fname
, dli
.dli_fbase
, dli
.dli_sname
, dli
.dli_saddr
);
545 log("%sframe #8: ---\n", prefix
);
549 if (levels
<= 8) return;
551 if ((p
= __builtin_extract_return_addr(__builtin_return_address(8))) && dladdr(p
, &dli
)) {
552 log("%sframe #9: %p %s(%p) %s(%p)\n", prefix
, p
, dli
.dli_fname
, dli
.dli_fbase
, dli
.dli_sname
, dli
.dli_saddr
);
554 log("%sframe #9: ---\n", prefix
);
558 if (levels
<= 9) return;
562 void log_backtrace(const char*, int) { }
565 void log_reset_stack()
567 while (header_count
.size() > 1)
568 header_count
.pop_back();
569 log_id_cache_clear();
571 string_buf_index
= -1;
577 for (auto f
: log_files
)
580 for (auto f
: log_streams
)
584 void log_dump_val_worker(RTLIL::IdString v
) {
585 log("%s", log_id(v
));
588 void log_dump_val_worker(RTLIL::SigSpec v
) {
589 log("%s", log_signal(v
));
592 void log_dump_val_worker(RTLIL::State v
) {
593 log("%s", log_signal(v
));
596 const char *log_signal(const RTLIL::SigSpec
&sig
, bool autoint
)
598 std::stringstream buf
;
599 RTLIL_BACKEND::dump_sigspec(buf
, sig
, autoint
);
601 if (string_buf
.size() < 100) {
602 string_buf
.push_back(buf
.str());
603 return string_buf
.back().c_str();
605 if (++string_buf_index
== 100)
606 string_buf_index
= 0;
607 string_buf
[string_buf_index
] = buf
.str();
608 return string_buf
[string_buf_index
].c_str();
612 const char *log_const(const RTLIL::Const
&value
, bool autoint
)
614 if ((value
.flags
& RTLIL::CONST_FLAG_STRING
) == 0)
615 return log_signal(value
, autoint
);
617 std::string str
= "\"" + value
.decode_string() + "\"";
619 if (string_buf
.size() < 100) {
620 string_buf
.push_back(str
);
621 return string_buf
.back().c_str();
623 if (++string_buf_index
== 100)
624 string_buf_index
= 0;
625 string_buf
[string_buf_index
] = str
;
626 return string_buf
[string_buf_index
].c_str();
630 const char *log_id(RTLIL::IdString str
)
632 log_id_cache
.push_back(strdup(str
.c_str()));
633 const char *p
= log_id_cache
.back();
636 if (p
[1] == '$' || p
[1] == '\\' || p
[1] == 0)
638 if (p
[1] >= '0' && p
[1] <= '9')
643 void log_module(RTLIL::Module
*module
, std::string indent
)
645 std::stringstream buf
;
646 RTLIL_BACKEND::dump_module(buf
, indent
, module
, module
->design
, false);
647 log("%s", buf
.str().c_str());
650 void log_cell(RTLIL::Cell
*cell
, std::string indent
)
652 std::stringstream buf
;
653 RTLIL_BACKEND::dump_cell(buf
, indent
, cell
);
654 log("%s", buf
.str().c_str());
657 void log_wire(RTLIL::Wire
*wire
, std::string indent
)
659 std::stringstream buf
;
660 RTLIL_BACKEND::dump_wire(buf
, indent
, wire
);
661 log("%s", buf
.str().c_str());
664 void log_check_expected()
666 // copy out all of the expected logs so that they cannot be re-checked
667 // or match against themselves
668 dict
<std::string
, LogExpectedItem
> expect_log
, expect_warning
, expect_error
;
669 std::swap(expect_warning
, log_expect_warning
);
670 std::swap(expect_log
, log_expect_log
);
671 std::swap(expect_error
, log_expect_error
);
673 for (auto &item
: expect_warning
) {
674 if (item
.second
.current_count
== 0) {
675 log_warn_regexes
.clear();
676 log_error("Expected warning pattern '%s' not found !\n", item
.first
.c_str());
678 if (item
.second
.current_count
!= item
.second
.expected_count
) {
679 log_warn_regexes
.clear();
680 log_error("Expected warning pattern '%s' found %d time(s), instead of %d time(s) !\n",
681 item
.first
.c_str(), item
.second
.current_count
, item
.second
.expected_count
);
685 for (auto &item
: expect_log
) {
686 if (item
.second
.current_count
== 0) {
687 log_warn_regexes
.clear();
688 log_error("Expected log pattern '%s' not found !\n", item
.first
.c_str());
690 if (item
.second
.current_count
!= item
.second
.expected_count
) {
691 log_warn_regexes
.clear();
692 log_error("Expected log pattern '%s' found %d time(s), instead of %d time(s) !\n",
693 item
.first
.c_str(), item
.second
.current_count
, item
.second
.expected_count
);
697 for (auto &item
: expect_error
)
698 if (item
.second
.current_count
== item
.second
.expected_count
) {
699 log_warn_regexes
.clear();
700 log("Expected error pattern '%s' found !!!\n", item
.first
.c_str());
703 #elif defined(_MSC_VER)
709 log_warn_regexes
.clear();
710 log_error("Expected error pattern '%s' not found !\n", item
.first
.c_str());
714 // ---------------------------------------------------
715 // This is the magic behind the code coverage counters
716 // ---------------------------------------------------
717 #if defined(YOSYS_ENABLE_COVER) && (defined(__linux__) || defined(__FreeBSD__))
719 dict
<std::string
, std::pair
<std::string
, int>> extra_coverage_data
;
721 void cover_extra(std::string parent
, std::string id
, bool increment
) {
722 if (extra_coverage_data
.count(id
) == 0) {
723 for (CoverData
*p
= __start_yosys_cover_list
; p
!= __stop_yosys_cover_list
; p
++)
725 extra_coverage_data
[id
].first
= stringf("%s:%d:%s", p
->file
, p
->line
, p
->func
);
726 log_assert(extra_coverage_data
.count(id
));
729 extra_coverage_data
[id
].second
++;
732 dict
<std::string
, std::pair
<std::string
, int>> get_coverage_data()
734 dict
<std::string
, std::pair
<std::string
, int>> coverage_data
;
736 for (auto &it
: pass_register
) {
737 std::string key
= stringf("passes.%s", it
.first
.c_str());
738 coverage_data
[key
].first
= stringf("%s:%d:%s", __FILE__
, __LINE__
, __FUNCTION__
);
739 coverage_data
[key
].second
+= it
.second
->call_counter
;
742 for (auto &it
: extra_coverage_data
) {
743 if (coverage_data
.count(it
.first
))
744 log_warning("found duplicate coverage id \"%s\".\n", it
.first
.c_str());
745 coverage_data
[it
.first
].first
= it
.second
.first
;
746 coverage_data
[it
.first
].second
+= it
.second
.second
;
749 for (CoverData
*p
= __start_yosys_cover_list
; p
!= __stop_yosys_cover_list
; p
++) {
750 if (coverage_data
.count(p
->id
))
751 log_warning("found duplicate coverage id \"%s\".\n", p
->id
);
752 coverage_data
[p
->id
].first
= stringf("%s:%d:%s", p
->file
, p
->line
, p
->func
);
753 coverage_data
[p
->id
].second
+= p
->counter
;
756 for (auto &it
: coverage_data
)
757 if (!it
.second
.first
.compare(0, strlen(YOSYS_SRC
"/"), YOSYS_SRC
"/"))
758 it
.second
.first
= it
.second
.first
.substr(strlen(YOSYS_SRC
"/"));
760 return coverage_data
;