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