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