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 #include "kernel/register.h"
21 #include "kernel/celltypes.h"
22 #include "kernel/log.h"
33 #ifdef YOSYS_ENABLE_READLINE
34 # include <readline/readline.h>
37 #ifdef YOSYS_ENABLE_EDITLINE
38 # include <editline/readline.h>
42 PRIVATE_NAMESPACE_BEGIN
44 #undef CLUSTER_CELLS_AND_PORTBOXES
50 vector
<shared_str
> dot_escape_store
;
51 std::map
<RTLIL::IdString
, int> dot_id2num_store
;
52 std::map
<RTLIL::IdString
, int> autonames
;
55 struct net_conn
{ std::set
<std::string
> in
, out
; int bits
; std::string color
; };
56 std::map
<std::string
, net_conn
> net_conn_map
;
59 RTLIL::Design
*design
;
60 RTLIL::Module
*module
;
61 uint32_t currentColor
;
70 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &color_selections
;
71 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &label_selections
;
73 std::map
<RTLIL::Const
, int> colorattr_cache
;
74 RTLIL::IdString colorattr
;
77 static uint32_t xorshift32(uint32_t x
) {
84 std::string
nextColor()
86 if (currentColor
== 0)
87 return "color=\"black\"";
88 return stringf("colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", currentColor
%8+1, currentColor
%8+1);
91 std::string
nextColor(std::string presetColor
)
93 if (presetColor
.empty())
98 std::string
nextColor(RTLIL::SigSpec sig
, std::string defaultColor
)
100 sig
.sort_and_unify();
101 for (auto &c
: sig
.chunks()) {
102 if (c
.wire
!= nullptr)
103 for (auto &s
: color_selections
)
104 if (s
.second
.selected_members
.count(module
->name
) > 0 && s
.second
.selected_members
.at(module
->name
).count(c
.wire
->name
) > 0)
105 return stringf("color=\"%s\"", s
.first
.c_str());
110 std::string
nextColor(const RTLIL::SigSig
&conn
, std::string defaultColor
)
112 return nextColor(conn
.first
, nextColor(conn
.second
, defaultColor
));
115 std::string
nextColor(const RTLIL::SigSpec
&sig
)
117 return nextColor(sig
, nextColor());
120 std::string
nextColor(const RTLIL::SigSig
&conn
)
122 return nextColor(conn
, nextColor());
125 std::string
widthLabel(int bits
)
130 return "style=\"setlinewidth(3)\", label=\"\"";
131 return stringf("style=\"setlinewidth(3)\", label=\"<%d>\"", bits
);
134 const char *findColor(std::string member_name
)
136 for (auto &s
: color_selections
)
137 if (s
.second
.selected_member(module
->name
, member_name
)) {
138 dot_escape_store
.push_back(stringf(", color=\"%s\"", s
.first
.c_str()));
139 return dot_escape_store
.back().c_str();
142 RTLIL::Const colorattr_value
;
143 RTLIL::Cell
*cell
= module
->cell(member_name
);
144 RTLIL::Wire
*wire
= module
->wire(member_name
);
146 if (cell
&& cell
->attributes
.count(colorattr
))
147 colorattr_value
= cell
->attributes
.at(colorattr
);
148 else if (wire
&& wire
->attributes
.count(colorattr
))
149 colorattr_value
= wire
->attributes
.at(colorattr
);
153 if (colorattr_cache
.count(colorattr_value
) == 0) {
154 int next_id
= GetSize(colorattr_cache
);
155 colorattr_cache
[colorattr_value
] = (next_id
% 8) + 1;
158 dot_escape_store
.push_back(stringf(", colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", colorattr_cache
.at(colorattr_value
), colorattr_cache
.at(colorattr_value
)));
159 return dot_escape_store
.back().c_str();
162 const char *findLabel(std::string member_name
)
164 for (auto &s
: label_selections
)
165 if (s
.second
.selected_member(module
->name
, member_name
))
166 return escape(s
.first
);
167 return escape(member_name
, true);
170 const char *escape(std::string id
, bool is_name
= false)
175 if (id
[0] == '$' && is_name
) {
177 if (autonames
.count(id
) == 0) {
178 autonames
[id
] = autonames
.size() + 1;
179 log("Generated short name for internal identifier: _%d_ -> %s\n", autonames
[id
], id
.c_str());
181 id
= stringf("_%d_", autonames
[id
]);
182 } else if (abbreviateIds
) {
183 const char *p
= id
.c_str();
184 const char *q
= strrchr(p
, '$');
194 if (ch
== '\\' || ch
== '"')
199 dot_escape_store
.push_back(str
);
200 return dot_escape_store
.back().c_str();
203 int id2num(RTLIL::IdString id
)
205 if (dot_id2num_store
.count(id
) > 0)
206 return dot_id2num_store
[id
];
207 return dot_id2num_store
[id
] = dot_id2num_store
.size() + 1;
210 std::string
gen_signode_simple(RTLIL::SigSpec sig
, bool range_check
= true)
212 if (GetSize(sig
) == 0) {
213 fprintf(f
, "v%d [ label=\"\" ];\n", single_idx_count
);
214 return stringf("v%d", single_idx_count
++);
217 if (sig
.is_chunk()) {
218 const RTLIL::SigChunk
&c
= sig
.as_chunk();
219 if (c
.wire
!= nullptr && design
->selected_member(module
->name
, c
.wire
->name
)) {
220 if (!range_check
|| c
.wire
->width
== c
.width
)
221 return stringf("n%d", id2num(c
.wire
->name
));
223 fprintf(f
, "v%d [ label=\"%s\" ];\n", single_idx_count
, findLabel(log_signal(c
)));
224 return stringf("v%d", single_idx_count
++);
228 return std::string();
231 std::string
gen_portbox(std::string port
, RTLIL::SigSpec sig
, bool driver
, std::string
*node
= nullptr)
234 std::string net
= gen_signode_simple(sig
);
237 std::string label_string
;
238 int pos
= sig
.size()-1;
239 int idx
= single_idx_count
++;
240 for (int rep
, i
= int(sig
.chunks().size())-1; i
>= 0; i
-= rep
) {
241 const RTLIL::SigChunk
&c
= sig
.chunks().at(i
);
242 if (!driver
&& c
.wire
== nullptr) {
243 RTLIL::State s1
= c
.data
.front();
244 for (auto s2
: c
.data
)
246 goto not_const_stream
;
250 net
= gen_signode_simple(c
, false);
251 log_assert(!net
.empty());
253 for (rep
= 1; i
-rep
>= 0 && c
== sig
.chunks().at(i
-rep
); rep
++) {}
254 std::string repinfo
= rep
> 1 ? stringf("%dx ", rep
) : "";
256 log_assert(!net
.empty());
257 label_string
+= stringf("<s%d> %d:%d - %s%d:%d |", i
, pos
, pos
-c
.width
+1, repinfo
.c_str(), c
.offset
+c
.width
-1, c
.offset
);
258 net_conn_map
[net
].in
.insert(stringf("x%d:s%d", idx
, i
));
259 net_conn_map
[net
].bits
= rep
*c
.width
;
260 net_conn_map
[net
].color
= nextColor(c
, net_conn_map
[net
].color
);
263 log_assert(rep
== 1);
264 label_string
+= stringf("%c -> %d:%d |",
265 c
.data
.front() == State::S0
? '0' :
266 c
.data
.front() == State::S1
? '1' :
267 c
.data
.front() == State::Sx
? 'X' :
268 c
.data
.front() == State::Sz
? 'Z' : '?',
269 pos
, pos
-rep
*c
.width
+1);
271 label_string
+= stringf("<s%d> %s%d:%d - %d:%d |", i
, repinfo
.c_str(), c
.offset
+c
.width
-1, c
.offset
, pos
, pos
-rep
*c
.width
+1);
272 net_conn_map
[net
].out
.insert(stringf("x%d:s%d", idx
, i
));
273 net_conn_map
[net
].bits
= rep
*c
.width
;
274 net_conn_map
[net
].color
= nextColor(c
, net_conn_map
[net
].color
);
276 pos
-= rep
* c
.width
;
278 if (label_string
[label_string
.size()-1] == '|')
279 label_string
= label_string
.substr(0, label_string
.size()-1);
280 code
+= stringf("x%d [ shape=record, style=rounded, label=\"%s\" ];\n", idx
, label_string
.c_str());
282 currentColor
= xorshift32(currentColor
);
284 code
+= stringf("%s:e -> x%d:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", port
.c_str(), idx
, nextColor(sig
).c_str(), widthLabel(sig
.size()).c_str());
286 code
+= stringf("x%d:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", idx
, port
.c_str(), nextColor(sig
).c_str(), widthLabel(sig
.size()).c_str());
289 *node
= stringf("x%d", idx
);
295 net_conn_map
[net
].in
.insert(port
);
297 net_conn_map
[net
].out
.insert(port
);
298 net_conn_map
[net
].bits
= sig
.size();
299 net_conn_map
[net
].color
= nextColor(sig
, net_conn_map
[net
].color
);
307 void collect_proc_signals(std::vector
<RTLIL::SigSpec
> &obj
, std::set
<RTLIL::SigSpec
> &signals
)
310 if (!it
.is_fully_const())
314 void collect_proc_signals(std::vector
<RTLIL::SigSig
> &obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
316 for (auto &it
: obj
) {
317 output_signals
.insert(it
.first
);
318 if (!it
.second
.is_fully_const())
319 input_signals
.insert(it
.second
);
323 void collect_proc_signals(RTLIL::CaseRule
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
325 collect_proc_signals(obj
->compare
, input_signals
);
326 collect_proc_signals(obj
->actions
, input_signals
, output_signals
);
327 for (auto it
: obj
->switches
)
328 collect_proc_signals(it
, input_signals
, output_signals
);
331 void collect_proc_signals(RTLIL::SwitchRule
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
333 input_signals
.insert(obj
->signal
);
334 for (auto it
: obj
->cases
)
335 collect_proc_signals(it
, input_signals
, output_signals
);
338 void collect_proc_signals(RTLIL::SyncRule
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
340 input_signals
.insert(obj
->signal
);
341 collect_proc_signals(obj
->actions
, input_signals
, output_signals
);
344 void collect_proc_signals(RTLIL::Process
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
346 collect_proc_signals(&obj
->root_case
, input_signals
, output_signals
);
347 for (auto it
: obj
->syncs
)
348 collect_proc_signals(it
, input_signals
, output_signals
);
353 single_idx_count
= 0;
354 dot_escape_store
.clear();
355 dot_id2num_store
.clear();
356 net_conn_map
.clear();
358 fprintf(f
, "digraph \"%s\" {\n", escape(module
->name
.str()));
360 fprintf(f
, "label=\"%s\";\n", escape(module
->name
.str()));
361 fprintf(f
, "rankdir=\"LR\";\n");
362 fprintf(f
, "remincross=true;\n");
364 std::set
<std::string
> all_sources
, all_sinks
;
366 std::map
<std::string
, std::string
> wires_on_demand
;
367 for (auto wire
: module
->selected_wires()) {
368 const char *shape
= "diamond";
369 if (wire
->port_input
|| wire
->port_output
)
371 if (wire
->name
[0] == '\\') {
372 fprintf(f
, "n%d [ shape=%s, label=\"%s\", %s, fontcolor=\"black\" ];\n",
373 id2num(wire
->name
), shape
, findLabel(wire
->name
.str()),
374 nextColor(RTLIL::SigSpec(wire
), "color=\"black\"").c_str());
375 if (wire
->port_input
)
376 all_sources
.insert(stringf("n%d", id2num(wire
->name
)));
377 else if (wire
->port_output
)
378 all_sinks
.insert(stringf("n%d", id2num(wire
->name
)));
380 wires_on_demand
[stringf("n%d", id2num(wire
->name
))] = wire
->name
.str();
386 fprintf(f
, "{ rank=\"source\";");
387 for (auto n
: all_sources
)
388 fprintf(f
, " %s;", n
.c_str());
391 fprintf(f
, "{ rank=\"sink\";");
392 for (auto n
: all_sinks
)
393 fprintf(f
, " %s;", n
.c_str());
397 for (auto cell
: module
->selected_cells())
399 std::vector
<RTLIL::IdString
> in_ports
, out_ports
;
401 for (auto &conn
: cell
->connections()) {
402 if (!ct
.cell_output(cell
->type
, conn
.first
))
403 in_ports
.push_back(conn
.first
);
405 out_ports
.push_back(conn
.first
);
408 std::sort(in_ports
.begin(), in_ports
.end(), RTLIL::sort_by_id_str());
409 std::sort(out_ports
.begin(), out_ports
.end(), RTLIL::sort_by_id_str());
411 std::string label_string
= "{{";
413 for (auto &p
: in_ports
)
414 label_string
+= stringf("<p%d> %s%s|", id2num(p
), escape(p
.str()),
415 genSignedLabels
&& cell
->hasParam(p
.str() + "_SIGNED") &&
416 cell
->getParam(p
.str() + "_SIGNED").as_bool() ? "*" : "");
417 if (label_string
[label_string
.size()-1] == '|')
418 label_string
= label_string
.substr(0, label_string
.size()-1);
420 label_string
+= stringf("}|%s\\n%s|{", findLabel(cell
->name
.str()), escape(cell
->type
.str()));
422 for (auto &p
: out_ports
)
423 label_string
+= stringf("<p%d> %s|", id2num(p
), escape(p
.str()));
424 if (label_string
[label_string
.size()-1] == '|')
425 label_string
= label_string
.substr(0, label_string
.size()-1);
427 label_string
+= "}}";
430 for (auto &conn
: cell
->connections()) {
431 code
+= gen_portbox(stringf("c%d:p%d", id2num(cell
->name
), id2num(conn
.first
)),
432 conn
.second
, ct
.cell_output(cell
->type
, conn
.first
));
435 #ifdef CLUSTER_CELLS_AND_PORTBOXES
437 fprintf(f
, "subgraph cluster_c%d {\nc%d [ shape=record, label=\"%s\"%s ];\n%s}\n",
438 id2num(cell
->name
), id2num(cell
->name
), label_string
.c_str(), findColor(cell
->name
), code
.c_str());
441 fprintf(f
, "c%d [ shape=record, label=\"%s\"%s ];\n%s",
442 id2num(cell
->name
), label_string
.c_str(), findColor(cell
->name
.str()), code
.c_str());
445 for (auto &it
: module
->processes
)
447 RTLIL::Process
*proc
= it
.second
;
449 if (!design
->selected_member(module
->name
, proc
->name
))
452 std::set
<RTLIL::SigSpec
> input_signals
, output_signals
;
453 collect_proc_signals(proc
, input_signals
, output_signals
);
455 int pidx
= single_idx_count
++;
456 input_signals
.erase(RTLIL::SigSpec());
457 output_signals
.erase(RTLIL::SigSpec());
459 for (auto &sig
: input_signals
) {
460 std::string code
, node
;
461 code
+= gen_portbox("", sig
, false, &node
);
462 fprintf(f
, "%s", code
.c_str());
463 net_conn_map
[node
].out
.insert(stringf("p%d", pidx
));
464 net_conn_map
[node
].bits
= sig
.size();
465 net_conn_map
[node
].color
= nextColor(sig
, net_conn_map
[node
].color
);
468 for (auto &sig
: output_signals
) {
469 std::string code
, node
;
470 code
+= gen_portbox("", sig
, true, &node
);
471 fprintf(f
, "%s", code
.c_str());
472 net_conn_map
[node
].in
.insert(stringf("p%d", pidx
));
473 net_conn_map
[node
].bits
= sig
.size();
474 net_conn_map
[node
].color
= nextColor(sig
, net_conn_map
[node
].color
);
477 std::string proc_src
= RTLIL::unescape_id(proc
->name
);
478 if (proc
->attributes
.count(ID::src
) > 0)
479 proc_src
= proc
->attributes
.at(ID::src
).decode_string();
480 fprintf(f
, "p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\"];\n", pidx
, findLabel(proc
->name
.str()), proc_src
.c_str());
483 for (auto &conn
: module
->connections())
485 bool found_lhs_wire
= false;
486 for (auto &c
: conn
.first
.chunks()) {
487 if (c
.wire
== nullptr || design
->selected_member(module
->name
, c
.wire
->name
))
488 found_lhs_wire
= true;
490 bool found_rhs_wire
= false;
491 for (auto &c
: conn
.second
.chunks()) {
492 if (c
.wire
== nullptr || design
->selected_member(module
->name
, c
.wire
->name
))
493 found_rhs_wire
= true;
495 if (!found_lhs_wire
|| !found_rhs_wire
)
498 std::string code
, left_node
, right_node
;
499 code
+= gen_portbox("", conn
.second
, false, &left_node
);
500 code
+= gen_portbox("", conn
.first
, true, &right_node
);
501 fprintf(f
, "%s", code
.c_str());
503 if (left_node
[0] == 'x' && right_node
[0] == 'x') {
504 currentColor
= xorshift32(currentColor
);
505 fprintf(f
, "%s:e -> %s:w [arrowhead=odiamond, arrowtail=odiamond, dir=both, %s, %s];\n", left_node
.c_str(), right_node
.c_str(), nextColor(conn
).c_str(), widthLabel(conn
.first
.size()).c_str());
507 net_conn_map
[right_node
].bits
= conn
.first
.size();
508 net_conn_map
[right_node
].color
= nextColor(conn
, net_conn_map
[right_node
].color
);
509 net_conn_map
[left_node
].bits
= conn
.first
.size();
510 net_conn_map
[left_node
].color
= nextColor(conn
, net_conn_map
[left_node
].color
);
511 if (left_node
[0] == 'x') {
512 net_conn_map
[right_node
].in
.insert(left_node
);
513 } else if (right_node
[0] == 'x') {
514 net_conn_map
[left_node
].out
.insert(right_node
);
516 net_conn_map
[right_node
].in
.insert(stringf("x%d:e", single_idx_count
));
517 net_conn_map
[left_node
].out
.insert(stringf("x%d:w", single_idx_count
));
518 fprintf(f
, "x%d [shape=box, style=rounded, label=\"BUF\"];\n", single_idx_count
++);
523 for (auto &it
: net_conn_map
)
525 currentColor
= xorshift32(currentColor
);
526 if (wires_on_demand
.count(it
.first
) > 0) {
527 if (it
.second
.in
.size() == 1 && it
.second
.out
.size() > 1 && it
.second
.in
.begin()->compare(0, 1, "p") == 0)
528 it
.second
.out
.erase(*it
.second
.in
.begin());
529 if (it
.second
.in
.size() == 1 && it
.second
.out
.size() == 1) {
530 std::string from
= *it
.second
.in
.begin(), to
= *it
.second
.out
.begin();
531 if (from
!= to
|| from
.compare(0, 1, "p") != 0)
532 fprintf(f
, "%s:e -> %s:w [%s, %s];\n", from
.c_str(), to
.c_str(), nextColor(it
.second
.color
).c_str(), widthLabel(it
.second
.bits
).c_str());
535 if (it
.second
.in
.size() == 0 || it
.second
.out
.size() == 0)
536 fprintf(f
, "%s [ shape=diamond, label=\"%s\" ];\n", it
.first
.c_str(), findLabel(wires_on_demand
[it
.first
]));
538 fprintf(f
, "%s [ shape=point ];\n", it
.first
.c_str());
540 for (auto &it2
: it
.second
.in
)
541 fprintf(f
, "%s:e -> %s:w [%s, %s];\n", it2
.c_str(), it
.first
.c_str(), nextColor(it
.second
.color
).c_str(), widthLabel(it
.second
.bits
).c_str());
542 for (auto &it2
: it
.second
.out
)
543 fprintf(f
, "%s:e -> %s:w [%s, %s];\n", it
.first
.c_str(), it2
.c_str(), nextColor(it
.second
.color
).c_str(), widthLabel(it
.second
.bits
).c_str());
549 ShowWorker(FILE *f
, RTLIL::Design
*design
, std::vector
<RTLIL::Design
*> &libs
, uint32_t colorSeed
, bool genWidthLabels
,
550 bool genSignedLabels
, bool stretchIO
, bool enumerateIds
, bool abbreviateIds
, bool notitle
,
551 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &color_selections
,
552 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &label_selections
, RTLIL::IdString colorattr
) :
553 f(f
), design(design
), currentColor(colorSeed
), genWidthLabels(genWidthLabels
),
554 genSignedLabels(genSignedLabels
), stretchIO(stretchIO
), enumerateIds(enumerateIds
), abbreviateIds(abbreviateIds
),
555 notitle(notitle
), color_selections(color_selections
), label_selections(label_selections
), colorattr(colorattr
)
557 ct
.setup_internals();
558 ct
.setup_internals_mem();
560 ct
.setup_stdcells_mem();
561 ct
.setup_design(design
);
563 for (auto lib
: libs
)
564 ct
.setup_design(lib
);
568 for (auto mod
: design
->selected_modules())
571 if (design
->selected_whole_module(module
->name
)) {
572 if (module
->get_blackbox_attribute()) {
573 // log("Skipping blackbox module %s.\n", log_id(module->name));
576 if (module
->cells().size() == 0 && module
->connections().empty() && module
->processes
.empty()) {
577 log("Skipping empty module %s.\n", log_id(module
->name
));
580 log("Dumping module %s to page %d.\n", log_id(module
->name
), ++page_counter
);
582 log("Dumping selected parts of module %s to page %d.\n", log_id(module
->name
), ++page_counter
);
588 struct ShowPass
: public Pass
{
589 ShowPass() : Pass("show", "generate schematics using graphviz") { }
590 void help() YS_OVERRIDE
592 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
594 log(" show [options] [selection]\n");
596 log("Create a graphviz DOT file for the selected part of the design and compile it\n");
597 log("to a graphics file (usually SVG or PostScript).\n");
599 log(" -viewer <viewer>\n");
600 log(" Run the specified command with the graphics file as parameter.\n");
601 log(" On Windows, this pauses yosys until the viewer exits.\n");
603 log(" -format <format>\n");
604 log(" Generate a graphics file in the specified format. Use 'dot' to just\n");
605 log(" generate a .dot file, or other <format> strings such as 'svg' or 'ps'\n");
606 log(" to generate files in other formats (this calls the 'dot' command).\n");
608 log(" -lib <verilog_or_ilang_file>\n");
609 log(" Use the specified library file for determining whether cell ports are\n");
610 log(" inputs or outputs. This option can be used multiple times to specify\n");
611 log(" more than one library.\n");
613 log(" note: in most cases it is better to load the library before calling\n");
614 log(" show with 'read_verilog -lib <filename>'. it is also possible to\n");
615 log(" load liberty files with 'read_liberty -lib <filename>'.\n");
617 log(" -prefix <prefix>\n");
618 log(" generate <prefix>.* instead of ~/.yosys_show.*\n");
620 log(" -color <color> <object>\n");
621 log(" assign the specified color to the specified object. The object can be\n");
622 log(" a single selection wildcard expressions or a saved set of objects in\n");
623 log(" the @<name> syntax (see \"help select\" for details).\n");
625 log(" -label <text> <object>\n");
626 log(" assign the specified label text to the specified object. The object can\n");
627 log(" be a single selection wildcard expressions or a saved set of objects in\n");
628 log(" the @<name> syntax (see \"help select\" for details).\n");
630 log(" -colors <seed>\n");
631 log(" Randomly assign colors to the wires. The integer argument is the seed\n");
632 log(" for the random number generator. Change the seed value if the colored\n");
633 log(" graph still is ambiguous. A seed of zero deactivates the coloring.\n");
635 log(" -colorattr <attribute_name>\n");
636 log(" Use the specified attribute to assign colors. A unique color is\n");
637 log(" assigned to each unique value of this attribute.\n");
640 log(" annotate buses with a label indicating the width of the bus.\n");
643 log(" mark ports (A, B) that are declared as signed (using the [AB]_SIGNED\n");
644 log(" cell parameter) with an asterisk next to the port name.\n");
647 log(" stretch the graph so all inputs are on the left side and all outputs\n");
648 log(" (including inout ports) are on the right side.\n");
651 log(" wait for the use to press enter to before returning\n");
654 log(" enumerate objects with internal ($-prefixed) names\n");
657 log(" do not abbreviate objects with internal ($-prefixed) names\n");
660 log(" do not add the module name as graph title to the dot file\n");
663 log(" don't run viewer in the background, IE wait for the viewer tool to\n");
664 log(" exit before returning\n");
666 log("When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n");
667 log("specified, 'xdot' is used to display the schematic (POSIX systems only).\n");
669 log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
670 log("unless another prefix is specified using -prefix <prefix>.\n");
672 log("Yosys on Windows and YosysJS use different defaults: The output is written\n");
673 log("to 'show.dot' in the current directory and new viewer is launched each time\n");
674 log("the 'show' command is executed.\n");
677 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
679 log_header(design
, "Generating Graphviz representation of design.\n");
682 std::vector
<std::pair
<std::string
, RTLIL::Selection
>> color_selections
;
683 std::vector
<std::pair
<std::string
, RTLIL::Selection
>> label_selections
;
685 #if defined(_WIN32) || defined(YOSYS_DISABLE_SPAWN)
686 std::string format
= "dot";
687 std::string prefix
= "show";
690 std::string prefix
= stringf("%s/.yosys_show", getenv("HOME") ? getenv("HOME") : ".");
692 std::string viewer_exe
;
693 std::vector
<std::string
> libfiles
;
694 std::vector
<RTLIL::Design
*> libs
;
695 uint32_t colorSeed
= 0;
696 bool flag_width
= false;
697 bool flag_signed
= false;
698 bool flag_stretch
= false;
699 bool flag_pause
= false;
700 bool flag_enum
= false;
701 bool flag_abbreviate
= true;
702 bool flag_notitle
= false;
703 bool custom_prefix
= false;
704 std::string background
= "&";
705 RTLIL::IdString colorattr
;
708 for (argidx
= 1; argidx
< args
.size(); argidx
++)
710 std::string arg
= args
[argidx
];
711 if (arg
== "-viewer" && argidx
+1 < args
.size()) {
712 viewer_exe
= args
[++argidx
];
715 if (arg
== "-lib" && argidx
+1 < args
.size()) {
716 libfiles
.push_back(args
[++argidx
]);
719 if (arg
== "-prefix" && argidx
+1 < args
.size()) {
720 prefix
= args
[++argidx
];
721 custom_prefix
= true;
724 if (arg
== "-color" && argidx
+2 < args
.size()) {
725 std::pair
<std::string
, RTLIL::Selection
> data
;
726 data
.first
= args
[++argidx
], argidx
++;
727 handle_extra_select_args(this, args
, argidx
, argidx
+1, design
);
728 data
.second
= design
->selection_stack
.back();
729 design
->selection_stack
.pop_back();
730 color_selections
.push_back(data
);
733 if (arg
== "-label" && argidx
+2 < args
.size()) {
734 std::pair
<std::string
, RTLIL::Selection
> data
;
735 data
.first
= args
[++argidx
], argidx
++;
736 handle_extra_select_args(this, args
, argidx
, argidx
+1, design
);
737 data
.second
= design
->selection_stack
.back();
738 design
->selection_stack
.pop_back();
739 label_selections
.push_back(data
);
742 if (arg
== "-colors" && argidx
+1 < args
.size()) {
743 colorSeed
= atoi(args
[++argidx
].c_str());
744 for (int i
= 0; i
< 100; i
++)
745 colorSeed
= ShowWorker::xorshift32(colorSeed
);
748 if (arg
== "-colorattr" && argidx
+1 < args
.size()) {
749 colorattr
= RTLIL::escape_id(args
[++argidx
]);
752 if (arg
== "-format" && argidx
+1 < args
.size()) {
753 format
= args
[++argidx
];
756 if (arg
== "-width") {
760 if (arg
== "-signed") {
764 if (arg
== "-stretch") {
768 if (arg
== "-pause") {
772 if (arg
== "-enum") {
774 flag_abbreviate
= false;
777 if (arg
== "-long") {
779 flag_abbreviate
= false;
782 if (arg
== "-notitle") {
786 if (arg
== "-nobg") {
792 extra_args(args
, argidx
, design
);
794 if (format
!= "ps" && format
!= "dot") {
796 for (auto module
: design
->selected_modules()) {
797 if (module
->get_blackbox_attribute())
799 if (module
->cells().size() == 0 && module
->connections().empty())
804 log_cmd_error("For formats different than 'ps' or 'dot' only one module must be selected.\n");
807 for (auto filename
: libfiles
) {
809 f
.open(filename
.c_str());
810 yosys_input_files
.insert(filename
);
812 log_error("Can't open lib file `%s'.\n", filename
.c_str());
813 RTLIL::Design
*lib
= new RTLIL::Design
;
814 Frontend::frontend_call(lib
, &f
, filename
, (filename
.size() > 3 && filename
.compare(filename
.size()-3, std::string::npos
, ".il") == 0 ? "ilang" : "verilog"));
819 log_header(design
, "Continuing show pass.\n");
821 std::string dot_file
= stringf("%s.dot", prefix
.c_str());
822 std::string out_file
= stringf("%s.%s", prefix
.c_str(), format
.empty() ? "svg" : format
.c_str());
824 log("Writing dot description to `%s'.\n", dot_file
.c_str());
825 FILE *f
= fopen(dot_file
.c_str(), "w");
827 yosys_output_files
.insert(dot_file
);
829 for (auto lib
: libs
)
831 log_cmd_error("Can't open dot file `%s' for writing.\n", dot_file
.c_str());
833 ShowWorker
worker(f
, design
, libs
, colorSeed
, flag_width
, flag_signed
, flag_stretch
, flag_enum
, flag_abbreviate
, flag_notitle
, color_selections
, label_selections
, colorattr
);
836 for (auto lib
: libs
)
839 if (worker
.page_counter
== 0)
840 log_cmd_error("Nothing there to show.\n");
842 if (format
!= "dot" && !format
.empty()) {
844 // system()/cmd.exe does not understand single quotes on Windows.
845 #define DOT_CMD "dot -T%s \"%s\" > \"%s.new\" && move \"%s.new\" \"%s\""
847 #define DOT_CMD "dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'"
849 std::string cmd
= stringf(DOT_CMD
, format
.c_str(), dot_file
.c_str(), out_file
.c_str(), out_file
.c_str(), out_file
.c_str());
851 log("Exec: %s\n", cmd
.c_str());
852 #if !defined(YOSYS_DISABLE_SPAWN)
853 if (run_command(cmd
) != 0)
854 log_cmd_error("Shell command failed!\n");
858 #if defined(YOSYS_DISABLE_SPAWN)
859 log_assert(viewer_exe
.empty() && !format
.empty());
861 if (!viewer_exe
.empty()) {
863 // system()/cmd.exe does not understand single quotes nor
864 // background tasks on Windows. So we have to pause yosys
865 // until the viewer exits.
866 std::string cmd
= stringf("%s \"%s\"", viewer_exe
.c_str(), out_file
.c_str());
868 std::string cmd
= stringf("%s '%s' %s", viewer_exe
.c_str(), out_file
.c_str(), background
.c_str());
870 log("Exec: %s\n", cmd
.c_str());
871 if (run_command(cmd
) != 0)
872 log_cmd_error("Shell command failed!\n");
874 if (format
.empty()) {
876 std::string cmd
= stringf("ps -fu %d | grep -q '[ ]%s' || xdot '%s' %s", getuid(), dot_file
.c_str(), dot_file
.c_str(), background
.c_str());
878 std::string cmd
= stringf("{ test -f '%s.pid' && fuser -s '%s.pid' 2> /dev/null; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' %s", dot_file
.c_str(), dot_file
.c_str(), dot_file
.c_str(), dot_file
.c_str(), background
.c_str());
880 log("Exec: %s\n", cmd
.c_str());
881 if (run_command(cmd
) != 0)
882 log_cmd_error("Shell command failed!\n");
887 #ifdef YOSYS_ENABLE_READLINE
888 char *input
= nullptr;
889 while ((input
= readline("Press ENTER to continue (or type 'shell' to open a shell)> ")) != nullptr) {
890 if (input
[strspn(input
, " \t\r\n")] == 0)
892 char *p
= input
+ strspn(input
, " \t\r\n");
893 if (!strcmp(p
, "shell")) {
894 Pass::call(design
, "shell");
899 log_cmd_error("This version of yosys is built without readline support => 'show -pause' is not available.\n");
907 PRIVATE_NAMESPACE_END