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