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