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