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