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