Cosmetic changes in verilog output format
[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 "kernel/register.h"
30 #include "kernel/celltypes.h"
31 #include "kernel/log.h"
32 #include <string>
33 #include <sstream>
34 #include <set>
35 #include <map>
36
37 USING_YOSYS_NAMESPACE
38 PRIVATE_NAMESPACE_BEGIN
39
40 bool norename, noattr, attr2comment, noexpr;
41 int auto_name_counter, auto_name_offset, auto_name_digits;
42 std::map<RTLIL::IdString, int> auto_name_map;
43 std::set<RTLIL::IdString> reg_wires, reg_ct;
44
45 RTLIL::Module *active_module;
46
47 void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
48 {
49 const char *str = id.c_str();
50
51 if (*str == '$' && may_rename && !norename)
52 auto_name_map[id] = auto_name_counter++;
53
54 if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
55 return;
56
57 for (int i = 2; str[i] != 0; i++) {
58 if (str[i] == '_' && str[i+1] == 0)
59 continue;
60 if (str[i] < '0' || str[i] > '9')
61 return;
62 }
63
64 int num = atoi(str+2);
65 if (num >= auto_name_offset)
66 auto_name_offset = num + 1;
67 }
68
69 void reset_auto_counter(RTLIL::Module *module)
70 {
71 auto_name_map.clear();
72 auto_name_counter = 0;
73 auto_name_offset = 0;
74
75 reset_auto_counter_id(module->name, false);
76
77 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
78 reset_auto_counter_id(it->second->name, true);
79
80 for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it) {
81 reset_auto_counter_id(it->second->name, true);
82 reset_auto_counter_id(it->second->type, false);
83 }
84
85 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
86 reset_auto_counter_id(it->second->name, false);
87
88 auto_name_digits = 1;
89 for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
90 auto_name_digits++;
91
92 for (auto it = auto_name_map.begin(); it != auto_name_map.end(); ++it)
93 log(" renaming `%s' to `_%0*d_'.\n", it->first.c_str(), auto_name_digits, auto_name_offset + it->second);
94 }
95
96 std::string id(RTLIL::IdString internal_id, bool may_rename = true)
97 {
98 const char *str = internal_id.c_str();
99 bool do_escape = false;
100
101 if (may_rename && auto_name_map.count(internal_id) != 0) {
102 char buffer[100];
103 snprintf(buffer, 100, "_%0*d_", auto_name_digits, auto_name_offset + auto_name_map[internal_id]);
104 return std::string(buffer);
105 }
106
107 if (*str == '\\')
108 str++;
109
110 if ('0' <= *str && *str <= '9')
111 do_escape = true;
112
113 for (int i = 0; str[i]; i++)
114 {
115 if ('0' <= str[i] && str[i] <= '9')
116 continue;
117 if ('a' <= str[i] && str[i] <= 'z')
118 continue;
119 if ('A' <= str[i] && str[i] <= 'Z')
120 continue;
121 if (str[i] == '_')
122 continue;
123 do_escape = true;
124 break;
125 }
126
127 if (do_escape)
128 return "\\" + std::string(str) + " ";
129 return std::string(str);
130 }
131
132 bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
133 {
134 if (!sig.is_chunk() || sig.as_chunk().wire == NULL)
135 return false;
136
137 RTLIL::SigChunk chunk = sig.as_chunk();
138
139 if (reg_wires.count(chunk.wire->name) == 0)
140 return false;
141
142 reg_name = id(chunk.wire->name);
143 if (sig.size() != chunk.wire->width) {
144 if (sig.size() == 1)
145 reg_name += stringf("[%d]", chunk.wire->start_offset + chunk.offset);
146 else
147 reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1,
148 chunk.wire->start_offset + chunk.offset);
149 }
150
151 return true;
152 }
153
154 void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false)
155 {
156 if (width < 0)
157 width = data.bits.size() - offset;
158 if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
159 if (width == 32 && !no_decimal) {
160 int32_t val = 0;
161 for (int i = offset+width-1; i >= offset; i--) {
162 log_assert(i < (int)data.bits.size());
163 if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
164 goto dump_bits;
165 if (data.bits[i] == RTLIL::S1 && (i - offset) == 31)
166 goto dump_bits;
167 if (data.bits[i] == RTLIL::S1)
168 val |= 1 << (i - offset);
169 }
170 f << stringf("32'%sd %d", set_signed ? "s" : "", val);
171 } else {
172 dump_bits:
173 f << stringf("%d'%sb", width, set_signed ? "s" : "");
174 if (width == 0)
175 f << stringf("0");
176 for (int i = offset+width-1; i >= offset; i--) {
177 log_assert(i < (int)data.bits.size());
178 switch (data.bits[i]) {
179 case RTLIL::S0: f << stringf("0"); break;
180 case RTLIL::S1: f << stringf("1"); break;
181 case RTLIL::Sx: f << stringf("x"); break;
182 case RTLIL::Sz: f << stringf("z"); break;
183 case RTLIL::Sa: f << stringf("z"); break;
184 case RTLIL::Sm: log_error("Found marker state in final netlist.");
185 }
186 }
187 }
188 } else {
189 f << stringf("\"");
190 std::string str = data.decode_string();
191 for (size_t i = 0; i < str.size(); i++) {
192 if (str[i] == '\n')
193 f << stringf("\\n");
194 else if (str[i] == '\t')
195 f << stringf("\\t");
196 else if (str[i] < 32)
197 f << stringf("\\%03o", str[i]);
198 else if (str[i] == '"')
199 f << stringf("\\\"");
200 else if (str[i] == '\\')
201 f << stringf("\\\\");
202 else
203 f << str[i];
204 }
205 f << stringf("\"");
206 }
207 }
208
209 void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
210 {
211 if (chunk.wire == NULL) {
212 dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal);
213 } else {
214 if (chunk.width == chunk.wire->width && chunk.offset == 0) {
215 f << stringf("%s", id(chunk.wire->name).c_str());
216 } else if (chunk.width == 1) {
217 if (chunk.wire->upto)
218 f << stringf("%s[%d]", id(chunk.wire->name).c_str(), (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
219 else
220 f << stringf("%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset);
221 } else {
222 if (chunk.wire->upto)
223 f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
224 (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset,
225 (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
226 else
227 f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
228 (chunk.offset + chunk.width - 1) + chunk.wire->start_offset,
229 chunk.offset + chunk.wire->start_offset);
230 }
231 }
232 }
233
234 void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
235 {
236 if (sig.is_chunk()) {
237 dump_sigchunk(f, sig.as_chunk());
238 } else {
239 f << stringf("{ ");
240 for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
241 if (it != sig.chunks().rbegin())
242 f << stringf(", ");
243 dump_sigchunk(f, *it, true);
244 }
245 f << stringf(" }");
246 }
247 }
248
249 void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false)
250 {
251 if (noattr)
252 return;
253 for (auto it = attributes.begin(); it != attributes.end(); ++it) {
254 f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
255 f << stringf(" = ");
256 if (modattr && (it->second == Const(0, 1) || it->second == Const(0)))
257 f << stringf(" 0 ");
258 else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
259 f << stringf(" 1 ");
260 else
261 dump_const(f, it->second);
262 f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
263 }
264 }
265
266 void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
267 {
268 dump_attributes(f, indent, wire->attributes);
269 #if 0
270 if (wire->port_input && !wire->port_output)
271 f << stringf("%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
272 else if (!wire->port_input && wire->port_output)
273 f << stringf("%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
274 else if (wire->port_input && wire->port_output)
275 f << stringf("%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
276 else
277 f << stringf("%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire");
278 if (wire->width != 1)
279 f << stringf("[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset);
280 f << stringf("%s;\n", id(wire->name).c_str());
281 #else
282 // do not use Verilog-2k "outut reg" syntax in verilog export
283 std::string range = "";
284 if (wire->width != 1) {
285 if (wire->upto)
286 range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
287 else
288 range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
289 }
290 if (wire->port_input && !wire->port_output)
291 f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
292 if (!wire->port_input && wire->port_output)
293 f << stringf("%s" "output%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
294 if (wire->port_input && wire->port_output)
295 f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
296 if (reg_wires.count(wire->name))
297 f << stringf("%s" "reg%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
298 else if (!wire->port_input && !wire->port_output)
299 f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
300 #endif
301 }
302
303 void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory)
304 {
305 dump_attributes(f, indent, memory->attributes);
306 f << stringf("%s" "reg [%d:0] %s [%d:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
307 }
308
309 void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
310 {
311 if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) {
312 f << stringf("$signed(");
313 dump_sigspec(f, cell->getPort("\\" + port));
314 f << stringf(")");
315 } else
316 dump_sigspec(f, cell->getPort("\\" + port));
317 }
318
319 std::string cellname(RTLIL::Cell *cell)
320 {
321 if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q"))
322 {
323 RTLIL::SigSpec sig = cell->getPort("\\Q");
324 if (GetSize(sig) != 1 || sig.is_fully_const())
325 goto no_special_reg_name;
326
327 RTLIL::Wire *wire = sig[0].wire;
328
329 if (wire->name[0] != '\\')
330 goto no_special_reg_name;
331
332 std::string cell_name = wire->name.str();
333
334 size_t pos = cell_name.find('[');
335 if (pos != std::string::npos)
336 cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos);
337 else
338 cell_name = cell_name + "_reg";
339
340 if (wire->width != 1)
341 cell_name += stringf("[%d]", wire->start_offset + sig[0].offset);
342
343 if (active_module && active_module->count_id(cell_name) > 0)
344 goto no_special_reg_name;
345
346 return id(cell_name);
347 }
348 else
349 {
350 no_special_reg_name:
351 return id(cell->name).c_str();
352 }
353 }
354
355 void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
356 {
357 f << stringf("%s" "assign ", indent.c_str());
358 dump_sigspec(f, cell->getPort("\\Y"));
359 f << stringf(" = %s ", op.c_str());
360 dump_attributes(f, "", cell->attributes, ' ');
361 dump_cell_expr_port(f, cell, "A", true);
362 f << stringf(";\n");
363 }
364
365 void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
366 {
367 f << stringf("%s" "assign ", indent.c_str());
368 dump_sigspec(f, cell->getPort("\\Y"));
369 f << stringf(" = ");
370 dump_cell_expr_port(f, cell, "A", true);
371 f << stringf(" %s ", op.c_str());
372 dump_attributes(f, "", cell->attributes, ' ');
373 dump_cell_expr_port(f, cell, "B", true);
374 f << stringf(";\n");
375 }
376
377 bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
378 {
379 if (cell->type == "$_NOT_") {
380 f << stringf("%s" "assign ", indent.c_str());
381 dump_sigspec(f, cell->getPort("\\Y"));
382 f << stringf(" = ");
383 f << stringf("~");
384 dump_attributes(f, "", cell->attributes, ' ');
385 dump_cell_expr_port(f, cell, "A", false);
386 f << stringf(";\n");
387 return true;
388 }
389
390 if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) {
391 f << stringf("%s" "assign ", indent.c_str());
392 dump_sigspec(f, cell->getPort("\\Y"));
393 f << stringf(" = ");
394 if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
395 f << stringf("~(");
396 dump_cell_expr_port(f, cell, "A", false);
397 f << stringf(" ");
398 if (cell->type.in("$_AND_", "$_NAND_"))
399 f << stringf("&");
400 if (cell->type.in("$_OR_", "$_NOR_"))
401 f << stringf("|");
402 if (cell->type.in("$_XOR_", "$_XNOR_"))
403 f << stringf("^");
404 dump_attributes(f, "", cell->attributes, ' ');
405 f << stringf(" ");
406 dump_cell_expr_port(f, cell, "B", false);
407 if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
408 f << stringf(")");
409 f << stringf(";\n");
410 return true;
411 }
412
413 if (cell->type == "$_MUX_") {
414 f << stringf("%s" "assign ", indent.c_str());
415 dump_sigspec(f, cell->getPort("\\Y"));
416 f << stringf(" = ");
417 dump_cell_expr_port(f, cell, "S", false);
418 f << stringf(" ? ");
419 dump_attributes(f, "", cell->attributes, ' ');
420 dump_cell_expr_port(f, cell, "B", false);
421 f << stringf(" : ");
422 dump_cell_expr_port(f, cell, "A", false);
423 f << stringf(";\n");
424 return true;
425 }
426
427 if (cell->type.in("$_AOI3_", "$_OAI3_")) {
428 f << stringf("%s" "assign ", indent.c_str());
429 dump_sigspec(f, cell->getPort("\\Y"));
430 f << stringf(" = ~((");
431 dump_cell_expr_port(f, cell, "A", false);
432 f << stringf(cell->type == "$_AOI3_" ? " & " : " | ");
433 dump_cell_expr_port(f, cell, "B", false);
434 f << stringf(cell->type == "$_AOI3_" ? ") |" : ") &");
435 dump_attributes(f, "", cell->attributes, ' ');
436 f << stringf(" ");
437 dump_cell_expr_port(f, cell, "C", false);
438 f << stringf(");\n");
439 return true;
440 }
441
442 if (cell->type.in("$_AOI4_", "$_OAI4_")) {
443 f << stringf("%s" "assign ", indent.c_str());
444 dump_sigspec(f, cell->getPort("\\Y"));
445 f << stringf(" = ~((");
446 dump_cell_expr_port(f, cell, "A", false);
447 f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
448 dump_cell_expr_port(f, cell, "B", false);
449 f << stringf(cell->type == "$_AOI4_" ? ") |" : ") &");
450 dump_attributes(f, "", cell->attributes, ' ');
451 f << stringf(" (");
452 dump_cell_expr_port(f, cell, "C", false);
453 f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
454 dump_cell_expr_port(f, cell, "D", false);
455 f << stringf("));\n");
456 return true;
457 }
458
459 if (cell->type.substr(0, 6) == "$_DFF_")
460 {
461 std::string reg_name = cellname(cell);
462 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
463
464 if (!out_is_reg_wire)
465 f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
466
467 dump_attributes(f, indent, cell->attributes);
468 f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
469 dump_sigspec(f, cell->getPort("\\C"));
470 if (cell->type[7] != '_') {
471 f << stringf(" or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
472 dump_sigspec(f, cell->getPort("\\R"));
473 }
474 f << stringf(")\n");
475
476 if (cell->type[7] != '_') {
477 f << stringf("%s" " if (%s", indent.c_str(), cell->type[7] == 'P' ? "" : "!");
478 dump_sigspec(f, cell->getPort("\\R"));
479 f << stringf(")\n");
480 f << stringf("%s" " %s <= %c;\n", indent.c_str(), reg_name.c_str(), cell->type[8]);
481 f << stringf("%s" " else\n", indent.c_str());
482 }
483
484 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
485 dump_cell_expr_port(f, cell, "D", false);
486 f << stringf(";\n");
487
488 if (!out_is_reg_wire) {
489 f << stringf("%s" "assign ", indent.c_str());
490 dump_sigspec(f, cell->getPort("\\Q"));
491 f << stringf(" = %s;\n", reg_name.c_str());
492 }
493
494 return true;
495 }
496
497 if (cell->type.substr(0, 8) == "$_DFFSR_")
498 {
499 char pol_c = cell->type[8], pol_s = cell->type[9], pol_r = cell->type[10];
500
501 std::string reg_name = cellname(cell);
502 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
503
504 if (!out_is_reg_wire)
505 f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
506
507 dump_attributes(f, indent, cell->attributes);
508 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
509 dump_sigspec(f, cell->getPort("\\C"));
510 f << stringf(" or %sedge ", pol_s == 'P' ? "pos" : "neg");
511 dump_sigspec(f, cell->getPort("\\S"));
512 f << stringf(" or %sedge ", pol_r == 'P' ? "pos" : "neg");
513 dump_sigspec(f, cell->getPort("\\R"));
514 f << stringf(")\n");
515
516 f << stringf("%s" " if (%s", indent.c_str(), pol_r == 'P' ? "" : "!");
517 dump_sigspec(f, cell->getPort("\\R"));
518 f << stringf(")\n");
519 f << stringf("%s" " %s <= 0;\n", indent.c_str(), reg_name.c_str());
520
521 f << stringf("%s" " else if (%s", indent.c_str(), pol_s == 'P' ? "" : "!");
522 dump_sigspec(f, cell->getPort("\\S"));
523 f << stringf(")\n");
524 f << stringf("%s" " %s <= 1;\n", indent.c_str(), reg_name.c_str());
525
526 f << stringf("%s" " else\n", indent.c_str());
527 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
528 dump_cell_expr_port(f, cell, "D", false);
529 f << stringf(";\n");
530
531 if (!out_is_reg_wire) {
532 f << stringf("%s" "assign ", indent.c_str());
533 dump_sigspec(f, cell->getPort("\\Q"));
534 f << stringf(" = %s;\n", reg_name.c_str());
535 }
536
537 return true;
538 }
539
540 #define HANDLE_UNIOP(_type, _operator) \
541 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
542 #define HANDLE_BINOP(_type, _operator) \
543 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
544
545 HANDLE_UNIOP("$not", "~")
546 HANDLE_UNIOP("$pos", "+")
547 HANDLE_UNIOP("$neg", "-")
548
549 HANDLE_BINOP("$and", "&")
550 HANDLE_BINOP("$or", "|")
551 HANDLE_BINOP("$xor", "^")
552 HANDLE_BINOP("$xnor", "~^")
553
554 HANDLE_UNIOP("$reduce_and", "&")
555 HANDLE_UNIOP("$reduce_or", "|")
556 HANDLE_UNIOP("$reduce_xor", "^")
557 HANDLE_UNIOP("$reduce_xnor", "~^")
558 HANDLE_UNIOP("$reduce_bool", "|")
559
560 HANDLE_BINOP("$shl", "<<")
561 HANDLE_BINOP("$shr", ">>")
562 HANDLE_BINOP("$sshl", "<<<")
563 HANDLE_BINOP("$sshr", ">>>")
564
565 HANDLE_BINOP("$lt", "<")
566 HANDLE_BINOP("$le", "<=")
567 HANDLE_BINOP("$eq", "==")
568 HANDLE_BINOP("$ne", "!=")
569 HANDLE_BINOP("$eqx", "===")
570 HANDLE_BINOP("$nex", "!==")
571 HANDLE_BINOP("$ge", ">=")
572 HANDLE_BINOP("$gt", ">")
573
574 HANDLE_BINOP("$add", "+")
575 HANDLE_BINOP("$sub", "-")
576 HANDLE_BINOP("$mul", "*")
577 HANDLE_BINOP("$div", "/")
578 HANDLE_BINOP("$mod", "%")
579 HANDLE_BINOP("$pow", "**")
580
581 HANDLE_UNIOP("$logic_not", "!")
582 HANDLE_BINOP("$logic_and", "&&")
583 HANDLE_BINOP("$logic_or", "||")
584
585 #undef HANDLE_UNIOP
586 #undef HANDLE_BINOP
587
588 if (cell->type == "$mux")
589 {
590 f << stringf("%s" "assign ", indent.c_str());
591 dump_sigspec(f, cell->getPort("\\Y"));
592 f << stringf(" = ");
593 dump_sigspec(f, cell->getPort("\\S"));
594 f << stringf(" ? ");
595 dump_attributes(f, "", cell->attributes, ' ');
596 dump_sigspec(f, cell->getPort("\\B"));
597 f << stringf(" : ");
598 dump_sigspec(f, cell->getPort("\\A"));
599 f << stringf(";\n");
600 return true;
601 }
602
603 if (cell->type == "$pmux" || cell->type == "$pmux_safe")
604 {
605 int width = cell->parameters["\\WIDTH"].as_int();
606 int s_width = cell->getPort("\\S").size();
607 std::string func_name = cellname(cell);
608
609 f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
610 f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
611 f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
612 f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
613
614 dump_attributes(f, indent + " ", cell->attributes);
615 if (cell->type != "$pmux_safe" && !noattr)
616 f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
617 f << stringf("%s" " casez (s)", indent.c_str());
618 if (cell->type != "$pmux_safe")
619 f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
620
621 for (int i = 0; i < s_width; i++)
622 {
623 f << stringf("%s" " %d'b", indent.c_str(), s_width);
624
625 for (int j = s_width-1; j >= 0; j--)
626 f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
627
628 f << stringf(":\n");
629 f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
630 }
631
632 f << stringf("%s" " default:\n", indent.c_str());
633 f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str());
634
635 f << stringf("%s" " endcase\n", indent.c_str());
636 f << stringf("%s" "endfunction\n", indent.c_str());
637
638 f << stringf("%s" "assign ", indent.c_str());
639 dump_sigspec(f, cell->getPort("\\Y"));
640 f << stringf(" = %s(", func_name.c_str());
641 dump_sigspec(f, cell->getPort("\\A"));
642 f << stringf(", ");
643 dump_sigspec(f, cell->getPort("\\B"));
644 f << stringf(", ");
645 dump_sigspec(f, cell->getPort("\\S"));
646 f << stringf(");\n");
647 return true;
648 }
649
650 if (cell->type == "$slice")
651 {
652 f << stringf("%s" "assign ", indent.c_str());
653 dump_sigspec(f, cell->getPort("\\Y"));
654 f << stringf(" = ");
655 dump_sigspec(f, cell->getPort("\\A"));
656 f << stringf(" >> %d;\n", cell->parameters.at("\\OFFSET").as_int());
657 return true;
658 }
659
660 if (cell->type == "$concat")
661 {
662 f << stringf("%s" "assign ", indent.c_str());
663 dump_sigspec(f, cell->getPort("\\Y"));
664 f << stringf(" = { ");
665 dump_sigspec(f, cell->getPort("\\B"));
666 f << stringf(" , ");
667 dump_sigspec(f, cell->getPort("\\A"));
668 f << stringf(" };\n");
669 return true;
670 }
671
672 if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
673 {
674 RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
675 bool pol_clk, pol_arst = false, pol_en = false;
676
677 sig_clk = cell->getPort("\\CLK");
678 pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
679
680 if (cell->type == "$adff") {
681 sig_arst = cell->getPort("\\ARST");
682 pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool();
683 val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
684 }
685
686 if (cell->type == "$dffe") {
687 sig_en = cell->getPort("\\EN");
688 pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
689 }
690
691 std::string reg_name = cellname(cell);
692 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
693
694 if (!out_is_reg_wire)
695 f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
696
697 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
698 dump_sigspec(f, sig_clk);
699 if (cell->type == "$adff") {
700 f << stringf(" or %sedge ", pol_arst ? "pos" : "neg");
701 dump_sigspec(f, sig_arst);
702 }
703 f << stringf(")\n");
704
705 if (cell->type == "$adff") {
706 f << stringf("%s" " if (%s", indent.c_str(), pol_arst ? "" : "!");
707 dump_sigspec(f, sig_arst);
708 f << stringf(")\n");
709 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
710 dump_sigspec(f, val_arst);
711 f << stringf(";\n");
712 f << stringf("%s" " else\n", indent.c_str());
713 }
714
715 if (cell->type == "$dffe") {
716 f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
717 dump_sigspec(f, sig_en);
718 f << stringf(")\n");
719 }
720
721 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
722 dump_cell_expr_port(f, cell, "D", false);
723 f << stringf(";\n");
724
725 if (!out_is_reg_wire) {
726 f << stringf("%s" "assign ", indent.c_str());
727 dump_sigspec(f, cell->getPort("\\Q"));
728 f << stringf(" = %s;\n", reg_name.c_str());
729 }
730
731 return true;
732 }
733
734 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
735 // FIXME: $sr, $dffsr, $dlatch, $memrd, $memwr, $mem, $fsm
736
737 return false;
738 }
739
740 void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
741 {
742 if (cell->type[0] == '$' && !noexpr) {
743 if (dump_cell_expr(f, indent, cell))
744 return;
745 }
746
747 dump_attributes(f, indent, cell->attributes);
748 f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
749
750 if (cell->parameters.size() > 0) {
751 f << stringf(" #(");
752 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
753 if (it != cell->parameters.begin())
754 f << stringf(",");
755 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
756 bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
757 dump_const(f, it->second, -1, 0, false, is_signed);
758 f << stringf(")");
759 }
760 f << stringf("\n%s" ")", indent.c_str());
761 }
762
763 std::string cell_name = cellname(cell);
764 if (cell_name != id(cell->name))
765 f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
766 else
767 f << stringf(" %s (", cell_name.c_str());
768
769 bool first_arg = true;
770 std::set<RTLIL::IdString> numbered_ports;
771 for (int i = 1; true; i++) {
772 char str[16];
773 snprintf(str, 16, "$%d", i);
774 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
775 if (it->first != str)
776 continue;
777 if (!first_arg)
778 f << stringf(",");
779 first_arg = false;
780 f << stringf("\n%s ", indent.c_str());
781 dump_sigspec(f, it->second);
782 numbered_ports.insert(it->first);
783 goto found_numbered_port;
784 }
785 break;
786 found_numbered_port:;
787 }
788 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
789 if (numbered_ports.count(it->first))
790 continue;
791 if (!first_arg)
792 f << stringf(",");
793 first_arg = false;
794 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
795 if (it->second.size() > 0)
796 dump_sigspec(f, it->second);
797 f << stringf(")");
798 }
799 f << stringf("\n%s" ");\n", indent.c_str());
800 }
801
802 void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
803 {
804 f << stringf("%s" "assign ", indent.c_str());
805 dump_sigspec(f, left);
806 f << stringf(" = ");
807 dump_sigspec(f, right);
808 f << stringf(";\n");
809 }
810
811 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
812
813 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
814 {
815 int number_of_stmts = cs->switches.size() + cs->actions.size();
816
817 if (!omit_trailing_begin && number_of_stmts >= 2)
818 f << stringf("%s" "begin\n", indent.c_str());
819
820 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
821 if (it->first.size() == 0)
822 continue;
823 f << stringf("%s ", indent.c_str());
824 dump_sigspec(f, it->first);
825 f << stringf(" = ");
826 dump_sigspec(f, it->second);
827 f << stringf(";\n");
828 }
829
830 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
831 dump_proc_switch(f, indent + " ", *it);
832
833 if (!omit_trailing_begin && number_of_stmts == 0)
834 f << stringf("%s /* empty */;\n", indent.c_str());
835
836 if (omit_trailing_begin || number_of_stmts >= 2)
837 f << stringf("%s" "end\n", indent.c_str());
838 }
839
840 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
841 {
842 if (sw->signal.size() == 0) {
843 f << stringf("%s" "begin\n", indent.c_str());
844 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
845 if ((*it)->compare.size() == 0)
846 dump_case_body(f, indent + " ", *it);
847 }
848 f << stringf("%s" "end\n", indent.c_str());
849 return;
850 }
851
852 f << stringf("%s" "casez (", indent.c_str());
853 dump_sigspec(f, sw->signal);
854 f << stringf(")\n");
855
856 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
857 f << stringf("%s ", indent.c_str());
858 if ((*it)->compare.size() == 0)
859 f << stringf("default");
860 else {
861 for (size_t i = 0; i < (*it)->compare.size(); i++) {
862 if (i > 0)
863 f << stringf(", ");
864 dump_sigspec(f, (*it)->compare[i]);
865 }
866 }
867 f << stringf(":\n");
868 dump_case_body(f, indent + " ", *it);
869 }
870
871 f << stringf("%s" "endcase\n", indent.c_str());
872 }
873
874 void case_body_find_regs(RTLIL::CaseRule *cs)
875 {
876 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
877 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
878 case_body_find_regs(*it2);
879
880 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
881 for (auto &c : it->first.chunks())
882 if (c.wire != NULL)
883 reg_wires.insert(c.wire->name);
884 }
885 }
886
887 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
888 {
889 if (find_regs) {
890 case_body_find_regs(&proc->root_case);
891 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
892 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
893 for (auto &c : it2->first.chunks())
894 if (c.wire != NULL)
895 reg_wires.insert(c.wire->name);
896 }
897 return;
898 }
899
900 f << stringf("%s" "always @* begin\n", indent.c_str());
901 dump_case_body(f, indent, &proc->root_case, true);
902
903 std::string backup_indent = indent;
904
905 for (size_t i = 0; i < proc->syncs.size(); i++)
906 {
907 RTLIL::SyncRule *sync = proc->syncs[i];
908 indent = backup_indent;
909
910 if (sync->type == RTLIL::STa) {
911 f << stringf("%s" "always @* begin\n", indent.c_str());
912 } else {
913 f << stringf("%s" "always @(", indent.c_str());
914 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
915 f << stringf("posedge ");
916 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
917 f << stringf("negedge ");
918 dump_sigspec(f, sync->signal);
919 f << stringf(") begin\n");
920 }
921 std::string ends = indent + "end\n";
922 indent += " ";
923
924 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
925 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
926 dump_sigspec(f, sync->signal);
927 f << stringf(") begin\n");
928 ends = indent + "end\n" + ends;
929 indent += " ";
930 }
931
932 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
933 for (size_t j = 0; j < proc->syncs.size(); j++) {
934 RTLIL::SyncRule *sync2 = proc->syncs[j];
935 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
936 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
937 dump_sigspec(f, sync2->signal);
938 f << stringf(") begin\n");
939 ends = indent + "end\n" + ends;
940 indent += " ";
941 }
942 }
943 }
944
945 for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
946 if (it->first.size() == 0)
947 continue;
948 f << stringf("%s ", indent.c_str());
949 dump_sigspec(f, it->first);
950 f << stringf(" <= ");
951 dump_sigspec(f, it->second);
952 f << stringf(";\n");
953 }
954
955 f << stringf("%s", ends.c_str());
956 }
957 }
958
959 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
960 {
961 reg_wires.clear();
962 reset_auto_counter(module);
963 active_module = module;
964
965 f << stringf("\n");
966 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
967 dump_process(f, indent + " ", it->second, true);
968
969 if (!noexpr)
970 {
971 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
972 for (auto &it : module->cells_)
973 {
974 RTLIL::Cell *cell = it.second;
975 if (!reg_ct.count(cell->type) || !cell->hasPort("\\Q"))
976 continue;
977
978 RTLIL::SigSpec sig = cell->getPort("\\Q");
979
980 if (sig.is_chunk()) {
981 RTLIL::SigChunk chunk = sig.as_chunk();
982 if (chunk.wire != NULL)
983 for (int i = 0; i < chunk.width; i++)
984 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
985 }
986 }
987 for (auto &it : module->wires_)
988 {
989 RTLIL::Wire *wire = it.second;
990 for (int i = 0; i < wire->width; i++)
991 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
992 goto this_wire_aint_reg;
993 if (wire->width)
994 reg_wires.insert(wire->name);
995 this_wire_aint_reg:;
996 }
997 }
998
999 dump_attributes(f, indent, module->attributes, '\n', true);
1000 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
1001 bool keep_running = true;
1002 for (int port_id = 1; keep_running; port_id++) {
1003 keep_running = false;
1004 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) {
1005 RTLIL::Wire *wire = it->second;
1006 if (wire->port_id == port_id) {
1007 if (port_id != 1)
1008 f << stringf(", ");
1009 f << stringf("%s", id(wire->name).c_str());
1010 keep_running = true;
1011 continue;
1012 }
1013 }
1014 }
1015 f << stringf(");\n");
1016
1017 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
1018 dump_wire(f, indent + " ", it->second);
1019
1020 for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
1021 dump_memory(f, indent + " ", it->second);
1022
1023 for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
1024 dump_cell(f, indent + " ", it->second);
1025
1026 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1027 dump_process(f, indent + " ", it->second);
1028
1029 for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
1030 dump_conn(f, indent + " ", it->first, it->second);
1031
1032 f << stringf("%s" "endmodule\n", indent.c_str());
1033 active_module = NULL;
1034 }
1035
1036 struct VerilogBackend : public Backend {
1037 VerilogBackend() : Backend("verilog", "write design to verilog file") { }
1038 virtual void help()
1039 {
1040 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1041 log("\n");
1042 log(" write_verilog [options] [filename]\n");
1043 log("\n");
1044 log("Write the current design to a verilog file.\n");
1045 log("\n");
1046 log(" -norename\n");
1047 log(" without this option all internal object names (the ones with a dollar\n");
1048 log(" instead of a backslash prefix) are changed to short names in the\n");
1049 log(" format '_<number>_'.\n");
1050 log("\n");
1051 log(" -noattr\n");
1052 log(" with this option no attributes are included in the output\n");
1053 log("\n");
1054 log(" -attr2comment\n");
1055 log(" with this option attributes are included as comments in the output\n");
1056 log("\n");
1057 log(" -noexpr\n");
1058 log(" without this option all internal cells are converted to verilog\n");
1059 log(" expressions.\n");
1060 log("\n");
1061 log(" -blackboxes\n");
1062 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1063 log(" this option set only the modules with the 'blackbox' attribute\n");
1064 log(" are written to the output file.\n");
1065 log("\n");
1066 log(" -selected\n");
1067 log(" only write selected modules. modules must be selected entirely or\n");
1068 log(" not at all.\n");
1069 log("\n");
1070 }
1071 virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
1072 {
1073 log_header("Executing Verilog backend.\n");
1074
1075 norename = false;
1076 noattr = false;
1077 attr2comment = false;
1078 noexpr = false;
1079
1080 bool blackboxes = false;
1081 bool selected = false;
1082
1083 reg_ct.clear();
1084
1085 reg_ct.insert("$dff");
1086 reg_ct.insert("$adff");
1087
1088 reg_ct.insert("$_DFF_N_");
1089 reg_ct.insert("$_DFF_P_");
1090
1091 reg_ct.insert("$_DFF_NN0_");
1092 reg_ct.insert("$_DFF_NN1_");
1093 reg_ct.insert("$_DFF_NP0_");
1094 reg_ct.insert("$_DFF_NP1_");
1095 reg_ct.insert("$_DFF_PN0_");
1096 reg_ct.insert("$_DFF_PN1_");
1097 reg_ct.insert("$_DFF_PP0_");
1098 reg_ct.insert("$_DFF_PP1_");
1099
1100 reg_ct.insert("$_DFFSR_NNN_");
1101 reg_ct.insert("$_DFFSR_NNP_");
1102 reg_ct.insert("$_DFFSR_NPN_");
1103 reg_ct.insert("$_DFFSR_NPP_");
1104 reg_ct.insert("$_DFFSR_PNN_");
1105 reg_ct.insert("$_DFFSR_PNP_");
1106 reg_ct.insert("$_DFFSR_PPN_");
1107 reg_ct.insert("$_DFFSR_PPP_");
1108
1109 size_t argidx;
1110 for (argidx = 1; argidx < args.size(); argidx++) {
1111 std::string arg = args[argidx];
1112 if (arg == "-norename") {
1113 norename = true;
1114 continue;
1115 }
1116 if (arg == "-noattr") {
1117 noattr = true;
1118 continue;
1119 }
1120 if (arg == "-attr2comment") {
1121 attr2comment = true;
1122 continue;
1123 }
1124 if (arg == "-noexpr") {
1125 noexpr = true;
1126 continue;
1127 }
1128 if (arg == "-blackboxes") {
1129 blackboxes = true;
1130 continue;
1131 }
1132 if (arg == "-selected") {
1133 selected = true;
1134 continue;
1135 }
1136 break;
1137 }
1138 extra_args(f, filename, args, argidx);
1139
1140 *f << stringf("/* Generated by %s */\n", yosys_version_str);
1141 for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
1142 if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
1143 continue;
1144 if (selected && !design->selected_whole_module(it->first)) {
1145 if (design->selected_module(it->first))
1146 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it->first));
1147 continue;
1148 }
1149 log("Dumping module `%s'.\n", it->first.c_str());
1150 dump_module(*f, "", it->second);
1151 }
1152
1153 reg_ct.clear();
1154 }
1155 } VerilogBackend;
1156
1157 PRIVATE_NAMESPACE_END