Merge pull request #2357 from whitequark/cxxflags-MP
[yosys.git] / backends / rtlil / rtlil_backend.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 * ---
19 *
20 * A very simple and straightforward backend for the RTLIL text
21 * representation.
22 *
23 */
24
25 #include "rtlil_backend.h"
26 #include "kernel/yosys.h"
27 #include <errno.h>
28
29 USING_YOSYS_NAMESPACE
30 using namespace RTLIL_BACKEND;
31 YOSYS_NAMESPACE_BEGIN
32
33 void RTLIL_BACKEND::dump_const(std::ostream &f, const RTLIL::Const &data, int width, int offset, bool autoint)
34 {
35 if (width < 0)
36 width = data.bits.size() - offset;
37 if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
38 if (width == 32 && autoint) {
39 int32_t val = 0;
40 for (int i = 0; i < width; i++) {
41 log_assert(offset+i < (int)data.bits.size());
42 switch (data.bits[offset+i]) {
43 case State::S0: break;
44 case State::S1: val |= 1 << i; break;
45 default: val = -1; break;
46 }
47 }
48 if (val >= 0) {
49 f << stringf("%d", val);
50 return;
51 }
52 }
53 f << stringf("%d'", width);
54 for (int i = offset+width-1; i >= offset; i--) {
55 log_assert(i < (int)data.bits.size());
56 switch (data.bits[i]) {
57 case State::S0: f << stringf("0"); break;
58 case State::S1: f << stringf("1"); break;
59 case RTLIL::Sx: f << stringf("x"); break;
60 case RTLIL::Sz: f << stringf("z"); break;
61 case RTLIL::Sa: f << stringf("-"); break;
62 case RTLIL::Sm: f << stringf("m"); break;
63 }
64 }
65 } else {
66 f << stringf("\"");
67 std::string str = data.decode_string();
68 for (size_t i = 0; i < str.size(); i++) {
69 if (str[i] == '\n')
70 f << stringf("\\n");
71 else if (str[i] == '\t')
72 f << stringf("\\t");
73 else if (str[i] < 32)
74 f << stringf("\\%03o", str[i]);
75 else if (str[i] == '"')
76 f << stringf("\\\"");
77 else if (str[i] == '\\')
78 f << stringf("\\\\");
79 else
80 f << str[i];
81 }
82 f << stringf("\"");
83 }
84 }
85
86 void RTLIL_BACKEND::dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool autoint)
87 {
88 if (chunk.wire == NULL) {
89 dump_const(f, chunk.data, chunk.width, chunk.offset, autoint);
90 } else {
91 if (chunk.width == chunk.wire->width && chunk.offset == 0)
92 f << stringf("%s", chunk.wire->name.c_str());
93 else if (chunk.width == 1)
94 f << stringf("%s [%d]", chunk.wire->name.c_str(), chunk.offset);
95 else
96 f << stringf("%s [%d:%d]", chunk.wire->name.c_str(), chunk.offset+chunk.width-1, chunk.offset);
97 }
98 }
99
100 void RTLIL_BACKEND::dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig, bool autoint)
101 {
102 if (sig.is_chunk()) {
103 dump_sigchunk(f, sig.as_chunk(), autoint);
104 } else {
105 f << stringf("{ ");
106 for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
107 dump_sigchunk(f, *it, false);
108 f << stringf(" ");
109 }
110 f << stringf("}");
111 }
112 }
113
114 void RTLIL_BACKEND::dump_wire(std::ostream &f, std::string indent, const RTLIL::Wire *wire)
115 {
116 for (auto &it : wire->attributes) {
117 f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
118 dump_const(f, it.second);
119 f << stringf("\n");
120 }
121 f << stringf("%s" "wire ", indent.c_str());
122 if (wire->width != 1)
123 f << stringf("width %d ", wire->width);
124 if (wire->upto)
125 f << stringf("upto ");
126 if (wire->start_offset != 0)
127 f << stringf("offset %d ", wire->start_offset);
128 if (wire->port_input && !wire->port_output)
129 f << stringf("input %d ", wire->port_id);
130 if (!wire->port_input && wire->port_output)
131 f << stringf("output %d ", wire->port_id);
132 if (wire->port_input && wire->port_output)
133 f << stringf("inout %d ", wire->port_id);
134 if (wire->is_signed)
135 f << stringf("signed ");
136 f << stringf("%s\n", wire->name.c_str());
137 }
138
139 void RTLIL_BACKEND::dump_memory(std::ostream &f, std::string indent, const RTLIL::Memory *memory)
140 {
141 for (auto &it : memory->attributes) {
142 f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
143 dump_const(f, it.second);
144 f << stringf("\n");
145 }
146 f << stringf("%s" "memory ", indent.c_str());
147 if (memory->width != 1)
148 f << stringf("width %d ", memory->width);
149 if (memory->size != 0)
150 f << stringf("size %d ", memory->size);
151 if (memory->start_offset != 0)
152 f << stringf("offset %d ", memory->start_offset);
153 f << stringf("%s\n", memory->name.c_str());
154 }
155
156 void RTLIL_BACKEND::dump_cell(std::ostream &f, std::string indent, const RTLIL::Cell *cell)
157 {
158 for (auto &it : cell->attributes) {
159 f << stringf("%s" "attribute %s ", indent.c_str(), it.first.c_str());
160 dump_const(f, it.second);
161 f << stringf("\n");
162 }
163 f << stringf("%s" "cell %s %s\n", indent.c_str(), cell->type.c_str(), cell->name.c_str());
164 for (auto &it : cell->parameters) {
165 f << stringf("%s parameter%s%s %s ", indent.c_str(),
166 (it.second.flags & RTLIL::CONST_FLAG_SIGNED) != 0 ? " signed" : "",
167 (it.second.flags & RTLIL::CONST_FLAG_REAL) != 0 ? " real" : "",
168 it.first.c_str());
169 dump_const(f, it.second);
170 f << stringf("\n");
171 }
172 for (auto &it : cell->connections()) {
173 f << stringf("%s connect %s ", indent.c_str(), it.first.c_str());
174 dump_sigspec(f, it.second);
175 f << stringf("\n");
176 }
177 f << stringf("%s" "end\n", indent.c_str());
178 }
179
180 void RTLIL_BACKEND::dump_proc_case_body(std::ostream &f, std::string indent, const RTLIL::CaseRule *cs)
181 {
182 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it)
183 {
184 f << stringf("%s" "assign ", indent.c_str());
185 dump_sigspec(f, it->first);
186 f << stringf(" ");
187 dump_sigspec(f, it->second);
188 f << stringf("\n");
189 }
190
191 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
192 dump_proc_switch(f, indent, *it);
193 }
194
195 void RTLIL_BACKEND::dump_proc_switch(std::ostream &f, std::string indent, const RTLIL::SwitchRule *sw)
196 {
197 for (auto it = sw->attributes.begin(); it != sw->attributes.end(); ++it) {
198 f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
199 dump_const(f, it->second);
200 f << stringf("\n");
201 }
202
203 f << stringf("%s" "switch ", indent.c_str());
204 dump_sigspec(f, sw->signal);
205 f << stringf("\n");
206
207 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it)
208 {
209 for (auto ait = (*it)->attributes.begin(); ait != (*it)->attributes.end(); ++ait) {
210 f << stringf("%s attribute %s ", indent.c_str(), ait->first.c_str());
211 dump_const(f, ait->second);
212 f << stringf("\n");
213 }
214 f << stringf("%s case ", indent.c_str());
215 for (size_t i = 0; i < (*it)->compare.size(); i++) {
216 if (i > 0)
217 f << stringf(" , ");
218 dump_sigspec(f, (*it)->compare[i]);
219 }
220 f << stringf("\n");
221
222 dump_proc_case_body(f, indent + " ", *it);
223 }
224
225 f << stringf("%s" "end\n", indent.c_str());
226 }
227
228 void RTLIL_BACKEND::dump_proc_sync(std::ostream &f, std::string indent, const RTLIL::SyncRule *sy)
229 {
230 f << stringf("%s" "sync ", indent.c_str());
231 switch (sy->type) {
232 case RTLIL::ST0: f << stringf("low ");
233 if (0) case RTLIL::ST1: f << stringf("high ");
234 if (0) case RTLIL::STp: f << stringf("posedge ");
235 if (0) case RTLIL::STn: f << stringf("negedge ");
236 if (0) case RTLIL::STe: f << stringf("edge ");
237 dump_sigspec(f, sy->signal);
238 f << stringf("\n");
239 break;
240 case RTLIL::STa: f << stringf("always\n"); break;
241 case RTLIL::STg: f << stringf("global\n"); break;
242 case RTLIL::STi: f << stringf("init\n"); break;
243 }
244
245 for (auto it = sy->actions.begin(); it != sy->actions.end(); ++it) {
246 f << stringf("%s update ", indent.c_str());
247 dump_sigspec(f, it->first);
248 f << stringf(" ");
249 dump_sigspec(f, it->second);
250 f << stringf("\n");
251 }
252 }
253
254 void RTLIL_BACKEND::dump_proc(std::ostream &f, std::string indent, const RTLIL::Process *proc)
255 {
256 for (auto it = proc->attributes.begin(); it != proc->attributes.end(); ++it) {
257 f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
258 dump_const(f, it->second);
259 f << stringf("\n");
260 }
261 f << stringf("%s" "process %s\n", indent.c_str(), proc->name.c_str());
262 dump_proc_case_body(f, indent + " ", &proc->root_case);
263 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
264 dump_proc_sync(f, indent + " ", *it);
265 f << stringf("%s" "end\n", indent.c_str());
266 }
267
268 void RTLIL_BACKEND::dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
269 {
270 f << stringf("%s" "connect ", indent.c_str());
271 dump_sigspec(f, left);
272 f << stringf(" ");
273 dump_sigspec(f, right);
274 f << stringf("\n");
275 }
276
277 void RTLIL_BACKEND::dump_module(std::ostream &f, std::string indent, RTLIL::Module *module, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
278 {
279 bool print_header = flag_m || design->selected_whole_module(module->name);
280 bool print_body = !flag_n || !design->selected_whole_module(module->name);
281
282 if (print_header)
283 {
284 for (auto it = module->attributes.begin(); it != module->attributes.end(); ++it) {
285 f << stringf("%s" "attribute %s ", indent.c_str(), it->first.c_str());
286 dump_const(f, it->second);
287 f << stringf("\n");
288 }
289
290 f << stringf("%s" "module %s\n", indent.c_str(), module->name.c_str());
291
292 if (!module->avail_parameters.empty()) {
293 if (only_selected)
294 f << stringf("\n");
295 for (const auto &p : module->avail_parameters) {
296 const auto &it = module->parameter_default_values.find(p);
297 if (it == module->parameter_default_values.end()) {
298 f << stringf("%s" " parameter %s\n", indent.c_str(), p.c_str());
299 } else {
300 f << stringf("%s" " parameter %s ", indent.c_str(), p.c_str());
301 dump_const(f, it->second);
302 f << stringf("\n");
303 }
304 }
305 }
306 }
307
308 if (print_body)
309 {
310 for (auto it : module->wires())
311 if (!only_selected || design->selected(module, it)) {
312 if (only_selected)
313 f << stringf("\n");
314 dump_wire(f, indent + " ", it);
315 }
316
317 for (auto it : module->memories)
318 if (!only_selected || design->selected(module, it.second)) {
319 if (only_selected)
320 f << stringf("\n");
321 dump_memory(f, indent + " ", it.second);
322 }
323
324 for (auto it : module->cells())
325 if (!only_selected || design->selected(module, it)) {
326 if (only_selected)
327 f << stringf("\n");
328 dump_cell(f, indent + " ", it);
329 }
330
331 for (auto it : module->processes)
332 if (!only_selected || design->selected(module, it.second)) {
333 if (only_selected)
334 f << stringf("\n");
335 dump_proc(f, indent + " ", it.second);
336 }
337
338 bool first_conn_line = true;
339 for (auto it = module->connections().begin(); it != module->connections().end(); ++it) {
340 bool show_conn = !only_selected;
341 if (only_selected) {
342 RTLIL::SigSpec sigs = it->first;
343 sigs.append(it->second);
344 for (auto &c : sigs.chunks()) {
345 if (c.wire == NULL || !design->selected(module, c.wire))
346 continue;
347 show_conn = true;
348 }
349 }
350 if (show_conn) {
351 if (only_selected && first_conn_line)
352 f << stringf("\n");
353 dump_conn(f, indent + " ", it->first, it->second);
354 first_conn_line = false;
355 }
356 }
357 }
358
359 if (print_header)
360 f << stringf("%s" "end\n", indent.c_str());
361 }
362
363 void RTLIL_BACKEND::dump_design(std::ostream &f, RTLIL::Design *design, bool only_selected, bool flag_m, bool flag_n)
364 {
365 int init_autoidx = autoidx;
366
367 if (!flag_m) {
368 int count_selected_mods = 0;
369 for (auto module : design->modules()) {
370 if (design->selected_whole_module(module->name))
371 flag_m = true;
372 if (design->selected(module))
373 count_selected_mods++;
374 }
375 if (count_selected_mods > 1)
376 flag_m = true;
377 }
378
379 if (!only_selected || flag_m) {
380 if (only_selected)
381 f << stringf("\n");
382 f << stringf("autoidx %d\n", autoidx);
383 }
384
385 for (auto module : design->modules()) {
386 if (!only_selected || design->selected(module)) {
387 if (only_selected)
388 f << stringf("\n");
389 dump_module(f, "", module, design, only_selected, flag_m, flag_n);
390 }
391 }
392
393 log_assert(init_autoidx == autoidx);
394 }
395
396 YOSYS_NAMESPACE_END
397 PRIVATE_NAMESPACE_BEGIN
398
399 struct RTLILBackend : public Backend {
400 RTLILBackend() : Backend("rtlil", "write design to RTLIL file") { }
401 void help() override
402 {
403 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
404 log("\n");
405 log(" write_rtlil [filename]\n");
406 log("\n");
407 log("Write the current design to an RTLIL file. (RTLIL is a text representation\n");
408 log("of a design in yosys's internal format.)\n");
409 log("\n");
410 log(" -selected\n");
411 log(" only write selected parts of the design.\n");
412 log("\n");
413 }
414 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
415 {
416 bool selected = false;
417
418 log_header(design, "Executing RTLIL backend.\n");
419
420 size_t argidx;
421 for (argidx = 1; argidx < args.size(); argidx++) {
422 std::string arg = args[argidx];
423 if (arg == "-selected") {
424 selected = true;
425 continue;
426 }
427 break;
428 }
429 extra_args(f, filename, args, argidx);
430
431 design->sort();
432
433 log("Output filename: %s\n", filename.c_str());
434 *f << stringf("# Generated by %s\n", yosys_version_str);
435 RTLIL_BACKEND::dump_design(*f, design, selected, true, false);
436 }
437 } RTLILBackend;
438
439 struct IlangBackend : public Backend {
440 IlangBackend() : Backend("ilang", "(deprecated) alias of write_rtlil") { }
441 void help() override
442 {
443 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
444 log("\n");
445 log("See `help write_rtlil`.\n");
446 log("\n");
447 }
448 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
449 {
450 RTLILBackend.execute(f, filename, args, design);
451 }
452 } IlangBackend;
453
454 struct DumpPass : public Pass {
455 DumpPass() : Pass("dump", "print parts of the design in RTLIL format") { }
456 void help() override
457 {
458 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
459 log("\n");
460 log(" dump [options] [selection]\n");
461 log("\n");
462 log("Write the selected parts of the design to the console or specified file in\n");
463 log("RTLIL format.\n");
464 log("\n");
465 log(" -m\n");
466 log(" also dump the module headers, even if only parts of a single\n");
467 log(" module is selected\n");
468 log("\n");
469 log(" -n\n");
470 log(" only dump the module headers if the entire module is selected\n");
471 log("\n");
472 log(" -o <filename>\n");
473 log(" write to the specified file.\n");
474 log("\n");
475 log(" -a <filename>\n");
476 log(" like -outfile but append instead of overwrite\n");
477 log("\n");
478 }
479 void execute(std::vector<std::string> args, RTLIL::Design *design) override
480 {
481 std::string filename;
482 bool flag_m = false, flag_n = false, append = false;
483
484 size_t argidx;
485 for (argidx = 1; argidx < args.size(); argidx++)
486 {
487 std::string arg = args[argidx];
488 if ((arg == "-o" || arg == "-outfile") && argidx+1 < args.size()) {
489 filename = args[++argidx];
490 append = false;
491 continue;
492 }
493 if ((arg == "-a" || arg == "-append") && argidx+1 < args.size()) {
494 filename = args[++argidx];
495 append = true;
496 continue;
497 }
498 if (arg == "-m") {
499 flag_m = true;
500 continue;
501 }
502 if (arg == "-n") {
503 flag_n = true;
504 continue;
505 }
506 break;
507 }
508 extra_args(args, argidx, design);
509
510 std::ostream *f;
511 std::stringstream buf;
512
513 if (!filename.empty()) {
514 rewrite_filename(filename);
515 std::ofstream *ff = new std::ofstream;
516 ff->open(filename.c_str(), append ? std::ofstream::app : std::ofstream::trunc);
517 if (ff->fail()) {
518 delete ff;
519 log_error("Can't open file `%s' for writing: %s\n", filename.c_str(), strerror(errno));
520 }
521 f = ff;
522 } else {
523 f = &buf;
524 }
525
526 RTLIL_BACKEND::dump_design(*f, design, true, flag_m, flag_n);
527
528 if (!filename.empty()) {
529 delete f;
530 } else {
531 log("%s", buf.str().c_str());
532 }
533 }
534 } DumpPass;
535
536 PRIVATE_NAMESPACE_END