2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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 // [[CITE]] VlogHammer Verilog Regression Test Suite
21 // http://www.clifford.at/yosys/vloghammer.html
23 #include "kernel/register.h"
24 #include "kernel/celltypes.h"
25 #include "kernel/consteval.h"
26 #include "kernel/sigtools.h"
27 #include "kernel/satgen.h"
28 #include "kernel/log.h"
35 PRIVATE_NAMESPACE_BEGIN
37 /* this should only be used for regression testing of ConstEval -- see vloghammer */
38 struct BruteForceEquivChecker
40 RTLIL::Module
*mod1
, *mod2
;
41 RTLIL::SigSpec mod1_inputs
, mod1_outputs
;
42 RTLIL::SigSpec mod2_inputs
, mod2_outputs
;
46 void run_checker(RTLIL::SigSpec
&inputs
)
48 if (inputs
.size() < mod1_inputs
.size()) {
49 RTLIL::SigSpec inputs0
= inputs
, inputs1
= inputs
;
50 inputs0
.append(RTLIL::Const(0, 1));
51 inputs1
.append(RTLIL::Const(1, 1));
57 ConstEval
ce1(mod1
), ce2(mod2
);
58 ce1
.set(mod1_inputs
, inputs
.as_const());
59 ce2
.set(mod2_inputs
, inputs
.as_const());
61 RTLIL::SigSpec sig1
= mod1_outputs
, undef1
;
62 RTLIL::SigSpec sig2
= mod2_outputs
, undef2
;
64 if (!ce1
.eval(sig1
, undef1
))
65 log("Failed ConstEval of module 1 outputs at signal %s (input: %s = %s).\n",
66 log_signal(undef1
), log_signal(mod1_inputs
), log_signal(inputs
));
67 if (!ce2
.eval(sig2
, undef2
))
68 log("Failed ConstEval of module 2 outputs at signal %s (input: %s = %s).\n",
69 log_signal(undef2
), log_signal(mod1_inputs
), log_signal(inputs
));
72 for (int i
= 0; i
< GetSize(sig1
); i
++)
73 if (sig1
[i
] == RTLIL::State::Sx
)
74 sig2
[i
] = RTLIL::State::Sx
;
78 log("Found counter-example (ignore_x_mod1 = %s):\n", ignore_x_mod1
? "active" : "inactive");
79 log(" Module 1: %s = %s => %s = %s\n", log_signal(mod1_inputs
), log_signal(inputs
), log_signal(mod1_outputs
), log_signal(sig1
));
80 log(" Module 2: %s = %s => %s = %s\n", log_signal(mod2_inputs
), log_signal(inputs
), log_signal(mod2_outputs
), log_signal(sig2
));
87 BruteForceEquivChecker(RTLIL::Module
*mod1
, RTLIL::Module
*mod2
, bool ignore_x_mod1
) :
88 mod1(mod1
), mod2(mod2
), counter(0), errors(0), ignore_x_mod1(ignore_x_mod1
)
90 log("Checking for equivalence (brute-force): %s vs %s\n", mod1
->name
.c_str(), mod2
->name
.c_str());
91 for (auto &w
: mod1
->wires_
)
93 RTLIL::Wire
*wire1
= w
.second
;
94 if (wire1
->port_id
== 0)
97 if (mod2
->wires_
.count(wire1
->name
) == 0)
98 log_cmd_error("Port %s in module 1 has no counterpart in module 2!\n", wire1
->name
.c_str());
100 RTLIL::Wire
*wire2
= mod2
->wires_
.at(wire1
->name
);
101 if (wire1
->width
!= wire2
->width
|| wire1
->port_input
!= wire2
->port_input
|| wire1
->port_output
!= wire2
->port_output
)
102 log_cmd_error("Port %s in module 1 does not match its counterpart in module 2!\n", wire1
->name
.c_str());
104 if (wire1
->port_input
) {
105 mod1_inputs
.append(wire1
);
106 mod2_inputs
.append(wire2
);
108 mod1_outputs
.append(wire1
);
109 mod2_outputs
.append(wire2
);
113 RTLIL::SigSpec inputs
;
118 /* this should only be used for regression testing of ConstEval -- see vloghammer */
119 struct VlogHammerReporter
121 RTLIL::Design
*design
;
122 std::vector
<RTLIL::Module
*> modules
;
123 std::vector
<std::string
> module_names
;
124 std::vector
<RTLIL::IdString
> inputs
;
125 std::vector
<int> input_widths
;
126 std::vector
<RTLIL::Const
> patterns
;
127 int total_input_width
;
129 std::vector
<std::string
> split(std::string text
, const char *delim
)
131 std::vector
<std::string
> list
;
132 char *p
= strdup(text
.c_str());
133 char *t
= strtok(p
, delim
);
136 t
= strtok(NULL
, delim
);
142 void sat_check(RTLIL::Module
*module
, RTLIL::SigSpec recorded_set_vars
, RTLIL::Const recorded_set_vals
, RTLIL::SigSpec expected_y
, bool model_undef
)
144 log("Verifying SAT model (%s)..\n", model_undef
? "with undef" : "without undef");
147 SigMap
sigmap(module
);
148 SatGen
satgen(ez
.get(), &sigmap
);
149 satgen
.model_undef
= model_undef
;
151 for (auto &c
: module
->cells_
)
152 if (!satgen
.importCell(c
.second
))
153 log_error("Failed to import cell %s (type %s) to SAT database.\n", RTLIL::id2cstr(c
.first
), RTLIL::id2cstr(c
.second
->type
));
155 ez
->assume(satgen
.signals_eq(recorded_set_vars
, recorded_set_vals
));
157 std::vector
<int> y_vec
= satgen
.importDefSigSpec(module
->wires_
.at("\\y"));
158 std::vector
<bool> y_values
;
161 std::vector
<int> y_undef_vec
= satgen
.importUndefSigSpec(module
->wires_
.at("\\y"));
162 y_vec
.insert(y_vec
.end(), y_undef_vec
.begin(), y_undef_vec
.end());
165 log(" Created SAT problem with %d variables and %d clauses.\n",
166 ez
->numCnfVariables(), ez
->numCnfClauses());
168 if (!ez
->solve(y_vec
, y_values
))
169 log_error("Failed to find solution to SAT problem.\n");
171 for (int i
= 0; i
< expected_y
.size(); i
++) {
172 RTLIL::State solution_bit
= y_values
.at(i
) ? RTLIL::State::S1
: RTLIL::State::S0
;
173 RTLIL::State expected_bit
= expected_y
[i
].data
;
175 if (y_values
.at(expected_y
.size()+i
))
176 solution_bit
= RTLIL::State::Sx
;
178 if (expected_bit
== RTLIL::State::Sx
)
181 if (solution_bit
!= expected_bit
) {
182 std::string sat_bits
, rtl_bits
;
183 for (int k
= expected_y
.size()-1; k
>= 0; k
--) {
184 if (model_undef
&& y_values
.at(expected_y
.size()+k
))
187 sat_bits
+= y_values
.at(k
) ? "1" : "0";
188 rtl_bits
+= expected_y
[k
] == RTLIL::State::Sx
? "x" : expected_y
[k
] == RTLIL::State::S1
? "1" : "0";
190 log_error("Found error in SAT model: y[%d] = %s, should be %s:\n SAT: %s\n RTL: %s\n %*s^\n",
191 int(i
), log_signal(solution_bit
), log_signal(expected_bit
),
192 sat_bits
.c_str(), rtl_bits
.c_str(), expected_y
.size()-i
-1, "");
198 std::vector
<int> cmp_vars
;
199 std::vector
<bool> cmp_vals
;
201 std::vector
<bool> y_undef(y_values
.begin() + expected_y
.size(), y_values
.end());
203 for (int i
= 0; i
< expected_y
.size(); i
++)
206 log(" Toggling undef bit %d to test undef gating.\n", i
);
207 if (!ez
->solve(y_vec
, y_values
, ez
->IFF(y_vec
.at(i
), y_values
.at(i
) ? ez
->CONST_FALSE
: ez
->CONST_TRUE
)))
208 log_error("Failed to find solution with toggled bit!\n");
210 cmp_vars
.push_back(y_vec
.at(expected_y
.size() + i
));
211 cmp_vals
.push_back(true);
215 cmp_vars
.push_back(y_vec
.at(i
));
216 cmp_vals
.push_back(y_values
.at(i
));
218 cmp_vars
.push_back(y_vec
.at(expected_y
.size() + i
));
219 cmp_vals
.push_back(false);
222 log(" Testing if SAT solution is unique.\n");
223 ez
->assume(ez
->vec_ne(cmp_vars
, ez
->vec_const(cmp_vals
)));
224 if (ez
->solve(y_vec
, y_values
))
225 log_error("Found two distinct solutions to SAT problem.\n");
229 log(" Testing if SAT solution is unique.\n");
230 ez
->assume(ez
->vec_ne(y_vec
, ez
->vec_const(y_values
)));
231 if (ez
->solve(y_vec
, y_values
))
232 log_error("Found two distinct solutions to SAT problem.\n");
235 log(" SAT model verified.\n");
240 for (int idx
= 0; idx
< int(patterns
.size()); idx
++)
242 log("Creating report for pattern %d: %s\n", idx
, log_signal(patterns
[idx
]));
243 std::string input_pattern_list
;
244 RTLIL::SigSpec rtl_sig
;
246 for (int mod
= 0; mod
< int(modules
.size()); mod
++)
248 RTLIL::SigSpec recorded_set_vars
;
249 RTLIL::Const recorded_set_vals
;
250 RTLIL::Module
*module
= modules
[mod
];
251 std::string module_name
= module_names
[mod
].c_str();
252 ConstEval
ce(module
);
254 std::vector
<RTLIL::State
> bits(patterns
[idx
].bits
.begin(), patterns
[idx
].bits
.begin() + total_input_width
);
255 for (int i
= 0; i
< int(inputs
.size()); i
++) {
256 RTLIL::Wire
*wire
= module
->wires_
.at(inputs
[i
]);
257 for (int j
= input_widths
[i
]-1; j
>= 0; j
--) {
258 ce
.set(RTLIL::SigSpec(wire
, j
), bits
.back());
259 recorded_set_vars
.append(RTLIL::SigSpec(wire
, j
));
260 recorded_set_vals
.bits
.push_back(bits
.back());
263 if (module
== modules
.front()) {
264 RTLIL::SigSpec
sig(wire
);
266 log_error("Can't read back value for port %s!\n", RTLIL::id2cstr(inputs
[i
]));
267 input_pattern_list
+= stringf(" %s", sig
.as_const().as_string().c_str());
268 log("++PAT++ %d %s %s #\n", idx
, RTLIL::id2cstr(inputs
[i
]), sig
.as_const().as_string().c_str());
272 if (module
->wires_
.count("\\y") == 0)
273 log_error("No output wire (y) found in module %s!\n", RTLIL::id2cstr(module
->name
));
275 RTLIL::SigSpec
sig(module
->wires_
.at("\\y"));
276 RTLIL::SigSpec undef
;
278 while (!ce
.eval(sig
, undef
)) {
279 // log_error("Evaluation of y in module %s failed: sig=%s, undef=%s\n", RTLIL::id2cstr(module->name), log_signal(sig), log_signal(undef));
280 log_warning("Setting signal %s in module %s to undef.\n", log_signal(undef
), RTLIL::id2cstr(module
->name
));
281 ce
.set(undef
, RTLIL::Const(RTLIL::State::Sx
, undef
.size()));
284 log("++VAL++ %d %s %s #\n", idx
, module_name
.c_str(), sig
.as_const().as_string().c_str());
286 if (module_name
== "rtl") {
288 sat_check(module
, recorded_set_vars
, recorded_set_vals
, sig
, false);
289 sat_check(module
, recorded_set_vars
, recorded_set_vals
, sig
, true);
290 } else if (rtl_sig
.size() > 0) {
291 if (rtl_sig
.size() != sig
.size())
292 log_error("Output (y) has a different width in module %s compared to rtl!\n", RTLIL::id2cstr(module
->name
));
293 for (int i
= 0; i
< GetSize(sig
); i
++)
294 if (rtl_sig
[i
] == RTLIL::State::Sx
)
295 sig
[i
] = RTLIL::State::Sx
;
298 log("++RPT++ %d%s %s %s\n", idx
, input_pattern_list
.c_str(), sig
.as_const().as_string().c_str(), module_name
.c_str());
301 log("++RPT++ ----\n");
306 VlogHammerReporter(RTLIL::Design
*design
, std::string module_prefix
, std::string module_list
, std::string input_list
, std::string pattern_list
) : design(design
)
308 for (auto name
: split(module_list
, ",")) {
309 RTLIL::IdString esc_name
= RTLIL::escape_id(module_prefix
+ name
);
310 if (design
->modules_
.count(esc_name
) == 0)
311 log_error("Can't find module %s in current design!\n", name
.c_str());
312 log("Using module %s (%s).\n", esc_name
.c_str(), name
.c_str());
313 modules
.push_back(design
->modules_
.at(esc_name
));
314 module_names
.push_back(name
);
317 total_input_width
= 0;
318 for (auto name
: split(input_list
, ",")) {
320 RTLIL::IdString esc_name
= RTLIL::escape_id(name
);
321 for (auto mod
: modules
) {
322 if (mod
->wires_
.count(esc_name
) == 0)
323 log_error("Can't find input %s in module %s!\n", name
.c_str(), RTLIL::id2cstr(mod
->name
));
324 RTLIL::Wire
*port
= mod
->wires_
.at(esc_name
);
325 if (!port
->port_input
|| port
->port_output
)
326 log_error("Wire %s in module %s is not an input!\n", name
.c_str(), RTLIL::id2cstr(mod
->name
));
327 if (width
>= 0 && width
!= port
->width
)
328 log_error("Port %s has different sizes in the different modules!\n", name
.c_str());
331 log("Using input port %s with width %d.\n", esc_name
.c_str(), width
);
332 inputs
.push_back(esc_name
);
333 input_widths
.push_back(width
);
334 total_input_width
+= width
;
337 for (auto pattern
: split(pattern_list
, ",")) {
339 bool invert_pattern
= false;
340 if (pattern
.size() > 0 && pattern
[0] == '~') {
341 invert_pattern
= true;
342 pattern
= pattern
.substr(1);
344 if (!RTLIL::SigSpec::parse(sig
, NULL
, pattern
) || !sig
.is_fully_const())
345 log_error("Failed to parse pattern %s!\n", pattern
.c_str());
346 if (sig
.size() < total_input_width
)
347 log_error("Pattern %s is to short!\n", pattern
.c_str());
348 patterns
.push_back(sig
.as_const());
349 if (invert_pattern
) {
350 for (auto &bit
: patterns
.back().bits
)
351 if (bit
== RTLIL::State::S0
)
352 bit
= RTLIL::State::S1
;
353 else if (bit
== RTLIL::State::S1
)
354 bit
= RTLIL::State::S0
;
356 log("Using pattern %s.\n", patterns
.back().as_string().c_str());
361 struct EvalPass
: public Pass
{
362 EvalPass() : Pass("eval", "evaluate the circuit given an input") { }
363 void help() YS_OVERRIDE
365 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
367 log(" eval [options] [selection]\n");
369 log("This command evaluates the value of a signal given the value of all required\n");
372 log(" -set <signal> <value>\n");
373 log(" set the specified signal to the specified value.\n");
375 log(" -set-undef\n");
376 log(" set all unspecified source signals to undef (x)\n");
378 log(" -table <signal>\n");
379 log(" create a truth table using the specified input signals\n");
381 log(" -show <signal>\n");
382 log(" show the value for the specified signal. if no -show option is passed\n");
383 log(" then all output ports of the current module are used.\n");
386 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
388 std::vector
<std::pair
<std::string
, std::string
>> sets
;
389 std::vector
<std::string
> shows
, tables
;
390 bool set_undef
= false;
392 log_header(design
, "Executing EVAL pass (evaluate the circuit given an input).\n");
395 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
396 if (args
[argidx
] == "-set" && argidx
+2 < args
.size()) {
397 std::string lhs
= args
[++argidx
].c_str();
398 std::string rhs
= args
[++argidx
].c_str();
399 sets
.push_back(std::pair
<std::string
, std::string
>(lhs
, rhs
));
402 if (args
[argidx
] == "-set-undef") {
406 if (args
[argidx
] == "-show" && argidx
+1 < args
.size()) {
407 shows
.push_back(args
[++argidx
]);
410 if (args
[argidx
] == "-table" && argidx
+1 < args
.size()) {
411 tables
.push_back(args
[++argidx
]);
414 if ((args
[argidx
] == "-brute_force_equiv_checker" || args
[argidx
] == "-brute_force_equiv_checker_x") && argidx
+3 == args
.size()) {
415 /* this should only be used for regression testing of ConstEval -- see vloghammer */
416 std::string mod1_name
= RTLIL::escape_id(args
[++argidx
]);
417 std::string mod2_name
= RTLIL::escape_id(args
[++argidx
]);
418 if (design
->modules_
.count(mod1_name
) == 0)
419 log_error("Can't find module `%s'!\n", mod1_name
.c_str());
420 if (design
->modules_
.count(mod2_name
) == 0)
421 log_error("Can't find module `%s'!\n", mod2_name
.c_str());
422 BruteForceEquivChecker
checker(design
->modules_
.at(mod1_name
), design
->modules_
.at(mod2_name
), args
[argidx
-2] == "-brute_force_equiv_checker_x");
423 if (checker
.errors
> 0)
424 log_cmd_error("Modules are not equivalent!\n");
425 log("Verified %s = %s (using brute-force check on %d cases).\n",
426 mod1_name
.c_str(), mod2_name
.c_str(), checker
.counter
);
429 if (args
[argidx
] == "-vloghammer_report" && argidx
+5 == args
.size()) {
430 /* this should only be used for regression testing of ConstEval -- see vloghammer */
431 std::string module_prefix
= args
[++argidx
];
432 std::string module_list
= args
[++argidx
];
433 std::string input_list
= args
[++argidx
];
434 std::string pattern_list
= args
[++argidx
];
435 VlogHammerReporter
reporter(design
, module_prefix
, module_list
, input_list
, pattern_list
);
441 extra_args(args
, argidx
, design
);
443 RTLIL::Module
*module
= NULL
;
444 for (auto &mod_it
: design
->modules_
)
445 if (design
->selected(mod_it
.second
)) {
447 log_cmd_error("Only one module must be selected for the EVAL pass! (selected: %s and %s)\n",
448 RTLIL::id2cstr(module
->name
), RTLIL::id2cstr(mod_it
.first
));
449 module
= mod_it
.second
;
452 log_cmd_error("Can't perform EVAL on an empty selection!\n");
454 ConstEval
ce(module
);
456 for (auto &it
: sets
) {
457 RTLIL::SigSpec lhs
, rhs
;
458 if (!RTLIL::SigSpec::parse_sel(lhs
, design
, module
, it
.first
))
459 log_cmd_error("Failed to parse lhs set expression `%s'.\n", it
.first
.c_str());
460 if (!RTLIL::SigSpec::parse_rhs(lhs
, rhs
, module
, it
.second
))
461 log_cmd_error("Failed to parse rhs set expression `%s'.\n", it
.second
.c_str());
462 if (!rhs
.is_fully_const())
463 log_cmd_error("Right-hand-side set expression `%s' is not constant.\n", it
.second
.c_str());
464 if (lhs
.size() != rhs
.size())
465 log_cmd_error("Set expression with different lhs and rhs sizes: %s (%s, %d bits) vs. %s (%s, %d bits)\n",
466 it
.first
.c_str(), log_signal(lhs
), lhs
.size(), it
.second
.c_str(), log_signal(rhs
), rhs
.size());
467 ce
.set(lhs
, rhs
.as_const());
470 if (shows
.size() == 0) {
471 for (auto &it
: module
->wires_
)
472 if (it
.second
->port_output
)
473 shows
.push_back(it
.second
->name
.str());
478 for (auto &it
: shows
) {
479 RTLIL::SigSpec signal
, value
, undef
;
480 if (!RTLIL::SigSpec::parse_sel(signal
, design
, module
, it
))
481 log_cmd_error("Failed to parse show expression `%s'.\n", it
.c_str());
484 while (!ce
.eval(value
, undef
)) {
485 log("Failed to evaluate signal %s: Missing value for %s. -> setting to undef\n", log_signal(signal
), log_signal(undef
));
486 ce
.set(undef
, RTLIL::Const(RTLIL::State::Sx
, undef
.size()));
487 undef
= RTLIL::SigSpec();
489 log("Eval result: %s = %s.\n", log_signal(signal
), log_signal(value
));
491 if (!ce
.eval(value
, undef
))
492 log("Failed to evaluate signal %s: Missing value for %s.\n", log_signal(signal
), log_signal(undef
));
494 log("Eval result: %s = %s.\n", log_signal(signal
), log_signal(value
));
500 RTLIL::SigSpec tabsigs
, signal
, value
, undef
;
501 std::vector
<std::vector
<std::string
>> tab
;
502 int tab_sep_colidx
= 0;
504 for (auto &it
: shows
) {
506 if (!RTLIL::SigSpec::parse_sel(sig
, design
, module
, it
))
507 log_cmd_error("Failed to parse show expression `%s'.\n", it
.c_str());
511 for (auto &it
: tables
) {
513 if (!RTLIL::SigSpec::parse_sel(sig
, design
, module
, it
))
514 log_cmd_error("Failed to parse table expression `%s'.\n", it
.c_str());
518 std::vector
<std::string
> tab_line
;
519 for (auto &c
: tabsigs
.chunks())
520 tab_line
.push_back(log_signal(c
));
521 tab_sep_colidx
= tab_line
.size();
522 for (auto &c
: signal
.chunks())
523 tab_line
.push_back(log_signal(c
));
524 tab
.push_back(tab_line
);
527 RTLIL::Const
tabvals(0, tabsigs
.size());
531 ce
.set(tabsigs
, tabvals
);
534 RTLIL::SigSpec this_undef
;
535 while (!ce
.eval(value
, this_undef
)) {
537 log("Failed to evaluate signal %s at %s = %s: Missing value for %s.\n", log_signal(signal
),
538 log_signal(tabsigs
), log_signal(tabvals
), log_signal(this_undef
));
541 ce
.set(this_undef
, RTLIL::Const(RTLIL::State::Sx
, this_undef
.size()));
542 undef
.append(this_undef
);
543 this_undef
= RTLIL::SigSpec();
547 for (auto &c
: tabsigs
.chunks()) {
548 tab_line
.push_back(log_signal(RTLIL::SigSpec(tabvals
).extract(pos
, c
.width
)));
553 for (auto &c
: signal
.chunks()) {
554 tab_line
.push_back(log_signal(value
.extract(pos
, c
.width
)));
558 tab
.push_back(tab_line
);
562 tabvals
= RTLIL::const_add(tabvals
, RTLIL::Const(1), false, false, tabvals
.bits
.size());
564 while (tabvals
.as_bool());
566 std::vector
<int> tab_column_width
;
567 for (auto &row
: tab
) {
568 if (tab_column_width
.size() < row
.size())
569 tab_column_width
.resize(row
.size());
570 for (size_t i
= 0; i
< row
.size(); i
++)
571 tab_column_width
[i
] = max(tab_column_width
[i
], int(row
[i
].size()));
576 for (auto &row
: tab
) {
577 for (size_t i
= 0; i
< row
.size(); i
++) {
578 int k
= int(i
) < tab_sep_colidx
? tab_sep_colidx
- i
- 1 : i
;
579 log(" %s%*s", k
== tab_sep_colidx
? "| " : "", tab_column_width
[k
], row
[k
].c_str());
583 for (size_t i
= 0; i
< row
.size(); i
++) {
584 int k
= int(i
) < tab_sep_colidx
? tab_sep_colidx
- i
- 1 : i
;
585 log(" %s", k
== tab_sep_colidx
? "| " : "");
586 for (int j
= 0; j
< tab_column_width
[k
]; j
++)
595 if (undef
.size() > 0) {
596 undef
.sort_and_unify();
597 log("Assumed undef (x) value for the following signals: %s\n\n", log_signal(undef
));
603 PRIVATE_NAMESPACE_END