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"
29 #ifdef YOSYS_ENABLE_READLINE
30 # include <readline/readline.h>
33 #ifdef YOSYS_ENABLE_EDITLINE
34 # include <editline/readline.h>
38 PRIVATE_NAMESPACE_BEGIN
42 #undef CLUSTER_CELLS_AND_PORTBOXES
48 vector
<shared_str
> dot_escape_store
;
49 std::map
<RTLIL::IdString
, int> dot_id2num_store
;
50 std::map
<RTLIL::IdString
, int> autonames
;
53 struct net_conn
{ std::set
<std::string
> in
, out
; int bits
; std::string color
; };
54 std::map
<std::string
, net_conn
> net_conn_map
;
57 RTLIL::Design
*design
;
58 RTLIL::Module
*module
;
59 uint32_t currentColor
;
68 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &color_selections
;
69 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &label_selections
;
71 std::map
<RTLIL::Const
, int> colorattr_cache
;
72 RTLIL::IdString colorattr
;
75 static uint32_t xorshift32(uint32_t x
) {
82 std::string
nextColor()
84 if (currentColor
== 0)
85 return "color=\"black\"";
86 return stringf("colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", currentColor
%8+1, currentColor
%8+1);
89 std::string
nextColor(std::string presetColor
)
91 if (presetColor
.empty())
96 std::string
nextColor(RTLIL::SigSpec sig
, std::string defaultColor
)
99 for (auto &c
: sig
.chunks()) {
101 for (auto &s
: color_selections
)
102 if (s
.second
.selected_members
.count(module
->name
) > 0 && s
.second
.selected_members
.at(module
->name
).count(c
.wire
->name
) > 0)
103 return stringf("color=\"%s\"", s
.first
.c_str());
108 std::string
nextColor(const RTLIL::SigSig
&conn
, std::string defaultColor
)
110 return nextColor(conn
.first
, nextColor(conn
.second
, defaultColor
));
113 std::string
nextColor(const RTLIL::SigSpec
&sig
)
115 return nextColor(sig
, nextColor());
118 std::string
nextColor(const RTLIL::SigSig
&conn
)
120 return nextColor(conn
, nextColor());
123 std::string
widthLabel(int bits
)
128 return "style=\"setlinewidth(3)\", label=\"\"";
129 return stringf("style=\"setlinewidth(3)\", label=\"<%d>\"", bits
);
132 const char *findColor(std::string member_name
)
134 for (auto &s
: color_selections
)
135 if (s
.second
.selected_member(module
->name
, member_name
)) {
136 dot_escape_store
.push_back(stringf(", color=\"%s\"", s
.first
.c_str()));
137 return dot_escape_store
.back().c_str();
140 RTLIL::Const colorattr_value
;
141 RTLIL::Cell
*cell
= module
->cell(member_name
);
142 RTLIL::Wire
*wire
= module
->wire(member_name
);
144 if (cell
&& cell
->attributes
.count(colorattr
))
145 colorattr_value
= cell
->attributes
.at(colorattr
);
146 else if (wire
&& wire
->attributes
.count(colorattr
))
147 colorattr_value
= wire
->attributes
.at(colorattr
);
151 if (colorattr_cache
.count(colorattr_value
) == 0) {
152 int next_id
= GetSize(colorattr_cache
);
153 colorattr_cache
[colorattr_value
] = (next_id
% 8) + 1;
156 dot_escape_store
.push_back(stringf(", colorscheme=\"dark28\", color=\"%d\", fontcolor=\"%d\"", colorattr_cache
.at(colorattr_value
), colorattr_cache
.at(colorattr_value
)));
157 return dot_escape_store
.back().c_str();
160 const char *findLabel(std::string member_name
)
162 for (auto &s
: label_selections
)
163 if (s
.second
.selected_member(module
->name
, member_name
))
164 return escape(s
.first
);
165 return escape(member_name
, true);
168 const char *escape(std::string id
, bool is_name
= false)
173 if (id
[0] == '$' && is_name
) {
175 if (autonames
.count(id
) == 0) {
176 autonames
[id
] = autonames
.size() + 1;
177 log("Generated short name for internal identifier: _%d_ -> %s\n", autonames
[id
], id
.c_str());
179 id
= stringf("_%d_", autonames
[id
]);
180 } else if (abbreviateIds
) {
181 const char *p
= id
.c_str();
182 const char *q
= strrchr(p
, '$');
192 if (ch
== '\\' || ch
== '"')
197 dot_escape_store
.push_back(str
);
198 return dot_escape_store
.back().c_str();
201 int id2num(RTLIL::IdString id
)
203 if (dot_id2num_store
.count(id
) > 0)
204 return dot_id2num_store
[id
];
205 return dot_id2num_store
[id
] = dot_id2num_store
.size() + 1;
208 std::string
gen_signode_simple(RTLIL::SigSpec sig
, bool range_check
= true)
210 if (GetSize(sig
) == 0) {
211 fprintf(f
, "v%d [ label=\"\" ];\n", single_idx_count
);
212 return stringf("v%d", single_idx_count
++);
215 if (sig
.is_chunk()) {
216 const RTLIL::SigChunk
&c
= sig
.as_chunk();
217 if (c
.wire
!= NULL
&& design
->selected_member(module
->name
, c
.wire
->name
)) {
218 if (!range_check
|| c
.wire
->width
== c
.width
)
219 return stringf("n%d", id2num(c
.wire
->name
));
221 fprintf(f
, "v%d [ label=\"%s\" ];\n", single_idx_count
, findLabel(log_signal(c
)));
222 return stringf("v%d", single_idx_count
++);
226 return std::string();
229 std::string
gen_portbox(std::string port
, RTLIL::SigSpec sig
, bool driver
, std::string
*node
= NULL
)
232 std::string net
= gen_signode_simple(sig
);
235 std::string label_string
;
236 int pos
= sig
.size()-1;
237 int idx
= single_idx_count
++;
238 for (int rep
, i
= int(sig
.chunks().size())-1; i
>= 0; i
-= rep
) {
239 const RTLIL::SigChunk
&c
= sig
.chunks().at(i
);
240 if (!driver
&& c
.wire
== nullptr) {
241 RTLIL::State s1
= c
.data
.front();
242 for (auto s2
: c
.data
)
244 goto not_const_stream
;
248 net
= gen_signode_simple(c
, false);
249 log_assert(!net
.empty());
251 for (rep
= 1; i
-rep
>= 0 && c
== sig
.chunks().at(i
-rep
); rep
++) {}
252 std::string repinfo
= rep
> 1 ? stringf("%dx ", rep
) : "";
254 log_assert(!net
.empty());
255 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
);
256 net_conn_map
[net
].in
.insert(stringf("x%d:s%d", idx
, i
));
257 net_conn_map
[net
].bits
= rep
*c
.width
;
258 net_conn_map
[net
].color
= nextColor(c
, net_conn_map
[net
].color
);
261 log_assert(rep
== 1);
262 label_string
+= stringf("%c -> %d:%d |",
263 c
.data
.front() == State::S0
? '0' :
264 c
.data
.front() == State::S1
? '1' :
265 c
.data
.front() == State::Sx
? 'X' :
266 c
.data
.front() == State::Sz
? 'Z' : '?',
267 pos
, pos
-rep
*c
.width
+1);
269 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);
270 net_conn_map
[net
].out
.insert(stringf("x%d:s%d", idx
, i
));
271 net_conn_map
[net
].bits
= rep
*c
.width
;
272 net_conn_map
[net
].color
= nextColor(c
, net_conn_map
[net
].color
);
274 pos
-= rep
* c
.width
;
276 if (label_string
[label_string
.size()-1] == '|')
277 label_string
= label_string
.substr(0, label_string
.size()-1);
278 code
+= stringf("x%d [ shape=record, style=rounded, label=\"%s\" ];\n", idx
, label_string
.c_str());
280 currentColor
= xorshift32(currentColor
);
282 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());
284 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());
287 *node
= stringf("x%d", idx
);
293 net_conn_map
[net
].in
.insert(port
);
295 net_conn_map
[net
].out
.insert(port
);
296 net_conn_map
[net
].bits
= sig
.size();
297 net_conn_map
[net
].color
= nextColor(sig
, net_conn_map
[net
].color
);
305 void collect_proc_signals(std::vector
<RTLIL::SigSpec
> &obj
, std::set
<RTLIL::SigSpec
> &signals
)
308 if (!it
.is_fully_const())
312 void collect_proc_signals(std::vector
<RTLIL::SigSig
> &obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
314 for (auto &it
: obj
) {
315 output_signals
.insert(it
.first
);
316 if (!it
.second
.is_fully_const())
317 input_signals
.insert(it
.second
);
321 void collect_proc_signals(RTLIL::CaseRule
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
323 collect_proc_signals(obj
->compare
, input_signals
);
324 collect_proc_signals(obj
->actions
, input_signals
, output_signals
);
325 for (auto it
: obj
->switches
)
326 collect_proc_signals(it
, input_signals
, output_signals
);
329 void collect_proc_signals(RTLIL::SwitchRule
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
331 input_signals
.insert(obj
->signal
);
332 for (auto it
: obj
->cases
)
333 collect_proc_signals(it
, input_signals
, output_signals
);
336 void collect_proc_signals(RTLIL::SyncRule
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
338 input_signals
.insert(obj
->signal
);
339 collect_proc_signals(obj
->actions
, input_signals
, output_signals
);
342 void collect_proc_signals(RTLIL::Process
*obj
, std::set
<RTLIL::SigSpec
> &input_signals
, std::set
<RTLIL::SigSpec
> &output_signals
)
344 collect_proc_signals(&obj
->root_case
, input_signals
, output_signals
);
345 for (auto it
: obj
->syncs
)
346 collect_proc_signals(it
, input_signals
, output_signals
);
351 single_idx_count
= 0;
352 dot_escape_store
.clear();
353 dot_id2num_store
.clear();
354 net_conn_map
.clear();
356 fprintf(f
, "digraph \"%s\" {\n", escape(module
->name
.str()));
358 fprintf(f
, "label=\"%s\";\n", escape(module
->name
.str()));
359 fprintf(f
, "rankdir=\"LR\";\n");
360 fprintf(f
, "remincross=true;\n");
362 std::set
<std::string
> all_sources
, all_sinks
;
364 std::map
<std::string
, std::string
> wires_on_demand
;
365 for (auto &it
: module
->wires_
) {
366 if (!design
->selected_member(module
->name
, it
.first
))
368 const char *shape
= "diamond";
369 if (it
.second
->port_input
|| it
.second
->port_output
)
371 if (it
.first
[0] == '\\') {
372 fprintf(f
, "n%d [ shape=%s, label=\"%s\", %s, fontcolor=\"black\" ];\n",
373 id2num(it
.first
), shape
, findLabel(it
.first
.str()),
374 nextColor(RTLIL::SigSpec(it
.second
), "color=\"black\"").c_str());
375 if (it
.second
->port_input
)
376 all_sources
.insert(stringf("n%d", id2num(it
.first
)));
377 else if (it
.second
->port_output
)
378 all_sinks
.insert(stringf("n%d", id2num(it
.first
)));
380 wires_on_demand
[stringf("n%d", id2num(it
.first
))] = it
.first
.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 &it
: module
->cells_
)
399 if (!design
->selected_member(module
->name
, it
.first
))
402 std::vector
<RTLIL::IdString
> in_ports
, out_ports
;
404 for (auto &conn
: it
.second
->connections()) {
405 if (!ct
.cell_output(it
.second
->type
, conn
.first
))
406 in_ports
.push_back(conn
.first
);
408 out_ports
.push_back(conn
.first
);
411 std::sort(in_ports
.begin(), in_ports
.end(), RTLIL::sort_by_id_str());
412 std::sort(out_ports
.begin(), out_ports
.end(), RTLIL::sort_by_id_str());
414 std::string label_string
= "{{";
416 for (auto &p
: in_ports
)
417 label_string
+= stringf("<p%d> %s%s|", id2num(p
), escape(p
.str()),
418 genSignedLabels
&& it
.second
->hasParam(p
.str() + "_SIGNED") &&
419 it
.second
->getParam(p
.str() + "_SIGNED").as_bool() ? "*" : "");
420 if (label_string
[label_string
.size()-1] == '|')
421 label_string
= label_string
.substr(0, label_string
.size()-1);
423 label_string
+= stringf("}|%s\\n%s|{", findLabel(it
.first
.str()), escape(it
.second
->type
.str()));
425 for (auto &p
: out_ports
)
426 label_string
+= stringf("<p%d> %s|", id2num(p
), escape(p
.str()));
427 if (label_string
[label_string
.size()-1] == '|')
428 label_string
= label_string
.substr(0, label_string
.size()-1);
430 label_string
+= "}}";
433 for (auto &conn
: it
.second
->connections()) {
434 code
+= gen_portbox(stringf("c%d:p%d", id2num(it
.first
), id2num(conn
.first
)),
435 conn
.second
, ct
.cell_output(it
.second
->type
, conn
.first
));
438 #ifdef CLUSTER_CELLS_AND_PORTBOXES
440 fprintf(f
, "subgraph cluster_c%d {\nc%d [ shape=record, label=\"%s\"%s ];\n%s}\n",
441 id2num(it
.first
), id2num(it
.first
), label_string
.c_str(), findColor(it
.first
), code
.c_str());
444 fprintf(f
, "c%d [ shape=record, label=\"%s\"%s ];\n%s",
445 id2num(it
.first
), label_string
.c_str(), findColor(it
.first
.str()), code
.c_str());
448 for (auto &it
: module
->processes
)
450 RTLIL::Process
*proc
= it
.second
;
452 if (!design
->selected_member(module
->name
, proc
->name
))
455 std::set
<RTLIL::SigSpec
> input_signals
, output_signals
;
456 collect_proc_signals(proc
, input_signals
, output_signals
);
458 int pidx
= single_idx_count
++;
459 input_signals
.erase(RTLIL::SigSpec());
460 output_signals
.erase(RTLIL::SigSpec());
462 for (auto &sig
: input_signals
) {
463 std::string code
, node
;
464 code
+= gen_portbox("", sig
, false, &node
);
465 fprintf(f
, "%s", code
.c_str());
466 net_conn_map
[node
].out
.insert(stringf("p%d", pidx
));
467 net_conn_map
[node
].bits
= sig
.size();
468 net_conn_map
[node
].color
= nextColor(sig
, net_conn_map
[node
].color
);
471 for (auto &sig
: output_signals
) {
472 std::string code
, node
;
473 code
+= gen_portbox("", sig
, true, &node
);
474 fprintf(f
, "%s", code
.c_str());
475 net_conn_map
[node
].in
.insert(stringf("p%d", pidx
));
476 net_conn_map
[node
].bits
= sig
.size();
477 net_conn_map
[node
].color
= nextColor(sig
, net_conn_map
[node
].color
);
480 std::string proc_src
= RTLIL::unescape_id(proc
->name
);
481 if (proc
->attributes
.count("\\src") > 0)
482 proc_src
= proc
->attributes
.at("\\src").decode_string();
483 fprintf(f
, "p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\"];\n", pidx
, findLabel(proc
->name
.str()), proc_src
.c_str());
486 for (auto &conn
: module
->connections())
488 bool found_lhs_wire
= false;
489 for (auto &c
: conn
.first
.chunks()) {
490 if (c
.wire
== NULL
|| design
->selected_member(module
->name
, c
.wire
->name
))
491 found_lhs_wire
= true;
493 bool found_rhs_wire
= false;
494 for (auto &c
: conn
.second
.chunks()) {
495 if (c
.wire
== NULL
|| design
->selected_member(module
->name
, c
.wire
->name
))
496 found_rhs_wire
= true;
498 if (!found_lhs_wire
|| !found_rhs_wire
)
501 std::string code
, left_node
, right_node
;
502 code
+= gen_portbox("", conn
.second
, false, &left_node
);
503 code
+= gen_portbox("", conn
.first
, true, &right_node
);
504 fprintf(f
, "%s", code
.c_str());
506 if (left_node
[0] == 'x' && right_node
[0] == 'x') {
507 currentColor
= xorshift32(currentColor
);
508 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());
510 net_conn_map
[right_node
].bits
= conn
.first
.size();
511 net_conn_map
[right_node
].color
= nextColor(conn
, net_conn_map
[right_node
].color
);
512 net_conn_map
[left_node
].bits
= conn
.first
.size();
513 net_conn_map
[left_node
].color
= nextColor(conn
, net_conn_map
[left_node
].color
);
514 if (left_node
[0] == 'x') {
515 net_conn_map
[right_node
].in
.insert(left_node
);
516 } else if (right_node
[0] == 'x') {
517 net_conn_map
[left_node
].out
.insert(right_node
);
519 net_conn_map
[right_node
].in
.insert(stringf("x%d:e", single_idx_count
));
520 net_conn_map
[left_node
].out
.insert(stringf("x%d:w", single_idx_count
));
521 fprintf(f
, "x%d [shape=box, style=rounded, label=\"BUF\"];\n", single_idx_count
++);
526 for (auto &it
: net_conn_map
)
528 currentColor
= xorshift32(currentColor
);
529 if (wires_on_demand
.count(it
.first
) > 0) {
530 if (it
.second
.in
.size() == 1 && it
.second
.out
.size() > 1 && it
.second
.in
.begin()->substr(0, 1) == "p")
531 it
.second
.out
.erase(*it
.second
.in
.begin());
532 if (it
.second
.in
.size() == 1 && it
.second
.out
.size() == 1) {
533 std::string from
= *it
.second
.in
.begin(), to
= *it
.second
.out
.begin();
534 if (from
!= to
|| from
.substr(0, 1) != "p")
535 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());
538 if (it
.second
.in
.size() == 0 || it
.second
.out
.size() == 0)
539 fprintf(f
, "%s [ shape=diamond, label=\"%s\" ];\n", it
.first
.c_str(), findLabel(wires_on_demand
[it
.first
]));
541 fprintf(f
, "%s [ shape=point ];\n", it
.first
.c_str());
543 for (auto &it2
: it
.second
.in
)
544 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());
545 for (auto &it2
: it
.second
.out
)
546 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());
552 ShowWorker(FILE *f
, RTLIL::Design
*design
, std::vector
<RTLIL::Design
*> &libs
, uint32_t colorSeed
, bool genWidthLabels
,
553 bool genSignedLabels
, bool stretchIO
, bool enumerateIds
, bool abbreviateIds
, bool notitle
,
554 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &color_selections
,
555 const std::vector
<std::pair
<std::string
, RTLIL::Selection
>> &label_selections
, RTLIL::IdString colorattr
) :
556 f(f
), design(design
), currentColor(colorSeed
), genWidthLabels(genWidthLabels
),
557 genSignedLabels(genSignedLabels
), stretchIO(stretchIO
), enumerateIds(enumerateIds
), abbreviateIds(abbreviateIds
),
558 notitle(notitle
), color_selections(color_selections
), label_selections(label_selections
), colorattr(colorattr
)
560 ct
.setup_internals();
561 ct
.setup_internals_mem();
563 ct
.setup_stdcells_mem();
564 ct
.setup_design(design
);
566 for (auto lib
: libs
)
567 ct
.setup_design(lib
);
571 for (auto &mod_it
: design
->modules_
)
573 module
= mod_it
.second
;
574 if (!design
->selected_module(module
->name
))
576 if (design
->selected_whole_module(module
->name
)) {
577 if (module
->get_bool_attribute("\\blackbox")) {
578 // log("Skipping blackbox module %s.\n", id2cstr(module->name));
581 if (module
->cells_
.empty() && module
->connections().empty() && module
->processes
.empty()) {
582 log("Skipping empty module %s.\n", id2cstr(module
->name
));
585 log("Dumping module %s to page %d.\n", id2cstr(module
->name
), ++page_counter
);
587 log("Dumping selected parts of module %s to page %d.\n", id2cstr(module
->name
), ++page_counter
);
593 struct ShowPass
: public Pass
{
594 ShowPass() : Pass("show", "generate schematics using graphviz") { }
595 void help() YS_OVERRIDE
597 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
599 log(" show [options] [selection]\n");
601 log("Create a graphviz DOT file for the selected part of the design and compile it\n");
602 log("to a graphics file (usually SVG or PostScript).\n");
604 log(" -viewer <viewer>\n");
605 log(" Run the specified command with the graphics file as parameter.\n");
606 log(" On Windows, this pauses yosys until the viewer exits.\n");
608 log(" -format <format>\n");
609 log(" Generate a graphics file in the specified format. Use 'dot' to just\n");
610 log(" generate a .dot file, or other <format> strings such as 'svg' or 'ps'\n");
611 log(" to generate files in other formats (this calls the 'dot' command).\n");
613 log(" -lib <verilog_or_ilang_file>\n");
614 log(" Use the specified library file for determining whether cell ports are\n");
615 log(" inputs or outputs. This option can be used multiple times to specify\n");
616 log(" more than one library.\n");
618 log(" note: in most cases it is better to load the library before calling\n");
619 log(" show with 'read_verilog -lib <filename>'. it is also possible to\n");
620 log(" load liberty files with 'read_liberty -lib <filename>'.\n");
622 log(" -prefix <prefix>\n");
623 log(" generate <prefix>.* instead of ~/.yosys_show.*\n");
625 log(" -color <color> <object>\n");
626 log(" assign the specified color to the specified object. The object can be\n");
627 log(" 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(" -label <text> <object>\n");
631 log(" assign the specified label text to the specified object. The object can\n");
632 log(" be a single selection wildcard expressions or a saved set of objects in\n");
633 log(" the @<name> syntax (see \"help select\" for details).\n");
635 log(" -colors <seed>\n");
636 log(" Randomly assign colors to the wires. The integer argument is the seed\n");
637 log(" for the random number generator. Change the seed value if the colored\n");
638 log(" graph still is ambiguous. A seed of zero deactivates the coloring.\n");
640 log(" -colorattr <attribute_name>\n");
641 log(" Use the specified attribute to assign colors. A unique color is\n");
642 log(" assigned to each unique value of this attribute.\n");
645 log(" annotate buses with a label indicating the width of the bus.\n");
648 log(" mark ports (A, B) that are declared as signed (using the [AB]_SIGNED\n");
649 log(" cell parameter) with an asterisk next to the port name.\n");
652 log(" stretch the graph so all inputs are on the left side and all outputs\n");
653 log(" (including inout ports) are on the right side.\n");
656 log(" wait for the use to press enter to before returning\n");
659 log(" enumerate objects with internal ($-prefixed) names\n");
662 log(" do not abbreviate objects with internal ($-prefixed) names\n");
665 log(" do not add the module name as graph title to the dot file\n");
667 log("When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n");
668 log("specified, 'xdot' is used to display the schematic (POSIX systems only).\n");
670 log("The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
671 log("unless another prefix is specified using -prefix <prefix>.\n");
673 log("Yosys on Windows and YosysJS use different defaults: The output is written\n");
674 log("to 'show.dot' in the current directory and new viewer is launched each time\n");
675 log("the 'show' command is executed.\n");
678 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
680 log_header(design
, "Generating Graphviz representation of design.\n");
683 std::vector
<std::pair
<std::string
, RTLIL::Selection
>> color_selections
;
684 std::vector
<std::pair
<std::string
, RTLIL::Selection
>> label_selections
;
686 #if defined(EMSCRIPTEN) || defined(_WIN32)
687 std::string format
= "dot";
688 std::string prefix
= "show";
691 std::string prefix
= stringf("%s/.yosys_show", getenv("HOME") ? getenv("HOME") : ".");
693 std::string viewer_exe
;
694 std::vector
<std::string
> libfiles
;
695 std::vector
<RTLIL::Design
*> libs
;
696 uint32_t colorSeed
= 0;
697 bool flag_width
= false;
698 bool flag_signed
= false;
699 bool flag_stretch
= false;
700 bool flag_pause
= false;
701 bool flag_enum
= false;
702 bool flag_abbreviate
= true;
703 bool flag_notitle
= false;
704 bool custom_prefix
= false;
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") {
788 extra_args(args
, argidx
, design
);
790 if (format
!= "ps" && format
!= "dot") {
792 for (auto &mod_it
: design
->modules_
) {
793 if (mod_it
.second
->get_bool_attribute("\\blackbox"))
795 if (mod_it
.second
->cells_
.empty() && mod_it
.second
->connections().empty())
797 if (design
->selected_module(mod_it
.first
))
801 log_cmd_error("For formats different than 'ps' or 'dot' only one module must be selected.\n");
804 for (auto filename
: libfiles
) {
806 f
.open(filename
.c_str());
807 yosys_input_files
.insert(filename
);
809 log_error("Can't open lib file `%s'.\n", filename
.c_str());
810 RTLIL::Design
*lib
= new RTLIL::Design
;
811 Frontend::frontend_call(lib
, &f
, filename
, (filename
.size() > 3 && filename
.substr(filename
.size()-3) == ".il") ? "ilang" : "verilog");
816 log_header(design
, "Continuing show pass.\n");
818 std::string dot_file
= stringf("%s.dot", prefix
.c_str());
819 std::string out_file
= stringf("%s.%s", prefix
.c_str(), format
.empty() ? "svg" : format
.c_str());
821 log("Writing dot description to `%s'.\n", dot_file
.c_str());
822 FILE *f
= fopen(dot_file
.c_str(), "w");
824 yosys_output_files
.insert(dot_file
);
826 for (auto lib
: libs
)
828 log_cmd_error("Can't open dot file `%s' for writing.\n", dot_file
.c_str());
830 ShowWorker
worker(f
, design
, libs
, colorSeed
, flag_width
, flag_signed
, flag_stretch
, flag_enum
, flag_abbreviate
, flag_notitle
, color_selections
, label_selections
, colorattr
);
833 for (auto lib
: libs
)
836 if (worker
.page_counter
== 0)
837 log_cmd_error("Nothing there to show.\n");
839 if (format
!= "dot" && !format
.empty()) {
841 // system()/cmd.exe does not understand single quotes on Windows.
842 #define DOT_CMD "dot -T%s \"%s\" > \"%s.new\" && move \"%s.new\" \"%s\""
844 #define DOT_CMD "dot -T%s '%s' > '%s.new' && mv '%s.new' '%s'"
846 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());
848 log("Exec: %s\n", cmd
.c_str());
849 if (run_command(cmd
) != 0)
850 log_cmd_error("Shell command failed!\n");
853 if (!viewer_exe
.empty()) {
855 // system()/cmd.exe does not understand single quotes nor
856 // background tasks on Windows. So we have to pause yosys
857 // until the viewer exits.
858 #define VIEW_CMD "%s \"%s\""
860 #define VIEW_CMD "%s '%s' &"
862 std::string cmd
= stringf(VIEW_CMD
, viewer_exe
.c_str(), out_file
.c_str());
864 log("Exec: %s\n", cmd
.c_str());
865 if (run_command(cmd
) != 0)
866 log_cmd_error("Shell command failed!\n");
868 if (format
.empty()) {
869 std::string cmd
= stringf("{ test -f '%s.pid' && fuser -s '%s.pid'; } || ( echo $$ >&3; exec xdot '%s'; ) 3> '%s.pid' &", dot_file
.c_str(), dot_file
.c_str(), dot_file
.c_str(), dot_file
.c_str());
870 log("Exec: %s\n", cmd
.c_str());
871 if (run_command(cmd
) != 0)
872 log_cmd_error("Shell command failed!\n");
876 #ifdef YOSYS_ENABLE_READLINE
878 while ((input
= readline("Press ENTER to continue (or type 'shell' to open a shell)> ")) != NULL
) {
879 if (input
[strspn(input
, " \t\r\n")] == 0)
881 char *p
= input
+ strspn(input
, " \t\r\n");
882 if (!strcmp(p
, "shell")) {
883 Pass::call(design
, "shell");
888 log_cmd_error("This version of yosys is built without readline support => 'show -pause' is not available.\n");
896 PRIVATE_NAMESPACE_END