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