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