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