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