Fix handling of partial init attributes in write_verilog, fixes #997
[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 */
23
24 #include "kernel/register.h"
25 #include "kernel/celltypes.h"
26 #include "kernel/log.h"
27 #include "kernel/sigtools.h"
28 #include <string>
29 #include <sstream>
30 #include <set>
31 #include <map>
32
33 USING_YOSYS_NAMESPACE
34 PRIVATE_NAMESPACE_BEGIN
35
36 bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit;
37 int auto_name_counter, auto_name_offset, auto_name_digits;
38 std::map<RTLIL::IdString, int> auto_name_map;
39 std::set<RTLIL::IdString> reg_wires, reg_ct;
40 std::string auto_prefix;
41
42 RTLIL::Module *active_module;
43 dict<RTLIL::SigBit, RTLIL::State> active_initdata;
44 SigMap active_sigmap;
45
46 void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
47 {
48 const char *str = id.c_str();
49
50 if (*str == '$' && may_rename && !norename)
51 auto_name_map[id] = auto_name_counter++;
52
53 if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
54 return;
55
56 for (int i = 2; str[i] != 0; i++) {
57 if (str[i] == '_' && str[i+1] == 0)
58 continue;
59 if (str[i] < '0' || str[i] > '9')
60 return;
61 }
62
63 int num = atoi(str+2);
64 if (num >= auto_name_offset)
65 auto_name_offset = num + 1;
66 }
67
68 void reset_auto_counter(RTLIL::Module *module)
69 {
70 auto_name_map.clear();
71 auto_name_counter = 0;
72 auto_name_offset = 0;
73
74 reset_auto_counter_id(module->name, false);
75
76 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
77 reset_auto_counter_id(it->second->name, true);
78
79 for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it) {
80 reset_auto_counter_id(it->second->name, true);
81 reset_auto_counter_id(it->second->type, false);
82 }
83
84 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
85 reset_auto_counter_id(it->second->name, false);
86
87 auto_name_digits = 1;
88 for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
89 auto_name_digits++;
90
91 if (verbose)
92 for (auto it = auto_name_map.begin(); it != auto_name_map.end(); ++it)
93 log(" renaming `%s' to `%s_%0*d_'.\n", it->first.c_str(), auto_prefix.c_str(), auto_name_digits, auto_name_offset + it->second);
94 }
95
96 std::string next_auto_id()
97 {
98 return stringf("%s_%0*d_", auto_prefix.c_str(), auto_name_digits, auto_name_offset + auto_name_counter++);
99 }
100
101 std::string id(RTLIL::IdString internal_id, bool may_rename = true)
102 {
103 const char *str = internal_id.c_str();
104 bool do_escape = false;
105
106 if (may_rename && auto_name_map.count(internal_id) != 0)
107 return stringf("%s_%0*d_", auto_prefix.c_str(), auto_name_digits, auto_name_offset + auto_name_map[internal_id]);
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 const pool<string> keywords = {
130 // IEEE 1800-2017 Annex B
131 "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
132 "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
133 "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
134 "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
135 "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
136 "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
137 "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
138 "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
139 "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
140 "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
141 "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
142 "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
143 "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
144 "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
145 "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
146 "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
147 "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
148 "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
149 "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
150 "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
151 "wildcard", "wire", "with", "within", "wor", "xnor", "xor",
152 };
153 if (keywords.count(str))
154 do_escape = true;
155
156 if (do_escape)
157 return "\\" + std::string(str) + " ";
158 return std::string(str);
159 }
160
161 bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
162 {
163 if (!sig.is_chunk() || sig.as_chunk().wire == NULL)
164 return false;
165
166 RTLIL::SigChunk chunk = sig.as_chunk();
167
168 if (reg_wires.count(chunk.wire->name) == 0)
169 return false;
170
171 reg_name = id(chunk.wire->name);
172 if (sig.size() != chunk.wire->width) {
173 if (sig.size() == 1)
174 reg_name += stringf("[%d]", chunk.wire->start_offset + chunk.offset);
175 else if (chunk.wire->upto)
176 reg_name += stringf("[%d:%d]", (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset,
177 (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
178 else
179 reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1,
180 chunk.wire->start_offset + chunk.offset);
181 }
182
183 return true;
184 }
185
186 void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool escape_comment = false)
187 {
188 bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
189 if (width < 0)
190 width = data.bits.size() - offset;
191 if (width == 0) {
192 f << "\"\"";
193 return;
194 }
195 if (nostr)
196 goto dump_hex;
197 if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
198 if (width == 32 && !no_decimal && !nodec) {
199 int32_t val = 0;
200 for (int i = offset+width-1; i >= offset; i--) {
201 log_assert(i < (int)data.bits.size());
202 if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
203 goto dump_hex;
204 if (data.bits[i] == RTLIL::S1)
205 val |= 1 << (i - offset);
206 }
207 if (decimal)
208 f << stringf("%d", val);
209 else if (set_signed && val < 0)
210 f << stringf("-32'sd%u", -val);
211 else
212 f << stringf("32'%sd%u", set_signed ? "s" : "", val);
213 } else {
214 dump_hex:
215 if (nohex)
216 goto dump_bin;
217 vector<char> bin_digits, hex_digits;
218 for (int i = offset; i < offset+width; i++) {
219 log_assert(i < (int)data.bits.size());
220 switch (data.bits[i]) {
221 case RTLIL::S0: bin_digits.push_back('0'); break;
222 case RTLIL::S1: bin_digits.push_back('1'); break;
223 case RTLIL::Sx: bin_digits.push_back('x'); break;
224 case RTLIL::Sz: bin_digits.push_back('z'); break;
225 case RTLIL::Sa: bin_digits.push_back('z'); break;
226 case RTLIL::Sm: log_error("Found marker state in final netlist.");
227 }
228 }
229 if (GetSize(bin_digits) == 0)
230 goto dump_bin;
231 while (GetSize(bin_digits) % 4 != 0)
232 if (bin_digits.back() == '1')
233 bin_digits.push_back('0');
234 else
235 bin_digits.push_back(bin_digits.back());
236 for (int i = 0; i < GetSize(bin_digits); i += 4)
237 {
238 char bit_3 = bin_digits[i+3];
239 char bit_2 = bin_digits[i+2];
240 char bit_1 = bin_digits[i+1];
241 char bit_0 = bin_digits[i+0];
242 if (bit_3 == 'x' || bit_2 == 'x' || bit_1 == 'x' || bit_0 == 'x') {
243 if (bit_3 != 'x' || bit_2 != 'x' || bit_1 != 'x' || bit_0 != 'x')
244 goto dump_bin;
245 hex_digits.push_back('x');
246 continue;
247 }
248 if (bit_3 == 'z' || bit_2 == 'z' || bit_1 == 'z' || bit_0 == 'z') {
249 if (bit_3 != 'z' || bit_2 != 'z' || bit_1 != 'z' || bit_0 != 'z')
250 goto dump_bin;
251 hex_digits.push_back('z');
252 continue;
253 }
254 int val = 8*(bit_3 - '0') + 4*(bit_2 - '0') + 2*(bit_1 - '0') + (bit_0 - '0');
255 hex_digits.push_back(val < 10 ? '0' + val : 'a' + val - 10);
256 }
257 f << stringf("%d'%sh", width, set_signed ? "s" : "");
258 for (int i = GetSize(hex_digits)-1; i >= 0; i--)
259 f << hex_digits[i];
260 }
261 if (0) {
262 dump_bin:
263 f << stringf("%d'%sb", width, set_signed ? "s" : "");
264 if (width == 0)
265 f << stringf("0");
266 for (int i = offset+width-1; i >= offset; i--) {
267 log_assert(i < (int)data.bits.size());
268 switch (data.bits[i]) {
269 case RTLIL::S0: f << stringf("0"); break;
270 case RTLIL::S1: f << stringf("1"); break;
271 case RTLIL::Sx: f << stringf("x"); break;
272 case RTLIL::Sz: f << stringf("z"); break;
273 case RTLIL::Sa: f << stringf("z"); break;
274 case RTLIL::Sm: log_error("Found marker state in final netlist.");
275 }
276 }
277 }
278 } else {
279 if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
280 f << stringf("\"");
281 std::string str = data.decode_string();
282 for (size_t i = 0; i < str.size(); i++) {
283 if (str[i] == '\n')
284 f << stringf("\\n");
285 else if (str[i] == '\t')
286 f << stringf("\\t");
287 else if (str[i] < 32)
288 f << stringf("\\%03o", str[i]);
289 else if (str[i] == '"')
290 f << stringf("\\\"");
291 else if (str[i] == '\\')
292 f << stringf("\\\\");
293 else if (str[i] == '/' && escape_comment && i > 0 && str[i-1] == '*')
294 f << stringf("\\/");
295 else
296 f << str[i];
297 }
298 if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
299 f << stringf("\"");
300 }
301 }
302
303 void dump_reg_init(std::ostream &f, SigSpec sig)
304 {
305 Const initval;
306 bool gotinit = false;
307
308 for (auto bit : active_sigmap(sig)) {
309 if (active_initdata.count(bit)) {
310 initval.bits.push_back(active_initdata.at(bit));
311 gotinit = true;
312 } else {
313 initval.bits.push_back(State::Sx);
314 }
315 }
316
317 if (gotinit) {
318 f << " = ";
319 dump_const(f, initval);
320 }
321 }
322
323 void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
324 {
325 if (chunk.wire == NULL) {
326 dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal);
327 } else {
328 if (chunk.width == chunk.wire->width && chunk.offset == 0) {
329 f << stringf("%s", id(chunk.wire->name).c_str());
330 } else if (chunk.width == 1) {
331 if (chunk.wire->upto)
332 f << stringf("%s[%d]", id(chunk.wire->name).c_str(), (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
333 else
334 f << stringf("%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset);
335 } else {
336 if (chunk.wire->upto)
337 f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
338 (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset,
339 (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
340 else
341 f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
342 (chunk.offset + chunk.width - 1) + chunk.wire->start_offset,
343 chunk.offset + chunk.wire->start_offset);
344 }
345 }
346 }
347
348 void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
349 {
350 if (GetSize(sig) == 0) {
351 f << "\"\"";
352 return;
353 }
354 if (sig.is_chunk()) {
355 dump_sigchunk(f, sig.as_chunk());
356 } else {
357 f << stringf("{ ");
358 for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
359 if (it != sig.chunks().rbegin())
360 f << stringf(", ");
361 dump_sigchunk(f, *it, true);
362 }
363 f << stringf(" }");
364 }
365 }
366
367 void dump_attributes(std::ostream &f, std::string indent, dict<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n', bool modattr = false)
368 {
369 if (noattr)
370 return;
371 for (auto it = attributes.begin(); it != attributes.end(); ++it) {
372 f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
373 f << stringf(" = ");
374 if (modattr && (it->second == Const(0, 1) || it->second == Const(0)))
375 f << stringf(" 0 ");
376 else if (modattr && (it->second == Const(1, 1) || it->second == Const(1)))
377 f << stringf(" 1 ");
378 else
379 dump_const(f, it->second, -1, 0, false, attr2comment);
380 f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
381 }
382 }
383
384 void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
385 {
386 dump_attributes(f, indent, wire->attributes);
387 #if 0
388 if (wire->port_input && !wire->port_output)
389 f << stringf("%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
390 else if (!wire->port_input && wire->port_output)
391 f << stringf("%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
392 else if (wire->port_input && wire->port_output)
393 f << stringf("%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
394 else
395 f << stringf("%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire");
396 if (wire->width != 1)
397 f << stringf("[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset);
398 f << stringf("%s;\n", id(wire->name).c_str());
399 #else
400 // do not use Verilog-2k "output reg" syntax in Verilog export
401 std::string range = "";
402 if (wire->width != 1) {
403 if (wire->upto)
404 range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
405 else
406 range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
407 }
408 if (wire->port_input && !wire->port_output)
409 f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
410 if (!wire->port_input && wire->port_output)
411 f << stringf("%s" "output%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
412 if (wire->port_input && wire->port_output)
413 f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
414 if (reg_wires.count(wire->name)) {
415 f << stringf("%s" "reg%s %s", indent.c_str(), range.c_str(), id(wire->name).c_str());
416 if (wire->attributes.count("\\init")) {
417 f << stringf(" = ");
418 dump_const(f, wire->attributes.at("\\init"));
419 }
420 f << stringf(";\n");
421 } else if (!wire->port_input && !wire->port_output)
422 f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
423 #endif
424 }
425
426 void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory)
427 {
428 dump_attributes(f, indent, memory->attributes);
429 f << stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size+memory->start_offset-1, memory->start_offset);
430 }
431
432 void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
433 {
434 if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) {
435 f << stringf("$signed(");
436 dump_sigspec(f, cell->getPort("\\" + port));
437 f << stringf(")");
438 } else
439 dump_sigspec(f, cell->getPort("\\" + port));
440 }
441
442 std::string cellname(RTLIL::Cell *cell)
443 {
444 if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q"))
445 {
446 RTLIL::SigSpec sig = cell->getPort("\\Q");
447 if (GetSize(sig) != 1 || sig.is_fully_const())
448 goto no_special_reg_name;
449
450 RTLIL::Wire *wire = sig[0].wire;
451
452 if (wire->name[0] != '\\')
453 goto no_special_reg_name;
454
455 std::string cell_name = wire->name.str();
456
457 size_t pos = cell_name.find('[');
458 if (pos != std::string::npos)
459 cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos);
460 else
461 cell_name = cell_name + "_reg";
462
463 if (wire->width != 1)
464 cell_name += stringf("[%d]", wire->start_offset + sig[0].offset);
465
466 if (active_module && active_module->count_id(cell_name) > 0)
467 goto no_special_reg_name;
468
469 return id(cell_name);
470 }
471 else
472 {
473 no_special_reg_name:
474 return id(cell->name).c_str();
475 }
476 }
477
478 void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
479 {
480 f << stringf("%s" "assign ", indent.c_str());
481 dump_sigspec(f, cell->getPort("\\Y"));
482 f << stringf(" = %s ", op.c_str());
483 dump_attributes(f, "", cell->attributes, ' ');
484 dump_cell_expr_port(f, cell, "A", true);
485 f << stringf(";\n");
486 }
487
488 void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
489 {
490 f << stringf("%s" "assign ", indent.c_str());
491 dump_sigspec(f, cell->getPort("\\Y"));
492 f << stringf(" = ");
493 dump_cell_expr_port(f, cell, "A", true);
494 f << stringf(" %s ", op.c_str());
495 dump_attributes(f, "", cell->attributes, ' ');
496 dump_cell_expr_port(f, cell, "B", true);
497 f << stringf(";\n");
498 }
499
500 bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
501 {
502 if (cell->type == "$_NOT_") {
503 f << stringf("%s" "assign ", indent.c_str());
504 dump_sigspec(f, cell->getPort("\\Y"));
505 f << stringf(" = ");
506 f << stringf("~");
507 dump_attributes(f, "", cell->attributes, ' ');
508 dump_cell_expr_port(f, cell, "A", false);
509 f << stringf(";\n");
510 return true;
511 }
512
513 if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
514 f << stringf("%s" "assign ", indent.c_str());
515 dump_sigspec(f, cell->getPort("\\Y"));
516 f << stringf(" = ");
517 if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
518 f << stringf("~(");
519 dump_cell_expr_port(f, cell, "A", false);
520 f << stringf(" ");
521 if (cell->type.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
522 f << stringf("&");
523 if (cell->type.in("$_OR_", "$_NOR_", "$_ORNOT_"))
524 f << stringf("|");
525 if (cell->type.in("$_XOR_", "$_XNOR_"))
526 f << stringf("^");
527 dump_attributes(f, "", cell->attributes, ' ');
528 f << stringf(" ");
529 if (cell->type.in("$_ANDNOT_", "$_ORNOT_"))
530 f << stringf("~(");
531 dump_cell_expr_port(f, cell, "B", false);
532 if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
533 f << stringf(")");
534 f << stringf(";\n");
535 return true;
536 }
537
538 if (cell->type == "$_MUX_") {
539 f << stringf("%s" "assign ", indent.c_str());
540 dump_sigspec(f, cell->getPort("\\Y"));
541 f << stringf(" = ");
542 dump_cell_expr_port(f, cell, "S", false);
543 f << stringf(" ? ");
544 dump_attributes(f, "", cell->attributes, ' ');
545 dump_cell_expr_port(f, cell, "B", false);
546 f << stringf(" : ");
547 dump_cell_expr_port(f, cell, "A", false);
548 f << stringf(";\n");
549 return true;
550 }
551
552 if (cell->type.in("$_AOI3_", "$_OAI3_")) {
553 f << stringf("%s" "assign ", indent.c_str());
554 dump_sigspec(f, cell->getPort("\\Y"));
555 f << stringf(" = ~((");
556 dump_cell_expr_port(f, cell, "A", false);
557 f << stringf(cell->type == "$_AOI3_" ? " & " : " | ");
558 dump_cell_expr_port(f, cell, "B", false);
559 f << stringf(cell->type == "$_AOI3_" ? ") |" : ") &");
560 dump_attributes(f, "", cell->attributes, ' ');
561 f << stringf(" ");
562 dump_cell_expr_port(f, cell, "C", false);
563 f << stringf(");\n");
564 return true;
565 }
566
567 if (cell->type.in("$_AOI4_", "$_OAI4_")) {
568 f << stringf("%s" "assign ", indent.c_str());
569 dump_sigspec(f, cell->getPort("\\Y"));
570 f << stringf(" = ~((");
571 dump_cell_expr_port(f, cell, "A", false);
572 f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
573 dump_cell_expr_port(f, cell, "B", false);
574 f << stringf(cell->type == "$_AOI4_" ? ") |" : ") &");
575 dump_attributes(f, "", cell->attributes, ' ');
576 f << stringf(" (");
577 dump_cell_expr_port(f, cell, "C", false);
578 f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
579 dump_cell_expr_port(f, cell, "D", false);
580 f << stringf("));\n");
581 return true;
582 }
583
584 if (cell->type.substr(0, 6) == "$_DFF_")
585 {
586 std::string reg_name = cellname(cell);
587 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
588
589 if (!out_is_reg_wire) {
590 f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
591 dump_reg_init(f, cell->getPort("\\Q"));
592 f << ";\n";
593 }
594
595 dump_attributes(f, indent, cell->attributes);
596 f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
597 dump_sigspec(f, cell->getPort("\\C"));
598 if (cell->type[7] != '_') {
599 f << stringf(" or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
600 dump_sigspec(f, cell->getPort("\\R"));
601 }
602 f << stringf(")\n");
603
604 if (cell->type[7] != '_') {
605 f << stringf("%s" " if (%s", indent.c_str(), cell->type[7] == 'P' ? "" : "!");
606 dump_sigspec(f, cell->getPort("\\R"));
607 f << stringf(")\n");
608 f << stringf("%s" " %s <= %c;\n", indent.c_str(), reg_name.c_str(), cell->type[8]);
609 f << stringf("%s" " else\n", indent.c_str());
610 }
611
612 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
613 dump_cell_expr_port(f, cell, "D", false);
614 f << stringf(";\n");
615
616 if (!out_is_reg_wire) {
617 f << stringf("%s" "assign ", indent.c_str());
618 dump_sigspec(f, cell->getPort("\\Q"));
619 f << stringf(" = %s;\n", reg_name.c_str());
620 }
621
622 return true;
623 }
624
625 if (cell->type.substr(0, 8) == "$_DFFSR_")
626 {
627 char pol_c = cell->type[8], pol_s = cell->type[9], pol_r = cell->type[10];
628
629 std::string reg_name = cellname(cell);
630 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
631
632 if (!out_is_reg_wire) {
633 f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
634 dump_reg_init(f, cell->getPort("\\Q"));
635 f << ";\n";
636 }
637
638 dump_attributes(f, indent, cell->attributes);
639 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
640 dump_sigspec(f, cell->getPort("\\C"));
641 f << stringf(" or %sedge ", pol_s == 'P' ? "pos" : "neg");
642 dump_sigspec(f, cell->getPort("\\S"));
643 f << stringf(" or %sedge ", pol_r == 'P' ? "pos" : "neg");
644 dump_sigspec(f, cell->getPort("\\R"));
645 f << stringf(")\n");
646
647 f << stringf("%s" " if (%s", indent.c_str(), pol_r == 'P' ? "" : "!");
648 dump_sigspec(f, cell->getPort("\\R"));
649 f << stringf(")\n");
650 f << stringf("%s" " %s <= 0;\n", indent.c_str(), reg_name.c_str());
651
652 f << stringf("%s" " else if (%s", indent.c_str(), pol_s == 'P' ? "" : "!");
653 dump_sigspec(f, cell->getPort("\\S"));
654 f << stringf(")\n");
655 f << stringf("%s" " %s <= 1;\n", indent.c_str(), reg_name.c_str());
656
657 f << stringf("%s" " else\n", indent.c_str());
658 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
659 dump_cell_expr_port(f, cell, "D", false);
660 f << stringf(";\n");
661
662 if (!out_is_reg_wire) {
663 f << stringf("%s" "assign ", indent.c_str());
664 dump_sigspec(f, cell->getPort("\\Q"));
665 f << stringf(" = %s;\n", reg_name.c_str());
666 }
667
668 return true;
669 }
670
671 #define HANDLE_UNIOP(_type, _operator) \
672 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
673 #define HANDLE_BINOP(_type, _operator) \
674 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
675
676 HANDLE_UNIOP("$not", "~")
677 HANDLE_UNIOP("$pos", "+")
678 HANDLE_UNIOP("$neg", "-")
679
680 HANDLE_BINOP("$and", "&")
681 HANDLE_BINOP("$or", "|")
682 HANDLE_BINOP("$xor", "^")
683 HANDLE_BINOP("$xnor", "~^")
684
685 HANDLE_UNIOP("$reduce_and", "&")
686 HANDLE_UNIOP("$reduce_or", "|")
687 HANDLE_UNIOP("$reduce_xor", "^")
688 HANDLE_UNIOP("$reduce_xnor", "~^")
689 HANDLE_UNIOP("$reduce_bool", "|")
690
691 HANDLE_BINOP("$shl", "<<")
692 HANDLE_BINOP("$shr", ">>")
693 HANDLE_BINOP("$sshl", "<<<")
694 HANDLE_BINOP("$sshr", ">>>")
695
696 HANDLE_BINOP("$lt", "<")
697 HANDLE_BINOP("$le", "<=")
698 HANDLE_BINOP("$eq", "==")
699 HANDLE_BINOP("$ne", "!=")
700 HANDLE_BINOP("$eqx", "===")
701 HANDLE_BINOP("$nex", "!==")
702 HANDLE_BINOP("$ge", ">=")
703 HANDLE_BINOP("$gt", ">")
704
705 HANDLE_BINOP("$add", "+")
706 HANDLE_BINOP("$sub", "-")
707 HANDLE_BINOP("$mul", "*")
708 HANDLE_BINOP("$div", "/")
709 HANDLE_BINOP("$mod", "%")
710 HANDLE_BINOP("$pow", "**")
711
712 HANDLE_UNIOP("$logic_not", "!")
713 HANDLE_BINOP("$logic_and", "&&")
714 HANDLE_BINOP("$logic_or", "||")
715
716 #undef HANDLE_UNIOP
717 #undef HANDLE_BINOP
718
719 if (cell->type == "$shift")
720 {
721 f << stringf("%s" "assign ", indent.c_str());
722 dump_sigspec(f, cell->getPort("\\Y"));
723 f << stringf(" = ");
724 if (cell->getParam("\\B_SIGNED").as_bool())
725 {
726 f << stringf("$signed(");
727 dump_sigspec(f, cell->getPort("\\B"));
728 f << stringf(")");
729 f << stringf(" < 0 ? ");
730 dump_sigspec(f, cell->getPort("\\A"));
731 f << stringf(" << - ");
732 dump_sigspec(f, cell->getPort("\\B"));
733 f << stringf(" : ");
734 dump_sigspec(f, cell->getPort("\\A"));
735 f << stringf(" >> ");
736 dump_sigspec(f, cell->getPort("\\B"));
737 }
738 else
739 {
740 dump_sigspec(f, cell->getPort("\\A"));
741 f << stringf(" >> ");
742 dump_sigspec(f, cell->getPort("\\B"));
743 }
744 f << stringf(";\n");
745 return true;
746 }
747
748 if (cell->type == "$shiftx")
749 {
750 std::string temp_id = next_auto_id();
751 f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort("\\A"))-1, temp_id.c_str());
752 dump_sigspec(f, cell->getPort("\\A"));
753 f << stringf(";\n");
754
755 f << stringf("%s" "assign ", indent.c_str());
756 dump_sigspec(f, cell->getPort("\\Y"));
757 f << stringf(" = %s[", temp_id.c_str());
758 if (cell->getParam("\\B_SIGNED").as_bool())
759 f << stringf("$signed(");
760 dump_sigspec(f, cell->getPort("\\B"));
761 if (cell->getParam("\\B_SIGNED").as_bool())
762 f << stringf(")");
763 f << stringf(" +: %d", cell->getParam("\\Y_WIDTH").as_int());
764 f << stringf("];\n");
765 return true;
766 }
767
768 if (cell->type == "$mux")
769 {
770 f << stringf("%s" "assign ", indent.c_str());
771 dump_sigspec(f, cell->getPort("\\Y"));
772 f << stringf(" = ");
773 dump_sigspec(f, cell->getPort("\\S"));
774 f << stringf(" ? ");
775 dump_attributes(f, "", cell->attributes, ' ');
776 dump_sigspec(f, cell->getPort("\\B"));
777 f << stringf(" : ");
778 dump_sigspec(f, cell->getPort("\\A"));
779 f << stringf(";\n");
780 return true;
781 }
782
783 if (cell->type == "$pmux" || cell->type == "$pmux_safe")
784 {
785 int width = cell->parameters["\\WIDTH"].as_int();
786 int s_width = cell->getPort("\\S").size();
787 std::string func_name = cellname(cell);
788
789 f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
790 f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
791 f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
792 f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
793
794 dump_attributes(f, indent + " ", cell->attributes);
795 if (cell->type != "$pmux_safe" && !noattr)
796 f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
797 f << stringf("%s" " casez (s)", indent.c_str());
798 if (cell->type != "$pmux_safe")
799 f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
800
801 for (int i = 0; i < s_width; i++)
802 {
803 f << stringf("%s" " %d'b", indent.c_str(), s_width);
804
805 for (int j = s_width-1; j >= 0; j--)
806 f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
807
808 f << stringf(":\n");
809 f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
810 }
811
812 f << stringf("%s" " default:\n", indent.c_str());
813 f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str());
814
815 f << stringf("%s" " endcase\n", indent.c_str());
816 f << stringf("%s" "endfunction\n", indent.c_str());
817
818 f << stringf("%s" "assign ", indent.c_str());
819 dump_sigspec(f, cell->getPort("\\Y"));
820 f << stringf(" = %s(", func_name.c_str());
821 dump_sigspec(f, cell->getPort("\\A"));
822 f << stringf(", ");
823 dump_sigspec(f, cell->getPort("\\B"));
824 f << stringf(", ");
825 dump_sigspec(f, cell->getPort("\\S"));
826 f << stringf(");\n");
827 return true;
828 }
829
830 if (cell->type == "$tribuf")
831 {
832 f << stringf("%s" "assign ", indent.c_str());
833 dump_sigspec(f, cell->getPort("\\Y"));
834 f << stringf(" = ");
835 dump_sigspec(f, cell->getPort("\\EN"));
836 f << stringf(" ? ");
837 dump_sigspec(f, cell->getPort("\\A"));
838 f << stringf(" : %d'bz;\n", cell->parameters.at("\\WIDTH").as_int());
839 return true;
840 }
841
842 if (cell->type == "$slice")
843 {
844 f << stringf("%s" "assign ", indent.c_str());
845 dump_sigspec(f, cell->getPort("\\Y"));
846 f << stringf(" = ");
847 dump_sigspec(f, cell->getPort("\\A"));
848 f << stringf(" >> %d;\n", cell->parameters.at("\\OFFSET").as_int());
849 return true;
850 }
851
852 if (cell->type == "$concat")
853 {
854 f << stringf("%s" "assign ", indent.c_str());
855 dump_sigspec(f, cell->getPort("\\Y"));
856 f << stringf(" = { ");
857 dump_sigspec(f, cell->getPort("\\B"));
858 f << stringf(" , ");
859 dump_sigspec(f, cell->getPort("\\A"));
860 f << stringf(" };\n");
861 return true;
862 }
863
864 if (cell->type == "$lut")
865 {
866 f << stringf("%s" "assign ", indent.c_str());
867 dump_sigspec(f, cell->getPort("\\Y"));
868 f << stringf(" = ");
869 dump_const(f, cell->parameters.at("\\LUT"));
870 f << stringf(" >> ");
871 dump_attributes(f, "", cell->attributes, ' ');
872 dump_sigspec(f, cell->getPort("\\A"));
873 f << stringf(";\n");
874 return true;
875 }
876
877 if (cell->type == "$dffsr")
878 {
879 SigSpec sig_clk = cell->getPort("\\CLK");
880 SigSpec sig_set = cell->getPort("\\SET");
881 SigSpec sig_clr = cell->getPort("\\CLR");
882 SigSpec sig_d = cell->getPort("\\D");
883 SigSpec sig_q = cell->getPort("\\Q");
884
885 int width = cell->parameters["\\WIDTH"].as_int();
886 bool pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
887 bool pol_set = cell->parameters["\\SET_POLARITY"].as_bool();
888 bool pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool();
889
890 std::string reg_name = cellname(cell);
891 bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
892
893 if (!out_is_reg_wire) {
894 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), width-1, reg_name.c_str());
895 dump_reg_init(f, sig_q);
896 f << ";\n";
897 }
898
899 for (int i = 0; i < width; i++) {
900 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
901 dump_sigspec(f, sig_clk);
902 f << stringf(", %sedge ", pol_set ? "pos" : "neg");
903 dump_sigspec(f, sig_set);
904 f << stringf(", %sedge ", pol_clr ? "pos" : "neg");
905 dump_sigspec(f, sig_clr);
906 f << stringf(")\n");
907
908 f << stringf("%s" " if (%s", indent.c_str(), pol_clr ? "" : "!");
909 dump_sigspec(f, sig_clr);
910 f << stringf(") %s[%d] <= 1'b0;\n", reg_name.c_str(), i);
911
912 f << stringf("%s" " else if (%s", indent.c_str(), pol_set ? "" : "!");
913 dump_sigspec(f, sig_set);
914 f << stringf(") %s[%d] <= 1'b1;\n", reg_name.c_str(), i);
915
916 f << stringf("%s" " else %s[%d] <= ", indent.c_str(), reg_name.c_str(), i);
917 dump_sigspec(f, sig_d[i]);
918 f << stringf(";\n");
919 }
920
921 if (!out_is_reg_wire) {
922 f << stringf("%s" "assign ", indent.c_str());
923 dump_sigspec(f, sig_q);
924 f << stringf(" = %s;\n", reg_name.c_str());
925 }
926
927 return true;
928 }
929
930 if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
931 {
932 RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
933 bool pol_clk, pol_arst = false, pol_en = false;
934
935 sig_clk = cell->getPort("\\CLK");
936 pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
937
938 if (cell->type == "$adff") {
939 sig_arst = cell->getPort("\\ARST");
940 pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool();
941 val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
942 }
943
944 if (cell->type == "$dffe") {
945 sig_en = cell->getPort("\\EN");
946 pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
947 }
948
949 std::string reg_name = cellname(cell);
950 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
951
952 if (!out_is_reg_wire) {
953 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
954 dump_reg_init(f, cell->getPort("\\Q"));
955 f << ";\n";
956 }
957
958 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
959 dump_sigspec(f, sig_clk);
960 if (cell->type == "$adff") {
961 f << stringf(" or %sedge ", pol_arst ? "pos" : "neg");
962 dump_sigspec(f, sig_arst);
963 }
964 f << stringf(")\n");
965
966 if (cell->type == "$adff") {
967 f << stringf("%s" " if (%s", indent.c_str(), pol_arst ? "" : "!");
968 dump_sigspec(f, sig_arst);
969 f << stringf(")\n");
970 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
971 dump_sigspec(f, val_arst);
972 f << stringf(";\n");
973 f << stringf("%s" " else\n", indent.c_str());
974 }
975
976 if (cell->type == "$dffe") {
977 f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
978 dump_sigspec(f, sig_en);
979 f << stringf(")\n");
980 }
981
982 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
983 dump_cell_expr_port(f, cell, "D", false);
984 f << stringf(";\n");
985
986 if (!out_is_reg_wire) {
987 f << stringf("%s" "assign ", indent.c_str());
988 dump_sigspec(f, cell->getPort("\\Q"));
989 f << stringf(" = %s;\n", reg_name.c_str());
990 }
991
992 return true;
993 }
994
995 if (cell->type == "$dlatch")
996 {
997 RTLIL::SigSpec sig_en;
998 bool pol_en = false;
999
1000 sig_en = cell->getPort("\\EN");
1001 pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
1002
1003 std::string reg_name = cellname(cell);
1004 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
1005
1006 if (!out_is_reg_wire) {
1007 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
1008 dump_reg_init(f, cell->getPort("\\Q"));
1009 f << ";\n";
1010 }
1011
1012 f << stringf("%s" "always @*\n", indent.c_str());
1013
1014 f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
1015 dump_sigspec(f, sig_en);
1016 f << stringf(")\n");
1017
1018 f << stringf("%s" " %s = ", indent.c_str(), reg_name.c_str());
1019 dump_cell_expr_port(f, cell, "D", false);
1020 f << stringf(";\n");
1021
1022 if (!out_is_reg_wire) {
1023 f << stringf("%s" "assign ", indent.c_str());
1024 dump_sigspec(f, cell->getPort("\\Q"));
1025 f << stringf(" = %s;\n", reg_name.c_str());
1026 }
1027
1028 return true;
1029 }
1030
1031 if (cell->type == "$mem")
1032 {
1033 RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
1034 std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
1035 int abits = cell->parameters["\\ABITS"].as_int();
1036 int size = cell->parameters["\\SIZE"].as_int();
1037 int offset = cell->parameters["\\OFFSET"].as_int();
1038 int width = cell->parameters["\\WIDTH"].as_int();
1039 bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef());
1040
1041 // for memory block make something like:
1042 // reg [7:0] memid [3:0];
1043 // initial begin
1044 // memid[0] = ...
1045 // end
1046 f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size+offset-1, offset);
1047 if (use_init)
1048 {
1049 f << stringf("%s" "initial begin\n", indent.c_str());
1050 for (int i=0; i<size; i++)
1051 {
1052 f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i);
1053 dump_const(f, cell->parameters["\\INIT"].extract(i*width, width));
1054 f << stringf(";\n");
1055 }
1056 f << stringf("%s" "end\n", indent.c_str());
1057 }
1058
1059 // create a map : "edge clk" -> expressions within that clock domain
1060 dict<std::string, std::vector<std::string>> clk_to_lof_body;
1061 clk_to_lof_body[""] = std::vector<std::string>();
1062 std::string clk_domain_str;
1063 // create a list of reg declarations
1064 std::vector<std::string> lof_reg_declarations;
1065
1066 int nread_ports = cell->parameters["\\RD_PORTS"].as_int();
1067 RTLIL::SigSpec sig_rd_clk, sig_rd_en, sig_rd_data, sig_rd_addr;
1068 bool use_rd_clk, rd_clk_posedge, rd_transparent;
1069 // read ports
1070 for (int i=0; i < nread_ports; i++)
1071 {
1072 sig_rd_clk = cell->getPort("\\RD_CLK").extract(i);
1073 sig_rd_en = cell->getPort("\\RD_EN").extract(i);
1074 sig_rd_data = cell->getPort("\\RD_DATA").extract(i*width, width);
1075 sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
1076 use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
1077 rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
1078 rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
1079 if (use_rd_clk)
1080 {
1081 {
1082 std::ostringstream os;
1083 dump_sigspec(os, sig_rd_clk);
1084 clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
1085 if( clk_to_lof_body.count(clk_domain_str) == 0 )
1086 clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
1087 }
1088 if (!rd_transparent)
1089 {
1090 // for clocked read ports make something like:
1091 // reg [..] temp_id;
1092 // always @(posedge clk)
1093 // if (rd_en) temp_id <= array_reg[r_addr];
1094 // assign r_data = temp_id;
1095 std::string temp_id = next_auto_id();
1096 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
1097 {
1098 std::ostringstream os;
1099 if (sig_rd_en != RTLIL::SigBit(true))
1100 {
1101 os << stringf("if (");
1102 dump_sigspec(os, sig_rd_en);
1103 os << stringf(") ");
1104 }
1105 os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
1106 dump_sigspec(os, sig_rd_addr);
1107 os << stringf("];\n");
1108 clk_to_lof_body[clk_domain_str].push_back(os.str());
1109 }
1110 {
1111 std::ostringstream os;
1112 dump_sigspec(os, sig_rd_data);
1113 std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
1114 clk_to_lof_body[""].push_back(line);
1115 }
1116 }
1117 else
1118 {
1119 // for rd-transparent read-ports make something like:
1120 // reg [..] temp_id;
1121 // always @(posedge clk)
1122 // temp_id <= r_addr;
1123 // assign r_data = array_reg[temp_id];
1124 std::string temp_id = next_auto_id();
1125 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr.size() - 1, temp_id.c_str()) );
1126 {
1127 std::ostringstream os;
1128 dump_sigspec(os, sig_rd_addr);
1129 std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str());
1130 clk_to_lof_body[clk_domain_str].push_back(line);
1131 }
1132 {
1133 std::ostringstream os;
1134 dump_sigspec(os, sig_rd_data);
1135 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str());
1136 clk_to_lof_body[""].push_back(line);
1137 }
1138 }
1139 } else {
1140 // for non-clocked read-ports make something like:
1141 // assign r_data = array_reg[r_addr];
1142 std::ostringstream os, os2;
1143 dump_sigspec(os, sig_rd_data);
1144 dump_sigspec(os2, sig_rd_addr);
1145 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
1146 clk_to_lof_body[""].push_back(line);
1147 }
1148 }
1149
1150 int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
1151 RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en;
1152 bool wr_clk_posedge;
1153
1154 // write ports
1155 for (int i=0; i < nwrite_ports; i++)
1156 {
1157 sig_wr_clk = cell->getPort("\\WR_CLK").extract(i);
1158 sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width);
1159 sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits);
1160 sig_wr_en = cell->getPort("\\WR_EN").extract(i*width, width);
1161 wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool();
1162 {
1163 std::ostringstream os;
1164 dump_sigspec(os, sig_wr_clk);
1165 clk_domain_str = stringf("%sedge %s", wr_clk_posedge ? "pos" : "neg", os.str().c_str());
1166 if( clk_to_lof_body.count(clk_domain_str) == 0 )
1167 clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
1168 }
1169 // make something like:
1170 // always @(posedge clk)
1171 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1172 // ...
1173 for (int i = 0; i < GetSize(sig_wr_en); i++)
1174 {
1175 int start_i = i, width = 1;
1176 SigBit wen_bit = sig_wr_en[i];
1177
1178 while (i+1 < GetSize(sig_wr_en) && active_sigmap(sig_wr_en[i+1]) == active_sigmap(wen_bit))
1179 i++, width++;
1180
1181 if (wen_bit == State::S0)
1182 continue;
1183
1184 std::ostringstream os;
1185 if (wen_bit != State::S1)
1186 {
1187 os << stringf("if (");
1188 dump_sigspec(os, wen_bit);
1189 os << stringf(") ");
1190 }
1191 os << stringf("%s[", mem_id.c_str());
1192 dump_sigspec(os, sig_wr_addr);
1193 if (width == GetSize(sig_wr_en))
1194 os << stringf("] <= ");
1195 else
1196 os << stringf("][%d:%d] <= ", i, start_i);
1197 dump_sigspec(os, sig_wr_data.extract(start_i, width));
1198 os << stringf(";\n");
1199 clk_to_lof_body[clk_domain_str].push_back(os.str());
1200 }
1201 }
1202 // Output Verilog that looks something like this:
1203 // reg [..] _3_;
1204 // always @(posedge CLK2) begin
1205 // _3_ <= memory[D1ADDR];
1206 // if (A1EN)
1207 // memory[A1ADDR] <= A1DATA;
1208 // if (A2EN)
1209 // memory[A2ADDR] <= A2DATA;
1210 // ...
1211 // end
1212 // always @(negedge CLK1) begin
1213 // if (C1EN)
1214 // memory[C1ADDR] <= C1DATA;
1215 // end
1216 // ...
1217 // assign D1DATA = _3_;
1218 // assign D2DATA <= memory[D2ADDR];
1219
1220 // the reg ... definitions
1221 for(auto &reg : lof_reg_declarations)
1222 {
1223 f << stringf("%s" "%s", indent.c_str(), reg.c_str());
1224 }
1225 // the block of expressions by clock domain
1226 for(auto &pair : clk_to_lof_body)
1227 {
1228 std::string clk_domain = pair.first;
1229 std::vector<std::string> lof_lines = pair.second;
1230 if( clk_domain != "")
1231 {
1232 f << stringf("%s" "always @(%s) begin\n", indent.c_str(), clk_domain.c_str());
1233 for(auto &line : lof_lines)
1234 f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str());
1235 f << stringf("%s" "end\n", indent.c_str());
1236 }
1237 else
1238 {
1239 // the non-clocked assignments
1240 for(auto &line : lof_lines)
1241 f << stringf("%s" "%s", indent.c_str(), line.c_str());
1242 }
1243 }
1244
1245 return true;
1246 }
1247
1248 if (cell->type.in("$assert", "$assume", "$cover"))
1249 {
1250 f << stringf("%s" "always @* if (", indent.c_str());
1251 dump_sigspec(f, cell->getPort("\\EN"));
1252 f << stringf(") %s(", cell->type.c_str()+1);
1253 dump_sigspec(f, cell->getPort("\\A"));
1254 f << stringf(");\n");
1255 return true;
1256 }
1257
1258 if (cell->type.in("$specify2", "$specify3"))
1259 {
1260 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1261
1262 SigSpec en = cell->getPort("\\EN");
1263 if (en != State::S1) {
1264 f << stringf("if (");
1265 dump_sigspec(f, cell->getPort("\\EN"));
1266 f << stringf(") ");
1267 }
1268
1269 f << "(";
1270 if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool())
1271 f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1272
1273 dump_sigspec(f, cell->getPort("\\SRC"));
1274
1275 f << " ";
1276 if (cell->getParam("\\SRC_DST_PEN").as_bool())
1277 f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1278 f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1279
1280 if (cell->type == "$specify3") {
1281 f << "(";
1282 dump_sigspec(f, cell->getPort("\\DST"));
1283 f << " ";
1284 if (cell->getParam("\\DAT_DST_PEN").as_bool())
1285 f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1286 f << ": ";
1287 dump_sigspec(f, cell->getPort("\\DAT"));
1288 f << ")";
1289 } else {
1290 dump_sigspec(f, cell->getPort("\\DST"));
1291 }
1292
1293 bool bak_decimal = decimal;
1294 decimal = 1;
1295
1296 f << ") = (";
1297 dump_const(f, cell->getParam("\\T_RISE_MIN"));
1298 f << ":";
1299 dump_const(f, cell->getParam("\\T_RISE_TYP"));
1300 f << ":";
1301 dump_const(f, cell->getParam("\\T_RISE_MAX"));
1302 f << ", ";
1303 dump_const(f, cell->getParam("\\T_FALL_MIN"));
1304 f << ":";
1305 dump_const(f, cell->getParam("\\T_FALL_TYP"));
1306 f << ":";
1307 dump_const(f, cell->getParam("\\T_FALL_MAX"));
1308 f << ");\n";
1309
1310 decimal = bak_decimal;
1311
1312 f << stringf("%s" "endspecify\n", indent.c_str());
1313 return true;
1314 }
1315
1316 if (cell->type == "$specrule")
1317 {
1318 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1319
1320 string spec_type = cell->getParam("\\TYPE").decode_string();
1321 f << stringf("%s(", spec_type.c_str());
1322
1323 if (cell->getParam("\\SRC_PEN").as_bool())
1324 f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1325 dump_sigspec(f, cell->getPort("\\SRC"));
1326
1327 if (cell->getPort("\\SRC_EN") != State::S1) {
1328 f << " &&& ";
1329 dump_sigspec(f, cell->getPort("\\SRC_EN"));
1330 }
1331
1332 f << ", ";
1333 if (cell->getParam("\\DST_PEN").as_bool())
1334 f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1335 dump_sigspec(f, cell->getPort("\\DST"));
1336
1337 if (cell->getPort("\\DST_EN") != State::S1) {
1338 f << " &&& ";
1339 dump_sigspec(f, cell->getPort("\\DST_EN"));
1340 }
1341
1342 bool bak_decimal = decimal;
1343 decimal = 1;
1344
1345 f << ", ";
1346 dump_const(f, cell->getParam("\\T_LIMIT"));
1347
1348 if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") {
1349 f << ", ";
1350 dump_const(f, cell->getParam("\\T_LIMIT2"));
1351 }
1352
1353 f << ");\n";
1354 decimal = bak_decimal;
1355
1356 f << stringf("%s" "endspecify\n", indent.c_str());
1357 return true;
1358 }
1359
1360 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1361 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1362
1363 return false;
1364 }
1365
1366 void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
1367 {
1368 if (cell->type[0] == '$' && !noexpr) {
1369 if (dump_cell_expr(f, indent, cell))
1370 return;
1371 }
1372
1373 dump_attributes(f, indent, cell->attributes);
1374 f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
1375
1376 if (!defparam && cell->parameters.size() > 0) {
1377 f << stringf(" #(");
1378 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1379 if (it != cell->parameters.begin())
1380 f << stringf(",");
1381 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1382 dump_const(f, it->second);
1383 f << stringf(")");
1384 }
1385 f << stringf("\n%s" ")", indent.c_str());
1386 }
1387
1388 std::string cell_name = cellname(cell);
1389 if (cell_name != id(cell->name))
1390 f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
1391 else
1392 f << stringf(" %s (", cell_name.c_str());
1393
1394 bool first_arg = true;
1395 std::set<RTLIL::IdString> numbered_ports;
1396 for (int i = 1; true; i++) {
1397 char str[16];
1398 snprintf(str, 16, "$%d", i);
1399 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1400 if (it->first != str)
1401 continue;
1402 if (!first_arg)
1403 f << stringf(",");
1404 first_arg = false;
1405 f << stringf("\n%s ", indent.c_str());
1406 dump_sigspec(f, it->second);
1407 numbered_ports.insert(it->first);
1408 goto found_numbered_port;
1409 }
1410 break;
1411 found_numbered_port:;
1412 }
1413 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1414 if (numbered_ports.count(it->first))
1415 continue;
1416 if (!first_arg)
1417 f << stringf(",");
1418 first_arg = false;
1419 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1420 if (it->second.size() > 0)
1421 dump_sigspec(f, it->second);
1422 f << stringf(")");
1423 }
1424 f << stringf("\n%s" ");\n", indent.c_str());
1425
1426 if (defparam && cell->parameters.size() > 0) {
1427 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1428 f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
1429 dump_const(f, it->second);
1430 f << stringf(";\n");
1431 }
1432 }
1433
1434 if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) {
1435 std::stringstream ss;
1436 dump_reg_init(ss, cell->getPort("\\Q"));
1437 if (!ss.str().empty()) {
1438 f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str());
1439 f << ss.str();
1440 f << ";\n";
1441 }
1442 }
1443 }
1444
1445 void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
1446 {
1447 f << stringf("%s" "assign ", indent.c_str());
1448 dump_sigspec(f, left);
1449 f << stringf(" = ");
1450 dump_sigspec(f, right);
1451 f << stringf(";\n");
1452 }
1453
1454 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
1455
1456 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
1457 {
1458 int number_of_stmts = cs->switches.size() + cs->actions.size();
1459
1460 if (!omit_trailing_begin && number_of_stmts >= 2)
1461 f << stringf("%s" "begin\n", indent.c_str());
1462
1463 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1464 if (it->first.size() == 0)
1465 continue;
1466 f << stringf("%s ", indent.c_str());
1467 dump_sigspec(f, it->first);
1468 f << stringf(" = ");
1469 dump_sigspec(f, it->second);
1470 f << stringf(";\n");
1471 }
1472
1473 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1474 dump_proc_switch(f, indent + " ", *it);
1475
1476 if (!omit_trailing_begin && number_of_stmts == 0)
1477 f << stringf("%s /* empty */;\n", indent.c_str());
1478
1479 if (omit_trailing_begin || number_of_stmts >= 2)
1480 f << stringf("%s" "end\n", indent.c_str());
1481 }
1482
1483 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
1484 {
1485 if (sw->signal.size() == 0) {
1486 f << stringf("%s" "begin\n", indent.c_str());
1487 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1488 if ((*it)->compare.size() == 0)
1489 dump_case_body(f, indent + " ", *it);
1490 }
1491 f << stringf("%s" "end\n", indent.c_str());
1492 return;
1493 }
1494
1495 f << stringf("%s" "casez (", indent.c_str());
1496 dump_sigspec(f, sw->signal);
1497 f << stringf(")\n");
1498
1499 bool got_default = false;
1500 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1501 if ((*it)->compare.size() == 0) {
1502 if (got_default)
1503 continue;
1504 f << stringf("%s default", indent.c_str());
1505 got_default = true;
1506 } else {
1507 f << stringf("%s ", indent.c_str());
1508 for (size_t i = 0; i < (*it)->compare.size(); i++) {
1509 if (i > 0)
1510 f << stringf(", ");
1511 dump_sigspec(f, (*it)->compare[i]);
1512 }
1513 }
1514 f << stringf(":\n");
1515 dump_case_body(f, indent + " ", *it);
1516 }
1517
1518 f << stringf("%s" "endcase\n", indent.c_str());
1519 }
1520
1521 void case_body_find_regs(RTLIL::CaseRule *cs)
1522 {
1523 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1524 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
1525 case_body_find_regs(*it2);
1526
1527 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1528 for (auto &c : it->first.chunks())
1529 if (c.wire != NULL)
1530 reg_wires.insert(c.wire->name);
1531 }
1532 }
1533
1534 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
1535 {
1536 if (find_regs) {
1537 case_body_find_regs(&proc->root_case);
1538 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
1539 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
1540 for (auto &c : it2->first.chunks())
1541 if (c.wire != NULL)
1542 reg_wires.insert(c.wire->name);
1543 }
1544 return;
1545 }
1546
1547 f << stringf("%s" "always @* begin\n", indent.c_str());
1548 dump_case_body(f, indent, &proc->root_case, true);
1549
1550 std::string backup_indent = indent;
1551
1552 for (size_t i = 0; i < proc->syncs.size(); i++)
1553 {
1554 RTLIL::SyncRule *sync = proc->syncs[i];
1555 indent = backup_indent;
1556
1557 if (sync->type == RTLIL::STa) {
1558 f << stringf("%s" "always @* begin\n", indent.c_str());
1559 } else if (sync->type == RTLIL::STi) {
1560 f << stringf("%s" "initial begin\n", indent.c_str());
1561 } else {
1562 f << stringf("%s" "always @(", indent.c_str());
1563 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
1564 f << stringf("posedge ");
1565 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
1566 f << stringf("negedge ");
1567 dump_sigspec(f, sync->signal);
1568 f << stringf(") begin\n");
1569 }
1570 std::string ends = indent + "end\n";
1571 indent += " ";
1572
1573 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
1574 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
1575 dump_sigspec(f, sync->signal);
1576 f << stringf(") begin\n");
1577 ends = indent + "end\n" + ends;
1578 indent += " ";
1579 }
1580
1581 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
1582 for (size_t j = 0; j < proc->syncs.size(); j++) {
1583 RTLIL::SyncRule *sync2 = proc->syncs[j];
1584 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
1585 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
1586 dump_sigspec(f, sync2->signal);
1587 f << stringf(") begin\n");
1588 ends = indent + "end\n" + ends;
1589 indent += " ";
1590 }
1591 }
1592 }
1593
1594 for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
1595 if (it->first.size() == 0)
1596 continue;
1597 f << stringf("%s ", indent.c_str());
1598 dump_sigspec(f, it->first);
1599 f << stringf(" <= ");
1600 dump_sigspec(f, it->second);
1601 f << stringf(";\n");
1602 }
1603
1604 f << stringf("%s", ends.c_str());
1605 }
1606 }
1607
1608 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
1609 {
1610 reg_wires.clear();
1611 reset_auto_counter(module);
1612 active_module = module;
1613 active_sigmap.set(module);
1614 active_initdata.clear();
1615
1616 for (auto wire : module->wires())
1617 if (wire->attributes.count("\\init")) {
1618 SigSpec sig = active_sigmap(wire);
1619 Const val = wire->attributes.at("\\init");
1620 for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
1621 if (val[i] == State::S0 || val[i] == State::S1)
1622 active_initdata[sig[i]] = val[i];
1623 }
1624
1625 if (!module->processes.empty())
1626 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1627 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1628 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1629 "processes to logic networks and registers.\n", log_id(module));
1630
1631 f << stringf("\n");
1632 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1633 dump_process(f, indent + " ", it->second, true);
1634
1635 if (!noexpr)
1636 {
1637 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
1638 for (auto &it : module->cells_)
1639 {
1640 RTLIL::Cell *cell = it.second;
1641 if (!reg_ct.count(cell->type) || !cell->hasPort("\\Q"))
1642 continue;
1643
1644 RTLIL::SigSpec sig = cell->getPort("\\Q");
1645
1646 if (sig.is_chunk()) {
1647 RTLIL::SigChunk chunk = sig.as_chunk();
1648 if (chunk.wire != NULL)
1649 for (int i = 0; i < chunk.width; i++)
1650 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
1651 }
1652 }
1653 for (auto &it : module->wires_)
1654 {
1655 RTLIL::Wire *wire = it.second;
1656 for (int i = 0; i < wire->width; i++)
1657 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
1658 goto this_wire_aint_reg;
1659 if (wire->width)
1660 reg_wires.insert(wire->name);
1661 this_wire_aint_reg:;
1662 }
1663 }
1664
1665 dump_attributes(f, indent, module->attributes, '\n', true);
1666 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
1667 bool keep_running = true;
1668 for (int port_id = 1; keep_running; port_id++) {
1669 keep_running = false;
1670 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) {
1671 RTLIL::Wire *wire = it->second;
1672 if (wire->port_id == port_id) {
1673 if (port_id != 1)
1674 f << stringf(", ");
1675 f << stringf("%s", id(wire->name).c_str());
1676 keep_running = true;
1677 continue;
1678 }
1679 }
1680 }
1681 f << stringf(");\n");
1682
1683 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
1684 dump_wire(f, indent + " ", it->second);
1685
1686 for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
1687 dump_memory(f, indent + " ", it->second);
1688
1689 for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
1690 dump_cell(f, indent + " ", it->second);
1691
1692 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1693 dump_process(f, indent + " ", it->second);
1694
1695 for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
1696 dump_conn(f, indent + " ", it->first, it->second);
1697
1698 f << stringf("%s" "endmodule\n", indent.c_str());
1699 active_module = NULL;
1700 active_sigmap.clear();
1701 active_initdata.clear();
1702 }
1703
1704 struct VerilogBackend : public Backend {
1705 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1706 void help() YS_OVERRIDE
1707 {
1708 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1709 log("\n");
1710 log(" write_verilog [options] [filename]\n");
1711 log("\n");
1712 log("Write the current design to a Verilog file.\n");
1713 log("\n");
1714 log(" -norename\n");
1715 log(" without this option all internal object names (the ones with a dollar\n");
1716 log(" instead of a backslash prefix) are changed to short names in the\n");
1717 log(" format '_<number>_'.\n");
1718 log("\n");
1719 log(" -renameprefix <prefix>\n");
1720 log(" insert this prefix in front of auto-generated instance names\n");
1721 log("\n");
1722 log(" -noattr\n");
1723 log(" with this option no attributes are included in the output\n");
1724 log("\n");
1725 log(" -attr2comment\n");
1726 log(" with this option attributes are included as comments in the output\n");
1727 log("\n");
1728 log(" -noexpr\n");
1729 log(" without this option all internal cells are converted to Verilog\n");
1730 log(" expressions.\n");
1731 log("\n");
1732 log(" -siminit\n");
1733 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1734 log(" in -noexpr mode.\n");
1735 log("\n");
1736 log(" -nodec\n");
1737 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1738 log(" not bit pattern. This option deactivates this feature and instead\n");
1739 log(" will write out all constants in binary.\n");
1740 log("\n");
1741 log(" -decimal\n");
1742 log(" dump 32-bit constants in decimal and without size and radix\n");
1743 log("\n");
1744 log(" -nohex\n");
1745 log(" constant values that are compatible with hex output are usually\n");
1746 log(" dumped as hex values. This option deactivates this feature and\n");
1747 log(" instead will write out all constants in binary.\n");
1748 log("\n");
1749 log(" -nostr\n");
1750 log(" Parameters and attributes that are specified as strings in the\n");
1751 log(" original input will be output as strings by this back-end. This\n");
1752 log(" deactivates this feature and instead will write string constants\n");
1753 log(" as binary numbers.\n");
1754 log("\n");
1755 log(" -defparam\n");
1756 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1757 log(" cell parameters.\n");
1758 log("\n");
1759 log(" -blackboxes\n");
1760 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1761 log(" this option set only the modules with the 'blackbox' attribute\n");
1762 log(" are written to the output file.\n");
1763 log("\n");
1764 log(" -selected\n");
1765 log(" only write selected modules. modules must be selected entirely or\n");
1766 log(" not at all.\n");
1767 log("\n");
1768 log(" -v\n");
1769 log(" verbose output (print new names of all renamed wires and cells)\n");
1770 log("\n");
1771 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1772 log("always blocks. This frontend should only be used to export an RTLIL\n");
1773 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1774 log("processes to logic networks and registers. A warning is generated when\n");
1775 log("this command is called on a design with RTLIL processes.\n");
1776 log("\n");
1777 }
1778 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
1779 {
1780 log_header(design, "Executing Verilog backend.\n");
1781
1782 verbose = false;
1783 norename = false;
1784 noattr = false;
1785 attr2comment = false;
1786 noexpr = false;
1787 nodec = false;
1788 nohex = false;
1789 nostr = false;
1790 defparam = false;
1791 decimal = false;
1792 siminit = false;
1793 auto_prefix = "";
1794
1795 bool blackboxes = false;
1796 bool selected = false;
1797
1798 auto_name_map.clear();
1799 reg_wires.clear();
1800 reg_ct.clear();
1801
1802 reg_ct.insert("$dff");
1803 reg_ct.insert("$adff");
1804 reg_ct.insert("$dffe");
1805 reg_ct.insert("$dlatch");
1806
1807 reg_ct.insert("$_DFF_N_");
1808 reg_ct.insert("$_DFF_P_");
1809
1810 reg_ct.insert("$_DFF_NN0_");
1811 reg_ct.insert("$_DFF_NN1_");
1812 reg_ct.insert("$_DFF_NP0_");
1813 reg_ct.insert("$_DFF_NP1_");
1814 reg_ct.insert("$_DFF_PN0_");
1815 reg_ct.insert("$_DFF_PN1_");
1816 reg_ct.insert("$_DFF_PP0_");
1817 reg_ct.insert("$_DFF_PP1_");
1818
1819 reg_ct.insert("$_DFFSR_NNN_");
1820 reg_ct.insert("$_DFFSR_NNP_");
1821 reg_ct.insert("$_DFFSR_NPN_");
1822 reg_ct.insert("$_DFFSR_NPP_");
1823 reg_ct.insert("$_DFFSR_PNN_");
1824 reg_ct.insert("$_DFFSR_PNP_");
1825 reg_ct.insert("$_DFFSR_PPN_");
1826 reg_ct.insert("$_DFFSR_PPP_");
1827
1828 size_t argidx;
1829 for (argidx = 1; argidx < args.size(); argidx++) {
1830 std::string arg = args[argidx];
1831 if (arg == "-norename") {
1832 norename = true;
1833 continue;
1834 }
1835 if (arg == "-renameprefix" && argidx+1 < args.size()) {
1836 auto_prefix = args[++argidx];
1837 continue;
1838 }
1839 if (arg == "-noattr") {
1840 noattr = true;
1841 continue;
1842 }
1843 if (arg == "-attr2comment") {
1844 attr2comment = true;
1845 continue;
1846 }
1847 if (arg == "-noexpr") {
1848 noexpr = true;
1849 continue;
1850 }
1851 if (arg == "-nodec") {
1852 nodec = true;
1853 continue;
1854 }
1855 if (arg == "-nohex") {
1856 nohex = true;
1857 continue;
1858 }
1859 if (arg == "-nostr") {
1860 nostr = true;
1861 continue;
1862 }
1863 if (arg == "-defparam") {
1864 defparam = true;
1865 continue;
1866 }
1867 if (arg == "-decimal") {
1868 decimal = true;
1869 continue;
1870 }
1871 if (arg == "-siminit") {
1872 siminit = true;
1873 continue;
1874 }
1875 if (arg == "-blackboxes") {
1876 blackboxes = true;
1877 continue;
1878 }
1879 if (arg == "-selected") {
1880 selected = true;
1881 continue;
1882 }
1883 if (arg == "-v") {
1884 verbose = true;
1885 continue;
1886 }
1887 break;
1888 }
1889 extra_args(f, filename, args, argidx);
1890
1891 design->sort();
1892
1893 *f << stringf("/* Generated by %s */\n", yosys_version_str);
1894 for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
1895 if (it->second->get_blackbox_attribute() != blackboxes)
1896 continue;
1897 if (selected && !design->selected_whole_module(it->first)) {
1898 if (design->selected_module(it->first))
1899 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it->first));
1900 continue;
1901 }
1902 log("Dumping module `%s'.\n", it->first.c_str());
1903 dump_module(*f, "", it->second);
1904 }
1905
1906 auto_name_map.clear();
1907 reg_wires.clear();
1908 reg_ct.clear();
1909 }
1910 } VerilogBackend;
1911
1912 PRIVATE_NAMESPACE_END