write_verilog: dump zero width constants correctly.
[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" || cell->type == "$pmux_safe")
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 (cell->type != "$pmux_safe" && !noattr)
805 f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
806 f << stringf("%s" " casez (s)", indent.c_str());
807 if (cell->type != "$pmux_safe")
808 f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
809
810 for (int i = 0; i < s_width; i++)
811 {
812 f << stringf("%s" " %d'b", indent.c_str(), s_width);
813
814 for (int j = s_width-1; j >= 0; j--)
815 f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
816
817 f << stringf(":\n");
818 f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
819 }
820
821 f << stringf("%s" " default:\n", indent.c_str());
822 f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str());
823
824 f << stringf("%s" " endcase\n", indent.c_str());
825 f << stringf("%s" "endfunction\n", indent.c_str());
826
827 f << stringf("%s" "assign ", indent.c_str());
828 dump_sigspec(f, cell->getPort("\\Y"));
829 f << stringf(" = %s(", func_name.c_str());
830 dump_sigspec(f, cell->getPort("\\A"));
831 f << stringf(", ");
832 dump_sigspec(f, cell->getPort("\\B"));
833 f << stringf(", ");
834 dump_sigspec(f, cell->getPort("\\S"));
835 f << stringf(");\n");
836 return true;
837 }
838
839 if (cell->type == "$tribuf")
840 {
841 f << stringf("%s" "assign ", indent.c_str());
842 dump_sigspec(f, cell->getPort("\\Y"));
843 f << stringf(" = ");
844 dump_sigspec(f, cell->getPort("\\EN"));
845 f << stringf(" ? ");
846 dump_sigspec(f, cell->getPort("\\A"));
847 f << stringf(" : %d'bz;\n", cell->parameters.at("\\WIDTH").as_int());
848 return true;
849 }
850
851 if (cell->type == "$slice")
852 {
853 f << stringf("%s" "assign ", indent.c_str());
854 dump_sigspec(f, cell->getPort("\\Y"));
855 f << stringf(" = ");
856 dump_sigspec(f, cell->getPort("\\A"));
857 f << stringf(" >> %d;\n", cell->parameters.at("\\OFFSET").as_int());
858 return true;
859 }
860
861 if (cell->type == "$concat")
862 {
863 f << stringf("%s" "assign ", indent.c_str());
864 dump_sigspec(f, cell->getPort("\\Y"));
865 f << stringf(" = { ");
866 dump_sigspec(f, cell->getPort("\\B"));
867 f << stringf(" , ");
868 dump_sigspec(f, cell->getPort("\\A"));
869 f << stringf(" };\n");
870 return true;
871 }
872
873 if (cell->type == "$lut")
874 {
875 f << stringf("%s" "assign ", indent.c_str());
876 dump_sigspec(f, cell->getPort("\\Y"));
877 f << stringf(" = ");
878 dump_const(f, cell->parameters.at("\\LUT"));
879 f << stringf(" >> ");
880 dump_attributes(f, "", cell->attributes, ' ');
881 dump_sigspec(f, cell->getPort("\\A"));
882 f << stringf(";\n");
883 return true;
884 }
885
886 if (cell->type == "$dffsr")
887 {
888 SigSpec sig_clk = cell->getPort("\\CLK");
889 SigSpec sig_set = cell->getPort("\\SET");
890 SigSpec sig_clr = cell->getPort("\\CLR");
891 SigSpec sig_d = cell->getPort("\\D");
892 SigSpec sig_q = cell->getPort("\\Q");
893
894 int width = cell->parameters["\\WIDTH"].as_int();
895 bool pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
896 bool pol_set = cell->parameters["\\SET_POLARITY"].as_bool();
897 bool pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool();
898
899 std::string reg_name = cellname(cell);
900 bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
901
902 if (!out_is_reg_wire) {
903 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), width-1, reg_name.c_str());
904 dump_reg_init(f, sig_q);
905 f << ";\n";
906 }
907
908 for (int i = 0; i < width; i++) {
909 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
910 dump_sigspec(f, sig_clk);
911 f << stringf(", %sedge ", pol_set ? "pos" : "neg");
912 dump_sigspec(f, sig_set);
913 f << stringf(", %sedge ", pol_clr ? "pos" : "neg");
914 dump_sigspec(f, sig_clr);
915 f << stringf(")\n");
916
917 f << stringf("%s" " if (%s", indent.c_str(), pol_clr ? "" : "!");
918 dump_sigspec(f, sig_clr);
919 f << stringf(") %s[%d] <= 1'b0;\n", reg_name.c_str(), i);
920
921 f << stringf("%s" " else if (%s", indent.c_str(), pol_set ? "" : "!");
922 dump_sigspec(f, sig_set);
923 f << stringf(") %s[%d] <= 1'b1;\n", reg_name.c_str(), i);
924
925 f << stringf("%s" " else %s[%d] <= ", indent.c_str(), reg_name.c_str(), i);
926 dump_sigspec(f, sig_d[i]);
927 f << stringf(";\n");
928 }
929
930 if (!out_is_reg_wire) {
931 f << stringf("%s" "assign ", indent.c_str());
932 dump_sigspec(f, sig_q);
933 f << stringf(" = %s;\n", reg_name.c_str());
934 }
935
936 return true;
937 }
938
939 if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
940 {
941 RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
942 bool pol_clk, pol_arst = false, pol_en = false;
943
944 sig_clk = cell->getPort("\\CLK");
945 pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
946
947 if (cell->type == "$adff") {
948 sig_arst = cell->getPort("\\ARST");
949 pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool();
950 val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
951 }
952
953 if (cell->type == "$dffe") {
954 sig_en = cell->getPort("\\EN");
955 pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
956 }
957
958 std::string reg_name = cellname(cell);
959 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
960
961 if (!out_is_reg_wire) {
962 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
963 dump_reg_init(f, cell->getPort("\\Q"));
964 f << ";\n";
965 }
966
967 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
968 dump_sigspec(f, sig_clk);
969 if (cell->type == "$adff") {
970 f << stringf(" or %sedge ", pol_arst ? "pos" : "neg");
971 dump_sigspec(f, sig_arst);
972 }
973 f << stringf(")\n");
974
975 if (cell->type == "$adff") {
976 f << stringf("%s" " if (%s", indent.c_str(), pol_arst ? "" : "!");
977 dump_sigspec(f, sig_arst);
978 f << stringf(")\n");
979 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
980 dump_sigspec(f, val_arst);
981 f << stringf(";\n");
982 f << stringf("%s" " else\n", indent.c_str());
983 }
984
985 if (cell->type == "$dffe") {
986 f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
987 dump_sigspec(f, sig_en);
988 f << stringf(")\n");
989 }
990
991 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
992 dump_cell_expr_port(f, cell, "D", false);
993 f << stringf(";\n");
994
995 if (!out_is_reg_wire) {
996 f << stringf("%s" "assign ", indent.c_str());
997 dump_sigspec(f, cell->getPort("\\Q"));
998 f << stringf(" = %s;\n", reg_name.c_str());
999 }
1000
1001 return true;
1002 }
1003
1004 if (cell->type == "$dlatch")
1005 {
1006 RTLIL::SigSpec sig_en;
1007 bool pol_en = false;
1008
1009 sig_en = cell->getPort("\\EN");
1010 pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
1011
1012 std::string reg_name = cellname(cell);
1013 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
1014
1015 if (!out_is_reg_wire) {
1016 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
1017 dump_reg_init(f, cell->getPort("\\Q"));
1018 f << ";\n";
1019 }
1020
1021 f << stringf("%s" "always @*\n", indent.c_str());
1022
1023 f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
1024 dump_sigspec(f, sig_en);
1025 f << stringf(")\n");
1026
1027 f << stringf("%s" " %s = ", indent.c_str(), reg_name.c_str());
1028 dump_cell_expr_port(f, cell, "D", false);
1029 f << stringf(";\n");
1030
1031 if (!out_is_reg_wire) {
1032 f << stringf("%s" "assign ", indent.c_str());
1033 dump_sigspec(f, cell->getPort("\\Q"));
1034 f << stringf(" = %s;\n", reg_name.c_str());
1035 }
1036
1037 return true;
1038 }
1039
1040 if (cell->type == "$mem")
1041 {
1042 RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
1043 std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
1044 int abits = cell->parameters["\\ABITS"].as_int();
1045 int size = cell->parameters["\\SIZE"].as_int();
1046 int offset = cell->parameters["\\OFFSET"].as_int();
1047 int width = cell->parameters["\\WIDTH"].as_int();
1048 bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef());
1049
1050 // for memory block make something like:
1051 // reg [7:0] memid [3:0];
1052 // initial begin
1053 // memid[0] = ...
1054 // end
1055 f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size+offset-1, offset);
1056 if (use_init)
1057 {
1058 f << stringf("%s" "initial begin\n", indent.c_str());
1059 for (int i=0; i<size; i++)
1060 {
1061 f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i);
1062 dump_const(f, cell->parameters["\\INIT"].extract(i*width, width));
1063 f << stringf(";\n");
1064 }
1065 f << stringf("%s" "end\n", indent.c_str());
1066 }
1067
1068 // create a map : "edge clk" -> expressions within that clock domain
1069 dict<std::string, std::vector<std::string>> clk_to_lof_body;
1070 clk_to_lof_body[""] = std::vector<std::string>();
1071 std::string clk_domain_str;
1072 // create a list of reg declarations
1073 std::vector<std::string> lof_reg_declarations;
1074
1075 int nread_ports = cell->parameters["\\RD_PORTS"].as_int();
1076 RTLIL::SigSpec sig_rd_clk, sig_rd_en, sig_rd_data, sig_rd_addr;
1077 bool use_rd_clk, rd_clk_posedge, rd_transparent;
1078 // read ports
1079 for (int i=0; i < nread_ports; i++)
1080 {
1081 sig_rd_clk = cell->getPort("\\RD_CLK").extract(i);
1082 sig_rd_en = cell->getPort("\\RD_EN").extract(i);
1083 sig_rd_data = cell->getPort("\\RD_DATA").extract(i*width, width);
1084 sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
1085 use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
1086 rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
1087 rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
1088 if (use_rd_clk)
1089 {
1090 {
1091 std::ostringstream os;
1092 dump_sigspec(os, sig_rd_clk);
1093 clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
1094 if( clk_to_lof_body.count(clk_domain_str) == 0 )
1095 clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
1096 }
1097 if (!rd_transparent)
1098 {
1099 // for clocked read ports make something like:
1100 // reg [..] temp_id;
1101 // always @(posedge clk)
1102 // if (rd_en) temp_id <= array_reg[r_addr];
1103 // assign r_data = temp_id;
1104 std::string temp_id = next_auto_id();
1105 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
1106 {
1107 std::ostringstream os;
1108 if (sig_rd_en != RTLIL::SigBit(true))
1109 {
1110 os << stringf("if (");
1111 dump_sigspec(os, sig_rd_en);
1112 os << stringf(") ");
1113 }
1114 os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
1115 dump_sigspec(os, sig_rd_addr);
1116 os << stringf("];\n");
1117 clk_to_lof_body[clk_domain_str].push_back(os.str());
1118 }
1119 {
1120 std::ostringstream os;
1121 dump_sigspec(os, sig_rd_data);
1122 std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
1123 clk_to_lof_body[""].push_back(line);
1124 }
1125 }
1126 else
1127 {
1128 // for rd-transparent read-ports make something like:
1129 // reg [..] temp_id;
1130 // always @(posedge clk)
1131 // temp_id <= r_addr;
1132 // assign r_data = array_reg[temp_id];
1133 std::string temp_id = next_auto_id();
1134 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr.size() - 1, temp_id.c_str()) );
1135 {
1136 std::ostringstream os;
1137 dump_sigspec(os, sig_rd_addr);
1138 std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str());
1139 clk_to_lof_body[clk_domain_str].push_back(line);
1140 }
1141 {
1142 std::ostringstream os;
1143 dump_sigspec(os, sig_rd_data);
1144 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str());
1145 clk_to_lof_body[""].push_back(line);
1146 }
1147 }
1148 } else {
1149 // for non-clocked read-ports make something like:
1150 // assign r_data = array_reg[r_addr];
1151 std::ostringstream os, os2;
1152 dump_sigspec(os, sig_rd_data);
1153 dump_sigspec(os2, sig_rd_addr);
1154 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
1155 clk_to_lof_body[""].push_back(line);
1156 }
1157 }
1158
1159 int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
1160 RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en;
1161 bool wr_clk_posedge;
1162
1163 // write ports
1164 for (int i=0; i < nwrite_ports; i++)
1165 {
1166 sig_wr_clk = cell->getPort("\\WR_CLK").extract(i);
1167 sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width);
1168 sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits);
1169 sig_wr_en = cell->getPort("\\WR_EN").extract(i*width, width);
1170 wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool();
1171 {
1172 std::ostringstream os;
1173 dump_sigspec(os, sig_wr_clk);
1174 clk_domain_str = stringf("%sedge %s", wr_clk_posedge ? "pos" : "neg", os.str().c_str());
1175 if( clk_to_lof_body.count(clk_domain_str) == 0 )
1176 clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
1177 }
1178 // make something like:
1179 // always @(posedge clk)
1180 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1181 // ...
1182 for (int i = 0; i < GetSize(sig_wr_en); i++)
1183 {
1184 int start_i = i, width = 1;
1185 SigBit wen_bit = sig_wr_en[i];
1186
1187 while (i+1 < GetSize(sig_wr_en) && active_sigmap(sig_wr_en[i+1]) == active_sigmap(wen_bit))
1188 i++, width++;
1189
1190 if (wen_bit == State::S0)
1191 continue;
1192
1193 std::ostringstream os;
1194 if (wen_bit != State::S1)
1195 {
1196 os << stringf("if (");
1197 dump_sigspec(os, wen_bit);
1198 os << stringf(") ");
1199 }
1200 os << stringf("%s[", mem_id.c_str());
1201 dump_sigspec(os, sig_wr_addr);
1202 if (width == GetSize(sig_wr_en))
1203 os << stringf("] <= ");
1204 else
1205 os << stringf("][%d:%d] <= ", i, start_i);
1206 dump_sigspec(os, sig_wr_data.extract(start_i, width));
1207 os << stringf(";\n");
1208 clk_to_lof_body[clk_domain_str].push_back(os.str());
1209 }
1210 }
1211 // Output Verilog that looks something like this:
1212 // reg [..] _3_;
1213 // always @(posedge CLK2) begin
1214 // _3_ <= memory[D1ADDR];
1215 // if (A1EN)
1216 // memory[A1ADDR] <= A1DATA;
1217 // if (A2EN)
1218 // memory[A2ADDR] <= A2DATA;
1219 // ...
1220 // end
1221 // always @(negedge CLK1) begin
1222 // if (C1EN)
1223 // memory[C1ADDR] <= C1DATA;
1224 // end
1225 // ...
1226 // assign D1DATA = _3_;
1227 // assign D2DATA <= memory[D2ADDR];
1228
1229 // the reg ... definitions
1230 for(auto &reg : lof_reg_declarations)
1231 {
1232 f << stringf("%s" "%s", indent.c_str(), reg.c_str());
1233 }
1234 // the block of expressions by clock domain
1235 for(auto &pair : clk_to_lof_body)
1236 {
1237 std::string clk_domain = pair.first;
1238 std::vector<std::string> lof_lines = pair.second;
1239 if( clk_domain != "")
1240 {
1241 f << stringf("%s" "always @(%s) begin\n", indent.c_str(), clk_domain.c_str());
1242 for(auto &line : lof_lines)
1243 f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str());
1244 f << stringf("%s" "end\n", indent.c_str());
1245 }
1246 else
1247 {
1248 // the non-clocked assignments
1249 for(auto &line : lof_lines)
1250 f << stringf("%s" "%s", indent.c_str(), line.c_str());
1251 }
1252 }
1253
1254 return true;
1255 }
1256
1257 if (cell->type.in("$assert", "$assume", "$cover"))
1258 {
1259 f << stringf("%s" "always @* if (", indent.c_str());
1260 dump_sigspec(f, cell->getPort("\\EN"));
1261 f << stringf(") %s(", cell->type.c_str()+1);
1262 dump_sigspec(f, cell->getPort("\\A"));
1263 f << stringf(");\n");
1264 return true;
1265 }
1266
1267 if (cell->type.in("$specify2", "$specify3"))
1268 {
1269 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1270
1271 SigSpec en = cell->getPort("\\EN");
1272 if (en != State::S1) {
1273 f << stringf("if (");
1274 dump_sigspec(f, cell->getPort("\\EN"));
1275 f << stringf(") ");
1276 }
1277
1278 f << "(";
1279 if (cell->type == "$specify3" && cell->getParam("\\EDGE_EN").as_bool())
1280 f << (cell->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1281
1282 dump_sigspec(f, cell->getPort("\\SRC"));
1283
1284 f << " ";
1285 if (cell->getParam("\\SRC_DST_PEN").as_bool())
1286 f << (cell->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1287 f << (cell->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1288
1289 if (cell->type == "$specify3") {
1290 f << "(";
1291 dump_sigspec(f, cell->getPort("\\DST"));
1292 f << " ";
1293 if (cell->getParam("\\DAT_DST_PEN").as_bool())
1294 f << (cell->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1295 f << ": ";
1296 dump_sigspec(f, cell->getPort("\\DAT"));
1297 f << ")";
1298 } else {
1299 dump_sigspec(f, cell->getPort("\\DST"));
1300 }
1301
1302 bool bak_decimal = decimal;
1303 decimal = 1;
1304
1305 f << ") = (";
1306 dump_const(f, cell->getParam("\\T_RISE_MIN"));
1307 f << ":";
1308 dump_const(f, cell->getParam("\\T_RISE_TYP"));
1309 f << ":";
1310 dump_const(f, cell->getParam("\\T_RISE_MAX"));
1311 f << ", ";
1312 dump_const(f, cell->getParam("\\T_FALL_MIN"));
1313 f << ":";
1314 dump_const(f, cell->getParam("\\T_FALL_TYP"));
1315 f << ":";
1316 dump_const(f, cell->getParam("\\T_FALL_MAX"));
1317 f << ");\n";
1318
1319 decimal = bak_decimal;
1320
1321 f << stringf("%s" "endspecify\n", indent.c_str());
1322 return true;
1323 }
1324
1325 if (cell->type == "$specrule")
1326 {
1327 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1328
1329 string spec_type = cell->getParam("\\TYPE").decode_string();
1330 f << stringf("%s(", spec_type.c_str());
1331
1332 if (cell->getParam("\\SRC_PEN").as_bool())
1333 f << (cell->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1334 dump_sigspec(f, cell->getPort("\\SRC"));
1335
1336 if (cell->getPort("\\SRC_EN") != State::S1) {
1337 f << " &&& ";
1338 dump_sigspec(f, cell->getPort("\\SRC_EN"));
1339 }
1340
1341 f << ", ";
1342 if (cell->getParam("\\DST_PEN").as_bool())
1343 f << (cell->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1344 dump_sigspec(f, cell->getPort("\\DST"));
1345
1346 if (cell->getPort("\\DST_EN") != State::S1) {
1347 f << " &&& ";
1348 dump_sigspec(f, cell->getPort("\\DST_EN"));
1349 }
1350
1351 bool bak_decimal = decimal;
1352 decimal = 1;
1353
1354 f << ", ";
1355 dump_const(f, cell->getParam("\\T_LIMIT"));
1356
1357 if (spec_type == "$setuphold" || spec_type == "$recrem" || spec_type == "$fullskew") {
1358 f << ", ";
1359 dump_const(f, cell->getParam("\\T_LIMIT2"));
1360 }
1361
1362 f << ");\n";
1363 decimal = bak_decimal;
1364
1365 f << stringf("%s" "endspecify\n", indent.c_str());
1366 return true;
1367 }
1368
1369 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1370 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1371
1372 return false;
1373 }
1374
1375 void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
1376 {
1377 if (cell->type[0] == '$' && !noexpr) {
1378 if (dump_cell_expr(f, indent, cell))
1379 return;
1380 }
1381
1382 dump_attributes(f, indent, cell->attributes);
1383 f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
1384
1385 if (!defparam && cell->parameters.size() > 0) {
1386 f << stringf(" #(");
1387 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1388 if (it != cell->parameters.begin())
1389 f << stringf(",");
1390 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1391 dump_const(f, it->second);
1392 f << stringf(")");
1393 }
1394 f << stringf("\n%s" ")", indent.c_str());
1395 }
1396
1397 std::string cell_name = cellname(cell);
1398 if (cell_name != id(cell->name))
1399 f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
1400 else
1401 f << stringf(" %s (", cell_name.c_str());
1402
1403 bool first_arg = true;
1404 std::set<RTLIL::IdString> numbered_ports;
1405 for (int i = 1; true; i++) {
1406 char str[16];
1407 snprintf(str, 16, "$%d", i);
1408 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1409 if (it->first != str)
1410 continue;
1411 if (!first_arg)
1412 f << stringf(",");
1413 first_arg = false;
1414 f << stringf("\n%s ", indent.c_str());
1415 dump_sigspec(f, it->second);
1416 numbered_ports.insert(it->first);
1417 goto found_numbered_port;
1418 }
1419 break;
1420 found_numbered_port:;
1421 }
1422 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1423 if (numbered_ports.count(it->first))
1424 continue;
1425 if (!first_arg)
1426 f << stringf(",");
1427 first_arg = false;
1428 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1429 if (it->second.size() > 0)
1430 dump_sigspec(f, it->second);
1431 f << stringf(")");
1432 }
1433 f << stringf("\n%s" ");\n", indent.c_str());
1434
1435 if (defparam && cell->parameters.size() > 0) {
1436 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1437 f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
1438 dump_const(f, it->second);
1439 f << stringf(";\n");
1440 }
1441 }
1442
1443 if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) {
1444 std::stringstream ss;
1445 dump_reg_init(ss, cell->getPort("\\Q"));
1446 if (!ss.str().empty()) {
1447 f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str());
1448 f << ss.str();
1449 f << ";\n";
1450 }
1451 }
1452 }
1453
1454 void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
1455 {
1456 f << stringf("%s" "assign ", indent.c_str());
1457 dump_sigspec(f, left);
1458 f << stringf(" = ");
1459 dump_sigspec(f, right);
1460 f << stringf(";\n");
1461 }
1462
1463 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
1464
1465 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
1466 {
1467 int number_of_stmts = cs->switches.size() + cs->actions.size();
1468
1469 if (!omit_trailing_begin && number_of_stmts >= 2)
1470 f << stringf("%s" "begin\n", indent.c_str());
1471
1472 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1473 if (it->first.size() == 0)
1474 continue;
1475 f << stringf("%s ", indent.c_str());
1476 dump_sigspec(f, it->first);
1477 f << stringf(" = ");
1478 dump_sigspec(f, it->second);
1479 f << stringf(";\n");
1480 }
1481
1482 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1483 dump_proc_switch(f, indent + " ", *it);
1484
1485 if (!omit_trailing_begin && number_of_stmts == 0)
1486 f << stringf("%s /* empty */;\n", indent.c_str());
1487
1488 if (omit_trailing_begin || number_of_stmts >= 2)
1489 f << stringf("%s" "end\n", indent.c_str());
1490 }
1491
1492 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
1493 {
1494 if (sw->signal.size() == 0) {
1495 f << stringf("%s" "begin\n", indent.c_str());
1496 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1497 if ((*it)->compare.size() == 0)
1498 dump_case_body(f, indent + " ", *it);
1499 }
1500 f << stringf("%s" "end\n", indent.c_str());
1501 return;
1502 }
1503
1504 dump_attributes(f, indent, sw->attributes);
1505 f << stringf("%s" "casez (", indent.c_str());
1506 dump_sigspec(f, sw->signal);
1507 f << stringf(")\n");
1508
1509 bool got_default = false;
1510 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1511 dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*as_comment=*/true);
1512 if ((*it)->compare.size() == 0) {
1513 if (got_default)
1514 continue;
1515 f << stringf("%s default", indent.c_str());
1516 got_default = true;
1517 } else {
1518 f << stringf("%s ", indent.c_str());
1519 for (size_t i = 0; i < (*it)->compare.size(); i++) {
1520 if (i > 0)
1521 f << stringf(", ");
1522 dump_sigspec(f, (*it)->compare[i]);
1523 }
1524 }
1525 f << stringf(":\n");
1526 dump_case_body(f, indent + " ", *it);
1527 }
1528
1529 f << stringf("%s" "endcase\n", indent.c_str());
1530 }
1531
1532 void case_body_find_regs(RTLIL::CaseRule *cs)
1533 {
1534 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1535 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
1536 case_body_find_regs(*it2);
1537
1538 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1539 for (auto &c : it->first.chunks())
1540 if (c.wire != NULL)
1541 reg_wires.insert(c.wire->name);
1542 }
1543 }
1544
1545 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
1546 {
1547 if (find_regs) {
1548 case_body_find_regs(&proc->root_case);
1549 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
1550 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
1551 for (auto &c : it2->first.chunks())
1552 if (c.wire != NULL)
1553 reg_wires.insert(c.wire->name);
1554 }
1555 return;
1556 }
1557
1558 f << stringf("%s" "always @* begin\n", indent.c_str());
1559 dump_case_body(f, indent, &proc->root_case, true);
1560
1561 std::string backup_indent = indent;
1562
1563 for (size_t i = 0; i < proc->syncs.size(); i++)
1564 {
1565 RTLIL::SyncRule *sync = proc->syncs[i];
1566 indent = backup_indent;
1567
1568 if (sync->type == RTLIL::STa) {
1569 f << stringf("%s" "always @* begin\n", indent.c_str());
1570 } else if (sync->type == RTLIL::STi) {
1571 f << stringf("%s" "initial begin\n", indent.c_str());
1572 } else {
1573 f << stringf("%s" "always @(", indent.c_str());
1574 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
1575 f << stringf("posedge ");
1576 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
1577 f << stringf("negedge ");
1578 dump_sigspec(f, sync->signal);
1579 f << stringf(") begin\n");
1580 }
1581 std::string ends = indent + "end\n";
1582 indent += " ";
1583
1584 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
1585 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
1586 dump_sigspec(f, sync->signal);
1587 f << stringf(") begin\n");
1588 ends = indent + "end\n" + ends;
1589 indent += " ";
1590 }
1591
1592 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
1593 for (size_t j = 0; j < proc->syncs.size(); j++) {
1594 RTLIL::SyncRule *sync2 = proc->syncs[j];
1595 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
1596 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
1597 dump_sigspec(f, sync2->signal);
1598 f << stringf(") begin\n");
1599 ends = indent + "end\n" + ends;
1600 indent += " ";
1601 }
1602 }
1603 }
1604
1605 for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
1606 if (it->first.size() == 0)
1607 continue;
1608 f << stringf("%s ", indent.c_str());
1609 dump_sigspec(f, it->first);
1610 f << stringf(" <= ");
1611 dump_sigspec(f, it->second);
1612 f << stringf(";\n");
1613 }
1614
1615 f << stringf("%s", ends.c_str());
1616 }
1617 }
1618
1619 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
1620 {
1621 reg_wires.clear();
1622 reset_auto_counter(module);
1623 active_module = module;
1624 active_sigmap.set(module);
1625 active_initdata.clear();
1626
1627 for (auto wire : module->wires())
1628 if (wire->attributes.count("\\init")) {
1629 SigSpec sig = active_sigmap(wire);
1630 Const val = wire->attributes.at("\\init");
1631 for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
1632 if (val[i] == State::S0 || val[i] == State::S1)
1633 active_initdata[sig[i]] = val[i];
1634 }
1635
1636 if (!module->processes.empty())
1637 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1638 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1639 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1640 "processes to logic networks and registers.\n", log_id(module));
1641
1642 f << stringf("\n");
1643 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1644 dump_process(f, indent + " ", it->second, true);
1645
1646 if (!noexpr)
1647 {
1648 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
1649 for (auto &it : module->cells_)
1650 {
1651 RTLIL::Cell *cell = it.second;
1652 if (!reg_ct.count(cell->type) || !cell->hasPort("\\Q"))
1653 continue;
1654
1655 RTLIL::SigSpec sig = cell->getPort("\\Q");
1656
1657 if (sig.is_chunk()) {
1658 RTLIL::SigChunk chunk = sig.as_chunk();
1659 if (chunk.wire != NULL)
1660 for (int i = 0; i < chunk.width; i++)
1661 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
1662 }
1663 }
1664 for (auto &it : module->wires_)
1665 {
1666 RTLIL::Wire *wire = it.second;
1667 for (int i = 0; i < wire->width; i++)
1668 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
1669 goto this_wire_aint_reg;
1670 if (wire->width)
1671 reg_wires.insert(wire->name);
1672 this_wire_aint_reg:;
1673 }
1674 }
1675
1676 dump_attributes(f, indent, module->attributes, '\n', /*attr2comment=*/true);
1677 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
1678 bool keep_running = true;
1679 for (int port_id = 1; keep_running; port_id++) {
1680 keep_running = false;
1681 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) {
1682 RTLIL::Wire *wire = it->second;
1683 if (wire->port_id == port_id) {
1684 if (port_id != 1)
1685 f << stringf(", ");
1686 f << stringf("%s", id(wire->name).c_str());
1687 keep_running = true;
1688 continue;
1689 }
1690 }
1691 }
1692 f << stringf(");\n");
1693
1694 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
1695 dump_wire(f, indent + " ", it->second);
1696
1697 for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
1698 dump_memory(f, indent + " ", it->second);
1699
1700 for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
1701 dump_cell(f, indent + " ", it->second);
1702
1703 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1704 dump_process(f, indent + " ", it->second);
1705
1706 for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
1707 dump_conn(f, indent + " ", it->first, it->second);
1708
1709 f << stringf("%s" "endmodule\n", indent.c_str());
1710 active_module = NULL;
1711 active_sigmap.clear();
1712 active_initdata.clear();
1713 }
1714
1715 struct VerilogBackend : public Backend {
1716 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1717 void help() YS_OVERRIDE
1718 {
1719 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1720 log("\n");
1721 log(" write_verilog [options] [filename]\n");
1722 log("\n");
1723 log("Write the current design to a Verilog file.\n");
1724 log("\n");
1725 log(" -norename\n");
1726 log(" without this option all internal object names (the ones with a dollar\n");
1727 log(" instead of a backslash prefix) are changed to short names in the\n");
1728 log(" format '_<number>_'.\n");
1729 log("\n");
1730 log(" -renameprefix <prefix>\n");
1731 log(" insert this prefix in front of auto-generated instance names\n");
1732 log("\n");
1733 log(" -noattr\n");
1734 log(" with this option no attributes are included in the output\n");
1735 log("\n");
1736 log(" -attr2comment\n");
1737 log(" with this option attributes are included as comments in the output\n");
1738 log("\n");
1739 log(" -noexpr\n");
1740 log(" without this option all internal cells are converted to Verilog\n");
1741 log(" expressions.\n");
1742 log("\n");
1743 log(" -siminit\n");
1744 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1745 log(" in -noexpr mode.\n");
1746 log("\n");
1747 log(" -nodec\n");
1748 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1749 log(" not bit pattern. This option deactivates this feature and instead\n");
1750 log(" will write out all constants in binary.\n");
1751 log("\n");
1752 log(" -decimal\n");
1753 log(" dump 32-bit constants in decimal and without size and radix\n");
1754 log("\n");
1755 log(" -nohex\n");
1756 log(" constant values that are compatible with hex output are usually\n");
1757 log(" dumped as hex values. This option deactivates this feature and\n");
1758 log(" instead will write out all constants in binary.\n");
1759 log("\n");
1760 log(" -nostr\n");
1761 log(" Parameters and attributes that are specified as strings in the\n");
1762 log(" original input will be output as strings by this back-end. This\n");
1763 log(" deactivates this feature and instead will write string constants\n");
1764 log(" as binary numbers.\n");
1765 log("\n");
1766 log(" -defparam\n");
1767 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1768 log(" cell parameters.\n");
1769 log("\n");
1770 log(" -blackboxes\n");
1771 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1772 log(" this option set only the modules with the 'blackbox' attribute\n");
1773 log(" are written to the output file.\n");
1774 log("\n");
1775 log(" -selected\n");
1776 log(" only write selected modules. modules must be selected entirely or\n");
1777 log(" not at all.\n");
1778 log("\n");
1779 log(" -v\n");
1780 log(" verbose output (print new names of all renamed wires and cells)\n");
1781 log("\n");
1782 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1783 log("always blocks. This frontend should only be used to export an RTLIL\n");
1784 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1785 log("processes to logic networks and registers. A warning is generated when\n");
1786 log("this command is called on a design with RTLIL processes.\n");
1787 log("\n");
1788 }
1789 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
1790 {
1791 log_header(design, "Executing Verilog backend.\n");
1792
1793 verbose = false;
1794 norename = false;
1795 noattr = false;
1796 attr2comment = false;
1797 noexpr = false;
1798 nodec = false;
1799 nohex = false;
1800 nostr = false;
1801 defparam = false;
1802 decimal = false;
1803 siminit = false;
1804 auto_prefix = "";
1805
1806 bool blackboxes = false;
1807 bool selected = false;
1808
1809 auto_name_map.clear();
1810 reg_wires.clear();
1811 reg_ct.clear();
1812
1813 reg_ct.insert("$dff");
1814 reg_ct.insert("$adff");
1815 reg_ct.insert("$dffe");
1816 reg_ct.insert("$dlatch");
1817
1818 reg_ct.insert("$_DFF_N_");
1819 reg_ct.insert("$_DFF_P_");
1820
1821 reg_ct.insert("$_DFF_NN0_");
1822 reg_ct.insert("$_DFF_NN1_");
1823 reg_ct.insert("$_DFF_NP0_");
1824 reg_ct.insert("$_DFF_NP1_");
1825 reg_ct.insert("$_DFF_PN0_");
1826 reg_ct.insert("$_DFF_PN1_");
1827 reg_ct.insert("$_DFF_PP0_");
1828 reg_ct.insert("$_DFF_PP1_");
1829
1830 reg_ct.insert("$_DFFSR_NNN_");
1831 reg_ct.insert("$_DFFSR_NNP_");
1832 reg_ct.insert("$_DFFSR_NPN_");
1833 reg_ct.insert("$_DFFSR_NPP_");
1834 reg_ct.insert("$_DFFSR_PNN_");
1835 reg_ct.insert("$_DFFSR_PNP_");
1836 reg_ct.insert("$_DFFSR_PPN_");
1837 reg_ct.insert("$_DFFSR_PPP_");
1838
1839 size_t argidx;
1840 for (argidx = 1; argidx < args.size(); argidx++) {
1841 std::string arg = args[argidx];
1842 if (arg == "-norename") {
1843 norename = true;
1844 continue;
1845 }
1846 if (arg == "-renameprefix" && argidx+1 < args.size()) {
1847 auto_prefix = args[++argidx];
1848 continue;
1849 }
1850 if (arg == "-noattr") {
1851 noattr = true;
1852 continue;
1853 }
1854 if (arg == "-attr2comment") {
1855 attr2comment = true;
1856 continue;
1857 }
1858 if (arg == "-noexpr") {
1859 noexpr = true;
1860 continue;
1861 }
1862 if (arg == "-nodec") {
1863 nodec = true;
1864 continue;
1865 }
1866 if (arg == "-nohex") {
1867 nohex = true;
1868 continue;
1869 }
1870 if (arg == "-nostr") {
1871 nostr = true;
1872 continue;
1873 }
1874 if (arg == "-defparam") {
1875 defparam = true;
1876 continue;
1877 }
1878 if (arg == "-decimal") {
1879 decimal = true;
1880 continue;
1881 }
1882 if (arg == "-siminit") {
1883 siminit = true;
1884 continue;
1885 }
1886 if (arg == "-blackboxes") {
1887 blackboxes = true;
1888 continue;
1889 }
1890 if (arg == "-selected") {
1891 selected = true;
1892 continue;
1893 }
1894 if (arg == "-v") {
1895 verbose = true;
1896 continue;
1897 }
1898 break;
1899 }
1900 extra_args(f, filename, args, argidx);
1901
1902 design->sort();
1903
1904 *f << stringf("/* Generated by %s */\n", yosys_version_str);
1905 for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
1906 if (it->second->get_blackbox_attribute() != blackboxes)
1907 continue;
1908 if (selected && !design->selected_whole_module(it->first)) {
1909 if (design->selected_module(it->first))
1910 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it->first));
1911 continue;
1912 }
1913 log("Dumping module `%s'.\n", it->first.c_str());
1914 dump_module(*f, "", it->second);
1915 }
1916
1917 auto_name_map.clear();
1918 reg_wires.clear();
1919 reg_ct.clear();
1920 }
1921 } VerilogBackend;
1922
1923 PRIVATE_NAMESPACE_END