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