Fixed a gcc compiler warning [-Wparentheses]
[yosys.git] / backends / verilog / verilog_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 simple and straightforward verilog backend.
21 *
22 * Note that RTLIL processes can't always be mapped easily to a Verilog
23 * process. Therefore this frontend should only be used to export a
24 * Verilog netlist (i.e. after the "proc" pass has converted all processes
25 * to logic networks and registers).
26 *
27 */
28
29 #include "verilog_backend.h"
30 #include "kernel/register.h"
31 #include "kernel/celltypes.h"
32 #include "kernel/log.h"
33 #include <assert.h>
34 #include <string>
35 #include <sstream>
36 #include <set>
37 #include <map>
38
39 namespace {
40
41 bool norename, noattr, attr2comment, noexpr;
42 int auto_name_counter, auto_name_offset, auto_name_digits;
43 std::map<std::string, int> auto_name_map;
44
45 std::set<std::string> reg_wires;
46
47 CellTypes reg_ct;
48 RTLIL::Module *active_module;
49
50 void reset_auto_counter_id(const std::string &id, bool may_rename)
51 {
52 const char *str = id.c_str();
53
54 if (*str == '$' && may_rename && !norename)
55 auto_name_map[id] = auto_name_counter++;
56
57 if (str[0] != '_' && str[1] != 0)
58 return;
59 for (int i = 0; str[i] != 0; i++) {
60 if (str[i] == '_')
61 continue;
62 if (str[i] < '0' || str[i] > '9')
63 return;
64 }
65
66 int num = atoi(str+1);
67 if (num >= auto_name_offset)
68 auto_name_offset = num + 1;
69 }
70
71 void reset_auto_counter(RTLIL::Module *module)
72 {
73 auto_name_map.clear();
74 auto_name_counter = 0;
75 auto_name_offset = 0;
76
77 reset_auto_counter_id(module->name, false);
78
79 for (auto it = module->wires.begin(); it != module->wires.end(); it++)
80 reset_auto_counter_id(it->second->name, true);
81
82 for (auto it = module->cells.begin(); it != module->cells.end(); it++) {
83 reset_auto_counter_id(it->second->name, true);
84 reset_auto_counter_id(it->second->type, false);
85 }
86
87 for (auto it = module->processes.begin(); it != module->processes.end(); it++)
88 reset_auto_counter_id(it->second->name, false);
89
90 auto_name_digits = 1;
91 for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
92 auto_name_digits++;
93
94 for (auto it = auto_name_map.begin(); it != auto_name_map.end(); it++)
95 log(" renaming `%s' to `_%0*d_'.\n", it->first.c_str(), auto_name_digits, auto_name_offset + it->second);
96 }
97
98 std::string id(std::string internal_id, bool may_rename = true)
99 {
100 const char *str = internal_id.c_str();
101 bool do_escape = false;
102
103 if (may_rename && auto_name_map.count(internal_id) != 0) {
104 char buffer[100];
105 snprintf(buffer, 100, "_%0*d_", auto_name_digits, auto_name_offset + auto_name_map[internal_id]);
106 return std::string(buffer);
107 }
108
109 if (*str == '\\')
110 str++;
111
112 if ('0' <= *str && *str <= '9')
113 do_escape = true;
114
115 for (int i = 0; str[i]; i++)
116 {
117 if ('0' <= str[i] && str[i] <= '9')
118 continue;
119 if ('a' <= str[i] && str[i] <= 'z')
120 continue;
121 if ('A' <= str[i] && str[i] <= 'Z')
122 continue;
123 if (str[i] == '_')
124 continue;
125 do_escape = true;
126 break;
127 }
128
129 if (do_escape)
130 return "\\" + std::string(str) + " ";
131 return std::string(str);
132 }
133
134 bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
135 {
136 sig.optimize();
137 if (sig.chunks.size() != 1 || sig.chunks[0].wire == NULL)
138 return false;
139 if (reg_wires.count(sig.chunks[0].wire->name) == 0)
140 return false;
141 reg_name = id(sig.chunks[0].wire->name);
142 if (sig.width != sig.chunks[0].wire->width) {
143 if (sig.width == 1)
144 reg_name += stringf("[%d]", sig.chunks[0].wire->start_offset + sig.chunks[0].offset);
145 else
146 reg_name += stringf("[%d]", sig.chunks[0].wire->start_offset + sig.chunks[0].offset + sig.chunks[0].width - 1,
147 sig.chunks[0].wire->start_offset + sig.chunks[0].offset);
148 }
149 return true;
150 }
151
152 void dump_const(FILE *f, RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false)
153 {
154 if (width < 0)
155 width = data.bits.size() - offset;
156 if (data.str.empty() || width != (int)data.bits.size()) {
157 if (width == 32 && !no_decimal) {
158 uint32_t val = 0;
159 for (int i = offset+width-1; i >= offset; i--) {
160 assert(i < (int)data.bits.size());
161 if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
162 goto dump_bits;
163 if (data.bits[i] == RTLIL::S1)
164 val |= 1 << (i - offset);
165 }
166 fprintf(f, "%d", (int)val);
167 } else {
168 dump_bits:
169 fprintf(f, "%d'b", width);
170 for (int i = offset+width-1; i >= offset; i--) {
171 assert(i < (int)data.bits.size());
172 switch (data.bits[i]) {
173 case RTLIL::S0: fprintf(f, "0"); break;
174 case RTLIL::S1: fprintf(f, "1"); break;
175 case RTLIL::Sx: fprintf(f, "x"); break;
176 case RTLIL::Sz: fprintf(f, "z"); break;
177 case RTLIL::Sa: fprintf(f, "z"); break;
178 case RTLIL::Sm: log_error("Found marker state in final netlist.");
179 }
180 }
181 }
182 } else {
183 fprintf(f, "\"");
184 for (size_t i = 0; i < data.str.size(); i++) {
185 if (data.str[i] == '\n')
186 fprintf(f, "\\n");
187 else if (data.str[i] == '\t')
188 fprintf(f, "\\t");
189 else if (data.str[i] < 32)
190 fprintf(f, "\\%03o", data.str[i]);
191 else if (data.str[i] == '"')
192 fprintf(f, "\\\"");
193 else
194 fputc(data.str[i], f);
195 }
196 fprintf(f, "\"");
197 }
198 }
199
200 void dump_sigchunk(FILE *f, RTLIL::SigChunk &chunk, bool no_decimal = false)
201 {
202 if (chunk.wire == NULL) {
203 dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal);
204 } else {
205 if (chunk.width == chunk.wire->width && chunk.offset == 0)
206 fprintf(f, "%s", id(chunk.wire->name).c_str());
207 else if (chunk.width == 1)
208 fprintf(f, "%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset);
209 else
210 fprintf(f, "%s[%d:%d]", id(chunk.wire->name).c_str(),
211 chunk.offset + chunk.wire->start_offset + chunk.width - 1,
212 chunk.offset + chunk.wire->start_offset);
213 }
214 }
215
216 void dump_sigspec(FILE *f, RTLIL::SigSpec &sig)
217 {
218 if (sig.chunks.size() == 1) {
219 dump_sigchunk(f, sig.chunks[0]);
220 } else {
221 fprintf(f, "{ ");
222 for (auto it = sig.chunks.rbegin(); it != sig.chunks.rend(); it++) {
223 if (it != sig.chunks.rbegin())
224 fprintf(f, ", ");
225 dump_sigchunk(f, *it, true);
226 }
227 fprintf(f, " }");
228 }
229 }
230
231 void dump_attributes(FILE *f, std::string indent, std::map<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n')
232 {
233 if (noattr)
234 return;
235 for (auto it = attributes.begin(); it != attributes.end(); it++) {
236 fprintf(f, "%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
237 if (it->second.bits.size() > 0) {
238 fprintf(f, " = ");
239 dump_const(f, it->second);
240 }
241 fprintf(f, " %s%c", attr2comment ? "*/" : "*)", term);
242 }
243 }
244
245 void dump_wire(FILE *f, std::string indent, RTLIL::Wire *wire)
246 {
247 dump_attributes(f, indent, wire->attributes);
248 if (wire->port_input && !wire->port_output)
249 fprintf(f, "%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
250 else if (!wire->port_input && wire->port_output)
251 fprintf(f, "%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
252 else if (wire->port_input && wire->port_output)
253 fprintf(f, "%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
254 else
255 fprintf(f, "%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire");
256 if (wire->width != 1)
257 fprintf(f, "[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset);
258 fprintf(f, "%s;\n", id(wire->name).c_str());
259 }
260
261 void dump_memory(FILE *f, std::string indent, RTLIL::Memory *memory)
262 {
263 dump_attributes(f, indent, memory->attributes);
264 fprintf(f, "%s" "reg [%d:0] %s [%d:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
265 }
266
267 void dump_cell_expr_port(FILE *f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
268 {
269 if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) {
270 fprintf(f, "$signed(");
271 dump_sigspec(f, cell->connections["\\" + port]);
272 fprintf(f, ")");
273 } else
274 dump_sigspec(f, cell->connections["\\" + port]);
275 }
276
277 std::string cellname(RTLIL::Cell *cell)
278 {
279 if (!norename && cell->name[0] == '$' && reg_ct.cell_known(cell->type) && cell->connections.count("\\Q") > 0)
280 {
281 RTLIL::SigSpec sig = cell->connections["\\Q"];
282 if (sig.width != 1 || sig.is_fully_const())
283 goto no_special_reg_name;
284
285 sig.optimize();
286 RTLIL::Wire *wire = sig.chunks[0].wire;
287
288 if (wire->name[0] != '\\')
289 goto no_special_reg_name;
290
291 std::string cell_name = wire->name;
292
293 size_t pos = cell_name.find('[');
294 if (pos != std::string::npos)
295 cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos);
296 else
297 cell_name = cell_name + "_reg";
298
299 if (wire->width != 1)
300 cell_name += stringf("[%d]", wire->start_offset + sig.chunks[0].offset);
301
302 if (active_module && active_module->count_id(cell_name) > 0)
303 goto no_special_reg_name;
304
305 return id(cell_name);
306 }
307 else
308 {
309 no_special_reg_name:
310 return id(cell->name).c_str();
311 }
312 }
313
314 void dump_cell_expr_uniop(FILE *f, std::string indent, RTLIL::Cell *cell, std::string op)
315 {
316 fprintf(f, "%s" "assign ", indent.c_str());
317 dump_sigspec(f, cell->connections["\\Y"]);
318 fprintf(f, " = %s ", op.c_str());
319 dump_attributes(f, "", cell->attributes, ' ');
320 dump_cell_expr_port(f, cell, "A", true);
321 fprintf(f, ";\n");
322 }
323
324 void dump_cell_expr_binop(FILE *f, std::string indent, RTLIL::Cell *cell, std::string op)
325 {
326 fprintf(f, "%s" "assign ", indent.c_str());
327 dump_sigspec(f, cell->connections["\\Y"]);
328 fprintf(f, " = ");
329 dump_cell_expr_port(f, cell, "A", true);
330 fprintf(f, " %s ", op.c_str());
331 dump_attributes(f, "", cell->attributes, ' ');
332 dump_cell_expr_port(f, cell, "B", true);
333 fprintf(f, ";\n");
334 }
335
336 bool dump_cell_expr(FILE *f, std::string indent, RTLIL::Cell *cell)
337 {
338 if (cell->type == "$_INV_") {
339 fprintf(f, "%s" "assign ", indent.c_str());
340 dump_sigspec(f, cell->connections["\\Y"]);
341 fprintf(f, " = ");
342 fprintf(f, "~");
343 dump_attributes(f, "", cell->attributes, ' ');
344 dump_cell_expr_port(f, cell, "A", false);
345 fprintf(f, ";\n");
346 return true;
347 }
348
349 if (cell->type == "$_AND_" || cell->type == "$_OR_" || cell->type == "$_XOR_") {
350 fprintf(f, "%s" "assign ", indent.c_str());
351 dump_sigspec(f, cell->connections["\\Y"]);
352 fprintf(f, " = ");
353 dump_cell_expr_port(f, cell, "A", false);
354 fprintf(f, " ");
355 if (cell->type == "$_AND_")
356 fprintf(f, "&");
357 if (cell->type == "$_OR_")
358 fprintf(f, "|");
359 if (cell->type == "$_XOR_")
360 fprintf(f, "^");
361 dump_attributes(f, "", cell->attributes, ' ');
362 fprintf(f, " ");
363 dump_cell_expr_port(f, cell, "B", false);
364 fprintf(f, ";\n");
365 return true;
366 }
367
368 if (cell->type == "$_MUX_") {
369 fprintf(f, "%s" "assign ", indent.c_str());
370 dump_sigspec(f, cell->connections["\\Y"]);
371 fprintf(f, " = ");
372 dump_cell_expr_port(f, cell, "S", false);
373 fprintf(f, " ? ");
374 dump_attributes(f, "", cell->attributes, ' ');
375 dump_cell_expr_port(f, cell, "B", false);
376 fprintf(f, " : ");
377 dump_cell_expr_port(f, cell, "A", false);
378 fprintf(f, ";\n");
379 return true;
380 }
381
382 if (cell->type.substr(0, 6) == "$_DFF_")
383 {
384 std::string reg_name = cellname(cell);
385 bool out_is_reg_wire = is_reg_wire(cell->connections["\\Q"], reg_name);
386
387 if (!out_is_reg_wire)
388 fprintf(f, "%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
389
390 dump_attributes(f, indent, cell->attributes);
391 fprintf(f, "%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
392 dump_sigspec(f, cell->connections["\\C"]);
393 if (cell->type[7] != '_') {
394 fprintf(f, " or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
395 dump_sigspec(f, cell->connections["\\R"]);
396 }
397 fprintf(f, ")\n");
398
399 if (cell->type[7] != '_') {
400 fprintf(f, "%s" " if (%s", indent.c_str(), cell->type[7] == 'P' ? "" : "!");
401 dump_sigspec(f, cell->connections["\\R"]);
402 fprintf(f, ")\n");
403 fprintf(f, "%s" " %s <= %c;\n", indent.c_str(), reg_name.c_str(), cell->type[8]);
404 fprintf(f, "%s" " else\n", indent.c_str());
405 }
406
407 fprintf(f, "%s" " %s <= ", indent.c_str(), reg_name.c_str());
408 dump_cell_expr_port(f, cell, "D", false);
409 fprintf(f, ";\n");
410
411 if (!out_is_reg_wire) {
412 fprintf(f, "%s" "assign ", indent.c_str());
413 dump_sigspec(f, cell->connections["\\Q"]);
414 fprintf(f, " = %s;\n", reg_name.c_str());
415 }
416
417 return true;
418 }
419
420 #define HANDLE_UNIOP(_type, _operator) \
421 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
422 #define HANDLE_BINOP(_type, _operator) \
423 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
424
425 HANDLE_UNIOP("$not", "~")
426 HANDLE_UNIOP("$pos", "+")
427 HANDLE_UNIOP("$neg", "-")
428
429 HANDLE_BINOP("$and", "&")
430 HANDLE_BINOP("$or", "|")
431 HANDLE_BINOP("$xor", "^")
432 HANDLE_BINOP("$xnor", "~^")
433
434 HANDLE_UNIOP("$reduce_and", "&")
435 HANDLE_UNIOP("$reduce_or", "|")
436 HANDLE_UNIOP("$reduce_xor", "^")
437 HANDLE_UNIOP("$reduce_xnor", "~^")
438 HANDLE_UNIOP("$reduce_bool", "|")
439
440 HANDLE_BINOP("$shl", "<<")
441 HANDLE_BINOP("$shr", ">>")
442 HANDLE_BINOP("$sshl", "<<<")
443 HANDLE_BINOP("$sshr", ">>>")
444
445 HANDLE_BINOP("$lt", "<")
446 HANDLE_BINOP("$le", "<=")
447 HANDLE_BINOP("$eq", "==")
448 HANDLE_BINOP("$ne", "!=")
449 HANDLE_BINOP("$ge", ">=")
450 HANDLE_BINOP("$gt", ">")
451
452 HANDLE_BINOP("$add", "+")
453 HANDLE_BINOP("$sub", "-")
454 HANDLE_BINOP("$mul", "*")
455 HANDLE_BINOP("$div", "/")
456 HANDLE_BINOP("$mod", "%")
457 HANDLE_BINOP("$pow", "**")
458
459 HANDLE_UNIOP("$logic_not", "!")
460 HANDLE_BINOP("$logic_and", "&&")
461 HANDLE_BINOP("$logic_or", "||")
462
463 #undef HANDLE_UNIOP
464 #undef HANDLE_BINOP
465
466 if (cell->type == "$mux" || cell->type == "$pmux" || cell->type == "$pmux_safe")
467 {
468 int width = cell->parameters["\\WIDTH"].as_int();
469 int s_width = cell->connections["\\S"].width;
470 std::string reg_name = cellname(cell);
471 fprintf(f, "%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());
472
473 dump_attributes(f, indent, cell->attributes);
474 if (!noattr)
475 fprintf(f, "%s" "(* parallel_case *)\n", indent.c_str());
476 fprintf(f, "%s" "always @*\n", indent.c_str());
477 fprintf(f, "%s" " casez (", indent.c_str());
478 dump_sigspec(f, cell->connections["\\S"]);
479 fprintf(f, noattr ? ") // synopsys parallel_case\n" : ")\n");
480
481 for (int i = 0; i < s_width; i++)
482 {
483 fprintf(f, "%s" " %d'b", indent.c_str(), s_width);
484
485 for (int j = s_width-1; j >= 0; j--)
486 fprintf(f, "%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
487
488 fprintf(f, ":\n");
489 fprintf(f, "%s" " %s = ", indent.c_str(), reg_name.c_str());
490
491 RTLIL::SigSpec s = cell->connections["\\B"].extract(i * width, width);
492 dump_sigspec(f, s);
493 fprintf(f, ";\n");
494 }
495
496 fprintf(f, "%s" " default:\n", indent.c_str());
497 fprintf(f, "%s" " %s = ", indent.c_str(), reg_name.c_str());
498 dump_sigspec(f, cell->connections["\\A"]);
499 fprintf(f, ";\n");
500
501 fprintf(f, "%s" " endcase\n", indent.c_str());
502 fprintf(f, "%s" "assign ", indent.c_str());
503 dump_sigspec(f, cell->connections["\\Y"]);
504 fprintf(f, " = %s;\n", reg_name.c_str());
505 return true;
506 }
507
508 if (cell->type == "$dff" || cell->type == "$adff")
509 {
510 RTLIL::SigSpec sig_clk, sig_arst, val_arst;
511 bool pol_clk, pol_arst = false;
512
513 sig_clk = cell->connections["\\CLK"];
514 pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
515
516 if (cell->type == "$adff") {
517 sig_arst = cell->connections["\\ARST"];
518 pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool();
519 val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
520 }
521
522 std::string reg_name = cellname(cell);
523 bool out_is_reg_wire = is_reg_wire(cell->connections["\\Q"], reg_name);
524
525 if (!out_is_reg_wire)
526 fprintf(f, "%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
527
528 fprintf(f, "%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
529 dump_sigspec(f, sig_clk);
530 if (cell->type == "$adff") {
531 fprintf(f, " or %sedge ", pol_arst ? "pos" : "neg");
532 dump_sigspec(f, sig_arst);
533 }
534 fprintf(f, ")\n");
535
536 if (cell->type == "$adff") {
537 fprintf(f, "%s" " if (%s", indent.c_str(), pol_arst ? "" : "!");
538 dump_sigspec(f, sig_arst);
539 fprintf(f, ")\n");
540 fprintf(f, "%s" " %s <= ", indent.c_str(), reg_name.c_str());
541 dump_sigspec(f, val_arst);
542 fprintf(f, ";\n");
543 fprintf(f, "%s" " else\n", indent.c_str());
544 }
545
546 fprintf(f, "%s" " %s <= ", indent.c_str(), reg_name.c_str());
547 dump_cell_expr_port(f, cell, "D", false);
548 fprintf(f, ";\n");
549
550 if (!out_is_reg_wire) {
551 fprintf(f, "%s" "assign ", indent.c_str());
552 dump_sigspec(f, cell->connections["\\Q"]);
553 fprintf(f, " = %s;\n", reg_name.c_str());
554 }
555
556 return true;
557 }
558
559 // FIXME: $memrd, $memwr, $mem, $fsm
560
561 return false;
562 }
563
564 void dump_cell(FILE *f, std::string indent, RTLIL::Cell *cell)
565 {
566 if (cell->type[0] == '$' && !noexpr) {
567 if (dump_cell_expr(f, indent, cell))
568 return;
569 }
570
571 dump_attributes(f, indent, cell->attributes);
572 fprintf(f, "%s" "%s", indent.c_str(), id(cell->type, false).c_str());
573
574 if (cell->parameters.size() > 0) {
575 fprintf(f, " #(");
576 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
577 if (it != cell->parameters.begin())
578 fprintf(f, ",");
579 fprintf(f, "\n%s .%s(", indent.c_str(), id(it->first).c_str());
580 dump_const(f, it->second);
581 fprintf(f, ")");
582 }
583 fprintf(f, "\n%s" ")", indent.c_str());
584 }
585
586 std::string cell_name = cellname(cell);
587 if (cell_name != id(cell->name))
588 fprintf(f, " %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
589 else
590 fprintf(f, " %s (", cell_name.c_str());
591
592 bool first_arg = true;
593 std::set<std::string> numbered_ports;
594 for (int i = 1; true; i++) {
595 char str[16];
596 snprintf(str, 16, "$%d", i);
597 for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
598 if (it->first != str)
599 continue;
600 if (!first_arg)
601 fprintf(f, ",");
602 first_arg = false;
603 fprintf(f, "\n%s ", indent.c_str());
604 dump_sigspec(f, it->second);
605 numbered_ports.insert(it->first);
606 goto found_numbered_port;
607 }
608 break;
609 found_numbered_port:;
610 }
611 for (auto it = cell->connections.begin(); it != cell->connections.end(); it++) {
612 if (numbered_ports.count(it->first))
613 continue;
614 if (!first_arg)
615 fprintf(f, ",");
616 first_arg = false;
617 fprintf(f, "\n%s .%s(", indent.c_str(), id(it->first).c_str());
618 if (it->second.width > 0)
619 dump_sigspec(f, it->second);
620 fprintf(f, ")");
621 }
622 fprintf(f, "\n%s" ");\n", indent.c_str());
623 }
624
625 void dump_conn(FILE *f, std::string indent, RTLIL::SigSpec &left, RTLIL::SigSpec &right)
626 {
627 fprintf(f, "%s" "assign ", indent.c_str());
628 dump_sigspec(f, left);
629 fprintf(f, " = ");
630 dump_sigspec(f, right);
631 fprintf(f, ";\n");
632 }
633
634 void dump_proc_switch(FILE *f, std::string indent, RTLIL::SwitchRule *sw);
635
636 void dump_case_body(FILE *f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
637 {
638 int number_of_stmts = cs->switches.size() + cs->actions.size();
639
640 if (!omit_trailing_begin && number_of_stmts >= 2)
641 fprintf(f, "%s" "begin\n", indent.c_str());
642
643 for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
644 if (it->first.width == 0)
645 continue;
646 fprintf(f, "%s ", indent.c_str());
647 dump_sigspec(f, it->first);
648 fprintf(f, " = ");
649 dump_sigspec(f, it->second);
650 fprintf(f, ";\n");
651 }
652
653 for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
654 dump_proc_switch(f, indent + " ", *it);
655
656 if (!omit_trailing_begin && number_of_stmts == 0)
657 fprintf(f, "%s /* empty */;\n", indent.c_str());
658
659 if (omit_trailing_begin || number_of_stmts >= 2)
660 fprintf(f, "%s" "end\n", indent.c_str());
661 }
662
663 void dump_proc_switch(FILE *f, std::string indent, RTLIL::SwitchRule *sw)
664 {
665 if (sw->signal.width == 0) {
666 fprintf(f, "%s" "begin\n", indent.c_str());
667 for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
668 if ((*it)->compare.size() == 0)
669 dump_case_body(f, indent + " ", *it);
670 }
671 fprintf(f, "%s" "end\n", indent.c_str());
672 return;
673 }
674
675 fprintf(f, "%s" "casez (", indent.c_str());
676 dump_sigspec(f, sw->signal);
677 fprintf(f, ")\n");
678
679 for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
680 fprintf(f, "%s ", indent.c_str());
681 if ((*it)->compare.size() == 0)
682 fprintf(f, "default");
683 else {
684 for (size_t i = 0; i < (*it)->compare.size(); i++) {
685 if (i > 0)
686 fprintf(f, ", ");
687 dump_sigspec(f, (*it)->compare[i]);
688 }
689 }
690 fprintf(f, ":\n");
691 dump_case_body(f, indent + " ", *it);
692 }
693
694 fprintf(f, "%s" "endcase\n", indent.c_str());
695 }
696
697 void case_body_find_regs(RTLIL::CaseRule *cs)
698 {
699 for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
700 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
701 case_body_find_regs(*it2);
702
703 for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
704 for (size_t i = 0; i < it->first.chunks.size(); i++)
705 if (it->first.chunks[i].wire)
706 reg_wires.insert(it->first.chunks[i].wire->name);
707 }
708 }
709
710 void dump_process(FILE *f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
711 {
712 if (find_regs) {
713 case_body_find_regs(&proc->root_case);
714 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
715 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
716 for (size_t i = 0; i < it2->first.chunks.size(); i++)
717 if (it2->first.chunks[i].wire)
718 reg_wires.insert(it2->first.chunks[i].wire->name);
719 }
720 return;
721 }
722
723 fprintf(f, "%s" "always @* begin\n", indent.c_str());
724 dump_case_body(f, indent, &proc->root_case, true);
725
726 std::string backup_indent = indent;
727
728 for (size_t i = 0; i < proc->syncs.size(); i++)
729 {
730 RTLIL::SyncRule *sync = proc->syncs[i];
731 indent = backup_indent;
732
733 if (sync->type == RTLIL::STa) {
734 fprintf(f, "%s" "always @* begin\n", indent.c_str());
735 } else {
736 fprintf(f, "%s" "always @(", indent.c_str());
737 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
738 fprintf(f, "posedge ");
739 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
740 fprintf(f, "negedge ");
741 dump_sigspec(f, sync->signal);
742 fprintf(f, ") begin\n");
743 }
744 std::string ends = indent + "end\n";
745 indent += " ";
746
747 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
748 fprintf(f, "%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
749 dump_sigspec(f, sync->signal);
750 fprintf(f, ") begin\n");
751 ends = indent + "end\n" + ends;
752 indent += " ";
753 }
754
755 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
756 for (size_t j = 0; j < proc->syncs.size(); j++) {
757 RTLIL::SyncRule *sync2 = proc->syncs[j];
758 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
759 fprintf(f, "%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
760 dump_sigspec(f, sync2->signal);
761 fprintf(f, ") begin\n");
762 ends = indent + "end\n" + ends;
763 indent += " ";
764 }
765 }
766 }
767
768 for (auto it = sync->actions.begin(); it != sync->actions.end(); it++) {
769 if (it->first.width == 0)
770 continue;
771 fprintf(f, "%s ", indent.c_str());
772 dump_sigspec(f, it->first);
773 fprintf(f, " <= ");
774 dump_sigspec(f, it->second);
775 fprintf(f, ";\n");
776 }
777
778 fprintf(f, "%s", ends.c_str());
779 }
780 }
781
782 void dump_module(FILE *f, std::string indent, RTLIL::Module *module)
783 {
784 reg_wires.clear();
785 reset_auto_counter(module);
786 active_module = module;
787
788 for (auto it = module->processes.begin(); it != module->processes.end(); it++)
789 dump_process(f, indent + " ", it->second, true);
790
791 if (!noexpr)
792 {
793 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
794 for (auto &it : module->cells)
795 {
796 RTLIL::Cell *cell = it.second;
797 if (!reg_ct.cell_known(cell->type) || cell->connections.count("\\Q") == 0)
798 continue;
799
800 RTLIL::SigSpec sig = cell->connections["\\Q"];
801 sig.optimize();
802
803 if (sig.chunks.size() == 1 && sig.chunks[0].wire)
804 for (int i = 0; i < sig.chunks[0].width; i++)
805 reg_bits.insert(std::pair<RTLIL::Wire*,int>(sig.chunks[0].wire, sig.chunks[0].offset+i));
806 }
807 for (auto &it : module->wires)
808 {
809 RTLIL::Wire *wire = it.second;
810 for (int i = 0; i < wire->width; i++)
811 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
812 goto this_wire_aint_reg;
813 reg_wires.insert(wire->name);
814 this_wire_aint_reg:;
815 }
816 }
817
818 dump_attributes(f, indent, module->attributes);
819 fprintf(f, "%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
820 bool keep_running = true;
821 for (int port_id = 1; keep_running; port_id++) {
822 keep_running = false;
823 for (auto it = module->wires.begin(); it != module->wires.end(); it++) {
824 RTLIL::Wire *wire = it->second;
825 if (wire->port_id == port_id) {
826 if (port_id != 1)
827 fprintf(f, ", ");
828 fprintf(f, "%s", id(wire->name).c_str());
829 keep_running = true;
830 continue;
831 }
832 }
833 }
834 fprintf(f, ");\n");
835
836 for (auto it = module->wires.begin(); it != module->wires.end(); it++)
837 dump_wire(f, indent + " ", it->second);
838
839 for (auto it = module->memories.begin(); it != module->memories.end(); it++)
840 dump_memory(f, indent + " ", it->second);
841
842 for (auto it = module->cells.begin(); it != module->cells.end(); it++)
843 dump_cell(f, indent + " ", it->second);
844
845 for (auto it = module->processes.begin(); it != module->processes.end(); it++)
846 dump_process(f, indent + " ", it->second);
847
848 for (auto it = module->connections.begin(); it != module->connections.end(); it++)
849 dump_conn(f, indent + " ", it->first, it->second);
850
851 fprintf(f, "%s" "endmodule\n", indent.c_str());
852 active_module = NULL;
853 }
854
855 } /* namespace */
856
857 struct VerilogBackend : public Backend {
858 VerilogBackend() : Backend("verilog", "write design to verilog file") { }
859 virtual void help()
860 {
861 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
862 log("\n");
863 log(" write_verilog [options] [filename]\n");
864 log("\n");
865 log("Write the current design to a verilog file.\n");
866 log("\n");
867 log(" -norename\n");
868 log(" without this option all internal object names (the ones with a dollar\n");
869 log(" instead of a backslash prefix) are changed to short names in the\n");
870 log(" format '_<number>_'.\n");
871 log("\n");
872 log(" -noattr\n");
873 log(" with this option no attributes are included in the output\n");
874 log("\n");
875 log(" -attr2comment\n");
876 log(" with this option attributes are included as comments in the output\n");
877 log("\n");
878 log(" -noexpr\n");
879 log(" without this option all internal cells are converted to verilog\n");
880 log(" expressions.\n");
881 log("\n");
882 }
883 virtual void execute(FILE *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
884 {
885 log_header("Executing Verilog backend.\n");
886
887 norename = false;
888 noattr = false;
889 attr2comment = false;
890 noexpr = false;
891
892 reg_ct.clear();
893 reg_ct.setup_stdcells_mem();
894 reg_ct.cell_types.insert("$dff");
895 reg_ct.cell_types.insert("$adff");
896
897 size_t argidx;
898 for (argidx = 1; argidx < args.size(); argidx++) {
899 std::string arg = args[argidx];
900 if (arg == "-norename") {
901 norename = true;
902 continue;
903 }
904 if (arg == "-noattr") {
905 noattr = true;
906 continue;
907 }
908 if (arg == "-attr2comment") {
909 attr2comment = true;
910 continue;
911 }
912 if (arg == "-noexpr") {
913 noexpr = true;
914 continue;
915 }
916 break;
917 }
918 extra_args(f, filename, args, argidx);
919
920 for (auto it = design->modules.begin(); it != design->modules.end(); it++) {
921 log("Dumping module `%s'.\n", it->first.c_str());
922 if (it != design->modules.begin())
923 fprintf(f, "\n");
924 dump_module(f, "", it->second);
925 }
926
927 reg_ct.clear();
928 }
929 } VerilogBackend;
930