Fixed bug in $mem cell verilog code generation.
[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 "kernel/sigtools.h"
33 #include <string>
34 #include <sstream>
35 #include <set>
36 #include <map>
37 #include <ctime>
38
39 USING_YOSYS_NAMESPACE
40 PRIVATE_NAMESPACE_BEGIN
41
42 bool norename, noattr, attr2comment, noexpr;
43 int auto_name_counter, auto_name_offset, auto_name_digits;
44 std::map<RTLIL::IdString, int> auto_name_map;
45 std::set<RTLIL::IdString> reg_wires, reg_ct;
46
47 RTLIL::Module *active_module;
48
49 void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
50 {
51 const char *str = id.c_str();
52
53 if (*str == '$' && may_rename && !norename)
54 auto_name_map[id] = auto_name_counter++;
55
56 if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
57 return;
58
59 for (int i = 2; str[i] != 0; i++) {
60 if (str[i] == '_' && str[i+1] == 0)
61 continue;
62 if (str[i] < '0' || str[i] > '9')
63 return;
64 }
65
66 int num = atoi(str+2);
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(RTLIL::IdString 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 if (!sig.is_chunk() || sig.as_chunk().wire == NULL)
137 return false;
138
139 RTLIL::SigChunk chunk = sig.as_chunk();
140
141 if (reg_wires.count(chunk.wire->name) == 0)
142 return false;
143
144 reg_name = id(chunk.wire->name);
145 if (sig.size() != chunk.wire->width) {
146 if (sig.size() == 1)
147 reg_name += stringf("[%d]", chunk.wire->start_offset + chunk.offset);
148 else
149 reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1,
150 chunk.wire->start_offset + chunk.offset);
151 }
152
153 return true;
154 }
155
156 void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false, bool escape_comment = false)
157 {
158 if (width < 0)
159 width = data.bits.size() - offset;
160 if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
161 if (width == 32 && !no_decimal) {
162 int32_t val = 0;
163 for (int i = offset+width-1; i >= offset; i--) {
164 log_assert(i < (int)data.bits.size());
165 if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
166 goto dump_bits;
167 if (data.bits[i] == RTLIL::S1 && (i - offset) == 31)
168 goto dump_bits;
169 if (data.bits[i] == RTLIL::S1)
170 val |= 1 << (i - offset);
171 }
172 f << stringf("32'%sd %d", set_signed ? "s" : "", val);
173 } else {
174 dump_bits:
175 f << stringf("%d'%sb", width, set_signed ? "s" : "");
176 if (width == 0)
177 f << stringf("0");
178 for (int i = offset+width-1; i >= offset; i--) {
179 log_assert(i < (int)data.bits.size());
180 switch (data.bits[i]) {
181 case RTLIL::S0: f << stringf("0"); break;
182 case RTLIL::S1: f << stringf("1"); break;
183 case RTLIL::Sx: f << stringf("x"); break;
184 case RTLIL::Sz: f << stringf("z"); break;
185 case RTLIL::Sa: f << stringf("z"); break;
186 case RTLIL::Sm: log_error("Found marker state in final netlist.");
187 }
188 }
189 }
190 } else {
191 f << stringf("\"");
192 std::string str = data.decode_string();
193 for (size_t i = 0; i < str.size(); i++) {
194 if (str[i] == '\n')
195 f << stringf("\\n");
196 else if (str[i] == '\t')
197 f << stringf("\\t");
198 else if (str[i] < 32)
199 f << stringf("\\%03o", str[i]);
200 else if (str[i] == '"')
201 f << stringf("\\\"");
202 else if (str[i] == '\\')
203 f << stringf("\\\\");
204 else if (str[i] == '/' && escape_comment && i > 0 && str[i-1] == '*')
205 f << stringf("\\/");
206 else
207 f << str[i];
208 }
209 f << stringf("\"");
210 }
211 }
212
213 void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
214 {
215 if (chunk.wire == NULL) {
216 dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal);
217 } else {
218 if (chunk.width == chunk.wire->width && chunk.offset == 0) {
219 f << stringf("%s", id(chunk.wire->name).c_str());
220 } else if (chunk.width == 1) {
221 if (chunk.wire->upto)
222 f << stringf("%s[%d]", id(chunk.wire->name).c_str(), (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
223 else
224 f << stringf("%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset);
225 } else {
226 if (chunk.wire->upto)
227 f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
228 (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset,
229 (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
230 else
231 f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
232 (chunk.offset + chunk.width - 1) + chunk.wire->start_offset,
233 chunk.offset + chunk.wire->start_offset);
234 }
235 }
236 }
237
238 void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
239 {
240 if (sig.is_chunk()) {
241 dump_sigchunk(f, sig.as_chunk());
242 } else {
243 f << stringf("{ ");
244 for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
245 if (it != sig.chunks().rbegin())
246 f << stringf(", ");
247 dump_sigchunk(f, *it, true);
248 }
249 f << stringf(" }");
250 }
251 }
252
253 void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false)
254 {
255 if (noattr)
256 return;
257 for (auto it = attributes.begin(); it != attributes.end(); ++it) {
258 f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
259 f << stringf(" = ");
260 if (modattr && (it->second == Const(0, 1) || it->second == Const(0)))
261 f << stringf(" 0 ");
262 else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
263 f << stringf(" 1 ");
264 else
265 dump_const(f, it->second, -1, 0, false, false, attr2comment);
266 f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
267 }
268 }
269
270 void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
271 {
272 dump_attributes(f, indent, wire->attributes);
273 #if 0
274 if (wire->port_input && !wire->port_output)
275 f << stringf("%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
276 else if (!wire->port_input && wire->port_output)
277 f << stringf("%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
278 else if (wire->port_input && wire->port_output)
279 f << stringf("%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
280 else
281 f << stringf("%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire");
282 if (wire->width != 1)
283 f << stringf("[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset);
284 f << stringf("%s;\n", id(wire->name).c_str());
285 #else
286 // do not use Verilog-2k "outut reg" syntax in verilog export
287 std::string range = "";
288 if (wire->width != 1) {
289 if (wire->upto)
290 range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
291 else
292 range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
293 }
294 if (wire->port_input && !wire->port_output)
295 f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
296 if (!wire->port_input && wire->port_output)
297 f << stringf("%s" "output%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
298 if (wire->port_input && wire->port_output)
299 f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
300 if (reg_wires.count(wire->name)) {
301 f << stringf("%s" "reg%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
302 if (wire->attributes.count("\\init")) {
303 f << stringf("%s" "initial %s = ", indent.c_str(), id(wire->name).c_str());
304 dump_const(f, wire->attributes.at("\\init"));
305 f << stringf(";\n");
306 }
307 } else if (!wire->port_input && !wire->port_output)
308 f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
309 #endif
310 }
311
312 void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory)
313 {
314 dump_attributes(f, indent, memory->attributes);
315 f << stringf("%s" "reg [%d:0] %s [%d:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
316 }
317
318 void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
319 {
320 if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) {
321 f << stringf("$signed(");
322 dump_sigspec(f, cell->getPort("\\" + port));
323 f << stringf(")");
324 } else
325 dump_sigspec(f, cell->getPort("\\" + port));
326 }
327
328 std::string cellname(RTLIL::Cell *cell)
329 {
330 if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q"))
331 {
332 RTLIL::SigSpec sig = cell->getPort("\\Q");
333 if (GetSize(sig) != 1 || sig.is_fully_const())
334 goto no_special_reg_name;
335
336 RTLIL::Wire *wire = sig[0].wire;
337
338 if (wire->name[0] != '\\')
339 goto no_special_reg_name;
340
341 std::string cell_name = wire->name.str();
342
343 size_t pos = cell_name.find('[');
344 if (pos != std::string::npos)
345 cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos);
346 else
347 cell_name = cell_name + "_reg";
348
349 if (wire->width != 1)
350 cell_name += stringf("[%d]", wire->start_offset + sig[0].offset);
351
352 if (active_module && active_module->count_id(cell_name) > 0)
353 goto no_special_reg_name;
354
355 return id(cell_name);
356 }
357 else
358 {
359 no_special_reg_name:
360 return id(cell->name).c_str();
361 }
362 }
363
364 void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
365 {
366 f << stringf("%s" "assign ", indent.c_str());
367 dump_sigspec(f, cell->getPort("\\Y"));
368 f << stringf(" = %s ", op.c_str());
369 dump_attributes(f, "", cell->attributes, ' ');
370 dump_cell_expr_port(f, cell, "A", true);
371 f << stringf(";\n");
372 }
373
374 void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
375 {
376 f << stringf("%s" "assign ", indent.c_str());
377 dump_sigspec(f, cell->getPort("\\Y"));
378 f << stringf(" = ");
379 dump_cell_expr_port(f, cell, "A", true);
380 f << stringf(" %s ", op.c_str());
381 dump_attributes(f, "", cell->attributes, ' ');
382 dump_cell_expr_port(f, cell, "B", true);
383 f << stringf(";\n");
384 }
385
386 bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
387 {
388 if (cell->type == "$_NOT_") {
389 f << stringf("%s" "assign ", indent.c_str());
390 dump_sigspec(f, cell->getPort("\\Y"));
391 f << stringf(" = ");
392 f << stringf("~");
393 dump_attributes(f, "", cell->attributes, ' ');
394 dump_cell_expr_port(f, cell, "A", false);
395 f << stringf(";\n");
396 return true;
397 }
398
399 if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) {
400 f << stringf("%s" "assign ", indent.c_str());
401 dump_sigspec(f, cell->getPort("\\Y"));
402 f << stringf(" = ");
403 if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
404 f << stringf("~(");
405 dump_cell_expr_port(f, cell, "A", false);
406 f << stringf(" ");
407 if (cell->type.in("$_AND_", "$_NAND_"))
408 f << stringf("&");
409 if (cell->type.in("$_OR_", "$_NOR_"))
410 f << stringf("|");
411 if (cell->type.in("$_XOR_", "$_XNOR_"))
412 f << stringf("^");
413 dump_attributes(f, "", cell->attributes, ' ');
414 f << stringf(" ");
415 dump_cell_expr_port(f, cell, "B", false);
416 if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
417 f << stringf(")");
418 f << stringf(";\n");
419 return true;
420 }
421
422 if (cell->type == "$_MUX_") {
423 f << stringf("%s" "assign ", indent.c_str());
424 dump_sigspec(f, cell->getPort("\\Y"));
425 f << stringf(" = ");
426 dump_cell_expr_port(f, cell, "S", false);
427 f << stringf(" ? ");
428 dump_attributes(f, "", cell->attributes, ' ');
429 dump_cell_expr_port(f, cell, "B", false);
430 f << stringf(" : ");
431 dump_cell_expr_port(f, cell, "A", false);
432 f << stringf(";\n");
433 return true;
434 }
435
436 if (cell->type.in("$_AOI3_", "$_OAI3_")) {
437 f << stringf("%s" "assign ", indent.c_str());
438 dump_sigspec(f, cell->getPort("\\Y"));
439 f << stringf(" = ~((");
440 dump_cell_expr_port(f, cell, "A", false);
441 f << stringf(cell->type == "$_AOI3_" ? " & " : " | ");
442 dump_cell_expr_port(f, cell, "B", false);
443 f << stringf(cell->type == "$_AOI3_" ? ") |" : ") &");
444 dump_attributes(f, "", cell->attributes, ' ');
445 f << stringf(" ");
446 dump_cell_expr_port(f, cell, "C", false);
447 f << stringf(");\n");
448 return true;
449 }
450
451 if (cell->type.in("$_AOI4_", "$_OAI4_")) {
452 f << stringf("%s" "assign ", indent.c_str());
453 dump_sigspec(f, cell->getPort("\\Y"));
454 f << stringf(" = ~((");
455 dump_cell_expr_port(f, cell, "A", false);
456 f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
457 dump_cell_expr_port(f, cell, "B", false);
458 f << stringf(cell->type == "$_AOI4_" ? ") |" : ") &");
459 dump_attributes(f, "", cell->attributes, ' ');
460 f << stringf(" (");
461 dump_cell_expr_port(f, cell, "C", false);
462 f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
463 dump_cell_expr_port(f, cell, "D", false);
464 f << stringf("));\n");
465 return true;
466 }
467
468 if (cell->type.substr(0, 6) == "$_DFF_")
469 {
470 std::string reg_name = cellname(cell);
471 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
472
473 if (!out_is_reg_wire)
474 f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
475
476 dump_attributes(f, indent, cell->attributes);
477 f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
478 dump_sigspec(f, cell->getPort("\\C"));
479 if (cell->type[7] != '_') {
480 f << stringf(" or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
481 dump_sigspec(f, cell->getPort("\\R"));
482 }
483 f << stringf(")\n");
484
485 if (cell->type[7] != '_') {
486 f << stringf("%s" " if (%s", indent.c_str(), cell->type[7] == 'P' ? "" : "!");
487 dump_sigspec(f, cell->getPort("\\R"));
488 f << stringf(")\n");
489 f << stringf("%s" " %s <= %c;\n", indent.c_str(), reg_name.c_str(), cell->type[8]);
490 f << stringf("%s" " else\n", indent.c_str());
491 }
492
493 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
494 dump_cell_expr_port(f, cell, "D", false);
495 f << stringf(";\n");
496
497 if (!out_is_reg_wire) {
498 f << stringf("%s" "assign ", indent.c_str());
499 dump_sigspec(f, cell->getPort("\\Q"));
500 f << stringf(" = %s;\n", reg_name.c_str());
501 }
502
503 return true;
504 }
505
506 if (cell->type.substr(0, 8) == "$_DFFSR_")
507 {
508 char pol_c = cell->type[8], pol_s = cell->type[9], pol_r = cell->type[10];
509
510 std::string reg_name = cellname(cell);
511 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
512
513 if (!out_is_reg_wire)
514 f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
515
516 dump_attributes(f, indent, cell->attributes);
517 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
518 dump_sigspec(f, cell->getPort("\\C"));
519 f << stringf(" or %sedge ", pol_s == 'P' ? "pos" : "neg");
520 dump_sigspec(f, cell->getPort("\\S"));
521 f << stringf(" or %sedge ", pol_r == 'P' ? "pos" : "neg");
522 dump_sigspec(f, cell->getPort("\\R"));
523 f << stringf(")\n");
524
525 f << stringf("%s" " if (%s", indent.c_str(), pol_r == 'P' ? "" : "!");
526 dump_sigspec(f, cell->getPort("\\R"));
527 f << stringf(")\n");
528 f << stringf("%s" " %s <= 0;\n", indent.c_str(), reg_name.c_str());
529
530 f << stringf("%s" " else if (%s", indent.c_str(), pol_s == 'P' ? "" : "!");
531 dump_sigspec(f, cell->getPort("\\S"));
532 f << stringf(")\n");
533 f << stringf("%s" " %s <= 1;\n", indent.c_str(), reg_name.c_str());
534
535 f << stringf("%s" " else\n", indent.c_str());
536 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
537 dump_cell_expr_port(f, cell, "D", false);
538 f << stringf(";\n");
539
540 if (!out_is_reg_wire) {
541 f << stringf("%s" "assign ", indent.c_str());
542 dump_sigspec(f, cell->getPort("\\Q"));
543 f << stringf(" = %s;\n", reg_name.c_str());
544 }
545
546 return true;
547 }
548
549 #define HANDLE_UNIOP(_type, _operator) \
550 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
551 #define HANDLE_BINOP(_type, _operator) \
552 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
553
554 HANDLE_UNIOP("$not", "~")
555 HANDLE_UNIOP("$pos", "+")
556 HANDLE_UNIOP("$neg", "-")
557
558 HANDLE_BINOP("$and", "&")
559 HANDLE_BINOP("$or", "|")
560 HANDLE_BINOP("$xor", "^")
561 HANDLE_BINOP("$xnor", "~^")
562
563 HANDLE_UNIOP("$reduce_and", "&")
564 HANDLE_UNIOP("$reduce_or", "|")
565 HANDLE_UNIOP("$reduce_xor", "^")
566 HANDLE_UNIOP("$reduce_xnor", "~^")
567 HANDLE_UNIOP("$reduce_bool", "|")
568
569 HANDLE_BINOP("$shl", "<<")
570 HANDLE_BINOP("$shr", ">>")
571 HANDLE_BINOP("$sshl", "<<<")
572 HANDLE_BINOP("$sshr", ">>>")
573
574 HANDLE_BINOP("$lt", "<")
575 HANDLE_BINOP("$le", "<=")
576 HANDLE_BINOP("$eq", "==")
577 HANDLE_BINOP("$ne", "!=")
578 HANDLE_BINOP("$eqx", "===")
579 HANDLE_BINOP("$nex", "!==")
580 HANDLE_BINOP("$ge", ">=")
581 HANDLE_BINOP("$gt", ">")
582
583 HANDLE_BINOP("$add", "+")
584 HANDLE_BINOP("$sub", "-")
585 HANDLE_BINOP("$mul", "*")
586 HANDLE_BINOP("$div", "/")
587 HANDLE_BINOP("$mod", "%")
588 HANDLE_BINOP("$pow", "**")
589
590 HANDLE_UNIOP("$logic_not", "!")
591 HANDLE_BINOP("$logic_and", "&&")
592 HANDLE_BINOP("$logic_or", "||")
593
594 #undef HANDLE_UNIOP
595 #undef HANDLE_BINOP
596
597 if (cell->type == "$mux")
598 {
599 f << stringf("%s" "assign ", indent.c_str());
600 dump_sigspec(f, cell->getPort("\\Y"));
601 f << stringf(" = ");
602 dump_sigspec(f, cell->getPort("\\S"));
603 f << stringf(" ? ");
604 dump_attributes(f, "", cell->attributes, ' ');
605 dump_sigspec(f, cell->getPort("\\B"));
606 f << stringf(" : ");
607 dump_sigspec(f, cell->getPort("\\A"));
608 f << stringf(";\n");
609 return true;
610 }
611
612 if (cell->type == "$pmux" || cell->type == "$pmux_safe")
613 {
614 int width = cell->parameters["\\WIDTH"].as_int();
615 int s_width = cell->getPort("\\S").size();
616 std::string func_name = cellname(cell);
617
618 f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
619 f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
620 f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
621 f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
622
623 dump_attributes(f, indent + " ", cell->attributes);
624 if (cell->type != "$pmux_safe" && !noattr)
625 f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
626 f << stringf("%s" " casez (s)", indent.c_str());
627 if (cell->type != "$pmux_safe")
628 f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
629
630 for (int i = 0; i < s_width; i++)
631 {
632 f << stringf("%s" " %d'b", indent.c_str(), s_width);
633
634 for (int j = s_width-1; j >= 0; j--)
635 f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
636
637 f << stringf(":\n");
638 f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
639 }
640
641 f << stringf("%s" " default:\n", indent.c_str());
642 f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str());
643
644 f << stringf("%s" " endcase\n", indent.c_str());
645 f << stringf("%s" "endfunction\n", indent.c_str());
646
647 f << stringf("%s" "assign ", indent.c_str());
648 dump_sigspec(f, cell->getPort("\\Y"));
649 f << stringf(" = %s(", func_name.c_str());
650 dump_sigspec(f, cell->getPort("\\A"));
651 f << stringf(", ");
652 dump_sigspec(f, cell->getPort("\\B"));
653 f << stringf(", ");
654 dump_sigspec(f, cell->getPort("\\S"));
655 f << stringf(");\n");
656 return true;
657 }
658
659 if (cell->type == "$slice")
660 {
661 f << stringf("%s" "assign ", indent.c_str());
662 dump_sigspec(f, cell->getPort("\\Y"));
663 f << stringf(" = ");
664 dump_sigspec(f, cell->getPort("\\A"));
665 f << stringf(" >> %d;\n", cell->parameters.at("\\OFFSET").as_int());
666 return true;
667 }
668
669 if (cell->type == "$concat")
670 {
671 f << stringf("%s" "assign ", indent.c_str());
672 dump_sigspec(f, cell->getPort("\\Y"));
673 f << stringf(" = { ");
674 dump_sigspec(f, cell->getPort("\\B"));
675 f << stringf(" , ");
676 dump_sigspec(f, cell->getPort("\\A"));
677 f << stringf(" };\n");
678 return true;
679 }
680
681 if (cell->type == "$dffsr")
682 {
683 SigSpec sig_clk = cell->getPort("\\CLK");
684 SigSpec sig_set = cell->getPort("\\SET");
685 SigSpec sig_clr = cell->getPort("\\CLR");
686 SigSpec sig_d = cell->getPort("\\D");
687 SigSpec sig_q = cell->getPort("\\Q");
688
689 int width = cell->parameters["\\WIDTH"].as_int();
690 bool pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
691 bool pol_set = cell->parameters["\\SET_POLARITY"].as_bool();
692 bool pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool();
693
694 std::string reg_name = cellname(cell);
695 bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
696
697 if (!out_is_reg_wire)
698 f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), width-1, reg_name.c_str());
699
700 for (int i = 0; i < width; i++) {
701 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
702 dump_sigspec(f, sig_clk);
703 f << stringf(", %sedge ", pol_set ? "pos" : "neg");
704 dump_sigspec(f, sig_set);
705 f << stringf(", %sedge ", pol_clr ? "pos" : "neg");
706 dump_sigspec(f, sig_clr);
707 f << stringf(")\n");
708
709 f << stringf("%s" " if (%s", indent.c_str(), pol_clr ? "" : "!");
710 dump_sigspec(f, sig_clr);
711 f << stringf(") %s[%d] <= 1'b0;\n", reg_name.c_str(), i);
712
713 f << stringf("%s" " else if (%s", indent.c_str(), pol_set ? "" : "!");
714 dump_sigspec(f, sig_set);
715 f << stringf(") %s[%d] <= 1'b1;\n", reg_name.c_str(), i);
716
717 f << stringf("%s" " else %s[%d] <= ", indent.c_str(), reg_name.c_str(), i);
718 dump_sigspec(f, sig_d[i]);
719 f << stringf(";\n");
720 }
721
722 if (!out_is_reg_wire) {
723 f << stringf("%s" "assign ", indent.c_str());
724 dump_sigspec(f, sig_q);
725 f << stringf(" = %s;\n", reg_name.c_str());
726 }
727
728 return true;
729 }
730
731 if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
732 {
733 RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
734 bool pol_clk, pol_arst = false, pol_en = false;
735
736 sig_clk = cell->getPort("\\CLK");
737 pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
738
739 if (cell->type == "$adff") {
740 sig_arst = cell->getPort("\\ARST");
741 pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool();
742 val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
743 }
744
745 if (cell->type == "$dffe") {
746 sig_en = cell->getPort("\\EN");
747 pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
748 }
749
750 std::string reg_name = cellname(cell);
751 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
752
753 if (!out_is_reg_wire)
754 f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
755
756 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
757 dump_sigspec(f, sig_clk);
758 if (cell->type == "$adff") {
759 f << stringf(" or %sedge ", pol_arst ? "pos" : "neg");
760 dump_sigspec(f, sig_arst);
761 }
762 f << stringf(")\n");
763
764 if (cell->type == "$adff") {
765 f << stringf("%s" " if (%s", indent.c_str(), pol_arst ? "" : "!");
766 dump_sigspec(f, sig_arst);
767 f << stringf(")\n");
768 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
769 dump_sigspec(f, val_arst);
770 f << stringf(";\n");
771 f << stringf("%s" " else\n", indent.c_str());
772 }
773
774 if (cell->type == "$dffe") {
775 f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
776 dump_sigspec(f, sig_en);
777 f << stringf(")\n");
778 }
779
780 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
781 dump_cell_expr_port(f, cell, "D", false);
782 f << stringf(";\n");
783
784 if (!out_is_reg_wire) {
785 f << stringf("%s" "assign ", indent.c_str());
786 dump_sigspec(f, cell->getPort("\\Q"));
787 f << stringf(" = %s;\n", reg_name.c_str());
788 }
789
790 return true;
791 }
792
793 if (cell->type == "$mem")
794 {
795 RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
796 std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
797 int abits = cell->parameters["\\ABITS"].as_int();
798 int size = cell->parameters["\\SIZE"].as_int();
799 int width = cell->parameters["\\WIDTH"].as_int();
800 int offset = cell->parameters["\\OFFSET"].as_int();
801 bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef());
802
803 // for memory block make something like:
804 // reg [7:0] memid [3:0];
805 // initial begin
806 // memid[0] <= ...
807 // end
808 int mem_val;
809 RTLIL::Memory memory;
810 memory.name = memid;
811 memory.width = width;
812 memory.start_offset = offset;
813 memory.size = size;
814 dump_memory(f, indent.c_str(), &memory);
815 if (use_init)
816 {
817 f << stringf("%s" "initial begin\n", indent.c_str());
818 for (int i=0; i<size; i++)
819 {
820 mem_val = cell->parameters["\\INIT"].extract(i*width, width).as_int();
821 f << stringf("%s" " %s[%d] <= %d'd%d;\n", indent.c_str(), mem_id.c_str(), i, width, mem_val);
822 }
823 f << stringf("%s" "end\n", indent.c_str());
824 }
825
826 int nread_ports = cell->parameters["\\RD_PORTS"].as_int();
827 RTLIL::SigSpec sig_rd_clk, sig_rd_data, sig_rd_addr;
828 bool use_rd_clk, rd_clk_posedge, rd_transparent;
829 RTLIL::IdString new_id;
830 // read ports
831 for (int i=0; i < nread_ports; i++)
832 {
833 sig_rd_clk = cell->getPort("\\RD_CLK").extract(i);
834 sig_rd_data = cell->getPort("\\RD_DATA").extract(i*width, width);
835 sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
836 use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
837 rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
838 rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
839 if (use_rd_clk && !rd_transparent)
840 {
841 // for clocked read ports make something like:
842 // always @(posedge clk)
843 // r_data <= array_reg[r_addr];
844 f << stringf("%s" "always @(%sedge ", indent.c_str(), rd_clk_posedge ? "pos" : "neg");
845 dump_sigspec(f, sig_rd_clk);
846 f << stringf(")\n");
847 f << stringf("%s" " ", indent.c_str());
848 dump_sigspec(f, sig_rd_data);
849 f << stringf(" <= %s[", mem_id.c_str());
850 dump_sigspec(f, sig_rd_addr);
851 f << stringf("];\n");
852 } else {
853 if (rd_transparent) {
854 // for rd-transparent read-ports make something like:
855 // reg [..] new-id;
856 // always @(posedge clk)
857 // new-id <= r_addr;
858 // assign r_data = array_reg[new-id];
859 new_id = RTLIL::IdString(stringf("$%d", (int)time(NULL)));
860 reset_auto_counter_id(new_id, true);
861 f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), sig_rd_addr.size() - 1, id(new_id).c_str());
862 f << stringf("%s" "always @(%sedge ", indent.c_str(), rd_clk_posedge ? "pos" : "neg");
863 dump_sigspec(f, sig_rd_clk);
864 f << stringf(")\n");
865 f << stringf("%s" " %s <= ", indent.c_str(), id(new_id).c_str());
866 dump_sigspec(f, sig_rd_addr);
867 f << stringf(";\n");
868 f << stringf("%s" "assign ", indent.c_str());
869 dump_sigspec(f, sig_rd_data);
870 f << stringf(" = %s[%s];\n", mem_id.c_str(), id(new_id).c_str());
871 } else {
872 // for non-clocked read-ports make something like:
873 // assign r_data = array_reg[r_addr];
874 f << stringf("%s" "assign ", indent.c_str());
875 dump_sigspec(f, sig_rd_data);
876 f << stringf(" = %s[", mem_id.c_str());
877 dump_sigspec(f, sig_rd_addr);
878 f << stringf("];\n");
879 }
880 }
881 }
882
883 int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
884 RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en, sig_wr_en_bit;
885 RTLIL::SigBit last_bit, current_bit;
886 bool wr_clk_posedge;
887 RTLIL::SigSpec lof_wen;
888 dict<RTLIL::SigSpec, int> wen_to_width;
889 SigMap sigmap(active_module);
890 int n, wen_width;
891 // write ports
892 for (int i=0; i < nwrite_ports; i++)
893 {
894 // for write-ports make something like:
895 // always @(posedge clk)
896 // if (wr_en)
897 // memid[w_addr] <= w_data;
898 sig_wr_clk = cell->getPort("\\WR_CLK").extract(i);
899 sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width);
900 sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits);
901 sig_wr_en = cell->getPort("\\WR_EN").extract(i*width, width);
902 sig_wr_en_bit = sig_wr_en.extract(0);
903 wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool();
904 // group the wen bits
905 last_bit = sig_wr_en.extract(0);
906 lof_wen = RTLIL::SigSpec(last_bit);
907 wen_to_width.clear();
908 wen_to_width[last_bit] = 0;
909 for (int j=0; j<width; j++)
910 {
911 current_bit = sig_wr_en.extract(j);
912 if (sigmap(current_bit) == sigmap(last_bit)){
913 wen_to_width[current_bit] += 1;
914 } else {
915 lof_wen.append_bit(current_bit);
916 wen_to_width[current_bit] = 1;
917 }
918 last_bit = current_bit;
919 }
920 // make something like:
921 // always @(posedge clk)
922 // if (wr_en_bit)
923 // memid[w_addr][??] <= w_data[??];
924 // ...
925 n = 0;
926 for (auto &wen_bit : lof_wen) {
927 wen_width = wen_to_width[wen_bit];
928 if (!(wen_bit == RTLIL::SigBit(false)))
929 {
930 f << stringf("%s" "always @(%sedge ", indent.c_str(), wr_clk_posedge ? "pos" : "neg");
931 dump_sigspec(f, sig_wr_clk);
932 f << stringf(")\n");
933 if (!(wen_bit == RTLIL::SigBit(true)))
934 {
935 f << stringf("%s" " if (", indent.c_str());
936 dump_sigspec(f, wen_bit);
937 f << stringf(")\n ");
938 }
939 f << stringf("%s" " %s[", indent.c_str(), mem_id.c_str());
940 dump_sigspec(f, sig_wr_addr);
941 if (wen_width == width)
942 f << stringf("] <= ");
943 else
944 f << stringf("][%d:%d] <= ", n+wen_width-1, n);
945 dump_sigspec(f, sig_wr_data.extract(n, wen_width));
946 f << stringf(";\n");
947 }
948 n += wen_width;
949 }
950 }
951
952 return true;
953 }
954
955 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
956 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
957
958 return false;
959 }
960
961 void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
962 {
963 if (cell->type[0] == '$' && !noexpr) {
964 if (dump_cell_expr(f, indent, cell))
965 return;
966 }
967
968 dump_attributes(f, indent, cell->attributes);
969 f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
970
971 if (cell->parameters.size() > 0) {
972 f << stringf(" #(");
973 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
974 if (it != cell->parameters.begin())
975 f << stringf(",");
976 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
977 bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
978 dump_const(f, it->second, -1, 0, false, is_signed);
979 f << stringf(")");
980 }
981 f << stringf("\n%s" ")", indent.c_str());
982 }
983
984 std::string cell_name = cellname(cell);
985 if (cell_name != id(cell->name))
986 f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
987 else
988 f << stringf(" %s (", cell_name.c_str());
989
990 bool first_arg = true;
991 std::set<RTLIL::IdString> numbered_ports;
992 for (int i = 1; true; i++) {
993 char str[16];
994 snprintf(str, 16, "$%d", i);
995 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
996 if (it->first != str)
997 continue;
998 if (!first_arg)
999 f << stringf(",");
1000 first_arg = false;
1001 f << stringf("\n%s ", indent.c_str());
1002 dump_sigspec(f, it->second);
1003 numbered_ports.insert(it->first);
1004 goto found_numbered_port;
1005 }
1006 break;
1007 found_numbered_port:;
1008 }
1009 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1010 if (numbered_ports.count(it->first))
1011 continue;
1012 if (!first_arg)
1013 f << stringf(",");
1014 first_arg = false;
1015 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1016 if (it->second.size() > 0)
1017 dump_sigspec(f, it->second);
1018 f << stringf(")");
1019 }
1020 f << stringf("\n%s" ");\n", indent.c_str());
1021 }
1022
1023 void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
1024 {
1025 f << stringf("%s" "assign ", indent.c_str());
1026 dump_sigspec(f, left);
1027 f << stringf(" = ");
1028 dump_sigspec(f, right);
1029 f << stringf(";\n");
1030 }
1031
1032 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
1033
1034 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
1035 {
1036 int number_of_stmts = cs->switches.size() + cs->actions.size();
1037
1038 if (!omit_trailing_begin && number_of_stmts >= 2)
1039 f << stringf("%s" "begin\n", indent.c_str());
1040
1041 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1042 if (it->first.size() == 0)
1043 continue;
1044 f << stringf("%s ", indent.c_str());
1045 dump_sigspec(f, it->first);
1046 f << stringf(" = ");
1047 dump_sigspec(f, it->second);
1048 f << stringf(";\n");
1049 }
1050
1051 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1052 dump_proc_switch(f, indent + " ", *it);
1053
1054 if (!omit_trailing_begin && number_of_stmts == 0)
1055 f << stringf("%s /* empty */;\n", indent.c_str());
1056
1057 if (omit_trailing_begin || number_of_stmts >= 2)
1058 f << stringf("%s" "end\n", indent.c_str());
1059 }
1060
1061 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
1062 {
1063 if (sw->signal.size() == 0) {
1064 f << stringf("%s" "begin\n", indent.c_str());
1065 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1066 if ((*it)->compare.size() == 0)
1067 dump_case_body(f, indent + " ", *it);
1068 }
1069 f << stringf("%s" "end\n", indent.c_str());
1070 return;
1071 }
1072
1073 f << stringf("%s" "casez (", indent.c_str());
1074 dump_sigspec(f, sw->signal);
1075 f << stringf(")\n");
1076
1077 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1078 f << stringf("%s ", indent.c_str());
1079 if ((*it)->compare.size() == 0)
1080 f << stringf("default");
1081 else {
1082 for (size_t i = 0; i < (*it)->compare.size(); i++) {
1083 if (i > 0)
1084 f << stringf(", ");
1085 dump_sigspec(f, (*it)->compare[i]);
1086 }
1087 }
1088 f << stringf(":\n");
1089 dump_case_body(f, indent + " ", *it);
1090 }
1091
1092 f << stringf("%s" "endcase\n", indent.c_str());
1093 }
1094
1095 void case_body_find_regs(RTLIL::CaseRule *cs)
1096 {
1097 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1098 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
1099 case_body_find_regs(*it2);
1100
1101 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1102 for (auto &c : it->first.chunks())
1103 if (c.wire != NULL)
1104 reg_wires.insert(c.wire->name);
1105 }
1106 }
1107
1108 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
1109 {
1110 if (find_regs) {
1111 case_body_find_regs(&proc->root_case);
1112 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
1113 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
1114 for (auto &c : it2->first.chunks())
1115 if (c.wire != NULL)
1116 reg_wires.insert(c.wire->name);
1117 }
1118 return;
1119 }
1120
1121 f << stringf("%s" "always @* begin\n", indent.c_str());
1122 dump_case_body(f, indent, &proc->root_case, true);
1123
1124 std::string backup_indent = indent;
1125
1126 for (size_t i = 0; i < proc->syncs.size(); i++)
1127 {
1128 RTLIL::SyncRule *sync = proc->syncs[i];
1129 indent = backup_indent;
1130
1131 if (sync->type == RTLIL::STa) {
1132 f << stringf("%s" "always @* begin\n", indent.c_str());
1133 } else {
1134 f << stringf("%s" "always @(", indent.c_str());
1135 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
1136 f << stringf("posedge ");
1137 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
1138 f << stringf("negedge ");
1139 dump_sigspec(f, sync->signal);
1140 f << stringf(") begin\n");
1141 }
1142 std::string ends = indent + "end\n";
1143 indent += " ";
1144
1145 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
1146 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
1147 dump_sigspec(f, sync->signal);
1148 f << stringf(") begin\n");
1149 ends = indent + "end\n" + ends;
1150 indent += " ";
1151 }
1152
1153 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
1154 for (size_t j = 0; j < proc->syncs.size(); j++) {
1155 RTLIL::SyncRule *sync2 = proc->syncs[j];
1156 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
1157 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
1158 dump_sigspec(f, sync2->signal);
1159 f << stringf(") begin\n");
1160 ends = indent + "end\n" + ends;
1161 indent += " ";
1162 }
1163 }
1164 }
1165
1166 for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
1167 if (it->first.size() == 0)
1168 continue;
1169 f << stringf("%s ", indent.c_str());
1170 dump_sigspec(f, it->first);
1171 f << stringf(" <= ");
1172 dump_sigspec(f, it->second);
1173 f << stringf(";\n");
1174 }
1175
1176 f << stringf("%s", ends.c_str());
1177 }
1178 }
1179
1180 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
1181 {
1182 reg_wires.clear();
1183 reset_auto_counter(module);
1184 active_module = module;
1185
1186 f << stringf("\n");
1187 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1188 dump_process(f, indent + " ", it->second, true);
1189
1190 if (!noexpr)
1191 {
1192 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
1193 for (auto &it : module->cells_)
1194 {
1195 RTLIL::Cell *cell = it.second;
1196 if (!reg_ct.count(cell->type) || !cell->hasPort("\\Q"))
1197 continue;
1198
1199 RTLIL::SigSpec sig = cell->getPort("\\Q");
1200
1201 if (sig.is_chunk()) {
1202 RTLIL::SigChunk chunk = sig.as_chunk();
1203 if (chunk.wire != NULL)
1204 for (int i = 0; i < chunk.width; i++)
1205 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
1206 }
1207 }
1208 for (auto &it : module->wires_)
1209 {
1210 RTLIL::Wire *wire = it.second;
1211 for (int i = 0; i < wire->width; i++)
1212 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
1213 goto this_wire_aint_reg;
1214 if (wire->width)
1215 reg_wires.insert(wire->name);
1216 this_wire_aint_reg:;
1217 }
1218 }
1219
1220 dump_attributes(f, indent, module->attributes, '\n', true);
1221 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
1222 bool keep_running = true;
1223 for (int port_id = 1; keep_running; port_id++) {
1224 keep_running = false;
1225 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) {
1226 RTLIL::Wire *wire = it->second;
1227 if (wire->port_id == port_id) {
1228 if (port_id != 1)
1229 f << stringf(", ");
1230 f << stringf("%s", id(wire->name).c_str());
1231 keep_running = true;
1232 continue;
1233 }
1234 }
1235 }
1236 f << stringf(");\n");
1237
1238 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
1239 dump_wire(f, indent + " ", it->second);
1240
1241 for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
1242 dump_memory(f, indent + " ", it->second);
1243
1244 for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
1245 dump_cell(f, indent + " ", it->second);
1246
1247 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1248 dump_process(f, indent + " ", it->second);
1249
1250 for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
1251 dump_conn(f, indent + " ", it->first, it->second);
1252
1253 f << stringf("%s" "endmodule\n", indent.c_str());
1254 active_module = NULL;
1255 }
1256
1257 struct VerilogBackend : public Backend {
1258 VerilogBackend() : Backend("verilog", "write design to verilog file") { }
1259 virtual void help()
1260 {
1261 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1262 log("\n");
1263 log(" write_verilog [options] [filename]\n");
1264 log("\n");
1265 log("Write the current design to a verilog file.\n");
1266 log("\n");
1267 log(" -norename\n");
1268 log(" without this option all internal object names (the ones with a dollar\n");
1269 log(" instead of a backslash prefix) are changed to short names in the\n");
1270 log(" format '_<number>_'.\n");
1271 log("\n");
1272 log(" -noattr\n");
1273 log(" with this option no attributes are included in the output\n");
1274 log("\n");
1275 log(" -attr2comment\n");
1276 log(" with this option attributes are included as comments in the output\n");
1277 log("\n");
1278 log(" -noexpr\n");
1279 log(" without this option all internal cells are converted to verilog\n");
1280 log(" expressions.\n");
1281 log("\n");
1282 log(" -blackboxes\n");
1283 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1284 log(" this option set only the modules with the 'blackbox' attribute\n");
1285 log(" are written to the output file.\n");
1286 log("\n");
1287 log(" -selected\n");
1288 log(" only write selected modules. modules must be selected entirely or\n");
1289 log(" not at all.\n");
1290 log("\n");
1291 }
1292 virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
1293 {
1294 log_header("Executing Verilog backend.\n");
1295
1296 norename = false;
1297 noattr = false;
1298 attr2comment = false;
1299 noexpr = false;
1300
1301 bool blackboxes = false;
1302 bool selected = false;
1303
1304 reg_ct.clear();
1305
1306 reg_ct.insert("$dff");
1307 reg_ct.insert("$adff");
1308
1309 reg_ct.insert("$_DFF_N_");
1310 reg_ct.insert("$_DFF_P_");
1311
1312 reg_ct.insert("$_DFF_NN0_");
1313 reg_ct.insert("$_DFF_NN1_");
1314 reg_ct.insert("$_DFF_NP0_");
1315 reg_ct.insert("$_DFF_NP1_");
1316 reg_ct.insert("$_DFF_PN0_");
1317 reg_ct.insert("$_DFF_PN1_");
1318 reg_ct.insert("$_DFF_PP0_");
1319 reg_ct.insert("$_DFF_PP1_");
1320
1321 reg_ct.insert("$_DFFSR_NNN_");
1322 reg_ct.insert("$_DFFSR_NNP_");
1323 reg_ct.insert("$_DFFSR_NPN_");
1324 reg_ct.insert("$_DFFSR_NPP_");
1325 reg_ct.insert("$_DFFSR_PNN_");
1326 reg_ct.insert("$_DFFSR_PNP_");
1327 reg_ct.insert("$_DFFSR_PPN_");
1328 reg_ct.insert("$_DFFSR_PPP_");
1329
1330 size_t argidx;
1331 for (argidx = 1; argidx < args.size(); argidx++) {
1332 std::string arg = args[argidx];
1333 if (arg == "-norename") {
1334 norename = true;
1335 continue;
1336 }
1337 if (arg == "-noattr") {
1338 noattr = true;
1339 continue;
1340 }
1341 if (arg == "-attr2comment") {
1342 attr2comment = true;
1343 continue;
1344 }
1345 if (arg == "-noexpr") {
1346 noexpr = true;
1347 continue;
1348 }
1349 if (arg == "-blackboxes") {
1350 blackboxes = true;
1351 continue;
1352 }
1353 if (arg == "-selected") {
1354 selected = true;
1355 continue;
1356 }
1357 break;
1358 }
1359 extra_args(f, filename, args, argidx);
1360
1361 design->sort();
1362
1363 *f << stringf("/* Generated by %s */\n", yosys_version_str);
1364 for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
1365 if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
1366 continue;
1367 if (selected && !design->selected_whole_module(it->first)) {
1368 if (design->selected_module(it->first))
1369 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it->first));
1370 continue;
1371 }
1372 log("Dumping module `%s'.\n", it->first.c_str());
1373 dump_module(*f, "", it->second);
1374 }
1375
1376 reg_ct.clear();
1377 }
1378 } VerilogBackend;
1379
1380 PRIVATE_NAMESPACE_END