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