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
46 #undef CLUSTER_CELLS_AND_PORTBOXES
52 vector
<shared_str
> dot_escape_store
;
53 std::map
<RTLIL::IdString
, int> dot_id2num_store
;
54 std::map
<RTLIL::IdString
, int> autonames
;
57 struct net_conn
{ std::set
<std::string
> in
, out
; int bits
; std::string color
; };
58 std::map
<std::string
, net_conn
> net_conn_map
;
61 RTLIL::Design
*design
;
62 RTLIL::Module
*module
;
63 uint32_t currentColor
;
72 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &color_selections
;
73 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &label_selections
;
75 std::map
<RTLIL::Const
, int> colorattr_cache
;
76 RTLIL::IdString colorattr
;
79 static uint32_t xorshift32(uint32_t x
) {
86 std::string
nextColor()
88 if (currentColor
== 0)
89 return "color=\"black\"";
90 return stringf("colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", currentColor
%8+1, currentColor
%8+1);
93 std::string
nextColor(std::string presetColor
)
95 if (presetColor
.empty())
100 std::string
nextColor(RTLIL::SigSpec sig
, std::string defaultColor
)
102 sig
.sort_and_unify();
103 for (auto &c
: sig
.chunks()) {
105 for (auto &s
: color_selections
)
106 if (s
.second
.selected_members
.count(module
->name
) > 0 && s
.second
.selected_members
.at(module
->name
).count(c
.wire
->name
) > 0)
107 return stringf("color=\"%s\"", s
.first
.c_str());
112 std::string
nextColor(const RTLIL::SigSig
&conn
, std::string defaultColor
)
114 return nextColor(conn
.first
, nextColor(conn
.second
, defaultColor
));
117 std::string
nextColor(const RTLIL::SigSpec
&sig
)
119 return nextColor(sig
, nextColor());
122 std::string
nextColor(const RTLIL::SigSig
&conn
)
124 return nextColor(conn
, nextColor());
127 std::string
widthLabel(int bits
)
132 return "style=\"setlinewidth(3)\", label=\"\"";
133 return stringf("style=\"setlinewidth(3)\", label=\"<%d>\"", bits
);
136 const char *findColor(std::string member_name
)
138 for (auto &s
: color_selections
)
139 if (s
.second
.selected_member(module
->name
, member_name
)) {
140 dot_escape_store
.push_back(stringf(", color=\"%s\"", s
.first
.c_str()));
141 return dot_escape_store
.back().c_str();
144 RTLIL::Const colorattr_value
;
145 RTLIL::Cell
*cell
= module
->cell(member_name
);
146 RTLIL::Wire
*wire
= module
->wire(member_name
);
148 if (cell
&& cell
->attributes
.count(colorattr
))
149 colorattr_value
= cell
->attributes
.at(colorattr
);
150 else if (wire
&& wire
->attributes
.count(colorattr
))
151 colorattr_value
= wire
->attributes
.at(colorattr
);
155 if (colorattr_cache
.count(colorattr_value
) == 0) {
156 int next_id
= GetSize(colorattr_cache
);
157 colorattr_cache
[colorattr_value
] = (next_id
% 8) + 1;
160 dot_escape_store
.push_back(stringf(", colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", colorattr_cache
.at(colorattr_value
), colorattr_cache
.at(colorattr_value
)));
161 return dot_escape_store
.back().c_str();
164 const char *findLabel(std::string member_name
)
166 for (auto &s
: label_selections
)
167 if (s
.second
.selected_member(module
->name
, member_name
))
168 return escape(s
.first
);
169 return escape(member_name
, true);
172 const char *escape(std::string id
, bool is_name
= false)
177 if (id
[0] == '$' && is_name
) {
179 if (autonames
.count(id
) == 0) {
180 autonames
[id
] = autonames
.size() + 1;
181 log("Generated short name for internal identifier: _%d_ -> %s\n", autonames
[id
], id
.c_str());
183 id
= stringf("_%d_", autonames
[id
]);
184 } else if (abbreviateIds
) {
185 const char *p
= id
.c_str();
186 const char *q
= strrchr(p
, '$');
196 if (ch
== '\\' || ch
== '"')
201 dot_escape_store
.push_back(str
);
202 return dot_escape_store
.back().c_str();
205 int id2num(RTLIL::IdString id
)
207 if (dot_id2num_store
.count(id
) > 0)
208 return dot_id2num_store
[id
];
209 return dot_id2num_store
[id
] = dot_id2num_store
.size() + 1;
212 std::string
gen_signode_simple(RTLIL::SigSpec sig
, bool range_check
= true)
214 if (GetSize(sig
) == 0) {
215 fprintf(f
, "v%d [ label=\"\" ];\n", single_idx_count
);
216 return stringf("v%d", single_idx_count
++);
219 if (sig
.is_chunk()) {
220 const RTLIL::SigChunk
&c
= sig
.as_chunk();
221 if (c
.wire
!= NULL
&& design
->selected_member(module
->name
, c
.wire
->name
)) {
222 if (!range_check
|| c
.wire
->width
== c
.width
)
223 return stringf("n%d", id2num(c
.wire
->name
));
225 fprintf(f
, "v%d [ label=\"%s\" ];\n", single_idx_count
, findLabel(log_signal(c
)));
226 return stringf("v%d", single_idx_count
++);
230 return std::string();
233 std::string
gen_portbox(std::string port
, RTLIL::SigSpec sig
, bool driver
, std::string
*node
= NULL
)
236 std::string net
= gen_signode_simple(sig
);
239 std::string label_string
;
240 int pos
= sig
.size()-1;
241 int idx
= single_idx_count
++;
242 for (int rep
, i
= int(sig
.chunks().size())-1; i
>= 0; i
-= rep
) {
243 const RTLIL::SigChunk
&c
= sig
.chunks().at(i
);
244 if (!driver
&& c
.wire
== nullptr) {
245 RTLIL::State s1
= c
.data
.front();
246 for (auto s2
: c
.data
)
248 goto not_const_stream
;
252 net
= gen_signode_simple(c
, false);
253 log_assert(!net
.empty());
255 for (rep
= 1; i
-rep
>= 0 && c
== sig
.chunks().at(i
-rep
); rep
++) {}
256 std::string repinfo
= rep
> 1 ? stringf("%dx ", rep
) : "";
258 log_assert(!net
.empty());
259 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
);
260 net_conn_map
[net
].in
.insert(stringf("x%d:s%d", idx
, i
));
261 net_conn_map
[net
].bits
= rep
*c
.width
;
262 net_conn_map
[net
].color
= nextColor(c
, net_conn_map
[net
].color
);
265 log_assert(rep
== 1);
266 label_string
+= stringf("%c -> %d:%d |",
267 c
.data
.front() == State::S0
? '0' :
268 c
.data
.front() == State::S1
? '1' :
269 c
.data
.front() == State::Sx
? 'X' :
270 c
.data
.front() == State::Sz
? 'Z' : '?',
271 pos
, pos
-rep
*c
.width
+1);
273 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);
274 net_conn_map
[net
].out
.insert(stringf("x%d:s%d", idx
, i
));
275 net_conn_map
[net
].bits
= rep
*c
.width
;
276 net_conn_map
[net
].color
= nextColor(c
, net_conn_map
[net
].color
);
278 pos
-= rep
* c
.width
;
280 if (label_string
[label_string
.size()-1] == '|')
281 label_string
= label_string
.substr(0, label_string
.size()-1);
282 code
+= stringf("x%d [ shape=record, style=rounded, label=\"%s\" ];\n", idx
, label_string
.c_str());
284 currentColor
= xorshift32(currentColor
);
286 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());
288 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());
291 *node
= stringf("x%d", idx
);
297 net_conn_map
[net
].in
.insert(port
);
299 net_conn_map
[net
].out
.insert(port
);
300 net_conn_map
[net
].bits
= sig
.size();
301 net_conn_map
[net
].color
= nextColor(sig
, net_conn_map
[net
].color
);
309 void collect_proc_signals(std::vector
<RTLIL::SigSpec
> &obj
, std::set
<RTLIL::SigSpec
> &signals
)
312 if (!it
.is_fully_const())
316 void collect_proc_signals(std::vector
<RTLIL::SigSig
> &obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
318 for (auto &it
: obj
) {
319 output_signals
.insert(it
.first
);
320 if (!it
.second
.is_fully_const())
321 input_signals
.insert(it
.second
);
325 void collect_proc_signals(RTLIL::CaseRule
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
327 collect_proc_signals(obj
->compare
, input_signals
);
328 collect_proc_signals(obj
->actions
, input_signals
, output_signals
);
329 for (auto it
: obj
->switches
)
330 collect_proc_signals(it
, input_signals
, output_signals
);
333 void collect_proc_signals(RTLIL::SwitchRule
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
335 input_signals
.insert(obj
->signal
);
336 for (auto it
: obj
->cases
)
337 collect_proc_signals(it
, input_signals
, output_signals
);
340 void collect_proc_signals(RTLIL::SyncRule
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
342 input_signals
.insert(obj
->signal
);
343 collect_proc_signals(obj
->actions
, input_signals
, output_signals
);
346 void collect_proc_signals(RTLIL::Process
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
348 collect_proc_signals(&obj
->root_case
, input_signals
, output_signals
);
349 for (auto it
: obj
->syncs
)
350 collect_proc_signals(it
, input_signals
, output_signals
);
355 single_idx_count
= 0;
356 dot_escape_store
.clear();
357 dot_id2num_store
.clear();
358 net_conn_map
.clear();
360 fprintf(f
, "digraph \"%s\" {\n", escape(module
->name
.str()));
362 fprintf(f
, "label=\"%s\";\n", escape(module
->name
.str()));
363 fprintf(f
, "rankdir=\"LR\";\n");
364 fprintf(f
, "remincross=true;\n");
366 std::set
<std::string
> all_sources
, all_sinks
;
368 std::map
<std::string
, std::string
> wires_on_demand
;
369 for (auto &it
: module
->wires_
) {
370 if (!design
->selected_member(module
->name
, it
.first
))
372 const char *shape
= "diamond";
373 if (it
.second
->port_input
|| it
.second
->port_output
)
375 if (it
.first
[0] == '\\') {
376 fprintf(f
, "n%d [ shape=%s, label=\"%s\", %s, fontcolor=\"black\" ];\n",
377 id2num(it
.first
), shape
, findLabel(it
.first
.str()),
378 nextColor(RTLIL::SigSpec(it
.second
), "color=\"black\"").c_str());
379 if (it
.second
->port_input
)
380 all_sources
.insert(stringf("n%d", id2num(it
.first
)));
381 else if (it
.second
->port_output
)
382 all_sinks
.insert(stringf("n%d", id2num(it
.first
)));
384 wires_on_demand
[stringf("n%d", id2num(it
.first
))] = it
.first
.str();
390 fprintf(f
, "{ rank=\"source\";");
391 for (auto n
: all_sources
)
392 fprintf(f
, " %s;", n
.c_str());
395 fprintf(f
, "{ rank=\"sink\";");
396 for (auto n
: all_sinks
)
397 fprintf(f
, " %s;", n
.c_str());
401 for (auto &it
: module
->cells_
)
403 if (!design
->selected_member(module
->name
, it
.first
))
406 std::vector
<RTLIL::IdString
> in_ports
, out_ports
;
408 for (auto &conn
: it
.second
->connections()) {
409 if (!ct
.cell_output(it
.second
->type
, conn
.first
))
410 in_ports
.push_back(conn
.first
);
412 out_ports
.push_back(conn
.first
);
415 std::sort(in_ports
.begin(), in_ports
.end(), RTLIL::sort_by_id_str());
416 std::sort(out_ports
.begin(), out_ports
.end(), RTLIL::sort_by_id_str());
418 std::string label_string
= "{{";
420 for (auto &p
: in_ports
)
421 label_string
+= stringf("<p%d> %s%s|", id2num(p
), escape(p
.str()),
422 genSignedLabels
&& it
.second
->hasParam(p
.str() + "_SIGNED") &&
423 it
.second
->getParam(p
.str() + "_SIGNED").as_bool() ? "*" : "");
424 if (label_string
[label_string
.size()-1] == '|')
425 label_string
= label_string
.substr(0, label_string
.size()-1);
427 label_string
+= stringf("}|%s\\n%s|{", findLabel(it
.first
.str()), escape(it
.second
->type
.str()));
429 for (auto &p
: out_ports
)
430 label_string
+= stringf("<p%d> %s|", id2num(p
), escape(p
.str()));
431 if (label_string
[label_string
.size()-1] == '|')
432 label_string
= label_string
.substr(0, label_string
.size()-1);
434 label_string
+= "}}";
437 for (auto &conn
: it
.second
->connections()) {
438 code
+= gen_portbox(stringf("c%d:p%d", id2num(it
.first
), id2num(conn
.first
)),
439 conn
.second
, ct
.cell_output(it
.second
->type
, conn
.first
));
442 #ifdef CLUSTER_CELLS_AND_PORTBOXES
444 fprintf(f
, "subgraph cluster_c%d {\nc%d [ shape=record, label=\"%s\"%s ];\n%s}\n",
445 id2num(it
.first
), id2num(it
.first
), label_string
.c_str(), findColor(it
.first
), code
.c_str());
448 fprintf(f
, "c%d [ shape=record, label=\"%s\"%s ];\n%s",
449 id2num(it
.first
), label_string
.c_str(), findColor(it
.first
.str()), code
.c_str());
452 for (auto &it
: module
->processes
)
454 RTLIL::Process
*proc
= it
.second
;
456 if (!design
->selected_member(module
->name
, proc
->name
))
459 std::set
<RTLIL::SigSpec
> input_signals
, output_signals
;
460 collect_proc_signals(proc
, input_signals
, output_signals
);
462 int pidx
= single_idx_count
++;
463 input_signals
.erase(RTLIL::SigSpec());
464 output_signals
.erase(RTLIL::SigSpec());
466 for (auto &sig
: input_signals
) {
467 std::string code
, node
;
468 code
+= gen_portbox("", sig
, false, &node
);
469 fprintf(f
, "%s", code
.c_str());
470 net_conn_map
[node
].out
.insert(stringf("p%d", pidx
));
471 net_conn_map
[node
].bits
= sig
.size();
472 net_conn_map
[node
].color
= nextColor(sig
, net_conn_map
[node
].color
);
475 for (auto &sig
: output_signals
) {
476 std::string code
, node
;
477 code
+= gen_portbox("", sig
, true, &node
);
478 fprintf(f
, "%s", code
.c_str());
479 net_conn_map
[node
].in
.insert(stringf("p%d", pidx
));
480 net_conn_map
[node
].bits
= sig
.size();
481 net_conn_map
[node
].color
= nextColor(sig
, net_conn_map
[node
].color
);
484 std::string proc_src
= RTLIL::unescape_id(proc
->name
);
485 if (proc
->attributes
.count(ID::src
) > 0)
486 proc_src
= proc
->attributes
.at(ID::src
).decode_string();
487 fprintf(f
, "p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\"];\n", pidx
, findLabel(proc
->name
.str()), proc_src
.c_str());
490 for (auto &conn
: module
->connections())
492 bool found_lhs_wire
= false;
493 for (auto &c
: conn
.first
.chunks()) {
494 if (c
.wire
== NULL
|| design
->selected_member(module
->name
, c
.wire
->name
))
495 found_lhs_wire
= true;
497 bool found_rhs_wire
= false;
498 for (auto &c
: conn
.second
.chunks()) {
499 if (c
.wire
== NULL
|| design
->selected_member(module
->name
, c
.wire
->name
))
500 found_rhs_wire
= true;
502 if (!found_lhs_wire
|| !found_rhs_wire
)
505 std::string code
, left_node
, right_node
;
506 code
+= gen_portbox("", conn
.second
, false, &left_node
);
507 code
+= gen_portbox("", conn
.first
, true, &right_node
);
508 fprintf(f
, "%s", code
.c_str());
510 if (left_node
[0] == 'x' && right_node
[0] == 'x') {
511 currentColor
= xorshift32(currentColor
);
512 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());
514 net_conn_map
[right_node
].bits
= conn
.first
.size();
515 net_conn_map
[right_node
].color
= nextColor(conn
, net_conn_map
[right_node
].color
);
516 net_conn_map
[left_node
].bits
= conn
.first
.size();
517 net_conn_map
[left_node
].color
= nextColor(conn
, net_conn_map
[left_node
].color
);
518 if (left_node
[0] == 'x') {
519 net_conn_map
[right_node
].in
.insert(left_node
);
520 } else if (right_node
[0] == 'x') {
521 net_conn_map
[left_node
].out
.insert(right_node
);
523 net_conn_map
[right_node
].in
.insert(stringf("x%d:e", single_idx_count
));
524 net_conn_map
[left_node
].out
.insert(stringf("x%d:w", single_idx_count
));
525 fprintf(f
, "x%d [shape=box, style=rounded, label=\"BUF\"];\n", single_idx_count
++);
530 for (auto &it
: net_conn_map
)
532 currentColor
= xorshift32(currentColor
);
533 if (wires_on_demand
.count(it
.first
) > 0) {
534 if (it
.second
.in
.size() == 1 && it
.second
.out
.size() > 1 && it
.second
.in
.begin()->compare(0, 1, "p") == 0)
535 it
.second
.out
.erase(*it
.second
.in
.begin());
536 if (it
.second
.in
.size() == 1 && it
.second
.out
.size() == 1) {
537 std::string from
= *it
.second
.in
.begin(), to
= *it
.second
.out
.begin();
538 if (from
!= to
|| from
.compare(0, 1, "p") != 0)
539 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());
542 if (it
.second
.in
.size() == 0 || it
.second
.out
.size() == 0)
543 fprintf(f
, "%s [ shape=diamond, label=\"%s\" ];\n", it
.first
.c_str(), findLabel(wires_on_demand
[it
.first
]));
545 fprintf(f
, "%s [ shape=point ];\n", it
.first
.c_str());
547 for (auto &it2
: it
.second
.in
)
548 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());
549 for (auto &it2
: it
.second
.out
)
550 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());
556 ShowWorker(FILE *f
, RTLIL::Design
*design
, std::vector
<RTLIL::Design
*> &libs
, uint32_t colorSeed
, bool genWidthLabels
,
557 bool genSignedLabels
, bool stretchIO
, bool enumerateIds
, bool abbreviateIds
, bool notitle
,
558 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &color_selections
,
559 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &label_selections
, RTLIL::IdString colorattr
) :
560 f(f
), design(design
), currentColor(colorSeed
), genWidthLabels(genWidthLabels
),
561 genSignedLabels(genSignedLabels
), stretchIO(stretchIO
), enumerateIds(enumerateIds
), abbreviateIds(abbreviateIds
),
562 notitle(notitle
), color_selections(color_selections
), label_selections(label_selections
), colorattr(colorattr
)
564 ct
.setup_internals();
565 ct
.setup_internals_mem();
567 ct
.setup_stdcells_mem();
568 ct
.setup_design(design
);
570 for (auto lib
: libs
)
571 ct
.setup_design(lib
);
575 for (auto &mod_it
: design
->modules_
)
577 module
= mod_it
.second
;
578 if (!design
->selected_module(module
->name
))
580 if (design
->selected_whole_module(module
->name
)) {
581 if (module
->get_blackbox_attribute()) {
582 // log("Skipping blackbox module %s.\n", id2cstr(module->name));
585 if (module
->cells_
.empty() && module
->connections().empty() && module
->processes
.empty()) {
586 log("Skipping empty module %s.\n", id2cstr(module
->name
));
589 log("Dumping module %s to page %d.\n", id2cstr(module
->name
), ++page_counter
);
591 log("Dumping selected parts of module %s to page %d.\n", id2cstr(module
->name
), ++page_counter
);
597 struct ShowPass
: public Pass
{
598 ShowPass() : Pass("show", "generate schematics using graphviz") { }
599 void help() YS_OVERRIDE
601 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
603 log(" show [options] [selection]\n");
605 log("Create a graphviz DOT file for the selected part of the design and compile it\n");
606 log("to a graphics file (usually SVG or PostScript).\n");
608 log(" -viewer <viewer>\n");
609 log(" Run the specified command with the graphics file as parameter.\n");
610 log(" On Windows, this pauses yosys until the viewer exits.\n");
612 log(" -format <format>\n");
613 log(" Generate a graphics file in the specified format. Use 'dot' to just\n");
614 log(" generate a .dot file, or other <format> strings such as 'svg' or 'ps'\n");
615 log(" to generate files in other formats (this calls the 'dot' command).\n");
617 log(" -lib <verilog_or_ilang_file>\n");
618 log(" Use the specified library file for determining whether cell ports are\n");
619 log(" inputs or outputs. This option can be used multiple times to specify\n");
620 log(" more than one library.\n");
622 log(" note: in most cases it is better to load the library before calling\n");
623 log(" show with 'read_verilog -lib <filename>'. it is also possible to\n");
624 log(" load liberty files with 'read_liberty -lib <filename>'.\n");
626 log(" -prefix <prefix>\n");
627 log(" generate <prefix>.* instead of ~/.yosys_show.*\n");
629 log(" -color <color> <object>\n");
630 log(" assign the specified color to the specified object. The object can be\n");
631 log(" a single selection wildcard expressions or a saved set of objects in\n");
632 log(" the @<name> syntax (see \"help select\" for details).\n");
634 log(" -label <text> <object>\n");
635 log(" assign the specified label text to the specified object. The object can\n");
636 log(" be a single selection wildcard expressions or a saved set of objects in\n");
637 log(" the @<name> syntax (see \"help select\" for details).\n");
639 log(" -colors <seed>\n");
640 log(" Randomly assign colors to the wires. The integer argument is the seed\n");
641 log(" for the random number generator. Change the seed value if the colored\n");
642 log(" graph still is ambiguous. A seed of zero deactivates the coloring.\n");
644 log(" -colorattr <attribute_name>\n");
645 log(" Use the specified attribute to assign colors. A unique color is\n");
646 log(" assigned to each unique value of this attribute.\n");
649 log(" annotate buses with a label indicating the width of the bus.\n");
652 log(" mark ports (A, B) that are declared as signed (using the [AB]_SIGNED\n");
653 log(" cell parameter) with an asterisk next to the port name.\n");
656 log(" stretch the graph so all inputs are on the left side and all outputs\n");
657 log(" (including inout ports) are on the right side.\n");
660 log(" wait for the use to press enter to before returning\n");
663 log(" enumerate objects with internal ($-prefixed) names\n");
666 log(" do not abbreviate objects with internal ($-prefixed) names\n");
669 log(" do not add the module name as graph title to the dot file\n");
672 log(" don't run viewer in the background, IE wait for the viewer tool to\n");
673 log(" exit before returning\n");
675 log("When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n");
676 log("specified, 'xdot' is used to display the schematic (POSIX systems only).\n");
678 log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
679 log("unless another prefix is specified using -prefix <prefix>.\n");
681 log("Yosys on Windows and YosysJS use different defaults: The output is written\n");
682 log("to 'show.dot' in the current directory and new viewer is launched each time\n");
683 log("the 'show' command is executed.\n");
686 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
688 log_header(design
, "Generating Graphviz representation of design.\n");
691 std::vector
<std::pair
<std::string
, RTLIL::Selection
>> color_selections
;
692 std::vector
<std::pair
<std::string
, RTLIL::Selection
>> label_selections
;
694 #if defined(EMSCRIPTEN) || defined(_WIN32)
695 std::string format
= "dot";
696 std::string prefix
= "show";
699 std::string prefix
= stringf("%s/.yosys_show", getenv("HOME") ? getenv("HOME") : ".");
701 std::string viewer_exe
;
702 std::vector
<std::string
> libfiles
;
703 std::vector
<RTLIL::Design
*> libs
;
704 uint32_t colorSeed
= 0;
705 bool flag_width
= false;
706 bool flag_signed
= false;
707 bool flag_stretch
= false;
708 bool flag_pause
= false;
709 bool flag_enum
= false;
710 bool flag_abbreviate
= true;
711 bool flag_notitle
= false;
712 bool custom_prefix
= false;
713 std::string background
= "&";
714 RTLIL::IdString colorattr
;
717 for (argidx
= 1; argidx
< args
.size(); argidx
++)
719 std::string arg
= args
[argidx
];
720 if (arg
== "-viewer" && argidx
+1 < args
.size()) {
721 viewer_exe
= args
[++argidx
];
724 if (arg
== "-lib" && argidx
+1 < args
.size()) {
725 libfiles
.push_back(args
[++argidx
]);
728 if (arg
== "-prefix" && argidx
+1 < args
.size()) {
729 prefix
= args
[++argidx
];
730 custom_prefix
= true;
733 if (arg
== "-color" && 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 color_selections
.push_back(data
);
742 if (arg
== "-label" && argidx
+2 < args
.size()) {
743 std::pair
<std::string
, RTLIL::Selection
> data
;
744 data
.first
= args
[++argidx
], argidx
++;
745 handle_extra_select_args(this, args
, argidx
, argidx
+1, design
);
746 data
.second
= design
->selection_stack
.back();
747 design
->selection_stack
.pop_back();
748 label_selections
.push_back(data
);
751 if (arg
== "-colors" && argidx
+1 < args
.size()) {
752 colorSeed
= atoi(args
[++argidx
].c_str());
753 for (int i
= 0; i
< 100; i
++)
754 colorSeed
= ShowWorker::xorshift32(colorSeed
);
757 if (arg
== "-colorattr" && argidx
+1 < args
.size()) {
758 colorattr
= RTLIL::escape_id(args
[++argidx
]);
761 if (arg
== "-format" && argidx
+1 < args
.size()) {
762 format
= args
[++argidx
];
765 if (arg
== "-width") {
769 if (arg
== "-signed") {
773 if (arg
== "-stretch") {
777 if (arg
== "-pause") {
781 if (arg
== "-enum") {
783 flag_abbreviate
= false;
786 if (arg
== "-long") {
788 flag_abbreviate
= false;
791 if (arg
== "-notitle") {
795 if (arg
== "-nobg") {
801 extra_args(args
, argidx
, design
);
803 if (format
!= "ps" && format
!= "dot") {
805 for (auto &mod_it
: design
->modules_
) {
806 if (mod_it
.second
->get_blackbox_attribute())
808 if (mod_it
.second
->cells_
.empty() && mod_it
.second
->connections().empty())
810 if (design
->selected_module(mod_it
.first
))
814 log_cmd_error("For formats different than 'ps' or 'dot' only one module must be selected.\n");
817 for (auto filename
: libfiles
) {
819 f
.open(filename
.c_str());
820 yosys_input_files
.insert(filename
);
822 log_error("Can't open lib file `%s'.\n", filename
.c_str());
823 RTLIL::Design
*lib
= new RTLIL::Design
;
824 Frontend::frontend_call(lib
, &f
, filename
, (filename
.size() > 3 && filename
.compare(filename
.size()-3, std::string::npos
, ".il") == 0 ? "ilang" : "verilog"));
829 log_header(design
, "Continuing show pass.\n");
831 std::string dot_file
= stringf("%s.dot", prefix
.c_str());
832 std::string out_file
= stringf("%s.%s", prefix
.c_str(), format
.empty() ? "svg" : format
.c_str());
834 log("Writing dot description to `%s'.\n", dot_file
.c_str());
835 FILE *f
= fopen(dot_file
.c_str(), "w");
837 yosys_output_files
.insert(dot_file
);
839 for (auto lib
: libs
)
841 log_cmd_error("Can't open dot file `%s' for writing.\n", dot_file
.c_str());
843 ShowWorker
worker(f
, design
, libs
, colorSeed
, flag_width
, flag_signed
, flag_stretch
, flag_enum
, flag_abbreviate
, flag_notitle
, color_selections
, label_selections
, colorattr
);
846 for (auto lib
: libs
)
849 if (worker
.page_counter
== 0)
850 log_cmd_error("Nothing there to show.\n");
852 if (format
!= "dot" && !format
.empty()) {
854 // system()/cmd.exe does not understand single quotes on Windows.
855 #define DOT_CMD "dot -T%s \"%s\" > \"%s.new\" && move \"%s.new\" \"%s\""
857 #define DOT_CMD "dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'"
859 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());
861 log("Exec: %s\n", cmd
.c_str());
862 if (run_command(cmd
) != 0)
863 log_cmd_error("Shell command failed!\n");
866 if (!viewer_exe
.empty()) {
868 // system()/cmd.exe does not understand single quotes nor
869 // background tasks on Windows. So we have to pause yosys
870 // until the viewer exits.
871 std::string cmd
= stringf("%s \"%s\"", viewer_exe
.c_str(), out_file
.c_str());
873 std::string cmd
= stringf("%s '%s' %s", viewer_exe
.c_str(), out_file
.c_str(), background
.c_str());
875 log("Exec: %s\n", cmd
.c_str());
876 if (run_command(cmd
) != 0)
877 log_cmd_error("Shell command failed!\n");
879 if (format
.empty()) {
881 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());
883 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());
885 log("Exec: %s\n", cmd
.c_str());
886 if (run_command(cmd
) != 0)
887 log_cmd_error("Shell command failed!\n");
891 #ifdef YOSYS_ENABLE_READLINE
893 while ((input
= readline("Press ENTER to continue (or type 'shell' to open a shell)> ")) != NULL
) {
894 if (input
[strspn(input
, " \t\r\n")] == 0)
896 char *p
= input
+ strspn(input
, " \t\r\n");
897 if (!strcmp(p
, "shell")) {
898 Pass::call(design
, "shell");
903 log_cmd_error("This version of yosys is built without readline support => 'show -pause' is not available.\n");
911 PRIVATE_NAMESPACE_END