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