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