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