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