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.
27 using namespace REGISTER_INTERN
;
28 #define MAX_REG_COUNT 1000
30 namespace REGISTER_INTERN
32 bool echo_mode
= false;
33 int raw_register_count
= 0;
34 bool raw_register_done
= false;
35 Pass
*raw_register_array
[MAX_REG_COUNT
];
37 std::map
<std::string
, Frontend
*> frontend_register
;
38 std::map
<std::string
, Pass
*> pass_register
;
39 std::map
<std::string
, Backend
*> backend_register
;
42 std::vector
<std::string
> Frontend::next_args
;
44 Pass::Pass(std::string name
, std::string short_help
) : pass_name(name
), short_help(short_help
)
46 assert(!raw_register_done
);
47 assert(raw_register_count
< MAX_REG_COUNT
);
48 raw_register_array
[raw_register_count
++] = this;
51 void Pass::run_register()
53 assert(pass_register
.count(pass_name
) == 0);
54 pass_register
[pass_name
] = this;
57 void Pass::init_register()
59 if (raw_register_done
)
61 while (raw_register_count
> 0)
62 raw_register_array
[--raw_register_count
]->run_register();
63 raw_register_done
= true;
66 void Pass::done_register()
68 frontend_register
.clear();
69 pass_register
.clear();
70 backend_register
.clear();
71 raw_register_done
= false;
81 log("No help message for command `%s'.\n", pass_name
.c_str());
85 void Pass::cmd_log_args(const std::vector
<std::string
> &args
)
89 log("Full command line:");
90 for (size_t i
= 0; i
< args
.size(); i
++)
91 log(" %s", args
[i
].c_str());
95 void Pass::cmd_error(const std::vector
<std::string
> &args
, size_t argidx
, std::string msg
)
97 std::string command_text
;
100 for (size_t i
= 0; i
< args
.size(); i
++) {
102 error_pos
+= args
[i
].size() + 1;
103 command_text
= command_text
+ (command_text
.empty() ? "" : " ") + args
[i
];
106 log("\nSyntax error in command `%s':\n", command_text
.c_str());
109 log_cmd_error("Command syntax error: %s\n> %s\n> %*s^\n",
110 msg
.c_str(), command_text
.c_str(), error_pos
, "");
113 void Pass::extra_args(std::vector
<std::string
> args
, size_t argidx
, RTLIL::Design
*design
, bool select
)
115 for (; argidx
< args
.size(); argidx
++)
117 std::string arg
= args
[argidx
];
119 if (arg
.substr(0, 1) == "-")
120 cmd_error(args
, argidx
, "Unkown option or option in arguments.");
123 cmd_error(args
, argidx
, "Extra argument.");
125 handle_extra_select_args(this, args
, argidx
, args
.size(), design
);
128 // cmd_log_args(args);
131 void Pass::call(RTLIL::Design
*design
, std::string command
)
133 std::vector
<std::string
> args
;
134 char *s
= strdup(command
.c_str()), *sstart
= s
, *saveptr
;
135 s
+= strspn(s
, " \t\r\n");
136 if (*s
== 0 || *s
== '#') {
141 for (s
++; *s
== ' ' || *s
== '\t'; s
++) { }
142 char *p
= s
+ strlen(s
) - 1;
143 while (p
>= s
&& (*p
== '\r' || *p
== '\n'))
145 log_header("Shell command: %s\n", s
);
146 int retCode
= system(s
);
148 log_cmd_error("Shell command returned error code %d.\n", retCode
);
152 for (char *p
= strtok_r(s
, " \t\r\n", &saveptr
); p
; p
= strtok_r(NULL
, " \t\r\n", &saveptr
)) {
154 int strsz
= str
.size();
157 if (strsz
> 0 && str
[strsz
-1] == ';') {
158 int num_semikolon
= 0;
159 while (strsz
> 0 && str
[strsz
-1] == ';')
160 strsz
--, num_semikolon
++;
162 args
.push_back(str
.substr(0, strsz
));
165 if (num_semikolon
== 2)
166 call(design
, "clean");
167 if (num_semikolon
== 3)
168 call(design
, "clean -purge");
176 void Pass::call(RTLIL::Design
*design
, std::vector
<std::string
> args
)
178 if (args
.size() == 0 || args
[0][0] == '#')
182 log("%s", create_prompt(design
, 0));
183 for (size_t i
= 0; i
< args
.size(); i
++)
184 log("%s%s", i
? " " : "", args
[i
].c_str());
188 if (pass_register
.count(args
[0]) == 0)
189 log_cmd_error("No such command: %s (type 'help' for a command overview)\n", args
[0].c_str());
191 size_t orig_sel_stack_pos
= design
->selection_stack
.size();
192 pass_register
[args
[0]]->execute(args
, design
);
193 while (design
->selection_stack
.size() > orig_sel_stack_pos
)
194 design
->selection_stack
.pop_back();
199 void Pass::call_newsel(RTLIL::Design
*design
, std::string command
)
201 std::string backup_selected_active_module
= design
->selected_active_module
;
202 design
->selected_active_module
.clear();
203 design
->selection_stack
.push_back(RTLIL::Selection());
205 Pass::call(design
, command
);
207 design
->selection_stack
.pop_back();
208 design
->selected_active_module
= backup_selected_active_module
;
211 void Pass::call_newsel(RTLIL::Design
*design
, std::vector
<std::string
> args
)
213 std::string backup_selected_active_module
= design
->selected_active_module
;
214 design
->selected_active_module
.clear();
215 design
->selection_stack
.push_back(RTLIL::Selection());
217 Pass::call(design
, args
);
219 design
->selection_stack
.pop_back();
220 design
->selected_active_module
= backup_selected_active_module
;
223 Frontend::Frontend(std::string name
, std::string short_help
) : Pass("read_"+name
, short_help
), frontend_name(name
)
227 void Frontend::run_register()
229 assert(pass_register
.count(pass_name
) == 0);
230 pass_register
[pass_name
] = this;
232 assert(frontend_register
.count(frontend_name
) == 0);
233 frontend_register
[frontend_name
] = this;
236 Frontend::~Frontend()
240 void Frontend::execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
242 assert(next_args
.empty());
246 execute(f
, std::string(), args
, design
);
249 } while (!args
.empty());
252 void Frontend::extra_args(FILE *&f
, std::string
&filename
, std::vector
<std::string
> args
, size_t argidx
)
254 bool called_with_fp
= f
!= NULL
;
257 for (; argidx
< args
.size(); argidx
++)
259 std::string arg
= args
[argidx
];
261 if (arg
.substr(0, 1) == "-")
262 cmd_error(args
, argidx
, "Unkown option or option in arguments.");
264 cmd_error(args
, argidx
, "Extra filename argument in direct file mode.");
267 f
= fopen(filename
.c_str(), "r");
269 log_cmd_error("Can't open input file `%s' for reading: %s\n", filename
.c_str(), strerror(errno
));
271 if (argidx
+1 < args
.size()) {
272 next_args
.insert(next_args
.begin(), args
.begin(), args
.begin()+argidx
);
273 next_args
.insert(next_args
.begin()+argidx
, args
.begin()+argidx
+1, args
.end());
274 args
.erase(args
.begin()+argidx
+1, args
.end());
279 cmd_error(args
, argidx
, "No filename given.");
282 args
.push_back(filename
);
284 // cmd_log_args(args);
287 void Frontend::frontend_call(RTLIL::Design
*design
, FILE *f
, std::string filename
, std::string command
)
289 std::vector
<std::string
> args
;
290 char *s
= strdup(command
.c_str());
291 for (char *p
= strtok(s
, " \t\r\n"); p
; p
= strtok(NULL
, " \t\r\n"))
294 frontend_call(design
, f
, filename
, args
);
297 void Frontend::frontend_call(RTLIL::Design
*design
, FILE *f
, std::string filename
, std::vector
<std::string
> args
)
299 if (args
.size() == 0)
301 if (frontend_register
.count(args
[0]) == 0)
302 log_cmd_error("No such frontend: %s\n", args
[0].c_str());
305 frontend_register
[args
[0]]->execute(f
, filename
, args
, design
);
306 } else if (filename
== "-") {
307 frontend_register
[args
[0]]->execute(stdin
, "<stdin>", args
, design
);
309 if (!filename
.empty())
310 args
.push_back(filename
);
311 frontend_register
[args
[0]]->execute(args
, design
);
317 Backend::Backend(std::string name
, std::string short_help
) : Pass("write_"+name
, short_help
), backend_name(name
)
321 void Backend::run_register()
323 assert(pass_register
.count(pass_name
) == 0);
324 pass_register
[pass_name
] = this;
326 assert(backend_register
.count(backend_name
) == 0);
327 backend_register
[backend_name
] = this;
334 void Backend::execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
337 execute(f
, std::string(), args
, design
);
342 void Backend::extra_args(FILE *&f
, std::string
&filename
, std::vector
<std::string
> args
, size_t argidx
)
344 bool called_with_fp
= f
!= NULL
;
346 for (; argidx
< args
.size(); argidx
++)
348 std::string arg
= args
[argidx
];
350 if (arg
.substr(0, 1) == "-" && arg
!= "-")
351 cmd_error(args
, argidx
, "Unkown option or option in arguments.");
353 cmd_error(args
, argidx
, "Extra filename argument in direct file mode.");
356 filename
= "<stdout>";
362 f
= fopen(filename
.c_str(), "w");
364 log_cmd_error("Can't open output file `%s' for writing: %s\n", filename
.c_str(), strerror(errno
));
368 args
.push_back(filename
);
370 // cmd_log_args(args);
373 filename
= "<stdout>";
378 void Backend::backend_call(RTLIL::Design
*design
, FILE *f
, std::string filename
, std::string command
)
380 std::vector
<std::string
> args
;
381 char *s
= strdup(command
.c_str());
382 for (char *p
= strtok(s
, " \t\r\n"); p
; p
= strtok(NULL
, " \t\r\n"))
385 backend_call(design
, f
, filename
, args
);
388 void Backend::backend_call(RTLIL::Design
*design
, FILE *f
, std::string filename
, std::vector
<std::string
> args
)
390 if (args
.size() == 0)
392 if (backend_register
.count(args
[0]) == 0)
393 log_cmd_error("No such backend: %s\n", args
[0].c_str());
395 size_t orig_sel_stack_pos
= design
->selection_stack
.size();
398 backend_register
[args
[0]]->execute(f
, filename
, args
, design
);
399 } else if (filename
== "-") {
400 backend_register
[args
[0]]->execute(stdout
, "<stdout>", args
, design
);
402 if (!filename
.empty())
403 args
.push_back(filename
);
404 backend_register
[args
[0]]->execute(args
, design
);
407 while (design
->selection_stack
.size() > orig_sel_stack_pos
)
408 design
->selection_stack
.pop_back();
413 struct HelpPass
: public Pass
{
414 HelpPass() : Pass("help", "display help messages") { }
418 log(" help ............. list all commands\n");
419 log(" help <command> ... print help message for given command\n");
420 log(" help -all ........ print complete command reference\n");
423 void escape_tex(std::string
&tex
)
426 while ((pos
= tex
.find('_', pos
)) != std::string::npos
) {
427 tex
.replace(pos
, 1, "\\_");
431 void write_tex(FILE *f
, std::string cmd
, std::string title
, std::string text
)
433 size_t begin
= text
.find_first_not_of("\n"), end
= text
.find_last_not_of("\n");
434 if (begin
!= std::string::npos
&& end
!= std::string::npos
&& begin
< end
)
435 text
= text
.substr(begin
, end
-begin
+1);
436 std::string cmd_unescaped
= cmd
;
439 fprintf(f
, "\\section{%s -- %s}\n", cmd
.c_str(), title
.c_str());
440 fprintf(f
, "\\label{cmd:%s}\n", cmd_unescaped
.c_str());
441 fprintf(f
, "\\begin{lstlisting}[numbers=left,frame=single]\n");
442 fprintf(f
, "%s\n\\end{lstlisting}\n\n", text
.c_str());
444 void escape_html(std::string
&html
)
447 while ((pos
= html
.find_first_of("<>&", pos
)) != std::string::npos
)
450 html
.replace(pos
, 1, "<");
454 html
.replace(pos
, 1, ">");
458 html
.replace(pos
, 1, "&");
463 void write_html(FILE *idxf
, std::string cmd
, std::string title
, std::string text
)
465 FILE *f
= fopen(stringf("cmd_%s.in", cmd
.c_str()).c_str(), "wt");
466 fprintf(idxf
, "<li><a href=\"cmd_%s.html\"> ", cmd
.c_str());
472 fprintf(idxf
, "%s</a> <span>%s</span></a>\n", cmd
.c_str(), title
.c_str());
474 fprintf(f
, "@cmd_header %s@\n", cmd
.c_str());
475 fprintf(f
, "<h1>%s - %s</h1>\n", cmd
.c_str(), title
.c_str());
476 fprintf(f
, "<pre>%s</pre>\n", text
.c_str());
477 fprintf(f
, "@footer@\n");
481 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*)
483 if (args
.size() == 1) {
485 for (auto &it
: REGISTER_INTERN::pass_register
)
486 log(" %-20s %s\n", it
.first
.c_str(), it
.second
->short_help
.c_str());
488 log("Type 'help <command>' for more information on a command.\n");
493 if (args
.size() == 2) {
494 if (args
[1] == "-all") {
495 for (auto &it
: REGISTER_INTERN::pass_register
) {
497 log("%s -- %s\n", it
.first
.c_str(), it
.second
->short_help
.c_str());
498 for (size_t i
= 0; i
< it
.first
.size() + it
.second
->short_help
.size() + 6; i
++)
504 // this option is undocumented as it is for internal use only
505 else if (args
[1] == "-write-tex-command-reference-manual") {
506 FILE *f
= fopen("command-reference-manual.tex", "wt");
507 fprintf(f
, "%% Generated using the yosys 'help -write-tex-command-reference-manual' command.\n\n");
508 for (auto &it
: REGISTER_INTERN::pass_register
) {
511 FILE *memf
= open_memstream(&memptr
, &memsize
);
512 log_files
.push_back(memf
);
514 log_files
.pop_back();
516 write_tex(f
, it
.first
, it
.second
->short_help
, memptr
);
521 // this option is undocumented as it is for internal use only
522 else if (args
[1] == "-write-web-command-reference-manual") {
523 FILE *f
= fopen("templates/cmd_index.in", "wt");
524 for (auto &it
: REGISTER_INTERN::pass_register
) {
527 FILE *memf
= open_memstream(&memptr
, &memsize
);
528 log_files
.push_back(memf
);
530 log_files
.pop_back();
532 write_html(f
, it
.first
, it
.second
->short_help
, memptr
);
537 else if (REGISTER_INTERN::pass_register
.count(args
[1]) == 0)
538 log("No such command: %s\n", args
[1].c_str());
540 REGISTER_INTERN::pass_register
.at(args
[1])->help();
548 struct EchoPass
: public Pass
{
549 EchoPass() : Pass("echo", "turning echoing back of commands on and off") { }
555 log("Print all commands to log before executing them.\n");
560 log("Do not print all commands to log before executing them. (default)\n");
563 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*)
566 cmd_error(args
, 2, "Unexpected argument.");
568 if (args
.size() == 2) {
571 else if (args
[1] == "off")
574 cmd_error(args
, 1, "Unexpected argument.");
577 log("echo %s\n", echo_mode
? "on" : "off");