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