b363bc2fe439780288edc6cc1975c93e95e82575
[yosys.git] / backends / verilog / verilog_backend.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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 for (int j = 0; j < mem.width; j++)
508 {
509 if (init.en[j] != State::S1)
510 continue;
511
512 int start_j = j, width = 1;
513
514 while (j+1 < mem.width && init.en[j+1] == State::S1)
515 j++, width++;
516
517 if (width == mem.width) {
518 f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i + start);
519 } else {
520 f << stringf("%s" " %s[%d][%d:%d] = ", indent.c_str(), mem_id.c_str(), i + start, j, start_j);
521 }
522 dump_const(f, init.data.extract(i*mem.width+start_j, width));
523 f << stringf(";\n");
524 }
525 }
526 }
527 f << stringf("%s" "end\n", indent.c_str());
528 }
529 }
530
531 // create a map : "edge clk" -> expressions within that clock domain
532 dict<std::string, std::vector<std::string>> clk_to_lof_body;
533 dict<std::string, std::string> clk_to_arst_cond;
534 dict<std::string, std::vector<std::string>> clk_to_arst_body;
535 clk_to_lof_body[""] = std::vector<std::string>();
536 std::string clk_domain_str;
537 // create a list of reg declarations
538 std::vector<std::string> lof_reg_declarations;
539
540 // read ports
541 for (auto &port : mem.rd_ports)
542 {
543 if (port.clk_enable)
544 {
545 {
546 std::ostringstream os;
547 dump_sigspec(os, port.clk);
548 clk_domain_str = stringf("%sedge %s", port.clk_polarity ? "pos" : "neg", os.str().c_str());
549 if (port.arst != State::S0) {
550 std::ostringstream os2;
551 dump_sigspec(os2, port.arst);
552 clk_domain_str += stringf(", posedge %s", os2.str().c_str());
553 clk_to_arst_cond[clk_domain_str] = os2.str();
554 }
555 }
556 if (!port.transparent)
557 {
558 // for clocked read ports make something like:
559 // reg [..] temp_id;
560 // always @(posedge clk)
561 // if (rd_en) temp_id <= array_reg[r_addr];
562 // assign r_data = temp_id;
563 std::string temp_id = next_auto_id();
564 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", port.data.size() - 1, temp_id.c_str()) );
565
566 bool has_indent = false;
567
568 if (port.arst != State::S0) {
569 std::ostringstream os;
570 os << stringf("%s <= ", temp_id.c_str());
571 dump_sigspec(os, port.arst_value);
572 os << ";\n";
573 clk_to_arst_body[clk_domain_str].push_back(os.str());
574 }
575
576 if (port.srst != State::S0 && !port.ce_over_srst) {
577 std::ostringstream os;
578 os << stringf("if (");
579 dump_sigspec(os, port.srst);
580 os << stringf(")\n");
581 clk_to_lof_body[clk_domain_str].push_back(os.str());
582 std::ostringstream os2;
583 os2 << stringf("%s" "%s <= ", indent.c_str(), temp_id.c_str());
584 dump_sigspec(os2, port.srst_value);
585 os2 << ";\n";
586 clk_to_lof_body[clk_domain_str].push_back(os2.str());
587 std::ostringstream os3;
588 if (port.en == State::S1) {
589 os3 << "else begin\n";
590 } else {
591 os3 << "else if (";
592 dump_sigspec(os3, port.en);
593 os3 << ") begin\n";
594 }
595 clk_to_lof_body[clk_domain_str].push_back(os3.str());
596 has_indent = true;
597 } else if (port.en != State::S1) {
598 std::ostringstream os;
599 os << stringf("if (");
600 dump_sigspec(os, port.en);
601 os << stringf(") begin\n");
602 clk_to_lof_body[clk_domain_str].push_back(os.str());
603 has_indent = true;
604 }
605
606 for (int sub = 0; sub < (1 << port.wide_log2); sub++)
607 {
608 SigSpec addr = port.sub_addr(sub);
609 std::ostringstream os;
610 if (has_indent)
611 os << indent;
612 os << temp_id;
613 if (port.wide_log2)
614 os << stringf("[%d:%d]", (sub + 1) * mem.width - 1, sub * mem.width);
615 os << stringf(" <= %s[", mem_id.c_str());
616 dump_sigspec(os, addr);
617 os << stringf("];\n");
618 clk_to_lof_body[clk_domain_str].push_back(os.str());
619 }
620
621 if (port.srst != State::S0 && port.ce_over_srst)
622 {
623 std::ostringstream os;
624 if (has_indent)
625 os << indent;
626 os << stringf("if (");
627 dump_sigspec(os, port.srst);
628 os << stringf(")\n");
629 clk_to_lof_body[clk_domain_str].push_back(os.str());
630 std::ostringstream os2;
631 if (has_indent)
632 os2 << indent;
633 os2 << stringf("%s" "%s <= ", indent.c_str(), temp_id.c_str());
634 dump_sigspec(os2, port.srst_value);
635 os2 << ";\n";
636 clk_to_lof_body[clk_domain_str].push_back(os2.str());
637 }
638
639 if (has_indent)
640 clk_to_lof_body[clk_domain_str].push_back("end\n");
641
642 if (!port.init_value.is_fully_undef())
643 {
644 std::ostringstream os;
645 dump_sigspec(os, port.init_value);
646 std::string line = stringf("initial %s = %s;\n", temp_id.c_str(), os.str().c_str());
647 clk_to_lof_body[""].push_back(line);
648 }
649
650 {
651 std::ostringstream os;
652 dump_sigspec(os, port.data);
653 std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
654 clk_to_lof_body[""].push_back(line);
655 }
656 }
657 else
658 {
659 // for rd-transparent read-ports make something like:
660 // reg [..] temp_id;
661 // always @(posedge clk)
662 // temp_id <= r_addr;
663 // assign r_data = array_reg[temp_id];
664 std::string temp_id = next_auto_id();
665 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", port.addr.size() - 1 - port.wide_log2, temp_id.c_str()) );
666 {
667 std::ostringstream os;
668 dump_sigspec(os, port.addr.extract_end(port.wide_log2));
669 std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str());
670 clk_to_lof_body[clk_domain_str].push_back(line);
671 }
672 for (int sub = 0; sub < (1 << port.wide_log2); sub++)
673 {
674 std::ostringstream os;
675 os << "assign ";
676 dump_sigspec(os, port.data.extract(sub * mem.width, mem.width));
677 os << stringf(" = %s[", mem_id.c_str());;
678 if (port.wide_log2) {
679 Const addr_lo;
680 for (int i = 0; i < port.wide_log2; i++)
681 addr_lo.bits.push_back(State(sub >> i & 1));
682 os << "{";
683 os << temp_id;
684 os << ", ";
685 dump_const(os, addr_lo);
686 os << "}";
687 } else {
688 os << temp_id;
689 }
690 os << "];\n";
691 clk_to_lof_body[""].push_back(os.str());
692 }
693 }
694 } else {
695 // for non-clocked read-ports make something like:
696 // assign r_data = array_reg[r_addr];
697 for (int sub = 0; sub < (1 << port.wide_log2); sub++)
698 {
699 SigSpec addr = port.sub_addr(sub);
700
701 std::ostringstream os, os2;
702 dump_sigspec(os, port.data.extract(sub * mem.width, mem.width));
703 dump_sigspec(os2, addr);
704 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
705 clk_to_lof_body[""].push_back(line);
706 }
707 }
708 }
709
710 // Write ports. Those are messy because we try to preserve priority, as much as we can:
711 //
712 // 1. We split all ports into several disjoint processes.
713 // 2. If a port has priority over another port, the two ports need to share
714 // a process, so that priority can be reconstructed on the other end.
715 // 3. We want each process to be as small as possible, to avoid extra
716 // priorities inferred on the other end.
717 pool<int> wr_ports_done;
718 for (int ridx = 0; ridx < GetSize(mem.wr_ports); ridx++)
719 {
720 if (wr_ports_done.count(ridx))
721 continue;
722
723 auto &root = mem.wr_ports[ridx];
724
725 // Start from a root.
726 pool<int> wr_ports_now;
727 wr_ports_now.insert(ridx);
728
729 // Transitively fill list of ports in this process by following priority edges.
730 while (true)
731 {
732 bool changed = false;
733
734 for (int i = 0; i < GetSize(mem.wr_ports); i++)
735 for (int j = 0; j < i; j++)
736 if (mem.wr_ports[i].priority_mask[j])
737 {
738 if (wr_ports_now.count(i) && !wr_ports_now.count(j)) {
739 wr_ports_now.insert(j);
740 changed = true;
741 }
742 if (!wr_ports_now.count(i) && wr_ports_now.count(j)) {
743 wr_ports_now.insert(i);
744 changed = true;
745 }
746 }
747
748 if (!changed)
749 break;
750 }
751
752 if (root.clk_enable) {
753 f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", root.clk_polarity ? "pos" : "neg");
754 dump_sigspec(f, root.clk);
755 f << ") begin\n";
756 } else {
757 f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_latch" : " @*");
758 }
759
760 for (int pidx = 0; pidx < GetSize(mem.wr_ports); pidx++)
761 {
762 if (!wr_ports_now.count(pidx))
763 continue;
764 wr_ports_done.insert(pidx);
765
766 auto &port = mem.wr_ports[pidx];
767 log_assert(port.clk_enable == root.clk_enable);
768 if (port.clk_enable) {
769 log_assert(port.clk == root.clk);
770 log_assert(port.clk_polarity == root.clk_polarity);
771 }
772
773 // make something like:
774 // always @(posedge clk)
775 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
776 // ...
777 for (int sub = 0; sub < (1 << port.wide_log2); sub++)
778 {
779 SigSpec addr = port.sub_addr(sub);
780 for (int i = 0; i < mem.width; i++)
781 {
782 int start_i = i, width = 1;
783 SigBit wen_bit = port.en[sub * mem.width + i];
784
785 while (i+1 < mem.width && active_sigmap(port.en[sub * mem.width + i+1]) == active_sigmap(wen_bit))
786 i++, width++;
787
788 if (wen_bit == State::S0)
789 continue;
790
791 f << stringf("%s%s", indent.c_str(), indent.c_str());
792 if (wen_bit != State::S1)
793 {
794 f << stringf("if (");
795 dump_sigspec(f, wen_bit);
796 f << stringf(")\n");
797 f << stringf("%s%s%s", indent.c_str(), indent.c_str(), indent.c_str());
798 }
799 f << stringf("%s[", mem_id.c_str());
800 dump_sigspec(f, addr);
801 if (width == GetSize(port.en))
802 f << stringf("] <= ");
803 else
804 f << stringf("][%d:%d] <= ", i, start_i);
805 dump_sigspec(f, port.data.extract(sub * mem.width + start_i, width));
806 f << stringf(";\n");
807 }
808 }
809 }
810
811 f << stringf("%s" "end\n", indent.c_str());
812 }
813 // Output Verilog that looks something like this:
814 // reg [..] _3_;
815 // always @(posedge CLK2) begin
816 // _3_ <= memory[D1ADDR];
817 // if (A1EN)
818 // memory[A1ADDR] <= A1DATA;
819 // if (A2EN)
820 // memory[A2ADDR] <= A2DATA;
821 // ...
822 // end
823 // always @(negedge CLK1) begin
824 // if (C1EN)
825 // memory[C1ADDR] <= C1DATA;
826 // end
827 // ...
828 // assign D1DATA = _3_;
829 // assign D2DATA <= memory[D2ADDR];
830
831 // the reg ... definitions
832 for(auto &reg : lof_reg_declarations)
833 {
834 f << stringf("%s" "%s", indent.c_str(), reg.c_str());
835 }
836 // the block of expressions by clock domain
837 for(auto &pair : clk_to_lof_body)
838 {
839 std::string clk_domain = pair.first;
840 std::vector<std::string> lof_lines = pair.second;
841 if( clk_domain != "")
842 {
843 f << stringf("%s" "always%s @(%s) begin\n", indent.c_str(), systemverilog ? "_ff" : "", clk_domain.c_str());
844 bool has_arst = clk_to_arst_cond.count(clk_domain) != 0;
845 if (has_arst) {
846 f << stringf("%s%s" "if (%s) begin\n", indent.c_str(), indent.c_str(), clk_to_arst_cond[clk_domain].c_str());
847 for(auto &line : clk_to_arst_body[clk_domain])
848 f << stringf("%s%s%s" "%s", indent.c_str(), indent.c_str(), indent.c_str(), line.c_str());
849 f << stringf("%s%s" "end else begin\n", indent.c_str(), indent.c_str());
850 for(auto &line : lof_lines)
851 f << stringf("%s%s%s" "%s", indent.c_str(), indent.c_str(), indent.c_str(), line.c_str());
852 f << stringf("%s%s" "end\n", indent.c_str(), indent.c_str());
853 } else {
854 for(auto &line : lof_lines)
855 f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str());
856 }
857 f << stringf("%s" "end\n", indent.c_str());
858 }
859 else
860 {
861 // the non-clocked assignments
862 for(auto &line : lof_lines)
863 f << stringf("%s" "%s", indent.c_str(), line.c_str());
864 }
865 }
866 }
867
868 void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
869 {
870 if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) {
871 f << stringf("$signed(");
872 dump_sigspec(f, cell->getPort("\\" + port));
873 f << stringf(")");
874 } else
875 dump_sigspec(f, cell->getPort("\\" + port));
876 }
877
878 std::string cellname(RTLIL::Cell *cell)
879 {
880 if (!norename && cell->name[0] == '$' && RTLIL::builtin_ff_cell_types().count(cell->type) && cell->hasPort(ID::Q) && !cell->type.in(ID($ff), ID($_FF_)))
881 {
882 RTLIL::SigSpec sig = cell->getPort(ID::Q);
883 if (GetSize(sig) != 1 || sig.is_fully_const())
884 goto no_special_reg_name;
885
886 RTLIL::Wire *wire = sig[0].wire;
887
888 if (wire->name[0] != '\\')
889 goto no_special_reg_name;
890
891 std::string cell_name = wire->name.str();
892
893 size_t pos = cell_name.find('[');
894 if (pos != std::string::npos)
895 cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos);
896 else
897 cell_name = cell_name + "_reg";
898
899 if (wire->width != 1)
900 cell_name += stringf("[%d]", wire->start_offset + sig[0].offset);
901
902 if (active_module && active_module->count_id(cell_name) > 0)
903 goto no_special_reg_name;
904
905 return id(cell_name);
906 }
907 else
908 {
909 no_special_reg_name:
910 return id(cell->name).c_str();
911 }
912 }
913
914 void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
915 {
916 f << stringf("%s" "assign ", indent.c_str());
917 dump_sigspec(f, cell->getPort(ID::Y));
918 f << stringf(" = %s ", op.c_str());
919 dump_attributes(f, "", cell->attributes, ' ');
920 dump_cell_expr_port(f, cell, "A", true);
921 f << stringf(";\n");
922 }
923
924 void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
925 {
926 f << stringf("%s" "assign ", indent.c_str());
927 dump_sigspec(f, cell->getPort(ID::Y));
928 f << stringf(" = ");
929 dump_cell_expr_port(f, cell, "A", true);
930 f << stringf(" %s ", op.c_str());
931 dump_attributes(f, "", cell->attributes, ' ');
932 dump_cell_expr_port(f, cell, "B", true);
933 f << stringf(";\n");
934 }
935
936 bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
937 {
938 if (cell->type == ID($_NOT_)) {
939 f << stringf("%s" "assign ", indent.c_str());
940 dump_sigspec(f, cell->getPort(ID::Y));
941 f << stringf(" = ");
942 f << stringf("~");
943 dump_attributes(f, "", cell->attributes, ' ');
944 dump_cell_expr_port(f, cell, "A", false);
945 f << stringf(";\n");
946 return true;
947 }
948
949 if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) {
950 f << stringf("%s" "assign ", indent.c_str());
951 dump_sigspec(f, cell->getPort(ID::Y));
952 f << stringf(" = ");
953 if (cell->type.in(ID($_NAND_), ID($_NOR_), ID($_XNOR_)))
954 f << stringf("~(");
955 dump_cell_expr_port(f, cell, "A", false);
956 f << stringf(" ");
957 if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_ANDNOT_)))
958 f << stringf("&");
959 if (cell->type.in(ID($_OR_), ID($_NOR_), ID($_ORNOT_)))
960 f << stringf("|");
961 if (cell->type.in(ID($_XOR_), ID($_XNOR_)))
962 f << stringf("^");
963 dump_attributes(f, "", cell->attributes, ' ');
964 f << stringf(" ");
965 if (cell->type.in(ID($_ANDNOT_), ID($_ORNOT_)))
966 f << stringf("~(");
967 dump_cell_expr_port(f, cell, "B", false);
968 if (cell->type.in(ID($_NAND_), ID($_NOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_)))
969 f << stringf(")");
970 f << stringf(";\n");
971 return true;
972 }
973
974 if (cell->type == ID($_MUX_)) {
975 f << stringf("%s" "assign ", indent.c_str());
976 dump_sigspec(f, cell->getPort(ID::Y));
977 f << stringf(" = ");
978 dump_cell_expr_port(f, cell, "S", false);
979 f << stringf(" ? ");
980 dump_attributes(f, "", cell->attributes, ' ');
981 dump_cell_expr_port(f, cell, "B", false);
982 f << stringf(" : ");
983 dump_cell_expr_port(f, cell, "A", false);
984 f << stringf(";\n");
985 return true;
986 }
987
988 if (cell->type == ID($_NMUX_)) {
989 f << stringf("%s" "assign ", indent.c_str());
990 dump_sigspec(f, cell->getPort(ID::Y));
991 f << stringf(" = !(");
992 dump_cell_expr_port(f, cell, "S", false);
993 f << stringf(" ? ");
994 dump_attributes(f, "", cell->attributes, ' ');
995 dump_cell_expr_port(f, cell, "B", false);
996 f << stringf(" : ");
997 dump_cell_expr_port(f, cell, "A", false);
998 f << stringf(");\n");
999 return true;
1000 }
1001
1002 if (cell->type.in(ID($_AOI3_), ID($_OAI3_))) {
1003 f << stringf("%s" "assign ", indent.c_str());
1004 dump_sigspec(f, cell->getPort(ID::Y));
1005 f << stringf(" = ~((");
1006 dump_cell_expr_port(f, cell, "A", false);
1007 f << stringf(cell->type == ID($_AOI3_) ? " & " : " | ");
1008 dump_cell_expr_port(f, cell, "B", false);
1009 f << stringf(cell->type == ID($_AOI3_) ? ") |" : ") &");
1010 dump_attributes(f, "", cell->attributes, ' ');
1011 f << stringf(" ");
1012 dump_cell_expr_port(f, cell, "C", false);
1013 f << stringf(");\n");
1014 return true;
1015 }
1016
1017 if (cell->type.in(ID($_AOI4_), ID($_OAI4_))) {
1018 f << stringf("%s" "assign ", indent.c_str());
1019 dump_sigspec(f, cell->getPort(ID::Y));
1020 f << stringf(" = ~((");
1021 dump_cell_expr_port(f, cell, "A", false);
1022 f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
1023 dump_cell_expr_port(f, cell, "B", false);
1024 f << stringf(cell->type == ID($_AOI4_) ? ") |" : ") &");
1025 dump_attributes(f, "", cell->attributes, ' ');
1026 f << stringf(" (");
1027 dump_cell_expr_port(f, cell, "C", false);
1028 f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
1029 dump_cell_expr_port(f, cell, "D", false);
1030 f << stringf("));\n");
1031 return true;
1032 }
1033
1034 #define HANDLE_UNIOP(_type, _operator) \
1035 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
1036 #define HANDLE_BINOP(_type, _operator) \
1037 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
1038
1039 HANDLE_UNIOP(ID($not), "~")
1040 HANDLE_UNIOP(ID($pos), "+")
1041 HANDLE_UNIOP(ID($neg), "-")
1042
1043 HANDLE_BINOP(ID($and), "&")
1044 HANDLE_BINOP(ID($or), "|")
1045 HANDLE_BINOP(ID($xor), "^")
1046 HANDLE_BINOP(ID($xnor), "~^")
1047
1048 HANDLE_UNIOP(ID($reduce_and), "&")
1049 HANDLE_UNIOP(ID($reduce_or), "|")
1050 HANDLE_UNIOP(ID($reduce_xor), "^")
1051 HANDLE_UNIOP(ID($reduce_xnor), "~^")
1052 HANDLE_UNIOP(ID($reduce_bool), "|")
1053
1054 HANDLE_BINOP(ID($shl), "<<")
1055 HANDLE_BINOP(ID($shr), ">>")
1056 HANDLE_BINOP(ID($sshl), "<<<")
1057 HANDLE_BINOP(ID($sshr), ">>>")
1058
1059 HANDLE_BINOP(ID($lt), "<")
1060 HANDLE_BINOP(ID($le), "<=")
1061 HANDLE_BINOP(ID($eq), "==")
1062 HANDLE_BINOP(ID($ne), "!=")
1063 HANDLE_BINOP(ID($eqx), "===")
1064 HANDLE_BINOP(ID($nex), "!==")
1065 HANDLE_BINOP(ID($ge), ">=")
1066 HANDLE_BINOP(ID($gt), ">")
1067
1068 HANDLE_BINOP(ID($add), "+")
1069 HANDLE_BINOP(ID($sub), "-")
1070 HANDLE_BINOP(ID($mul), "*")
1071 HANDLE_BINOP(ID($div), "/")
1072 HANDLE_BINOP(ID($mod), "%")
1073 HANDLE_BINOP(ID($pow), "**")
1074
1075 HANDLE_UNIOP(ID($logic_not), "!")
1076 HANDLE_BINOP(ID($logic_and), "&&")
1077 HANDLE_BINOP(ID($logic_or), "||")
1078
1079 #undef HANDLE_UNIOP
1080 #undef HANDLE_BINOP
1081
1082 if (cell->type == ID($divfloor))
1083 {
1084 // wire [MAXLEN+1:0] _0_, _1_, _2_;
1085 // assign _0_ = $signed(A);
1086 // assign _1_ = $signed(B);
1087 // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
1088 // assign Y = $signed(_2_) / $signed(_1_);
1089
1090 if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) {
1091 SigSpec sig_a = cell->getPort(ID::A);
1092 SigSpec sig_b = cell->getPort(ID::B);
1093
1094 std::string buf_a = next_auto_id();
1095 std::string buf_b = next_auto_id();
1096 std::string buf_num = next_auto_id();
1097 int size_a = GetSize(sig_a);
1098 int size_b = GetSize(sig_b);
1099 int size_y = GetSize(cell->getPort(ID::Y));
1100 int size_max = std::max(size_a, std::max(size_b, size_y));
1101
1102 // intentionally one wider than maximum width
1103 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());
1104 f << stringf("%s" "assign %s = ", indent.c_str(), buf_a.c_str());
1105 dump_cell_expr_port(f, cell, "A", true);
1106 f << stringf(";\n");
1107 f << stringf("%s" "assign %s = ", indent.c_str(), buf_b.c_str());
1108 dump_cell_expr_port(f, cell, "B", true);
1109 f << stringf(";\n");
1110
1111 f << stringf("%s" "assign %s = ", indent.c_str(), buf_num.c_str());
1112 f << stringf("(");
1113 dump_sigspec(f, sig_a.extract(sig_a.size()-1));
1114 f << stringf(" == ");
1115 dump_sigspec(f, sig_b.extract(sig_b.size()-1));
1116 f << stringf(") || ");
1117 dump_sigspec(f, sig_a);
1118 f << stringf(" == 0 ? %s : ", buf_a.c_str());
1119 f << stringf("$signed(%s - (", buf_a.c_str());
1120 dump_sigspec(f, sig_b.extract(sig_b.size()-1));
1121 f << stringf(" ? %s + 1 : %s - 1));\n", buf_b.c_str(), buf_b.c_str());
1122
1123
1124 f << stringf("%s" "assign ", indent.c_str());
1125 dump_sigspec(f, cell->getPort(ID::Y));
1126 f << stringf(" = $signed(%s) / ", buf_num.c_str());
1127 dump_attributes(f, "", cell->attributes, ' ');
1128 f << stringf("$signed(%s);\n", buf_b.c_str());
1129 return true;
1130 } else {
1131 // same as truncating division
1132 dump_cell_expr_binop(f, indent, cell, "/");
1133 return true;
1134 }
1135 }
1136
1137 if (cell->type == ID($modfloor))
1138 {
1139 // wire truncated = $signed(A) % $signed(B);
1140 // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated);
1141
1142 if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) {
1143 SigSpec sig_a = cell->getPort(ID::A);
1144 SigSpec sig_b = cell->getPort(ID::B);
1145
1146 std::string temp_id = next_auto_id();
1147 f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str());
1148 dump_cell_expr_port(f, cell, "A", true);
1149 f << stringf(" %% ");
1150 dump_attributes(f, "", cell->attributes, ' ');
1151 dump_cell_expr_port(f, cell, "B", true);
1152 f << stringf(";\n");
1153
1154 f << stringf("%s" "assign ", indent.c_str());
1155 dump_sigspec(f, cell->getPort(ID::Y));
1156 f << stringf(" = (");
1157 dump_sigspec(f, sig_a.extract(sig_a.size()-1));
1158 f << stringf(" == ");
1159 dump_sigspec(f, sig_b.extract(sig_b.size()-1));
1160 f << stringf(") || %s == 0 ? %s : ", temp_id.c_str(), temp_id.c_str());
1161 dump_cell_expr_port(f, cell, "B", true);
1162 f << stringf(" + $signed(%s);\n", temp_id.c_str());
1163 return true;
1164 } else {
1165 // same as truncating modulo
1166 dump_cell_expr_binop(f, indent, cell, "%");
1167 return true;
1168 }
1169 }
1170
1171 if (cell->type == ID($shift))
1172 {
1173 f << stringf("%s" "assign ", indent.c_str());
1174 dump_sigspec(f, cell->getPort(ID::Y));
1175 f << stringf(" = ");
1176 if (cell->getParam(ID::B_SIGNED).as_bool())
1177 {
1178 dump_cell_expr_port(f, cell, "B", true);
1179 f << stringf(" < 0 ? ");
1180 dump_cell_expr_port(f, cell, "A", true);
1181 f << stringf(" << - ");
1182 dump_sigspec(f, cell->getPort(ID::B));
1183 f << stringf(" : ");
1184 dump_cell_expr_port(f, cell, "A", true);
1185 f << stringf(" >> ");
1186 dump_sigspec(f, cell->getPort(ID::B));
1187 }
1188 else
1189 {
1190 dump_cell_expr_port(f, cell, "A", true);
1191 f << stringf(" >> ");
1192 dump_sigspec(f, cell->getPort(ID::B));
1193 }
1194 f << stringf(";\n");
1195 return true;
1196 }
1197
1198 if (cell->type == ID($shiftx))
1199 {
1200 std::string temp_id = next_auto_id();
1201 f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str());
1202 dump_sigspec(f, cell->getPort(ID::A));
1203 f << stringf(";\n");
1204
1205 f << stringf("%s" "assign ", indent.c_str());
1206 dump_sigspec(f, cell->getPort(ID::Y));
1207 f << stringf(" = %s[", temp_id.c_str());
1208 if (cell->getParam(ID::B_SIGNED).as_bool())
1209 f << stringf("$signed(");
1210 dump_sigspec(f, cell->getPort(ID::B));
1211 if (cell->getParam(ID::B_SIGNED).as_bool())
1212 f << stringf(")");
1213 f << stringf(" +: %d", cell->getParam(ID::Y_WIDTH).as_int());
1214 f << stringf("];\n");
1215 return true;
1216 }
1217
1218 if (cell->type == ID($mux))
1219 {
1220 f << stringf("%s" "assign ", indent.c_str());
1221 dump_sigspec(f, cell->getPort(ID::Y));
1222 f << stringf(" = ");
1223 dump_sigspec(f, cell->getPort(ID::S));
1224 f << stringf(" ? ");
1225 dump_attributes(f, "", cell->attributes, ' ');
1226 dump_sigspec(f, cell->getPort(ID::B));
1227 f << stringf(" : ");
1228 dump_sigspec(f, cell->getPort(ID::A));
1229 f << stringf(";\n");
1230 return true;
1231 }
1232
1233 if (cell->type == ID($pmux))
1234 {
1235 int width = cell->parameters[ID::WIDTH].as_int();
1236 int s_width = cell->getPort(ID::S).size();
1237 std::string func_name = cellname(cell);
1238
1239 f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
1240 f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
1241 f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
1242 f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
1243
1244 dump_attributes(f, indent + " ", cell->attributes);
1245 if (!noattr)
1246 f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
1247 f << stringf("%s" " casez (s)", indent.c_str());
1248 f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
1249
1250 for (int i = 0; i < s_width; i++)
1251 {
1252 f << stringf("%s" " %d'b", indent.c_str(), s_width);
1253
1254 for (int j = s_width-1; j >= 0; j--)
1255 f << stringf("%c", j == i ? '1' : '?');
1256
1257 f << stringf(":\n");
1258 f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
1259 }
1260
1261 f << stringf("%s" " default:\n", indent.c_str());
1262 f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str());
1263
1264 f << stringf("%s" " endcase\n", indent.c_str());
1265 f << stringf("%s" "endfunction\n", indent.c_str());
1266
1267 f << stringf("%s" "assign ", indent.c_str());
1268 dump_sigspec(f, cell->getPort(ID::Y));
1269 f << stringf(" = %s(", func_name.c_str());
1270 dump_sigspec(f, cell->getPort(ID::A));
1271 f << stringf(", ");
1272 dump_sigspec(f, cell->getPort(ID::B));
1273 f << stringf(", ");
1274 dump_sigspec(f, cell->getPort(ID::S));
1275 f << stringf(");\n");
1276 return true;
1277 }
1278
1279 if (cell->type == ID($tribuf))
1280 {
1281 f << stringf("%s" "assign ", indent.c_str());
1282 dump_sigspec(f, cell->getPort(ID::Y));
1283 f << stringf(" = ");
1284 dump_sigspec(f, cell->getPort(ID::EN));
1285 f << stringf(" ? ");
1286 dump_sigspec(f, cell->getPort(ID::A));
1287 f << stringf(" : %d'bz;\n", cell->parameters.at(ID::WIDTH).as_int());
1288 return true;
1289 }
1290
1291 if (cell->type == ID($slice))
1292 {
1293 f << stringf("%s" "assign ", indent.c_str());
1294 dump_sigspec(f, cell->getPort(ID::Y));
1295 f << stringf(" = ");
1296 dump_sigspec(f, cell->getPort(ID::A));
1297 f << stringf(" >> %d;\n", cell->parameters.at(ID::OFFSET).as_int());
1298 return true;
1299 }
1300
1301 if (cell->type == ID($concat))
1302 {
1303 f << stringf("%s" "assign ", indent.c_str());
1304 dump_sigspec(f, cell->getPort(ID::Y));
1305 f << stringf(" = { ");
1306 dump_sigspec(f, cell->getPort(ID::B));
1307 f << stringf(" , ");
1308 dump_sigspec(f, cell->getPort(ID::A));
1309 f << stringf(" };\n");
1310 return true;
1311 }
1312
1313 if (cell->type == ID($lut))
1314 {
1315 f << stringf("%s" "assign ", indent.c_str());
1316 dump_sigspec(f, cell->getPort(ID::Y));
1317 f << stringf(" = ");
1318 dump_const(f, cell->parameters.at(ID::LUT));
1319 f << stringf(" >> ");
1320 dump_attributes(f, "", cell->attributes, ' ');
1321 dump_sigspec(f, cell->getPort(ID::A));
1322 f << stringf(";\n");
1323 return true;
1324 }
1325
1326 if (RTLIL::builtin_ff_cell_types().count(cell->type))
1327 {
1328 FfData ff(nullptr, cell);
1329
1330 // $ff / $_FF_ cell: not supported.
1331 if (ff.has_d && !ff.has_clk && !ff.has_en)
1332 return false;
1333
1334 std::string reg_name = cellname(cell);
1335 bool out_is_reg_wire = is_reg_wire(ff.sig_q, reg_name);
1336
1337 if (!out_is_reg_wire) {
1338 if (ff.width == 1)
1339 f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
1340 else
1341 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), ff.width-1, reg_name.c_str());
1342 dump_reg_init(f, ff.sig_q);
1343 f << ";\n";
1344 }
1345
1346 // If the FF has CLR/SET inputs, emit every bit slice separately.
1347 int chunks = ff.has_sr ? ff.width : 1;
1348 bool chunky = ff.has_sr && ff.width != 1;
1349
1350 for (int i = 0; i < chunks; i++)
1351 {
1352 SigSpec sig_d;
1353 Const val_arst, val_srst;
1354 std::string reg_bit_name, sig_set_name, sig_clr_name, sig_arst_name;
1355 if (chunky) {
1356 reg_bit_name = stringf("%s[%d]", reg_name.c_str(), i);
1357 if (ff.has_d)
1358 sig_d = ff.sig_d[i];
1359 } else {
1360 reg_bit_name = reg_name;
1361 if (ff.has_d)
1362 sig_d = ff.sig_d;
1363 }
1364 if (ff.has_arst)
1365 val_arst = chunky ? ff.val_arst[i] : ff.val_arst;
1366 if (ff.has_srst)
1367 val_srst = chunky ? ff.val_srst[i] : ff.val_srst;
1368
1369 // If there are constants in the sensitivity list, replace them with an intermediate wire
1370 if (ff.has_sr) {
1371 if (ff.sig_set[i].wire == NULL)
1372 {
1373 sig_set_name = next_auto_id();
1374 f << stringf("%s" "wire %s = ", indent.c_str(), sig_set_name.c_str());
1375 dump_const(f, ff.sig_set[i].data);
1376 f << stringf(";\n");
1377 }
1378 if (ff.sig_clr[i].wire == NULL)
1379 {
1380 sig_clr_name = next_auto_id();
1381 f << stringf("%s" "wire %s = ", indent.c_str(), sig_clr_name.c_str());
1382 dump_const(f, ff.sig_clr[i].data);
1383 f << stringf(";\n");
1384 }
1385 } else if (ff.has_arst) {
1386 if (ff.sig_arst[i].wire == NULL)
1387 {
1388 sig_arst_name = next_auto_id();
1389 f << stringf("%s" "wire %s = ", indent.c_str(), sig_arst_name.c_str());
1390 dump_const(f, ff.sig_arst[i].data);
1391 f << stringf(";\n");
1392 }
1393 }
1394
1395 dump_attributes(f, indent, cell->attributes);
1396 if (ff.has_clk)
1397 {
1398 // FFs.
1399 f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", ff.pol_clk ? "pos" : "neg");
1400 dump_sigspec(f, ff.sig_clk);
1401 if (ff.has_sr) {
1402 f << stringf(", %sedge ", ff.pol_set ? "pos" : "neg");
1403 if (ff.sig_set[i].wire == NULL)
1404 f << stringf("%s", sig_set_name.c_str());
1405 else
1406 dump_sigspec(f, ff.sig_set[i]);
1407
1408 f << stringf(", %sedge ", ff.pol_clr ? "pos" : "neg");
1409 if (ff.sig_clr[i].wire == NULL)
1410 f << stringf("%s", sig_clr_name.c_str());
1411 else
1412 dump_sigspec(f, ff.sig_clr[i]);
1413
1414 } else if (ff.has_arst) {
1415 f << stringf(", %sedge ", ff.pol_arst ? "pos" : "neg");
1416 if (ff.sig_arst[i].wire == NULL)
1417 f << stringf("%s", sig_arst_name.c_str());
1418 else
1419 dump_sigspec(f, ff.sig_arst);
1420 }
1421 f << stringf(")\n");
1422
1423 f << stringf("%s" " ", indent.c_str());
1424 if (ff.has_sr) {
1425 f << stringf("if (%s", ff.pol_clr ? "" : "!");
1426 if (ff.sig_clr[i].wire == NULL)
1427 f << stringf("%s", sig_clr_name.c_str());
1428 else
1429 dump_sigspec(f, ff.sig_clr[i]);
1430 f << stringf(") %s <= 1'b0;\n", reg_bit_name.c_str());
1431 f << stringf("%s" " else if (%s", indent.c_str(), ff.pol_set ? "" : "!");
1432 if (ff.sig_set[i].wire == NULL)
1433 f << stringf("%s", sig_set_name.c_str());
1434 else
1435 dump_sigspec(f, ff.sig_set[i]);
1436 f << stringf(") %s <= 1'b1;\n", reg_bit_name.c_str());
1437 f << stringf("%s" " else ", indent.c_str());
1438 } else if (ff.has_arst) {
1439 f << stringf("if (%s", ff.pol_arst ? "" : "!");
1440 if (ff.sig_arst[i].wire == NULL)
1441 f << stringf("%s", sig_arst_name.c_str());
1442 else
1443 dump_sigspec(f, ff.sig_arst);
1444 f << stringf(") %s <= ", reg_bit_name.c_str());
1445 dump_sigspec(f, val_arst);
1446 f << stringf(";\n");
1447 f << stringf("%s" " else ", indent.c_str());
1448 }
1449
1450 if (ff.has_srst && ff.has_en && ff.ce_over_srst) {
1451 f << stringf("if (%s", ff.pol_en ? "" : "!");
1452 dump_sigspec(f, ff.sig_en);
1453 f << stringf(")\n");
1454 f << stringf("%s" " if (%s", indent.c_str(), ff.pol_srst ? "" : "!");
1455 dump_sigspec(f, ff.sig_srst);
1456 f << stringf(") %s <= ", reg_bit_name.c_str());
1457 dump_sigspec(f, val_srst);
1458 f << stringf(";\n");
1459 f << stringf("%s" " else ", indent.c_str());
1460 } else {
1461 if (ff.has_srst) {
1462 f << stringf("if (%s", ff.pol_srst ? "" : "!");
1463 dump_sigspec(f, ff.sig_srst);
1464 f << stringf(") %s <= ", reg_bit_name.c_str());
1465 dump_sigspec(f, val_srst);
1466 f << stringf(";\n");
1467 f << stringf("%s" " else ", indent.c_str());
1468 }
1469 if (ff.has_en) {
1470 f << stringf("if (%s", ff.pol_en ? "" : "!");
1471 dump_sigspec(f, ff.sig_en);
1472 f << stringf(") ");
1473 }
1474 }
1475
1476 f << stringf("%s <= ", reg_bit_name.c_str());
1477 dump_sigspec(f, sig_d);
1478 f << stringf(";\n");
1479 }
1480 else
1481 {
1482 // Latches.
1483 f << stringf("%s" "always%s\n", indent.c_str(), systemverilog ? "_latch" : " @*");
1484
1485 f << stringf("%s" " ", indent.c_str());
1486 if (ff.has_sr) {
1487 f << stringf("if (%s", ff.pol_clr ? "" : "!");
1488 dump_sigspec(f, ff.sig_clr[i]);
1489 f << stringf(") %s = 1'b0;\n", reg_bit_name.c_str());
1490 f << stringf("%s" " else if (%s", indent.c_str(), ff.pol_set ? "" : "!");
1491 dump_sigspec(f, ff.sig_set[i]);
1492 f << stringf(") %s = 1'b1;\n", reg_bit_name.c_str());
1493 if (ff.has_d)
1494 f << stringf("%s" " else ", indent.c_str());
1495 } else if (ff.has_arst) {
1496 f << stringf("if (%s", ff.pol_arst ? "" : "!");
1497 dump_sigspec(f, ff.sig_arst);
1498 f << stringf(") %s = ", reg_bit_name.c_str());
1499 dump_sigspec(f, val_arst);
1500 f << stringf(";\n");
1501 if (ff.has_d)
1502 f << stringf("%s" " else ", indent.c_str());
1503 }
1504 if (ff.has_d) {
1505 f << stringf("if (%s", ff.pol_en ? "" : "!");
1506 dump_sigspec(f, ff.sig_en);
1507 f << stringf(") %s = ", reg_bit_name.c_str());
1508 dump_sigspec(f, sig_d);
1509 f << stringf(";\n");
1510 }
1511 }
1512 }
1513
1514 if (!out_is_reg_wire) {
1515 f << stringf("%s" "assign ", indent.c_str());
1516 dump_sigspec(f, ff.sig_q);
1517 f << stringf(" = %s;\n", reg_name.c_str());
1518 }
1519
1520 return true;
1521 }
1522
1523 if (cell->type.in(ID($assert), ID($assume), ID($cover)))
1524 {
1525 f << stringf("%s" "always%s if (", indent.c_str(), systemverilog ? "_comb" : " @*");
1526 dump_sigspec(f, cell->getPort(ID::EN));
1527 f << stringf(") %s(", cell->type.c_str()+1);
1528 dump_sigspec(f, cell->getPort(ID::A));
1529 f << stringf(");\n");
1530 return true;
1531 }
1532
1533 if (cell->type.in(ID($specify2), ID($specify3)))
1534 {
1535 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1536
1537 SigSpec en = cell->getPort(ID::EN);
1538 if (en != State::S1) {
1539 f << stringf("if (");
1540 dump_sigspec(f, cell->getPort(ID::EN));
1541 f << stringf(") ");
1542 }
1543
1544 f << "(";
1545 if (cell->type == ID($specify3) && cell->getParam(ID::EDGE_EN).as_bool())
1546 f << (cell->getParam(ID::EDGE_POL).as_bool() ? "posedge ": "negedge ");
1547
1548 dump_sigspec(f, cell->getPort(ID::SRC));
1549
1550 f << " ";
1551 if (cell->getParam(ID::SRC_DST_PEN).as_bool())
1552 f << (cell->getParam(ID::SRC_DST_POL).as_bool() ? "+": "-");
1553 f << (cell->getParam(ID::FULL).as_bool() ? "*> ": "=> ");
1554
1555 if (cell->type == ID($specify3)) {
1556 f << "(";
1557 dump_sigspec(f, cell->getPort(ID::DST));
1558 f << " ";
1559 if (cell->getParam(ID::DAT_DST_PEN).as_bool())
1560 f << (cell->getParam(ID::DAT_DST_POL).as_bool() ? "+": "-");
1561 f << ": ";
1562 dump_sigspec(f, cell->getPort(ID::DAT));
1563 f << ")";
1564 } else {
1565 dump_sigspec(f, cell->getPort(ID::DST));
1566 }
1567
1568 bool bak_decimal = decimal;
1569 decimal = 1;
1570
1571 f << ") = (";
1572 dump_const(f, cell->getParam(ID::T_RISE_MIN));
1573 f << ":";
1574 dump_const(f, cell->getParam(ID::T_RISE_TYP));
1575 f << ":";
1576 dump_const(f, cell->getParam(ID::T_RISE_MAX));
1577 f << ", ";
1578 dump_const(f, cell->getParam(ID::T_FALL_MIN));
1579 f << ":";
1580 dump_const(f, cell->getParam(ID::T_FALL_TYP));
1581 f << ":";
1582 dump_const(f, cell->getParam(ID::T_FALL_MAX));
1583 f << ");\n";
1584
1585 decimal = bak_decimal;
1586
1587 f << stringf("%s" "endspecify\n", indent.c_str());
1588 return true;
1589 }
1590
1591 if (cell->type == ID($specrule))
1592 {
1593 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1594
1595 IdString spec_type = cell->getParam(ID::TYPE).decode_string();
1596 f << stringf("%s(", spec_type.c_str());
1597
1598 if (cell->getParam(ID::SRC_PEN).as_bool())
1599 f << (cell->getParam(ID::SRC_POL).as_bool() ? "posedge ": "negedge ");
1600 dump_sigspec(f, cell->getPort(ID::SRC));
1601
1602 if (cell->getPort(ID::SRC_EN) != State::S1) {
1603 f << " &&& ";
1604 dump_sigspec(f, cell->getPort(ID::SRC_EN));
1605 }
1606
1607 f << ", ";
1608 if (cell->getParam(ID::DST_PEN).as_bool())
1609 f << (cell->getParam(ID::DST_POL).as_bool() ? "posedge ": "negedge ");
1610 dump_sigspec(f, cell->getPort(ID::DST));
1611
1612 if (cell->getPort(ID::DST_EN) != State::S1) {
1613 f << " &&& ";
1614 dump_sigspec(f, cell->getPort(ID::DST_EN));
1615 }
1616
1617 bool bak_decimal = decimal;
1618 decimal = 1;
1619
1620 f << ", ";
1621 dump_const(f, cell->getParam(ID::T_LIMIT_MIN));
1622 f << ": ";
1623 dump_const(f, cell->getParam(ID::T_LIMIT_TYP));
1624 f << ": ";
1625 dump_const(f, cell->getParam(ID::T_LIMIT_MAX));
1626
1627 if (spec_type.in(ID($setuphold), ID($recrem), ID($fullskew))) {
1628 f << ", ";
1629 dump_const(f, cell->getParam(ID::T_LIMIT2_MIN));
1630 f << ": ";
1631 dump_const(f, cell->getParam(ID::T_LIMIT2_TYP));
1632 f << ": ";
1633 dump_const(f, cell->getParam(ID::T_LIMIT2_MAX));
1634 }
1635
1636 f << ");\n";
1637 decimal = bak_decimal;
1638
1639 f << stringf("%s" "endspecify\n", indent.c_str());
1640 return true;
1641 }
1642
1643 // FIXME: $fsm
1644
1645 return false;
1646 }
1647
1648 void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
1649 {
1650 // Handled by dump_memory
1651 if (cell->is_mem_cell())
1652 return;
1653
1654 if (cell->type[0] == '$' && !noexpr) {
1655 if (dump_cell_expr(f, indent, cell))
1656 return;
1657 }
1658
1659 dump_attributes(f, indent, cell->attributes);
1660 f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
1661
1662 if (!defparam && cell->parameters.size() > 0) {
1663 f << stringf(" #(");
1664 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1665 if (it != cell->parameters.begin())
1666 f << stringf(",");
1667 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1668 dump_const(f, it->second);
1669 f << stringf(")");
1670 }
1671 f << stringf("\n%s" ")", indent.c_str());
1672 }
1673
1674 std::string cell_name = cellname(cell);
1675 if (cell_name != id(cell->name))
1676 f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
1677 else
1678 f << stringf(" %s (", cell_name.c_str());
1679
1680 bool first_arg = true;
1681 std::set<RTLIL::IdString> numbered_ports;
1682 for (int i = 1; true; i++) {
1683 char str[16];
1684 snprintf(str, 16, "$%d", i);
1685 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1686 if (it->first != str)
1687 continue;
1688 if (!first_arg)
1689 f << stringf(",");
1690 first_arg = false;
1691 f << stringf("\n%s ", indent.c_str());
1692 dump_sigspec(f, it->second);
1693 numbered_ports.insert(it->first);
1694 goto found_numbered_port;
1695 }
1696 break;
1697 found_numbered_port:;
1698 }
1699 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1700 if (numbered_ports.count(it->first))
1701 continue;
1702 if (!first_arg)
1703 f << stringf(",");
1704 first_arg = false;
1705 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1706 if (it->second.size() > 0)
1707 dump_sigspec(f, it->second);
1708 f << stringf(")");
1709 }
1710 f << stringf("\n%s" ");\n", indent.c_str());
1711
1712 if (defparam && cell->parameters.size() > 0) {
1713 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1714 f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
1715 dump_const(f, it->second);
1716 f << stringf(";\n");
1717 }
1718 }
1719
1720 if (siminit && RTLIL::builtin_ff_cell_types().count(cell->type) && cell->hasPort(ID::Q) && !cell->type.in(ID($ff), ID($_FF_))) {
1721 std::stringstream ss;
1722 dump_reg_init(ss, cell->getPort(ID::Q));
1723 if (!ss.str().empty()) {
1724 f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str());
1725 f << ss.str();
1726 f << ";\n";
1727 }
1728 }
1729 }
1730
1731 void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
1732 {
1733 if (simple_lhs) {
1734 int offset = 0;
1735 for (auto &chunk : left.chunks()) {
1736 f << stringf("%s" "assign ", indent.c_str());
1737 dump_sigspec(f, chunk);
1738 f << stringf(" = ");
1739 dump_sigspec(f, right.extract(offset, GetSize(chunk)));
1740 f << stringf(";\n");
1741 offset += GetSize(chunk);
1742 }
1743 } else {
1744 f << stringf("%s" "assign ", indent.c_str());
1745 dump_sigspec(f, left);
1746 f << stringf(" = ");
1747 dump_sigspec(f, right);
1748 f << stringf(";\n");
1749 }
1750 }
1751
1752 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
1753
1754 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
1755 {
1756 int number_of_stmts = cs->switches.size() + cs->actions.size();
1757
1758 if (!omit_trailing_begin && number_of_stmts >= 2)
1759 f << stringf("%s" "begin\n", indent.c_str());
1760
1761 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1762 if (it->first.size() == 0)
1763 continue;
1764 f << stringf("%s ", indent.c_str());
1765 dump_sigspec(f, it->first);
1766 f << stringf(" = ");
1767 dump_sigspec(f, it->second);
1768 f << stringf(";\n");
1769 }
1770
1771 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1772 dump_proc_switch(f, indent + " ", *it);
1773
1774 if (!omit_trailing_begin && number_of_stmts == 0)
1775 f << stringf("%s /* empty */;\n", indent.c_str());
1776
1777 if (omit_trailing_begin || number_of_stmts >= 2)
1778 f << stringf("%s" "end\n", indent.c_str());
1779 }
1780
1781 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
1782 {
1783 if (sw->signal.size() == 0) {
1784 f << stringf("%s" "begin\n", indent.c_str());
1785 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1786 if ((*it)->compare.size() == 0)
1787 dump_case_body(f, indent + " ", *it);
1788 }
1789 f << stringf("%s" "end\n", indent.c_str());
1790 return;
1791 }
1792
1793 dump_attributes(f, indent, sw->attributes);
1794 f << stringf("%s" "casez (", indent.c_str());
1795 dump_sigspec(f, sw->signal);
1796 f << stringf(")\n");
1797
1798 bool got_default = false;
1799 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1800 dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1801 if ((*it)->compare.size() == 0) {
1802 if (got_default)
1803 continue;
1804 f << stringf("%s default", indent.c_str());
1805 got_default = true;
1806 } else {
1807 f << stringf("%s ", indent.c_str());
1808 for (size_t i = 0; i < (*it)->compare.size(); i++) {
1809 if (i > 0)
1810 f << stringf(", ");
1811 dump_sigspec(f, (*it)->compare[i]);
1812 }
1813 }
1814 f << stringf(":\n");
1815 dump_case_body(f, indent + " ", *it);
1816 }
1817
1818 f << stringf("%s" "endcase\n", indent.c_str());
1819 }
1820
1821 void case_body_find_regs(RTLIL::CaseRule *cs)
1822 {
1823 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1824 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
1825 case_body_find_regs(*it2);
1826
1827 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1828 for (auto &c : it->first.chunks())
1829 if (c.wire != NULL)
1830 reg_wires.insert(c.wire->name);
1831 }
1832 }
1833
1834 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
1835 {
1836 if (find_regs) {
1837 case_body_find_regs(&proc->root_case);
1838 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
1839 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
1840 for (auto &c : it2->first.chunks())
1841 if (c.wire != NULL)
1842 reg_wires.insert(c.wire->name);
1843 }
1844 return;
1845 }
1846
1847 f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*");
1848 if (!systemverilog)
1849 f << indent + " " << "if (" << id("\\initial") << ") begin end\n";
1850 dump_case_body(f, indent, &proc->root_case, true);
1851
1852 std::string backup_indent = indent;
1853
1854 for (size_t i = 0; i < proc->syncs.size(); i++)
1855 {
1856 RTLIL::SyncRule *sync = proc->syncs[i];
1857 indent = backup_indent;
1858
1859 if (sync->type == RTLIL::STa) {
1860 f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*");
1861 } else if (sync->type == RTLIL::STi) {
1862 f << stringf("%s" "initial begin\n", indent.c_str());
1863 } else {
1864 f << stringf("%s" "always%s @(", indent.c_str(), systemverilog ? "_ff" : "");
1865 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
1866 f << stringf("posedge ");
1867 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
1868 f << stringf("negedge ");
1869 dump_sigspec(f, sync->signal);
1870 f << stringf(") begin\n");
1871 }
1872 std::string ends = indent + "end\n";
1873 indent += " ";
1874
1875 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
1876 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
1877 dump_sigspec(f, sync->signal);
1878 f << stringf(") begin\n");
1879 ends = indent + "end\n" + ends;
1880 indent += " ";
1881 }
1882
1883 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
1884 for (size_t j = 0; j < proc->syncs.size(); j++) {
1885 RTLIL::SyncRule *sync2 = proc->syncs[j];
1886 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
1887 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
1888 dump_sigspec(f, sync2->signal);
1889 f << stringf(") begin\n");
1890 ends = indent + "end\n" + ends;
1891 indent += " ";
1892 }
1893 }
1894 }
1895
1896 for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
1897 if (it->first.size() == 0)
1898 continue;
1899 f << stringf("%s ", indent.c_str());
1900 dump_sigspec(f, it->first);
1901 f << stringf(" <= ");
1902 dump_sigspec(f, it->second);
1903 f << stringf(";\n");
1904 }
1905
1906 f << stringf("%s", ends.c_str());
1907 }
1908 }
1909
1910 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
1911 {
1912 reg_wires.clear();
1913 reset_auto_counter(module);
1914 active_module = module;
1915 active_sigmap.set(module);
1916 active_initdata.clear();
1917
1918 for (auto wire : module->wires())
1919 if (wire->attributes.count(ID::init)) {
1920 SigSpec sig = active_sigmap(wire);
1921 Const val = wire->attributes.at(ID::init);
1922 for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
1923 if (val[i] == State::S0 || val[i] == State::S1)
1924 active_initdata[sig[i]] = val[i];
1925 }
1926
1927 if (!module->processes.empty())
1928 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1929 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1930 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1931 "processes to logic networks and registers.\n", log_id(module));
1932
1933 f << stringf("\n");
1934 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1935 dump_process(f, indent + " ", it->second, true);
1936
1937 if (!noexpr)
1938 {
1939 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
1940 for (auto cell : module->cells())
1941 {
1942 if (!RTLIL::builtin_ff_cell_types().count(cell->type) || !cell->hasPort(ID::Q) || cell->type.in(ID($ff), ID($_FF_)))
1943 continue;
1944
1945 RTLIL::SigSpec sig = cell->getPort(ID::Q);
1946
1947 if (sig.is_chunk()) {
1948 RTLIL::SigChunk chunk = sig.as_chunk();
1949 if (chunk.wire != NULL)
1950 for (int i = 0; i < chunk.width; i++)
1951 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
1952 }
1953 }
1954 for (auto wire : module->wires())
1955 {
1956 for (int i = 0; i < wire->width; i++)
1957 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
1958 goto this_wire_aint_reg;
1959 if (wire->width)
1960 reg_wires.insert(wire->name);
1961 this_wire_aint_reg:;
1962 }
1963 }
1964
1965 dump_attributes(f, indent, module->attributes, '\n', /*modattr=*/true);
1966 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
1967 bool keep_running = true;
1968 for (int port_id = 1; keep_running; port_id++) {
1969 keep_running = false;
1970 for (auto wire : module->wires()) {
1971 if (wire->port_id == port_id) {
1972 if (port_id != 1)
1973 f << stringf(", ");
1974 f << stringf("%s", id(wire->name).c_str());
1975 keep_running = true;
1976 continue;
1977 }
1978 }
1979 }
1980 f << stringf(");\n");
1981
1982 if (!systemverilog && !module->processes.empty())
1983 f << indent + " " << "reg " << id("\\initial") << " = 0;\n";
1984
1985 for (auto w : module->wires())
1986 dump_wire(f, indent + " ", w);
1987
1988 for (auto &mem : Mem::get_all_memories(module))
1989 dump_memory(f, indent + " ", mem);
1990
1991 for (auto cell : module->cells())
1992 dump_cell(f, indent + " ", cell);
1993
1994 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1995 dump_process(f, indent + " ", it->second);
1996
1997 for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
1998 dump_conn(f, indent + " ", it->first, it->second);
1999
2000 f << stringf("%s" "endmodule\n", indent.c_str());
2001 active_module = NULL;
2002 active_sigmap.clear();
2003 active_initdata.clear();
2004 }
2005
2006 struct VerilogBackend : public Backend {
2007 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
2008 void help() override
2009 {
2010 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2011 log("\n");
2012 log(" write_verilog [options] [filename]\n");
2013 log("\n");
2014 log("Write the current design to a Verilog file.\n");
2015 log("\n");
2016 log(" -sv\n");
2017 log(" with this option, SystemVerilog constructs like always_comb are used\n");
2018 log("\n");
2019 log(" -norename\n");
2020 log(" without this option all internal object names (the ones with a dollar\n");
2021 log(" instead of a backslash prefix) are changed to short names in the\n");
2022 log(" format '_<number>_'.\n");
2023 log("\n");
2024 log(" -renameprefix <prefix>\n");
2025 log(" insert this prefix in front of auto-generated instance names\n");
2026 log("\n");
2027 log(" -noattr\n");
2028 log(" with this option no attributes are included in the output\n");
2029 log("\n");
2030 log(" -attr2comment\n");
2031 log(" with this option attributes are included as comments in the output\n");
2032 log("\n");
2033 log(" -noexpr\n");
2034 log(" without this option all internal cells are converted to Verilog\n");
2035 log(" expressions.\n");
2036 log("\n");
2037 log(" -siminit\n");
2038 log(" add initial statements with hierarchical refs to initialize FFs when\n");
2039 log(" in -noexpr mode.\n");
2040 log("\n");
2041 log(" -nodec\n");
2042 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
2043 log(" not bit pattern. This option deactivates this feature and instead\n");
2044 log(" will write out all constants in binary.\n");
2045 log("\n");
2046 log(" -decimal\n");
2047 log(" dump 32-bit constants in decimal and without size and radix\n");
2048 log("\n");
2049 log(" -nohex\n");
2050 log(" constant values that are compatible with hex output are usually\n");
2051 log(" dumped as hex values. This option deactivates this feature and\n");
2052 log(" instead will write out all constants in binary.\n");
2053 log("\n");
2054 log(" -nostr\n");
2055 log(" Parameters and attributes that are specified as strings in the\n");
2056 log(" original input will be output as strings by this back-end. This\n");
2057 log(" deactivates this feature and instead will write string constants\n");
2058 log(" as binary numbers.\n");
2059 log("\n");
2060 log(" -simple-lhs\n");
2061 log(" Connection assignments with simple left hand side without concatenations.\n");
2062 log("\n");
2063 log(" -extmem\n");
2064 log(" instead of initializing memories using assignments to individual\n");
2065 log(" elements, use the '$readmemh' function to read initialization data\n");
2066 log(" from a file. This data is written to a file named by appending\n");
2067 log(" a sequential index to the Verilog filename and replacing the extension\n");
2068 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
2069 log(" 'foo-2.mem' and so on.\n");
2070 log("\n");
2071 log(" -defparam\n");
2072 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
2073 log(" cell parameters.\n");
2074 log("\n");
2075 log(" -blackboxes\n");
2076 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
2077 log(" this option set only the modules with the 'blackbox' attribute\n");
2078 log(" are written to the output file.\n");
2079 log("\n");
2080 log(" -selected\n");
2081 log(" only write selected modules. modules must be selected entirely or\n");
2082 log(" not at all.\n");
2083 log("\n");
2084 log(" -v\n");
2085 log(" verbose output (print new names of all renamed wires and cells)\n");
2086 log("\n");
2087 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
2088 log("always blocks. This frontend should only be used to export an RTLIL\n");
2089 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
2090 log("processes to logic networks and registers. A warning is generated when\n");
2091 log("this command is called on a design with RTLIL processes.\n");
2092 log("\n");
2093 }
2094 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
2095 {
2096 log_header(design, "Executing Verilog backend.\n");
2097
2098 verbose = false;
2099 norename = false;
2100 noattr = false;
2101 attr2comment = false;
2102 noexpr = false;
2103 nodec = false;
2104 nohex = false;
2105 nostr = false;
2106 extmem = false;
2107 defparam = false;
2108 decimal = false;
2109 siminit = false;
2110 simple_lhs = false;
2111 auto_prefix = "";
2112
2113 bool blackboxes = false;
2114 bool selected = false;
2115
2116 auto_name_map.clear();
2117 reg_wires.clear();
2118
2119 size_t argidx;
2120 for (argidx = 1; argidx < args.size(); argidx++) {
2121 std::string arg = args[argidx];
2122 if (arg == "-sv") {
2123 systemverilog = true;
2124 continue;
2125 }
2126 if (arg == "-norename") {
2127 norename = true;
2128 continue;
2129 }
2130 if (arg == "-renameprefix" && argidx+1 < args.size()) {
2131 auto_prefix = args[++argidx];
2132 continue;
2133 }
2134 if (arg == "-noattr") {
2135 noattr = true;
2136 continue;
2137 }
2138 if (arg == "-attr2comment") {
2139 attr2comment = true;
2140 continue;
2141 }
2142 if (arg == "-noexpr") {
2143 noexpr = true;
2144 continue;
2145 }
2146 if (arg == "-nodec") {
2147 nodec = true;
2148 continue;
2149 }
2150 if (arg == "-nohex") {
2151 nohex = true;
2152 continue;
2153 }
2154 if (arg == "-nostr") {
2155 nostr = true;
2156 continue;
2157 }
2158 if (arg == "-extmem") {
2159 extmem = true;
2160 extmem_counter = 1;
2161 continue;
2162 }
2163 if (arg == "-defparam") {
2164 defparam = true;
2165 continue;
2166 }
2167 if (arg == "-decimal") {
2168 decimal = true;
2169 continue;
2170 }
2171 if (arg == "-siminit") {
2172 siminit = true;
2173 continue;
2174 }
2175 if (arg == "-blackboxes") {
2176 blackboxes = true;
2177 continue;
2178 }
2179 if (arg == "-selected") {
2180 selected = true;
2181 continue;
2182 }
2183 if (arg == "-simple-lhs") {
2184 simple_lhs = true;
2185 continue;
2186 }
2187 if (arg == "-v") {
2188 verbose = true;
2189 continue;
2190 }
2191 break;
2192 }
2193 extra_args(f, filename, args, argidx);
2194 if (extmem)
2195 {
2196 if (filename == "<stdout>")
2197 log_cmd_error("Option -extmem must be used with a filename.\n");
2198 extmem_prefix = filename.substr(0, filename.rfind('.'));
2199 }
2200
2201 design->sort();
2202
2203 *f << stringf("/* Generated by %s */\n", yosys_version_str);
2204 for (auto module : design->modules()) {
2205 if (module->get_blackbox_attribute() != blackboxes)
2206 continue;
2207 if (selected && !design->selected_whole_module(module->name)) {
2208 if (design->selected_module(module->name))
2209 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module->name));
2210 continue;
2211 }
2212 log("Dumping module `%s'.\n", module->name.c_str());
2213 dump_module(*f, "", module);
2214 }
2215
2216 auto_name_map.clear();
2217 reg_wires.clear();
2218 }
2219 } VerilogBackend;
2220
2221 PRIVATE_NAMESPACE_END