29 #ifdef YOSYS_ENABLE_READLINE
30 # include <readline/readline.h>
38 #undef CLUSTER_CELLS_AND_PORTBOXES
77 return "color=\"black\"";
83 if (presetColor.empty())
91 for (
auto &c : sig.
chunks()) {
94 if (s.second.selected_members.count(
module->
name) > 0 && s.second.selected_members.at(
module->
name).count(c.wire->name) > 0)
95 return stringf(
"color=\"%s\"", s.first.c_str());
120 return "style=\"setlinewidth(3)\", label=\"\"";
121 return stringf(
"style=\"setlinewidth(3)\", label=\"<%d>\"", bits);
127 if (s.second.selected_member(
module->
name, member_name)) {
137 if (s.second.selected_member(
module->
name, member_name))
139 return escape(member_name,
true);
142 const char *
escape(std::string
id,
bool is_name =
false)
147 if (
id[0] ==
'$' && is_name) {
151 log(
"Generated short name for internal identifier: _%d_ -> %s\n",
autonames[
id],
id.c_str());
155 const char *p =
id.c_str();
156 const char *q = strrchr(p,
'$');
166 if (ch ==
'\\' || ch ==
'"')
200 return std::string();
209 std::string label_string;
210 int pos = sig.
size()-1;
212 for (
int rep, i =
int(sig.
chunks().size())-1; i >= 0; i -= rep) {
216 for (rep = 1; i-rep >= 0 && c == sig.
chunks().at(i-rep); rep++) {}
217 std::string repinfo = rep > 1 ?
stringf(
"%dx ", rep) :
"";
229 pos -= rep * c.
width;
231 if (label_string[label_string.size()-1] ==
'|')
232 label_string = label_string.substr(0, label_string.size()-1);
233 code +=
stringf(
"x%d [ shape=record, style=rounded, label=\"%s\" ];\n", idx, label_string.c_str());
237 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());
239 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());
263 if (!it.is_fully_const())
267 void collect_proc_signals(std::vector<RTLIL::SigSig> &obj, std::set<RTLIL::SigSpec> &input_signals, std::set<RTLIL::SigSpec> &output_signals)
269 for (
auto &it : obj) {
270 output_signals.insert(it.first);
271 if (!it.second.is_fully_const())
272 input_signals.insert(it.second);
286 input_signals.insert(obj->
signal);
287 for (
auto it : obj->
cases)
293 input_signals.insert(obj->
signal);
300 for (
auto it : obj->
syncs)
314 fprintf(
f,
"rankdir=\"LR\";\n");
315 fprintf(
f,
"remincross=true;\n");
317 std::set<std::string> all_sources, all_sinks;
319 std::map<std::string, std::string> wires_on_demand;
323 const char *shape =
"diamond";
324 if (it.second->port_input || it.second->port_output)
326 if (it.first[0] ==
'\\') {
327 fprintf(
f,
"n%d [ shape=%s, label=\"%s\", %s, fontcolor=\"black\" ];\n",
330 if (it.second->port_input)
332 else if (it.second->port_output)
335 wires_on_demand[
stringf(
"n%d",
id2num(it.first))] = it.first.str();
341 fprintf(
f,
"{ rank=\"source\";");
342 for (
auto n : all_sources)
343 fprintf(
f,
" %s;",
n.c_str());
346 fprintf(
f,
"{ rank=\"sink\";");
347 for (
auto n : all_sinks)
348 fprintf(
f,
" %s;",
n.c_str());
357 std::vector<RTLIL::IdString> in_ports, out_ports;
359 for (
auto &conn : it.second->connections()) {
361 in_ports.push_back(conn.first);
363 out_ports.push_back(conn.first);
369 std::string label_string =
"{{";
371 for (
auto &p : in_ports)
374 it.second->getParam(p.str() +
"_SIGNED").as_bool() ?
"*" :
"");
375 if (label_string[label_string.size()-1] ==
'|')
376 label_string = label_string.substr(0, label_string.size()-1);
380 for (
auto &p : out_ports)
382 if (label_string[label_string.size()-1] ==
'|')
383 label_string = label_string.substr(0, label_string.size()-1);
385 label_string +=
"}}";
388 for (
auto &conn : it.second->connections()) {
393 #ifdef CLUSTER_CELLS_AND_PORTBOXES
395 fprintf(
f,
"subgraph cluster_c%d {\nc%d [ shape=record, label=\"%s\"%s ];\n%s}\n",
399 fprintf(
f,
"c%d [ shape=record, label=\"%s\"%s ];\n%s",
400 id2num(it.first), label_string.c_str(),
findColor(it.first.str()), code.c_str());
410 std::set<RTLIL::SigSpec> input_signals, output_signals;
417 for (
auto &sig : input_signals) {
418 std::string code, node;
420 fprintf(
f,
"%s", code.c_str());
426 for (
auto &sig : output_signals) {
427 std::string code, node;
429 fprintf(
f,
"%s", code.c_str());
436 if (proc->attributes.count(
"\\src") > 0)
437 proc_src = proc->attributes.at(
"\\src").decode_string();
438 fprintf(
f,
"p%d [shape=box, style=rounded, label=\"PROC %s\\n%s\"];\n", pidx,
findLabel(proc->
name.
str()), proc_src.c_str());
443 bool found_lhs_wire =
false;
444 for (
auto &c : conn.first.chunks()) {
446 found_lhs_wire =
true;
448 bool found_rhs_wire =
false;
449 for (
auto &c : conn.second.chunks()) {
451 found_rhs_wire =
true;
453 if (!found_lhs_wire || !found_rhs_wire)
456 std::string code, left_node, right_node;
457 code +=
gen_portbox(
"", conn.second,
false, &left_node);
458 code +=
gen_portbox(
"", conn.first,
true, &right_node);
459 fprintf(
f,
"%s", code.c_str());
461 if (left_node[0] ==
'x' && right_node[0] ==
'x') {
463 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());
469 if (left_node[0] ==
'x') {
471 }
else if (right_node[0] ==
'x') {
476 fprintf(
f,
"x%d [shape=box, style=rounded, label=\"BUF\"];\n",
single_idx_count++);
484 if (wires_on_demand.count(it.first) > 0) {
485 if (it.second.in.size() == 1 && it.second.out.size() > 1 && it.second.in.begin()->substr(0, 1) ==
"p")
486 it.second.out.erase(*it.second.in.begin());
487 if (it.second.in.size() == 1 && it.second.out.size() == 1) {
488 std::string from = *it.second.in.begin(), to = *it.second.out.begin();
489 if (from != to || from.substr(0, 1) !=
"p")
490 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());
493 if (it.second.in.size() == 0 || it.second.out.size() == 0)
494 fprintf(
f,
"%s [ shape=diamond, label=\"%s\" ];\n", it.first.c_str(),
findLabel(wires_on_demand[it.first]));
496 fprintf(
f,
"%s [ shape=point ];\n", it.first.c_str());
498 for (
auto &it2 : it.second.in)
499 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());
500 for (
auto &it2 : it.second.out)
501 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());
509 const std::vector<std::pair<std::string, RTLIL::Selection>> &
color_selections,
510 const std::vector<std::pair<std::string, RTLIL::Selection>> &
label_selections) :
511 f(f), design(design),
currentColor(colorSeed), genWidthLabels(genWidthLabels),
512 genSignedLabels(genSignedLabels), stretchIO(stretchIO), enumerateIds(enumerateIds), abbreviateIds(abbreviateIds),
521 for (
auto lib : libs)
526 for (
auto &mod_it : design->
modules_)
532 if (
module->get_bool_attribute(
"\\blackbox")) {
554 log(
" show [options] [selection]\n");
556 log(
"Create a graphviz DOT file for the selected part of the design and compile it\n");
557 log(
"to a graphics file (usually SVG or PostScript).\n");
559 log(
" -viewer <viewer>\n");
560 log(
" Run the specified command with the graphics file as parameter.\n");
562 log(
" -format <format>\n");
563 log(
" Generate a graphics file in the specified format.\n");
564 log(
" Usually <format> is 'svg' or 'ps'.\n");
566 log(
" -lib <verilog_or_ilang_file>\n");
567 log(
" Use the specified library file for determining whether cell ports are\n");
568 log(
" inputs or outputs. This option can be used multiple times to specify\n");
569 log(
" more than one library.\n");
571 log(
" -prefix <prefix>\n");
572 log(
" generate <prefix>.* instead of ~/.yosys_show.*\n");
574 log(
" -color <color> <object>\n");
575 log(
" assign the specified color to the specified object. The object can be\n");
576 log(
" a single selection wildcard expressions or a saved set of objects in\n");
577 log(
" the @<name> syntax (see \"help select\" for details).\n");
579 log(
" -label <text> <object>\n");
580 log(
" assign the specified label text to the specified object. The object can\n");
581 log(
" be a single selection wildcard expressions or a saved set of objects in\n");
582 log(
" the @<name> syntax (see \"help select\" for details).\n");
584 log(
" -colors <seed>\n");
585 log(
" Randomly assign colors to the wires. The integer argument is the seed\n");
586 log(
" for the random number generator. Change the seed value if the colored\n");
587 log(
" graph still is ambigous. A seed of zero deactivates the coloring.\n");
590 log(
" annotate busses with a label indicating the width of the bus.\n");
593 log(
" mark ports (A, B) that are declarted as signed (using the [AB]_SIGNED\n");
594 log(
" cell parameter) with an asterisk next to the port name.\n");
597 log(
" stretch the graph so all inputs are on the left side and all outputs\n");
598 log(
" (including inout ports) are on the right side.\n");
601 log(
" wait for the use to press enter to before returning\n");
604 log(
" enumerate objects with internal ($-prefixed) names\n");
607 log(
" do not abbeviate objects with internal ($-prefixed) names\n");
610 log(
" do not add the module name as graph title to the dot file\n");
612 log(
"When no <format> is specified, 'dot' is used. When no <format> and <viewer> is\n");
613 log(
"specified, 'xdot' is used to display the schematic.\n");
615 log(
"The generated output files are '~/.yosys_show.dot' and '~/.yosys_show.<format>',\n");
616 log(
"unless another prefix is specified using -prefix <prefix>.\n");
621 log_header(
"Generating Graphviz representation of design.\n");
624 std::vector<std::pair<std::string, RTLIL::Selection>> color_selections;
625 std::vector<std::pair<std::string, RTLIL::Selection>> label_selections;
628 std::string viewer_exe;
629 std::string prefix =
stringf(
"%s/.yosys_show", getenv(
"HOME") ? getenv(
"HOME") :
".");
630 std::vector<std::string> libfiles;
631 std::vector<RTLIL::Design*> libs;
632 uint32_t colorSeed = 0;
633 bool flag_width =
false;
634 bool flag_signed =
false;
635 bool flag_stretch =
false;
636 bool flag_pause =
false;
637 bool flag_enum =
false;
638 bool flag_abbeviate =
true;
639 bool flag_notitle =
false;
642 for (argidx = 1; argidx < args.size(); argidx++)
644 std::string arg = args[argidx];
645 if (arg ==
"-viewer" && argidx+1 < args.size()) {
646 viewer_exe = args[++argidx];
649 if (arg ==
"-lib" && argidx+1 < args.size()) {
650 libfiles.push_back(args[++argidx]);
653 if (arg ==
"-prefix" && argidx+1 < args.size()) {
654 prefix = args[++argidx];
657 if (arg ==
"-color" && argidx+2 < args.size()) {
658 std::pair<std::string, RTLIL::Selection> data;
659 data.first = args[++argidx], argidx++;
663 color_selections.push_back(data);
666 if (arg ==
"-label" && argidx+2 < args.size()) {
667 std::pair<std::string, RTLIL::Selection> data;
668 data.first = args[++argidx], argidx++;
672 label_selections.push_back(data);
675 if (arg ==
"-colors" && argidx+1 < args.size()) {
676 colorSeed = atoi(args[++argidx].c_str());
677 for (
int i = 0; i < 100; i++)
681 if (arg ==
"-format" && argidx+1 < args.size()) {
682 format = args[++argidx];
685 if (arg ==
"-width") {
689 if (arg ==
"-signed") {
693 if (arg ==
"-stretch") {
697 if (arg ==
"-pause") {
701 if (arg ==
"-enum") {
703 flag_abbeviate =
false;
706 if (arg ==
"-long") {
708 flag_abbeviate =
false;
711 if (arg ==
"-notitle") {
719 if (format !=
"ps") {
721 for (
auto &mod_it : design->
modules_) {
722 if (mod_it.second->get_bool_attribute(
"\\blackbox"))
724 if (mod_it.second->cells_.empty() && mod_it.second->connections().empty())
730 log_cmd_error(
"For formats different than 'ps' only one module must be selected.\n");
733 for (
auto filename : libfiles) {
735 f.open(filename.c_str());
737 log_error(
"Can't open lib file `%s'.\n", filename.c_str());
739 Frontend::frontend_call(lib, &f, filename, (filename.size() > 3 && filename.substr(filename.size()-3) ==
".il") ?
"ilang" :
"verilog");
746 std::string dot_file =
stringf(
"%s.dot", prefix.c_str());
747 std::string out_file =
stringf(
"%s.%s", prefix.c_str(), format.empty() ?
"svg" : format.c_str());
749 log(
"Writing dot description to `%s'.\n", dot_file.c_str());
750 FILE *f = fopen(dot_file.c_str(),
"w");
752 for (
auto lib : libs)
754 log_cmd_error(
"Can't open dot file `%s' for writing.\n", dot_file.c_str());
756 ShowWorker worker(f, design, libs, colorSeed, flag_width, flag_signed, flag_stretch, flag_enum, flag_abbeviate, flag_notitle, color_selections, label_selections);
759 for (
auto lib : libs)
765 if (format !=
"dot" && !format.empty()) {
766 std::string cmd =
stringf(
"dot -T%s -o '%s' '%s'", format.c_str(), out_file.c_str(), dot_file.c_str());
767 log(
"Exec: %s\n", cmd.c_str());
772 if (!viewer_exe.empty()) {
773 std::string cmd =
stringf(
"%s '%s' &", viewer_exe.c_str(), out_file.c_str());
774 log(
"Exec: %s\n", cmd.c_str());
778 if (format.empty()) {
779 std::string cmd =
stringf(
"fuser -s '%s' || xdot '%s' < '%s' &", dot_file.c_str(), dot_file.c_str(), dot_file.c_str());
780 log(
"Exec: %s\n", cmd.c_str());
786 #ifdef YOSYS_ENABLE_READLINE
788 while ((input = readline(
"Press ENTER to continue (or type 'shell' to open a shell)> ")) !=
NULL) {
789 if (input[strspn(input,
" \t\r\n")] == 0)
791 char *p = input + strspn(input,
" \t\r\n");
792 if (!strcmp(p,
"shell")) {
798 log_cmd_error(
"This version of yosys is built without readline support => 'show -pause' is not available.\n");
void collect_proc_signals(RTLIL::SyncRule *obj, std::set< RTLIL::SigSpec > &input_signals, std::set< RTLIL::SigSpec > &output_signals)
std::string nextColor(const RTLIL::SigSpec &sig)
std::vector< RTLIL::Selection > selection_stack
std::string stringf(const char *fmt,...)
void sort(T *array, int size, LessThan lt)
void handle_extra_select_args(Pass *pass, std::vector< std::string > args, size_t argidx, size_t args_size, RTLIL::Design *design)
bool selected_module(RTLIL::IdString mod_name) const
void setup_internals_mem()
void log_header(const char *format,...)
const std::vector< RTLIL::SigSig > & connections() const
std::string gen_signode_simple(RTLIL::SigSpec sig, bool range_check=true)
std::map< RTLIL::IdString, int > dot_id2num_store
std::map< RTLIL::IdString, RTLIL::Wire * > wires_
static std::string unescape_id(std::string str)
const char * findColor(std::string member_name)
RTLIL_ATTRIBUTE_MEMBERS std::vector< RTLIL::CaseRule * > cases
const char * log_signal(const RTLIL::SigSpec &sig, bool autoint)
static void frontend_call(RTLIL::Design *design, std::istream *f, std::string filename, std::string command)
static std::string idx(std::string str)
std::map< RTLIL::IdString, int > autonames
std::string nextColor(const RTLIL::SigSig &conn)
std::map< std::string, net_conn > net_conn_map
void log_error(const char *format,...)
const char * findLabel(std::string member_name)
const std::vector< std::pair< std::string, RTLIL::Selection > > & label_selections
std::vector< RTLIL::SigSpec > compare
bool selected_member(RTLIL::IdString mod_name, RTLIL::IdString memb_name) const
const std::vector< std::pair< std::string, RTLIL::Selection > > & color_selections
int run_command(const std::string &command, std::function< void(const std::string &)> process_line)
std::string nextColor(std::string presetColor)
std::set< std::string > in
void collect_proc_signals(std::vector< RTLIL::SigSig > &obj, std::set< RTLIL::SigSpec > &input_signals, std::set< RTLIL::SigSpec > &output_signals)
#define PRIVATE_NAMESPACE_BEGIN
bool cell_output(RTLIL::IdString type, RTLIL::IdString port)
std::string nextColor(RTLIL::SigSpec sig, std::string defaultColor)
int GetSize(RTLIL::Wire *wire)
#define log_assert(_assert_expr_)
std::string nextColor(const RTLIL::SigSig &conn, std::string defaultColor)
RTLIL::SigChunk as_chunk() const
bool selected_whole_module(RTLIL::IdString mod_name) const
void collect_proc_signals(RTLIL::Process *obj, std::set< RTLIL::SigSpec > &input_signals, std::set< RTLIL::SigSpec > &output_signals)
const char * escape(std::string id, bool is_name=false)
std::set< std::string > out
#define PRIVATE_NAMESPACE_END
std::vector< RTLIL::SigSig > actions
static const char * id2cstr(const RTLIL::IdString &str)
void log_cmd_error(const char *format,...)
std::vector< std::string > dot_escape_store
static uint32_t xorshift32(uint32_t x)
std::map< RTLIL::IdString, RTLIL::Process * > processes
#define USING_YOSYS_NAMESPACE
std::map< RTLIL::IdString, RTLIL::Module * > modules_
std::map< RTLIL::IdString, RTLIL::Cell * > cells_
void log(const char *format,...)
std::vector< RTLIL::SyncRule * > syncs
void collect_proc_signals(std::vector< RTLIL::SigSpec > &obj, std::set< RTLIL::SigSpec > &signals)
void collect_proc_signals(RTLIL::SwitchRule *obj, std::set< RTLIL::SigSpec > &input_signals, std::set< RTLIL::SigSpec > &output_signals)
std::string widthLabel(int bits)
std::string gen_portbox(std::string port, RTLIL::SigSpec sig, bool driver, std::string *node=NULL)
void setup_design(RTLIL::Design *design)
void setup_stdcells_mem()
std::vector< RTLIL::SigSig > actions
int id2num(RTLIL::IdString id)
std::string id(RTLIL::IdString internal_id, bool may_rename=true)
void extra_args(std::vector< std::string > args, size_t argidx, RTLIL::Design *design, bool select=true)
std::vector< RTLIL::SwitchRule * > switches
static void call(RTLIL::Design *design, std::string command)
std::pair< SigSpec, SigSpec > SigSig
virtual void execute(std::vector< std::string > args, RTLIL::Design *design)
void collect_proc_signals(RTLIL::CaseRule *obj, std::set< RTLIL::SigSpec > &input_signals, std::set< RTLIL::SigSpec > &output_signals)
const std::vector< RTLIL::SigChunk > & chunks() const
ShowWorker(FILE *f, RTLIL::Design *design, std::vector< RTLIL::Design * > &libs, uint32_t colorSeed, bool genWidthLabels, bool genSignedLabels, bool stretchIO, bool enumerateIds, bool abbreviateIds, bool notitle, const std::vector< std::pair< std::string, RTLIL::Selection >> &color_selections, const std::vector< std::pair< std::string, RTLIL::Selection >> &label_selections)
RTLIL_ATTRIBUTE_MEMBERS RTLIL::CaseRule root_case