generate only simple assignments in verilog backend
[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;
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 int offset = 0;
1550 for (auto &chunk : left.chunks()) {
1551 f << stringf("%s" "assign ", indent.c_str());
1552 dump_sigspec(f, chunk);
1553 f << stringf(" = ");
1554 dump_sigspec(f, right.extract(offset, GetSize(chunk)));
1555 f << stringf(";\n");
1556 offset += GetSize(chunk);
1557 }
1558 }
1559
1560 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
1561
1562 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
1563 {
1564 int number_of_stmts = cs->switches.size() + cs->actions.size();
1565
1566 if (!omit_trailing_begin && number_of_stmts >= 2)
1567 f << stringf("%s" "begin\n", indent.c_str());
1568
1569 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1570 if (it->first.size() == 0)
1571 continue;
1572 f << stringf("%s ", indent.c_str());
1573 dump_sigspec(f, it->first);
1574 f << stringf(" = ");
1575 dump_sigspec(f, it->second);
1576 f << stringf(";\n");
1577 }
1578
1579 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1580 dump_proc_switch(f, indent + " ", *it);
1581
1582 if (!omit_trailing_begin && number_of_stmts == 0)
1583 f << stringf("%s /* empty */;\n", indent.c_str());
1584
1585 if (omit_trailing_begin || number_of_stmts >= 2)
1586 f << stringf("%s" "end\n", indent.c_str());
1587 }
1588
1589 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
1590 {
1591 if (sw->signal.size() == 0) {
1592 f << stringf("%s" "begin\n", indent.c_str());
1593 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1594 if ((*it)->compare.size() == 0)
1595 dump_case_body(f, indent + " ", *it);
1596 }
1597 f << stringf("%s" "end\n", indent.c_str());
1598 return;
1599 }
1600
1601 dump_attributes(f, indent, sw->attributes);
1602 f << stringf("%s" "casez (", indent.c_str());
1603 dump_sigspec(f, sw->signal);
1604 f << stringf(")\n");
1605
1606 bool got_default = false;
1607 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1608 dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1609 if ((*it)->compare.size() == 0) {
1610 if (got_default)
1611 continue;
1612 f << stringf("%s default", indent.c_str());
1613 got_default = true;
1614 } else {
1615 f << stringf("%s ", indent.c_str());
1616 for (size_t i = 0; i < (*it)->compare.size(); i++) {
1617 if (i > 0)
1618 f << stringf(", ");
1619 dump_sigspec(f, (*it)->compare[i]);
1620 }
1621 }
1622 f << stringf(":\n");
1623 dump_case_body(f, indent + " ", *it);
1624 }
1625
1626 f << stringf("%s" "endcase\n", indent.c_str());
1627 }
1628
1629 void case_body_find_regs(RTLIL::CaseRule *cs)
1630 {
1631 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1632 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
1633 case_body_find_regs(*it2);
1634
1635 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1636 for (auto &c : it->first.chunks())
1637 if (c.wire != NULL)
1638 reg_wires.insert(c.wire->name);
1639 }
1640 }
1641
1642 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
1643 {
1644 if (find_regs) {
1645 case_body_find_regs(&proc->root_case);
1646 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
1647 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
1648 for (auto &c : it2->first.chunks())
1649 if (c.wire != NULL)
1650 reg_wires.insert(c.wire->name);
1651 }
1652 return;
1653 }
1654
1655 f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*");
1656 if (!systemverilog)
1657 f << indent + " " << "if (" << id("\\initial") << ") begin end\n";
1658 dump_case_body(f, indent, &proc->root_case, true);
1659
1660 std::string backup_indent = indent;
1661
1662 for (size_t i = 0; i < proc->syncs.size(); i++)
1663 {
1664 RTLIL::SyncRule *sync = proc->syncs[i];
1665 indent = backup_indent;
1666
1667 if (sync->type == RTLIL::STa) {
1668 f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*");
1669 } else if (sync->type == RTLIL::STi) {
1670 f << stringf("%s" "initial begin\n", indent.c_str());
1671 } else {
1672 f << stringf("%s" "always%s @(", indent.c_str(), systemverilog ? "_ff" : "");
1673 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
1674 f << stringf("posedge ");
1675 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
1676 f << stringf("negedge ");
1677 dump_sigspec(f, sync->signal);
1678 f << stringf(") begin\n");
1679 }
1680 std::string ends = indent + "end\n";
1681 indent += " ";
1682
1683 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
1684 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
1685 dump_sigspec(f, sync->signal);
1686 f << stringf(") begin\n");
1687 ends = indent + "end\n" + ends;
1688 indent += " ";
1689 }
1690
1691 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
1692 for (size_t j = 0; j < proc->syncs.size(); j++) {
1693 RTLIL::SyncRule *sync2 = proc->syncs[j];
1694 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
1695 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
1696 dump_sigspec(f, sync2->signal);
1697 f << stringf(") begin\n");
1698 ends = indent + "end\n" + ends;
1699 indent += " ";
1700 }
1701 }
1702 }
1703
1704 for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
1705 if (it->first.size() == 0)
1706 continue;
1707 f << stringf("%s ", indent.c_str());
1708 dump_sigspec(f, it->first);
1709 f << stringf(" <= ");
1710 dump_sigspec(f, it->second);
1711 f << stringf(";\n");
1712 }
1713
1714 f << stringf("%s", ends.c_str());
1715 }
1716 }
1717
1718 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
1719 {
1720 reg_wires.clear();
1721 reset_auto_counter(module);
1722 active_module = module;
1723 active_sigmap.set(module);
1724 active_initdata.clear();
1725
1726 for (auto wire : module->wires())
1727 if (wire->attributes.count(ID::init)) {
1728 SigSpec sig = active_sigmap(wire);
1729 Const val = wire->attributes.at(ID::init);
1730 for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
1731 if (val[i] == State::S0 || val[i] == State::S1)
1732 active_initdata[sig[i]] = val[i];
1733 }
1734
1735 if (!module->processes.empty())
1736 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1737 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1738 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1739 "processes to logic networks and registers.\n", log_id(module));
1740
1741 f << stringf("\n");
1742 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1743 dump_process(f, indent + " ", it->second, true);
1744
1745 if (!noexpr)
1746 {
1747 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
1748 for (auto cell : module->cells())
1749 {
1750 if (!RTLIL::builtin_ff_cell_types().count(cell->type) || !cell->hasPort(ID::Q) || cell->type.in(ID($ff), ID($_FF_)))
1751 continue;
1752
1753 RTLIL::SigSpec sig = cell->getPort(ID::Q);
1754
1755 if (sig.is_chunk()) {
1756 RTLIL::SigChunk chunk = sig.as_chunk();
1757 if (chunk.wire != NULL)
1758 for (int i = 0; i < chunk.width; i++)
1759 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
1760 }
1761 }
1762 for (auto wire : module->wires())
1763 {
1764 for (int i = 0; i < wire->width; i++)
1765 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
1766 goto this_wire_aint_reg;
1767 if (wire->width)
1768 reg_wires.insert(wire->name);
1769 this_wire_aint_reg:;
1770 }
1771 }
1772
1773 dump_attributes(f, indent, module->attributes, '\n', /*modattr=*/true);
1774 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
1775 bool keep_running = true;
1776 for (int port_id = 1; keep_running; port_id++) {
1777 keep_running = false;
1778 for (auto wire : module->wires()) {
1779 if (wire->port_id == port_id) {
1780 if (port_id != 1)
1781 f << stringf(", ");
1782 f << stringf("%s", id(wire->name).c_str());
1783 keep_running = true;
1784 continue;
1785 }
1786 }
1787 }
1788 f << stringf(");\n");
1789
1790 if (!systemverilog && !module->processes.empty())
1791 f << indent + " " << "reg " << id("\\initial") << " = 0;\n";
1792
1793 for (auto w : module->wires())
1794 dump_wire(f, indent + " ", w);
1795
1796 for (auto &mem : Mem::get_all_memories(module))
1797 dump_memory(f, indent + " ", mem);
1798
1799 for (auto cell : module->cells())
1800 dump_cell(f, indent + " ", cell);
1801
1802 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1803 dump_process(f, indent + " ", it->second);
1804
1805 for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
1806 dump_conn(f, indent + " ", it->first, it->second);
1807
1808 f << stringf("%s" "endmodule\n", indent.c_str());
1809 active_module = NULL;
1810 active_sigmap.clear();
1811 active_initdata.clear();
1812 }
1813
1814 struct VerilogBackend : public Backend {
1815 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1816 void help() override
1817 {
1818 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1819 log("\n");
1820 log(" write_verilog [options] [filename]\n");
1821 log("\n");
1822 log("Write the current design to a Verilog file.\n");
1823 log("\n");
1824 log(" -sv\n");
1825 log(" with this option, SystemVerilog constructs like always_comb are used\n");
1826 log("\n");
1827 log(" -norename\n");
1828 log(" without this option all internal object names (the ones with a dollar\n");
1829 log(" instead of a backslash prefix) are changed to short names in the\n");
1830 log(" format '_<number>_'.\n");
1831 log("\n");
1832 log(" -renameprefix <prefix>\n");
1833 log(" insert this prefix in front of auto-generated instance names\n");
1834 log("\n");
1835 log(" -noattr\n");
1836 log(" with this option no attributes are included in the output\n");
1837 log("\n");
1838 log(" -attr2comment\n");
1839 log(" with this option attributes are included as comments in the output\n");
1840 log("\n");
1841 log(" -noexpr\n");
1842 log(" without this option all internal cells are converted to Verilog\n");
1843 log(" expressions.\n");
1844 log("\n");
1845 log(" -siminit\n");
1846 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1847 log(" in -noexpr mode.\n");
1848 log("\n");
1849 log(" -nodec\n");
1850 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1851 log(" not bit pattern. This option deactivates this feature and instead\n");
1852 log(" will write out all constants in binary.\n");
1853 log("\n");
1854 log(" -decimal\n");
1855 log(" dump 32-bit constants in decimal and without size and radix\n");
1856 log("\n");
1857 log(" -nohex\n");
1858 log(" constant values that are compatible with hex output are usually\n");
1859 log(" dumped as hex values. This option deactivates this feature and\n");
1860 log(" instead will write out all constants in binary.\n");
1861 log("\n");
1862 log(" -nostr\n");
1863 log(" Parameters and attributes that are specified as strings in the\n");
1864 log(" original input will be output as strings by this back-end. This\n");
1865 log(" deactivates this feature and instead will write string constants\n");
1866 log(" as binary numbers.\n");
1867 log("\n");
1868 log(" -extmem\n");
1869 log(" instead of initializing memories using assignments to individual\n");
1870 log(" elements, use the '$readmemh' function to read initialization data\n");
1871 log(" from a file. This data is written to a file named by appending\n");
1872 log(" a sequential index to the Verilog filename and replacing the extension\n");
1873 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
1874 log(" 'foo-2.mem' and so on.\n");
1875 log("\n");
1876 log(" -defparam\n");
1877 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1878 log(" cell parameters.\n");
1879 log("\n");
1880 log(" -blackboxes\n");
1881 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1882 log(" this option set only the modules with the 'blackbox' attribute\n");
1883 log(" are written to the output file.\n");
1884 log("\n");
1885 log(" -selected\n");
1886 log(" only write selected modules. modules must be selected entirely or\n");
1887 log(" not at all.\n");
1888 log("\n");
1889 log(" -v\n");
1890 log(" verbose output (print new names of all renamed wires and cells)\n");
1891 log("\n");
1892 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1893 log("always blocks. This frontend should only be used to export an RTLIL\n");
1894 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1895 log("processes to logic networks and registers. A warning is generated when\n");
1896 log("this command is called on a design with RTLIL processes.\n");
1897 log("\n");
1898 }
1899 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
1900 {
1901 log_header(design, "Executing Verilog backend.\n");
1902
1903 verbose = false;
1904 norename = false;
1905 noattr = false;
1906 attr2comment = false;
1907 noexpr = false;
1908 nodec = false;
1909 nohex = false;
1910 nostr = false;
1911 extmem = false;
1912 defparam = false;
1913 decimal = false;
1914 siminit = false;
1915 auto_prefix = "";
1916
1917 bool blackboxes = false;
1918 bool selected = false;
1919
1920 auto_name_map.clear();
1921 reg_wires.clear();
1922
1923 size_t argidx;
1924 for (argidx = 1; argidx < args.size(); argidx++) {
1925 std::string arg = args[argidx];
1926 if (arg == "-sv") {
1927 systemverilog = true;
1928 continue;
1929 }
1930 if (arg == "-norename") {
1931 norename = true;
1932 continue;
1933 }
1934 if (arg == "-renameprefix" && argidx+1 < args.size()) {
1935 auto_prefix = args[++argidx];
1936 continue;
1937 }
1938 if (arg == "-noattr") {
1939 noattr = true;
1940 continue;
1941 }
1942 if (arg == "-attr2comment") {
1943 attr2comment = true;
1944 continue;
1945 }
1946 if (arg == "-noexpr") {
1947 noexpr = true;
1948 continue;
1949 }
1950 if (arg == "-nodec") {
1951 nodec = true;
1952 continue;
1953 }
1954 if (arg == "-nohex") {
1955 nohex = true;
1956 continue;
1957 }
1958 if (arg == "-nostr") {
1959 nostr = true;
1960 continue;
1961 }
1962 if (arg == "-extmem") {
1963 extmem = true;
1964 extmem_counter = 1;
1965 continue;
1966 }
1967 if (arg == "-defparam") {
1968 defparam = true;
1969 continue;
1970 }
1971 if (arg == "-decimal") {
1972 decimal = true;
1973 continue;
1974 }
1975 if (arg == "-siminit") {
1976 siminit = true;
1977 continue;
1978 }
1979 if (arg == "-blackboxes") {
1980 blackboxes = true;
1981 continue;
1982 }
1983 if (arg == "-selected") {
1984 selected = true;
1985 continue;
1986 }
1987 if (arg == "-v") {
1988 verbose = true;
1989 continue;
1990 }
1991 break;
1992 }
1993 extra_args(f, filename, args, argidx);
1994 if (extmem)
1995 {
1996 if (filename == "<stdout>")
1997 log_cmd_error("Option -extmem must be used with a filename.\n");
1998 extmem_prefix = filename.substr(0, filename.rfind('.'));
1999 }
2000
2001 design->sort();
2002
2003 *f << stringf("/* Generated by %s */\n", yosys_version_str);
2004 for (auto module : design->modules()) {
2005 if (module->get_blackbox_attribute() != blackboxes)
2006 continue;
2007 if (selected && !design->selected_whole_module(module->name)) {
2008 if (design->selected_module(module->name))
2009 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module->name));
2010 continue;
2011 }
2012 log("Dumping module `%s'.\n", module->name.c_str());
2013 dump_module(*f, "", module);
2014 }
2015
2016 auto_name_map.clear();
2017 reg_wires.clear();
2018 }
2019 } VerilogBackend;
2020
2021 PRIVATE_NAMESPACE_END