Merge pull request #1814 from YosysHQ/mmicko/pyosys_makefile
[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 w : module->wires())
77 reset_auto_counter_id(w->name, true);
78
79 for (auto cell : module->cells()) {
80 reset_auto_counter_id(cell->name, true);
81 reset_auto_counter_id(cell->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 == ID::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(ID::init)) {
427 f << stringf(" = ");
428 dump_const(f, wire->attributes.at(ID::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(ID::Q))
455 {
456 RTLIL::SigSpec sig = cell->getPort(ID::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(ID::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(ID::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 == ID($_NOT_)) {
513 f << stringf("%s" "assign ", indent.c_str());
514 dump_sigspec(f, cell->getPort(ID::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(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) {
524 f << stringf("%s" "assign ", indent.c_str());
525 dump_sigspec(f, cell->getPort(ID::Y));
526 f << stringf(" = ");
527 if (cell->type.in(ID($_NAND_), ID($_NOR_), ID($_XNOR_)))
528 f << stringf("~(");
529 dump_cell_expr_port(f, cell, "A", false);
530 f << stringf(" ");
531 if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_ANDNOT_)))
532 f << stringf("&");
533 if (cell->type.in(ID($_OR_), ID($_NOR_), ID($_ORNOT_)))
534 f << stringf("|");
535 if (cell->type.in(ID($_XOR_), ID($_XNOR_)))
536 f << stringf("^");
537 dump_attributes(f, "", cell->attributes, ' ');
538 f << stringf(" ");
539 if (cell->type.in(ID($_ANDNOT_), ID($_ORNOT_)))
540 f << stringf("~(");
541 dump_cell_expr_port(f, cell, "B", false);
542 if (cell->type.in(ID($_NAND_), ID($_NOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_)))
543 f << stringf(")");
544 f << stringf(";\n");
545 return true;
546 }
547
548 if (cell->type == ID($_MUX_)) {
549 f << stringf("%s" "assign ", indent.c_str());
550 dump_sigspec(f, cell->getPort(ID::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 == ID($_NMUX_)) {
563 f << stringf("%s" "assign ", indent.c_str());
564 dump_sigspec(f, cell->getPort(ID::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(ID($_AOI3_), ID($_OAI3_))) {
577 f << stringf("%s" "assign ", indent.c_str());
578 dump_sigspec(f, cell->getPort(ID::Y));
579 f << stringf(" = ~((");
580 dump_cell_expr_port(f, cell, "A", false);
581 f << stringf(cell->type == ID($_AOI3_) ? " & " : " | ");
582 dump_cell_expr_port(f, cell, "B", false);
583 f << stringf(cell->type == ID($_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(ID($_AOI4_), ID($_OAI4_))) {
592 f << stringf("%s" "assign ", indent.c_str());
593 dump_sigspec(f, cell->getPort(ID::Y));
594 f << stringf(" = ~((");
595 dump_cell_expr_port(f, cell, "A", false);
596 f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
597 dump_cell_expr_port(f, cell, "B", false);
598 f << stringf(cell->type == ID($_AOI4_) ? ") |" : ") &");
599 dump_attributes(f, "", cell->attributes, ' ');
600 f << stringf(" (");
601 dump_cell_expr_port(f, cell, "C", false);
602 f << stringf(cell->type == ID($_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(ID::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(ID::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(ID::C));
622 if (cell->type[7] != '_') {
623 f << stringf(" or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
624 dump_sigspec(f, cell->getPort(ID::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(ID::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(ID::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(ID::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(ID::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(ID::C));
665 f << stringf(" or %sedge ", pol_s == 'P' ? "pos" : "neg");
666 dump_sigspec(f, cell->getPort(ID::S));
667 f << stringf(" or %sedge ", pol_r == 'P' ? "pos" : "neg");
668 dump_sigspec(f, cell->getPort(ID::R));
669 f << stringf(")\n");
670
671 f << stringf("%s" " if (%s", indent.c_str(), pol_r == 'P' ? "" : "!");
672 dump_sigspec(f, cell->getPort(ID::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(ID::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(ID::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(ID($not), "~")
701 HANDLE_UNIOP(ID($pos), "+")
702 HANDLE_UNIOP(ID($neg), "-")
703
704 HANDLE_BINOP(ID($and), "&")
705 HANDLE_BINOP(ID($or), "|")
706 HANDLE_BINOP(ID($xor), "^")
707 HANDLE_BINOP(ID($xnor), "~^")
708
709 HANDLE_UNIOP(ID($reduce_and), "&")
710 HANDLE_UNIOP(ID($reduce_or), "|")
711 HANDLE_UNIOP(ID($reduce_xor), "^")
712 HANDLE_UNIOP(ID($reduce_xnor), "~^")
713 HANDLE_UNIOP(ID($reduce_bool), "|")
714
715 HANDLE_BINOP(ID($shl), "<<")
716 HANDLE_BINOP(ID($shr), ">>")
717 HANDLE_BINOP(ID($sshl), "<<<")
718 HANDLE_BINOP(ID($sshr), ">>>")
719
720 HANDLE_BINOP(ID($lt), "<")
721 HANDLE_BINOP(ID($le), "<=")
722 HANDLE_BINOP(ID($eq), "==")
723 HANDLE_BINOP(ID($ne), "!=")
724 HANDLE_BINOP(ID($eqx), "===")
725 HANDLE_BINOP(ID($nex), "!==")
726 HANDLE_BINOP(ID($ge), ">=")
727 HANDLE_BINOP(ID($gt), ">")
728
729 HANDLE_BINOP(ID($add), "+")
730 HANDLE_BINOP(ID($sub), "-")
731 HANDLE_BINOP(ID($mul), "*")
732 HANDLE_BINOP(ID($div), "/")
733 HANDLE_BINOP(ID($mod), "%")
734 HANDLE_BINOP(ID($pow), "**")
735
736 HANDLE_UNIOP(ID($logic_not), "!")
737 HANDLE_BINOP(ID($logic_and), "&&")
738 HANDLE_BINOP(ID($logic_or), "||")
739
740 #undef HANDLE_UNIOP
741 #undef HANDLE_BINOP
742
743 if (cell->type == ID($shift))
744 {
745 f << stringf("%s" "assign ", indent.c_str());
746 dump_sigspec(f, cell->getPort(ID::Y));
747 f << stringf(" = ");
748 if (cell->getParam(ID::B_SIGNED).as_bool())
749 {
750 f << stringf("$signed(");
751 dump_sigspec(f, cell->getPort(ID::B));
752 f << stringf(")");
753 f << stringf(" < 0 ? ");
754 dump_sigspec(f, cell->getPort(ID::A));
755 f << stringf(" << - ");
756 dump_sigspec(f, cell->getPort(ID::B));
757 f << stringf(" : ");
758 dump_sigspec(f, cell->getPort(ID::A));
759 f << stringf(" >> ");
760 dump_sigspec(f, cell->getPort(ID::B));
761 }
762 else
763 {
764 dump_sigspec(f, cell->getPort(ID::A));
765 f << stringf(" >> ");
766 dump_sigspec(f, cell->getPort(ID::B));
767 }
768 f << stringf(";\n");
769 return true;
770 }
771
772 if (cell->type == ID($shiftx))
773 {
774 std::string temp_id = next_auto_id();
775 f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str());
776 dump_sigspec(f, cell->getPort(ID::A));
777 f << stringf(";\n");
778
779 f << stringf("%s" "assign ", indent.c_str());
780 dump_sigspec(f, cell->getPort(ID::Y));
781 f << stringf(" = %s[", temp_id.c_str());
782 if (cell->getParam(ID::B_SIGNED).as_bool())
783 f << stringf("$signed(");
784 dump_sigspec(f, cell->getPort(ID::B));
785 if (cell->getParam(ID::B_SIGNED).as_bool())
786 f << stringf(")");
787 f << stringf(" +: %d", cell->getParam(ID::Y_WIDTH).as_int());
788 f << stringf("];\n");
789 return true;
790 }
791
792 if (cell->type == ID($mux))
793 {
794 f << stringf("%s" "assign ", indent.c_str());
795 dump_sigspec(f, cell->getPort(ID::Y));
796 f << stringf(" = ");
797 dump_sigspec(f, cell->getPort(ID::S));
798 f << stringf(" ? ");
799 dump_attributes(f, "", cell->attributes, ' ');
800 dump_sigspec(f, cell->getPort(ID::B));
801 f << stringf(" : ");
802 dump_sigspec(f, cell->getPort(ID::A));
803 f << stringf(";\n");
804 return true;
805 }
806
807 if (cell->type == ID($pmux))
808 {
809 int width = cell->parameters[ID::WIDTH].as_int();
810 int s_width = cell->getPort(ID::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(ID::Y));
843 f << stringf(" = %s(", func_name.c_str());
844 dump_sigspec(f, cell->getPort(ID::A));
845 f << stringf(", ");
846 dump_sigspec(f, cell->getPort(ID::B));
847 f << stringf(", ");
848 dump_sigspec(f, cell->getPort(ID::S));
849 f << stringf(");\n");
850 return true;
851 }
852
853 if (cell->type == ID($tribuf))
854 {
855 f << stringf("%s" "assign ", indent.c_str());
856 dump_sigspec(f, cell->getPort(ID::Y));
857 f << stringf(" = ");
858 dump_sigspec(f, cell->getPort(ID::EN));
859 f << stringf(" ? ");
860 dump_sigspec(f, cell->getPort(ID::A));
861 f << stringf(" : %d'bz;\n", cell->parameters.at(ID::WIDTH).as_int());
862 return true;
863 }
864
865 if (cell->type == ID($slice))
866 {
867 f << stringf("%s" "assign ", indent.c_str());
868 dump_sigspec(f, cell->getPort(ID::Y));
869 f << stringf(" = ");
870 dump_sigspec(f, cell->getPort(ID::A));
871 f << stringf(" >> %d;\n", cell->parameters.at(ID::OFFSET).as_int());
872 return true;
873 }
874
875 if (cell->type == ID($concat))
876 {
877 f << stringf("%s" "assign ", indent.c_str());
878 dump_sigspec(f, cell->getPort(ID::Y));
879 f << stringf(" = { ");
880 dump_sigspec(f, cell->getPort(ID::B));
881 f << stringf(" , ");
882 dump_sigspec(f, cell->getPort(ID::A));
883 f << stringf(" };\n");
884 return true;
885 }
886
887 if (cell->type == ID($lut))
888 {
889 f << stringf("%s" "assign ", indent.c_str());
890 dump_sigspec(f, cell->getPort(ID::Y));
891 f << stringf(" = ");
892 dump_const(f, cell->parameters.at(ID::LUT));
893 f << stringf(" >> ");
894 dump_attributes(f, "", cell->attributes, ' ');
895 dump_sigspec(f, cell->getPort(ID::A));
896 f << stringf(";\n");
897 return true;
898 }
899
900 if (cell->type == ID($dffsr))
901 {
902 SigSpec sig_clk = cell->getPort(ID::CLK);
903 SigSpec sig_set = cell->getPort(ID::SET);
904 SigSpec sig_clr = cell->getPort(ID::CLR);
905 SigSpec sig_d = cell->getPort(ID::D);
906 SigSpec sig_q = cell->getPort(ID::Q);
907
908 int width = cell->parameters[ID::WIDTH].as_int();
909 bool pol_clk = cell->parameters[ID::CLK_POLARITY].as_bool();
910 bool pol_set = cell->parameters[ID::SET_POLARITY].as_bool();
911 bool pol_clr = cell->parameters[ID::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(ID($dff), ID($adff), ID($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(ID::CLK);
959 pol_clk = cell->parameters[ID::CLK_POLARITY].as_bool();
960
961 if (cell->type == ID($adff)) {
962 sig_arst = cell->getPort(ID::ARST);
963 pol_arst = cell->parameters[ID::ARST_POLARITY].as_bool();
964 val_arst = RTLIL::SigSpec(cell->parameters[ID::ARST_VALUE]);
965 }
966
967 if (cell->type == ID($dffe)) {
968 sig_en = cell->getPort(ID::EN);
969 pol_en = cell->parameters[ID::EN_POLARITY].as_bool();
970 }
971
972 std::string reg_name = cellname(cell);
973 bool out_is_reg_wire = is_reg_wire(cell->getPort(ID::Q), reg_name);
974
975 if (!out_is_reg_wire) {
976 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters[ID::WIDTH].as_int()-1, reg_name.c_str());
977 dump_reg_init(f, cell->getPort(ID::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 == ID($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 == ID($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 == ID($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(ID::Q));
1012 f << stringf(" = %s;\n", reg_name.c_str());
1013 }
1014
1015 return true;
1016 }
1017
1018 if (cell->type == ID($dlatch))
1019 {
1020 RTLIL::SigSpec sig_en;
1021 bool pol_en = false;
1022
1023 sig_en = cell->getPort(ID::EN);
1024 pol_en = cell->parameters[ID::EN_POLARITY].as_bool();
1025
1026 std::string reg_name = cellname(cell);
1027 bool out_is_reg_wire = is_reg_wire(cell->getPort(ID::Q), reg_name);
1028
1029 if (!out_is_reg_wire) {
1030 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters[ID::WIDTH].as_int()-1, reg_name.c_str());
1031 dump_reg_init(f, cell->getPort(ID::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(ID::Q));
1048 f << stringf(" = %s;\n", reg_name.c_str());
1049 }
1050
1051 return true;
1052 }
1053
1054 if (cell->type == ID($mem))
1055 {
1056 RTLIL::IdString memid = cell->parameters[ID::MEMID].decode_string();
1057 std::string mem_id = id(cell->parameters[ID::MEMID].decode_string());
1058 int abits = cell->parameters[ID::ABITS].as_int();
1059 int size = cell->parameters[ID::SIZE].as_int();
1060 int offset = cell->parameters[ID::OFFSET].as_int();
1061 int width = cell->parameters[ID::WIDTH].as_int();
1062 bool use_init = !(RTLIL::SigSpec(cell->parameters[ID::INIT]).is_fully_undef());
1063
1064 // for memory block make something like:
1065 // reg [7:0] memid [3:0];
1066 // initial begin
1067 // memid[0] = ...
1068 // end
1069 dump_attributes(f, indent.c_str(), cell->attributes);
1070 f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size+offset-1, offset);
1071 if (use_init)
1072 {
1073 if (extmem)
1074 {
1075 std::string extmem_filename = stringf("%s-%d.mem", extmem_prefix.c_str(), extmem_counter++);
1076
1077 std::string extmem_filename_esc;
1078 for (auto c : extmem_filename)
1079 {
1080 if (c == '\n')
1081 extmem_filename_esc += "\\n";
1082 else if (c == '\t')
1083 extmem_filename_esc += "\\t";
1084 else if (c < 32)
1085 extmem_filename_esc += stringf("\\%03o", c);
1086 else if (c == '"')
1087 extmem_filename_esc += "\\\"";
1088 else if (c == '\\')
1089 extmem_filename_esc += "\\\\";
1090 else
1091 extmem_filename_esc += c;
1092 }
1093 f << stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent.c_str(), extmem_filename_esc.c_str(), mem_id.c_str());
1094
1095 std::ofstream extmem_f(extmem_filename, std::ofstream::trunc);
1096 if (extmem_f.fail())
1097 log_error("Can't open file `%s' for writing: %s\n", extmem_filename.c_str(), strerror(errno));
1098 else
1099 {
1100 for (int i=0; i<size; i++)
1101 {
1102 RTLIL::Const element = cell->parameters[ID::INIT].extract(i*width, width);
1103 for (int j=0; j<element.size(); j++)
1104 {
1105 switch (element[element.size()-j-1])
1106 {
1107 case State::S0: extmem_f << '0'; break;
1108 case State::S1: extmem_f << '1'; break;
1109 case State::Sx: extmem_f << 'x'; break;
1110 case State::Sz: extmem_f << 'z'; break;
1111 case State::Sa: extmem_f << '_'; break;
1112 case State::Sm: log_error("Found marker state in final netlist.");
1113 }
1114 }
1115 extmem_f << '\n';
1116 }
1117 }
1118
1119 }
1120 else
1121 {
1122 f << stringf("%s" "initial begin\n", indent.c_str());
1123 for (int i=0; i<size; i++)
1124 {
1125 f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i);
1126 dump_const(f, cell->parameters[ID::INIT].extract(i*width, width));
1127 f << stringf(";\n");
1128 }
1129 f << stringf("%s" "end\n", indent.c_str());
1130 }
1131 }
1132
1133 // create a map : "edge clk" -> expressions within that clock domain
1134 dict<std::string, std::vector<std::string>> clk_to_lof_body;
1135 clk_to_lof_body[""] = std::vector<std::string>();
1136 std::string clk_domain_str;
1137 // create a list of reg declarations
1138 std::vector<std::string> lof_reg_declarations;
1139
1140 int nread_ports = cell->parameters[ID::RD_PORTS].as_int();
1141 RTLIL::SigSpec sig_rd_clk, sig_rd_en, sig_rd_data, sig_rd_addr;
1142 bool use_rd_clk, rd_clk_posedge, rd_transparent;
1143 // read ports
1144 for (int i=0; i < nread_ports; i++)
1145 {
1146 sig_rd_clk = cell->getPort(ID::RD_CLK).extract(i);
1147 sig_rd_en = cell->getPort(ID::RD_EN).extract(i);
1148 sig_rd_data = cell->getPort(ID::RD_DATA).extract(i*width, width);
1149 sig_rd_addr = cell->getPort(ID::RD_ADDR).extract(i*abits, abits);
1150 use_rd_clk = cell->parameters[ID::RD_CLK_ENABLE].extract(i).as_bool();
1151 rd_clk_posedge = cell->parameters[ID::RD_CLK_POLARITY].extract(i).as_bool();
1152 rd_transparent = cell->parameters[ID::RD_TRANSPARENT].extract(i).as_bool();
1153 if (use_rd_clk)
1154 {
1155 {
1156 std::ostringstream os;
1157 dump_sigspec(os, sig_rd_clk);
1158 clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
1159 if( clk_to_lof_body.count(clk_domain_str) == 0 )
1160 clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
1161 }
1162 if (!rd_transparent)
1163 {
1164 // for clocked read ports make something like:
1165 // reg [..] temp_id;
1166 // always @(posedge clk)
1167 // if (rd_en) temp_id <= array_reg[r_addr];
1168 // assign r_data = temp_id;
1169 std::string temp_id = next_auto_id();
1170 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
1171 {
1172 std::ostringstream os;
1173 if (sig_rd_en != RTLIL::SigBit(true))
1174 {
1175 os << stringf("if (");
1176 dump_sigspec(os, sig_rd_en);
1177 os << stringf(") ");
1178 }
1179 os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
1180 dump_sigspec(os, sig_rd_addr);
1181 os << stringf("];\n");
1182 clk_to_lof_body[clk_domain_str].push_back(os.str());
1183 }
1184 {
1185 std::ostringstream os;
1186 dump_sigspec(os, sig_rd_data);
1187 std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
1188 clk_to_lof_body[""].push_back(line);
1189 }
1190 }
1191 else
1192 {
1193 // for rd-transparent read-ports make something like:
1194 // reg [..] temp_id;
1195 // always @(posedge clk)
1196 // temp_id <= r_addr;
1197 // assign r_data = array_reg[temp_id];
1198 std::string temp_id = next_auto_id();
1199 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr.size() - 1, temp_id.c_str()) );
1200 {
1201 std::ostringstream os;
1202 dump_sigspec(os, sig_rd_addr);
1203 std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str());
1204 clk_to_lof_body[clk_domain_str].push_back(line);
1205 }
1206 {
1207 std::ostringstream os;
1208 dump_sigspec(os, sig_rd_data);
1209 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str());
1210 clk_to_lof_body[""].push_back(line);
1211 }
1212 }
1213 } else {
1214 // for non-clocked read-ports make something like:
1215 // assign r_data = array_reg[r_addr];
1216 std::ostringstream os, os2;
1217 dump_sigspec(os, sig_rd_data);
1218 dump_sigspec(os2, sig_rd_addr);
1219 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
1220 clk_to_lof_body[""].push_back(line);
1221 }
1222 }
1223
1224 int nwrite_ports = cell->parameters[ID::WR_PORTS].as_int();
1225 RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en;
1226 bool wr_clk_posedge;
1227
1228 // write ports
1229 for (int i=0; i < nwrite_ports; i++)
1230 {
1231 sig_wr_clk = cell->getPort(ID::WR_CLK).extract(i);
1232 sig_wr_data = cell->getPort(ID::WR_DATA).extract(i*width, width);
1233 sig_wr_addr = cell->getPort(ID::WR_ADDR).extract(i*abits, abits);
1234 sig_wr_en = cell->getPort(ID::WR_EN).extract(i*width, width);
1235 wr_clk_posedge = cell->parameters[ID::WR_CLK_POLARITY].extract(i).as_bool();
1236 {
1237 std::ostringstream os;
1238 dump_sigspec(os, sig_wr_clk);
1239 clk_domain_str = stringf("%sedge %s", wr_clk_posedge ? "pos" : "neg", os.str().c_str());
1240 if( clk_to_lof_body.count(clk_domain_str) == 0 )
1241 clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
1242 }
1243 // make something like:
1244 // always @(posedge clk)
1245 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1246 // ...
1247 for (int i = 0; i < GetSize(sig_wr_en); i++)
1248 {
1249 int start_i = i, width = 1;
1250 SigBit wen_bit = sig_wr_en[i];
1251
1252 while (i+1 < GetSize(sig_wr_en) && active_sigmap(sig_wr_en[i+1]) == active_sigmap(wen_bit))
1253 i++, width++;
1254
1255 if (wen_bit == State::S0)
1256 continue;
1257
1258 std::ostringstream os;
1259 if (wen_bit != State::S1)
1260 {
1261 os << stringf("if (");
1262 dump_sigspec(os, wen_bit);
1263 os << stringf(") ");
1264 }
1265 os << stringf("%s[", mem_id.c_str());
1266 dump_sigspec(os, sig_wr_addr);
1267 if (width == GetSize(sig_wr_en))
1268 os << stringf("] <= ");
1269 else
1270 os << stringf("][%d:%d] <= ", i, start_i);
1271 dump_sigspec(os, sig_wr_data.extract(start_i, width));
1272 os << stringf(";\n");
1273 clk_to_lof_body[clk_domain_str].push_back(os.str());
1274 }
1275 }
1276 // Output Verilog that looks something like this:
1277 // reg [..] _3_;
1278 // always @(posedge CLK2) begin
1279 // _3_ <= memory[D1ADDR];
1280 // if (A1EN)
1281 // memory[A1ADDR] <= A1DATA;
1282 // if (A2EN)
1283 // memory[A2ADDR] <= A2DATA;
1284 // ...
1285 // end
1286 // always @(negedge CLK1) begin
1287 // if (C1EN)
1288 // memory[C1ADDR] <= C1DATA;
1289 // end
1290 // ...
1291 // assign D1DATA = _3_;
1292 // assign D2DATA <= memory[D2ADDR];
1293
1294 // the reg ... definitions
1295 for(auto &reg : lof_reg_declarations)
1296 {
1297 f << stringf("%s" "%s", indent.c_str(), reg.c_str());
1298 }
1299 // the block of expressions by clock domain
1300 for(auto &pair : clk_to_lof_body)
1301 {
1302 std::string clk_domain = pair.first;
1303 std::vector<std::string> lof_lines = pair.second;
1304 if( clk_domain != "")
1305 {
1306 f << stringf("%s" "always @(%s) begin\n", indent.c_str(), clk_domain.c_str());
1307 for(auto &line : lof_lines)
1308 f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str());
1309 f << stringf("%s" "end\n", indent.c_str());
1310 }
1311 else
1312 {
1313 // the non-clocked assignments
1314 for(auto &line : lof_lines)
1315 f << stringf("%s" "%s", indent.c_str(), line.c_str());
1316 }
1317 }
1318
1319 return true;
1320 }
1321
1322 if (cell->type.in(ID($assert), ID($assume), ID($cover)))
1323 {
1324 f << stringf("%s" "always @* if (", indent.c_str());
1325 dump_sigspec(f, cell->getPort(ID::EN));
1326 f << stringf(") %s(", cell->type.c_str()+1);
1327 dump_sigspec(f, cell->getPort(ID::A));
1328 f << stringf(");\n");
1329 return true;
1330 }
1331
1332 if (cell->type.in(ID($specify2), ID($specify3)))
1333 {
1334 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1335
1336 SigSpec en = cell->getPort(ID::EN);
1337 if (en != State::S1) {
1338 f << stringf("if (");
1339 dump_sigspec(f, cell->getPort(ID::EN));
1340 f << stringf(") ");
1341 }
1342
1343 f << "(";
1344 if (cell->type == ID($specify3) && cell->getParam(ID::EDGE_EN).as_bool())
1345 f << (cell->getParam(ID::EDGE_POL).as_bool() ? "posedge ": "negedge ");
1346
1347 dump_sigspec(f, cell->getPort(ID::SRC));
1348
1349 f << " ";
1350 if (cell->getParam(ID::SRC_DST_PEN).as_bool())
1351 f << (cell->getParam(ID::SRC_DST_POL).as_bool() ? "+": "-");
1352 f << (cell->getParam(ID::FULL).as_bool() ? "*> ": "=> ");
1353
1354 if (cell->type == ID($specify3)) {
1355 f << "(";
1356 dump_sigspec(f, cell->getPort(ID::DST));
1357 f << " ";
1358 if (cell->getParam(ID::DAT_DST_PEN).as_bool())
1359 f << (cell->getParam(ID::DAT_DST_POL).as_bool() ? "+": "-");
1360 f << ": ";
1361 dump_sigspec(f, cell->getPort(ID::DAT));
1362 f << ")";
1363 } else {
1364 dump_sigspec(f, cell->getPort(ID::DST));
1365 }
1366
1367 bool bak_decimal = decimal;
1368 decimal = 1;
1369
1370 f << ") = (";
1371 dump_const(f, cell->getParam(ID::T_RISE_MIN));
1372 f << ":";
1373 dump_const(f, cell->getParam(ID::T_RISE_TYP));
1374 f << ":";
1375 dump_const(f, cell->getParam(ID::T_RISE_MAX));
1376 f << ", ";
1377 dump_const(f, cell->getParam(ID::T_FALL_MIN));
1378 f << ":";
1379 dump_const(f, cell->getParam(ID::T_FALL_TYP));
1380 f << ":";
1381 dump_const(f, cell->getParam(ID::T_FALL_MAX));
1382 f << ");\n";
1383
1384 decimal = bak_decimal;
1385
1386 f << stringf("%s" "endspecify\n", indent.c_str());
1387 return true;
1388 }
1389
1390 if (cell->type == ID($specrule))
1391 {
1392 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1393
1394 IdString spec_type = cell->getParam(ID::TYPE).decode_string();
1395 f << stringf("%s(", spec_type.c_str());
1396
1397 if (cell->getParam(ID::SRC_PEN).as_bool())
1398 f << (cell->getParam(ID::SRC_POL).as_bool() ? "posedge ": "negedge ");
1399 dump_sigspec(f, cell->getPort(ID::SRC));
1400
1401 if (cell->getPort(ID::SRC_EN) != State::S1) {
1402 f << " &&& ";
1403 dump_sigspec(f, cell->getPort(ID::SRC_EN));
1404 }
1405
1406 f << ", ";
1407 if (cell->getParam(ID::DST_PEN).as_bool())
1408 f << (cell->getParam(ID::DST_POL).as_bool() ? "posedge ": "negedge ");
1409 dump_sigspec(f, cell->getPort(ID::DST));
1410
1411 if (cell->getPort(ID::DST_EN) != State::S1) {
1412 f << " &&& ";
1413 dump_sigspec(f, cell->getPort(ID::DST_EN));
1414 }
1415
1416 bool bak_decimal = decimal;
1417 decimal = 1;
1418
1419 f << ", ";
1420 dump_const(f, cell->getParam(ID::T_LIMIT_MIN));
1421 f << ": ";
1422 dump_const(f, cell->getParam(ID::T_LIMIT_TYP));
1423 f << ": ";
1424 dump_const(f, cell->getParam(ID::T_LIMIT_MAX));
1425
1426 if (spec_type.in(ID($setuphold), ID($recrem), ID($fullskew))) {
1427 f << ", ";
1428 dump_const(f, cell->getParam(ID::T_LIMIT2_MIN));
1429 f << ": ";
1430 dump_const(f, cell->getParam(ID::T_LIMIT2_TYP));
1431 f << ": ";
1432 dump_const(f, cell->getParam(ID::T_LIMIT2_MAX));
1433 }
1434
1435 f << ");\n";
1436 decimal = bak_decimal;
1437
1438 f << stringf("%s" "endspecify\n", indent.c_str());
1439 return true;
1440 }
1441
1442 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1443 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1444
1445 return false;
1446 }
1447
1448 void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
1449 {
1450 if (cell->type[0] == '$' && !noexpr) {
1451 if (dump_cell_expr(f, indent, cell))
1452 return;
1453 }
1454
1455 dump_attributes(f, indent, cell->attributes);
1456 f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
1457
1458 if (!defparam && cell->parameters.size() > 0) {
1459 f << stringf(" #(");
1460 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1461 if (it != cell->parameters.begin())
1462 f << stringf(",");
1463 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1464 dump_const(f, it->second);
1465 f << stringf(")");
1466 }
1467 f << stringf("\n%s" ")", indent.c_str());
1468 }
1469
1470 std::string cell_name = cellname(cell);
1471 if (cell_name != id(cell->name))
1472 f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
1473 else
1474 f << stringf(" %s (", cell_name.c_str());
1475
1476 bool first_arg = true;
1477 std::set<RTLIL::IdString> numbered_ports;
1478 for (int i = 1; true; i++) {
1479 char str[16];
1480 snprintf(str, 16, "$%d", i);
1481 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1482 if (it->first != str)
1483 continue;
1484 if (!first_arg)
1485 f << stringf(",");
1486 first_arg = false;
1487 f << stringf("\n%s ", indent.c_str());
1488 dump_sigspec(f, it->second);
1489 numbered_ports.insert(it->first);
1490 goto found_numbered_port;
1491 }
1492 break;
1493 found_numbered_port:;
1494 }
1495 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1496 if (numbered_ports.count(it->first))
1497 continue;
1498 if (!first_arg)
1499 f << stringf(",");
1500 first_arg = false;
1501 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1502 if (it->second.size() > 0)
1503 dump_sigspec(f, it->second);
1504 f << stringf(")");
1505 }
1506 f << stringf("\n%s" ");\n", indent.c_str());
1507
1508 if (defparam && cell->parameters.size() > 0) {
1509 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1510 f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
1511 dump_const(f, it->second);
1512 f << stringf(";\n");
1513 }
1514 }
1515
1516 if (siminit && reg_ct.count(cell->type) && cell->hasPort(ID::Q)) {
1517 std::stringstream ss;
1518 dump_reg_init(ss, cell->getPort(ID::Q));
1519 if (!ss.str().empty()) {
1520 f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str());
1521 f << ss.str();
1522 f << ";\n";
1523 }
1524 }
1525 }
1526
1527 void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
1528 {
1529 f << stringf("%s" "assign ", indent.c_str());
1530 dump_sigspec(f, left);
1531 f << stringf(" = ");
1532 dump_sigspec(f, right);
1533 f << stringf(";\n");
1534 }
1535
1536 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
1537
1538 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
1539 {
1540 int number_of_stmts = cs->switches.size() + cs->actions.size();
1541
1542 if (!omit_trailing_begin && number_of_stmts >= 2)
1543 f << stringf("%s" "begin\n", indent.c_str());
1544
1545 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1546 if (it->first.size() == 0)
1547 continue;
1548 f << stringf("%s ", indent.c_str());
1549 dump_sigspec(f, it->first);
1550 f << stringf(" = ");
1551 dump_sigspec(f, it->second);
1552 f << stringf(";\n");
1553 }
1554
1555 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1556 dump_proc_switch(f, indent + " ", *it);
1557
1558 if (!omit_trailing_begin && number_of_stmts == 0)
1559 f << stringf("%s /* empty */;\n", indent.c_str());
1560
1561 if (omit_trailing_begin || number_of_stmts >= 2)
1562 f << stringf("%s" "end\n", indent.c_str());
1563 }
1564
1565 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
1566 {
1567 if (sw->signal.size() == 0) {
1568 f << stringf("%s" "begin\n", indent.c_str());
1569 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1570 if ((*it)->compare.size() == 0)
1571 dump_case_body(f, indent + " ", *it);
1572 }
1573 f << stringf("%s" "end\n", indent.c_str());
1574 return;
1575 }
1576
1577 dump_attributes(f, indent, sw->attributes);
1578 f << stringf("%s" "casez (", indent.c_str());
1579 dump_sigspec(f, sw->signal);
1580 f << stringf(")\n");
1581
1582 bool got_default = false;
1583 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1584 dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1585 if ((*it)->compare.size() == 0) {
1586 if (got_default)
1587 continue;
1588 f << stringf("%s default", indent.c_str());
1589 got_default = true;
1590 } else {
1591 f << stringf("%s ", indent.c_str());
1592 for (size_t i = 0; i < (*it)->compare.size(); i++) {
1593 if (i > 0)
1594 f << stringf(", ");
1595 dump_sigspec(f, (*it)->compare[i]);
1596 }
1597 }
1598 f << stringf(":\n");
1599 dump_case_body(f, indent + " ", *it);
1600 }
1601
1602 f << stringf("%s" "endcase\n", indent.c_str());
1603 }
1604
1605 void case_body_find_regs(RTLIL::CaseRule *cs)
1606 {
1607 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1608 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
1609 case_body_find_regs(*it2);
1610
1611 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1612 for (auto &c : it->first.chunks())
1613 if (c.wire != NULL)
1614 reg_wires.insert(c.wire->name);
1615 }
1616 }
1617
1618 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
1619 {
1620 if (find_regs) {
1621 case_body_find_regs(&proc->root_case);
1622 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
1623 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
1624 for (auto &c : it2->first.chunks())
1625 if (c.wire != NULL)
1626 reg_wires.insert(c.wire->name);
1627 }
1628 return;
1629 }
1630
1631 f << stringf("%s" "always @* begin\n", indent.c_str());
1632 dump_case_body(f, indent, &proc->root_case, true);
1633
1634 std::string backup_indent = indent;
1635
1636 for (size_t i = 0; i < proc->syncs.size(); i++)
1637 {
1638 RTLIL::SyncRule *sync = proc->syncs[i];
1639 indent = backup_indent;
1640
1641 if (sync->type == RTLIL::STa) {
1642 f << stringf("%s" "always @* begin\n", indent.c_str());
1643 } else if (sync->type == RTLIL::STi) {
1644 f << stringf("%s" "initial begin\n", indent.c_str());
1645 } else {
1646 f << stringf("%s" "always @(", indent.c_str());
1647 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
1648 f << stringf("posedge ");
1649 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
1650 f << stringf("negedge ");
1651 dump_sigspec(f, sync->signal);
1652 f << stringf(") begin\n");
1653 }
1654 std::string ends = indent + "end\n";
1655 indent += " ";
1656
1657 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
1658 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
1659 dump_sigspec(f, sync->signal);
1660 f << stringf(") begin\n");
1661 ends = indent + "end\n" + ends;
1662 indent += " ";
1663 }
1664
1665 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
1666 for (size_t j = 0; j < proc->syncs.size(); j++) {
1667 RTLIL::SyncRule *sync2 = proc->syncs[j];
1668 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
1669 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
1670 dump_sigspec(f, sync2->signal);
1671 f << stringf(") begin\n");
1672 ends = indent + "end\n" + ends;
1673 indent += " ";
1674 }
1675 }
1676 }
1677
1678 for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
1679 if (it->first.size() == 0)
1680 continue;
1681 f << stringf("%s ", indent.c_str());
1682 dump_sigspec(f, it->first);
1683 f << stringf(" <= ");
1684 dump_sigspec(f, it->second);
1685 f << stringf(";\n");
1686 }
1687
1688 f << stringf("%s", ends.c_str());
1689 }
1690 }
1691
1692 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
1693 {
1694 reg_wires.clear();
1695 reset_auto_counter(module);
1696 active_module = module;
1697 active_sigmap.set(module);
1698 active_initdata.clear();
1699
1700 for (auto wire : module->wires())
1701 if (wire->attributes.count(ID::init)) {
1702 SigSpec sig = active_sigmap(wire);
1703 Const val = wire->attributes.at(ID::init);
1704 for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
1705 if (val[i] == State::S0 || val[i] == State::S1)
1706 active_initdata[sig[i]] = val[i];
1707 }
1708
1709 if (!module->processes.empty())
1710 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1711 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1712 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1713 "processes to logic networks and registers.\n", log_id(module));
1714
1715 f << stringf("\n");
1716 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1717 dump_process(f, indent + " ", it->second, true);
1718
1719 if (!noexpr)
1720 {
1721 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
1722 for (auto cell : module->cells())
1723 {
1724 if (!reg_ct.count(cell->type) || !cell->hasPort(ID::Q))
1725 continue;
1726
1727 RTLIL::SigSpec sig = cell->getPort(ID::Q);
1728
1729 if (sig.is_chunk()) {
1730 RTLIL::SigChunk chunk = sig.as_chunk();
1731 if (chunk.wire != NULL)
1732 for (int i = 0; i < chunk.width; i++)
1733 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
1734 }
1735 }
1736 for (auto wire : module->wires())
1737 {
1738 for (int i = 0; i < wire->width; i++)
1739 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
1740 goto this_wire_aint_reg;
1741 if (wire->width)
1742 reg_wires.insert(wire->name);
1743 this_wire_aint_reg:;
1744 }
1745 }
1746
1747 dump_attributes(f, indent, module->attributes, '\n', /*modattr=*/true);
1748 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
1749 bool keep_running = true;
1750 for (int port_id = 1; keep_running; port_id++) {
1751 keep_running = false;
1752 for (auto wire : module->wires()) {
1753 if (wire->port_id == port_id) {
1754 if (port_id != 1)
1755 f << stringf(", ");
1756 f << stringf("%s", id(wire->name).c_str());
1757 keep_running = true;
1758 continue;
1759 }
1760 }
1761 }
1762 f << stringf(");\n");
1763
1764 for (auto w : module->wires())
1765 dump_wire(f, indent + " ", w);
1766
1767 for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
1768 dump_memory(f, indent + " ", it->second);
1769
1770 for (auto cell : module->cells())
1771 dump_cell(f, indent + " ", cell);
1772
1773 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1774 dump_process(f, indent + " ", it->second);
1775
1776 for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
1777 dump_conn(f, indent + " ", it->first, it->second);
1778
1779 f << stringf("%s" "endmodule\n", indent.c_str());
1780 active_module = NULL;
1781 active_sigmap.clear();
1782 active_initdata.clear();
1783 }
1784
1785 struct VerilogBackend : public Backend {
1786 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1787 void help() YS_OVERRIDE
1788 {
1789 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1790 log("\n");
1791 log(" write_verilog [options] [filename]\n");
1792 log("\n");
1793 log("Write the current design to a Verilog file.\n");
1794 log("\n");
1795 log(" -norename\n");
1796 log(" without this option all internal object names (the ones with a dollar\n");
1797 log(" instead of a backslash prefix) are changed to short names in the\n");
1798 log(" format '_<number>_'.\n");
1799 log("\n");
1800 log(" -renameprefix <prefix>\n");
1801 log(" insert this prefix in front of auto-generated instance names\n");
1802 log("\n");
1803 log(" -noattr\n");
1804 log(" with this option no attributes are included in the output\n");
1805 log("\n");
1806 log(" -attr2comment\n");
1807 log(" with this option attributes are included as comments in the output\n");
1808 log("\n");
1809 log(" -noexpr\n");
1810 log(" without this option all internal cells are converted to Verilog\n");
1811 log(" expressions.\n");
1812 log("\n");
1813 log(" -siminit\n");
1814 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1815 log(" in -noexpr mode.\n");
1816 log("\n");
1817 log(" -nodec\n");
1818 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1819 log(" not bit pattern. This option deactivates this feature and instead\n");
1820 log(" will write out all constants in binary.\n");
1821 log("\n");
1822 log(" -decimal\n");
1823 log(" dump 32-bit constants in decimal and without size and radix\n");
1824 log("\n");
1825 log(" -nohex\n");
1826 log(" constant values that are compatible with hex output are usually\n");
1827 log(" dumped as hex values. This option deactivates this feature and\n");
1828 log(" instead will write out all constants in binary.\n");
1829 log("\n");
1830 log(" -nostr\n");
1831 log(" Parameters and attributes that are specified as strings in the\n");
1832 log(" original input will be output as strings by this back-end. This\n");
1833 log(" deactivates this feature and instead will write string constants\n");
1834 log(" as binary numbers.\n");
1835 log("\n");
1836 log(" -extmem\n");
1837 log(" instead of initializing memories using assignments to individual\n");
1838 log(" elements, use the '$readmemh' function to read initialization data\n");
1839 log(" from a file. This data is written to a file named by appending\n");
1840 log(" a sequential index to the Verilog filename and replacing the extension\n");
1841 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
1842 log(" 'foo-2.mem' and so on.\n");
1843 log("\n");
1844 log(" -defparam\n");
1845 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1846 log(" cell parameters.\n");
1847 log("\n");
1848 log(" -blackboxes\n");
1849 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1850 log(" this option set only the modules with the 'blackbox' attribute\n");
1851 log(" are written to the output file.\n");
1852 log("\n");
1853 log(" -selected\n");
1854 log(" only write selected modules. modules must be selected entirely or\n");
1855 log(" not at all.\n");
1856 log("\n");
1857 log(" -v\n");
1858 log(" verbose output (print new names of all renamed wires and cells)\n");
1859 log("\n");
1860 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1861 log("always blocks. This frontend should only be used to export an RTLIL\n");
1862 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1863 log("processes to logic networks and registers. A warning is generated when\n");
1864 log("this command is called on a design with RTLIL processes.\n");
1865 log("\n");
1866 }
1867 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
1868 {
1869 log_header(design, "Executing Verilog backend.\n");
1870
1871 verbose = false;
1872 norename = false;
1873 noattr = false;
1874 attr2comment = false;
1875 noexpr = false;
1876 nodec = false;
1877 nohex = false;
1878 nostr = false;
1879 extmem = false;
1880 defparam = false;
1881 decimal = false;
1882 siminit = false;
1883 auto_prefix = "";
1884
1885 bool blackboxes = false;
1886 bool selected = false;
1887
1888 auto_name_map.clear();
1889 reg_wires.clear();
1890 reg_ct.clear();
1891
1892 reg_ct.insert(ID($dff));
1893 reg_ct.insert(ID($adff));
1894 reg_ct.insert(ID($dffe));
1895 reg_ct.insert(ID($dlatch));
1896
1897 reg_ct.insert(ID($_DFF_N_));
1898 reg_ct.insert(ID($_DFF_P_));
1899
1900 reg_ct.insert(ID($_DFF_NN0_));
1901 reg_ct.insert(ID($_DFF_NN1_));
1902 reg_ct.insert(ID($_DFF_NP0_));
1903 reg_ct.insert(ID($_DFF_NP1_));
1904 reg_ct.insert(ID($_DFF_PN0_));
1905 reg_ct.insert(ID($_DFF_PN1_));
1906 reg_ct.insert(ID($_DFF_PP0_));
1907 reg_ct.insert(ID($_DFF_PP1_));
1908
1909 reg_ct.insert(ID($_DFFSR_NNN_));
1910 reg_ct.insert(ID($_DFFSR_NNP_));
1911 reg_ct.insert(ID($_DFFSR_NPN_));
1912 reg_ct.insert(ID($_DFFSR_NPP_));
1913 reg_ct.insert(ID($_DFFSR_PNN_));
1914 reg_ct.insert(ID($_DFFSR_PNP_));
1915 reg_ct.insert(ID($_DFFSR_PPN_));
1916 reg_ct.insert(ID($_DFFSR_PPP_));
1917
1918 size_t argidx;
1919 for (argidx = 1; argidx < args.size(); argidx++) {
1920 std::string arg = args[argidx];
1921 if (arg == "-norename") {
1922 norename = true;
1923 continue;
1924 }
1925 if (arg == "-renameprefix" && argidx+1 < args.size()) {
1926 auto_prefix = args[++argidx];
1927 continue;
1928 }
1929 if (arg == "-noattr") {
1930 noattr = true;
1931 continue;
1932 }
1933 if (arg == "-attr2comment") {
1934 attr2comment = true;
1935 continue;
1936 }
1937 if (arg == "-noexpr") {
1938 noexpr = true;
1939 continue;
1940 }
1941 if (arg == "-nodec") {
1942 nodec = true;
1943 continue;
1944 }
1945 if (arg == "-nohex") {
1946 nohex = true;
1947 continue;
1948 }
1949 if (arg == "-nostr") {
1950 nostr = true;
1951 continue;
1952 }
1953 if (arg == "-extmem") {
1954 extmem = true;
1955 extmem_counter = 1;
1956 continue;
1957 }
1958 if (arg == "-defparam") {
1959 defparam = true;
1960 continue;
1961 }
1962 if (arg == "-decimal") {
1963 decimal = true;
1964 continue;
1965 }
1966 if (arg == "-siminit") {
1967 siminit = true;
1968 continue;
1969 }
1970 if (arg == "-blackboxes") {
1971 blackboxes = true;
1972 continue;
1973 }
1974 if (arg == "-selected") {
1975 selected = true;
1976 continue;
1977 }
1978 if (arg == "-v") {
1979 verbose = true;
1980 continue;
1981 }
1982 break;
1983 }
1984 extra_args(f, filename, args, argidx);
1985 if (extmem)
1986 {
1987 if (filename.empty())
1988 log_cmd_error("Option -extmem must be used with a filename.\n");
1989 extmem_prefix = filename.substr(0, filename.rfind('.'));
1990 }
1991
1992 design->sort();
1993
1994 *f << stringf("/* Generated by %s */\n", yosys_version_str);
1995 for (auto module : design->modules()) {
1996 if (module->get_blackbox_attribute() != blackboxes)
1997 continue;
1998 if (selected && !design->selected_whole_module(module->name)) {
1999 if (design->selected_module(module->name))
2000 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module->name));
2001 continue;
2002 }
2003 log("Dumping module `%s'.\n", module->name.c_str());
2004 dump_module(*f, "", module);
2005 }
2006
2007 auto_name_map.clear();
2008 reg_wires.clear();
2009 reg_ct.clear();
2010 }
2011 } VerilogBackend;
2012
2013 PRIVATE_NAMESPACE_END