Add $shiftx support to verilog front-end
[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:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
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 == "$dffsr")
783 {
784 SigSpec sig_clk = cell->getPort("\\CLK");
785 SigSpec sig_set = cell->getPort("\\SET");
786 SigSpec sig_clr = cell->getPort("\\CLR");
787 SigSpec sig_d = cell->getPort("\\D");
788 SigSpec sig_q = cell->getPort("\\Q");
789
790 int width = cell->parameters["\\WIDTH"].as_int();
791 bool pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
792 bool pol_set = cell->parameters["\\SET_POLARITY"].as_bool();
793 bool pol_clr = cell->parameters["\\CLR_POLARITY"].as_bool();
794
795 std::string reg_name = cellname(cell);
796 bool out_is_reg_wire = is_reg_wire(sig_q, reg_name);
797
798 if (!out_is_reg_wire) {
799 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), width-1, reg_name.c_str());
800 dump_reg_init(f, sig_q);
801 f << ";\n";
802 }
803
804 for (int i = 0; i < width; i++) {
805 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
806 dump_sigspec(f, sig_clk);
807 f << stringf(", %sedge ", pol_set ? "pos" : "neg");
808 dump_sigspec(f, sig_set);
809 f << stringf(", %sedge ", pol_clr ? "pos" : "neg");
810 dump_sigspec(f, sig_clr);
811 f << stringf(")\n");
812
813 f << stringf("%s" " if (%s", indent.c_str(), pol_clr ? "" : "!");
814 dump_sigspec(f, sig_clr);
815 f << stringf(") %s[%d] <= 1'b0;\n", reg_name.c_str(), i);
816
817 f << stringf("%s" " else if (%s", indent.c_str(), pol_set ? "" : "!");
818 dump_sigspec(f, sig_set);
819 f << stringf(") %s[%d] <= 1'b1;\n", reg_name.c_str(), i);
820
821 f << stringf("%s" " else %s[%d] <= ", indent.c_str(), reg_name.c_str(), i);
822 dump_sigspec(f, sig_d[i]);
823 f << stringf(";\n");
824 }
825
826 if (!out_is_reg_wire) {
827 f << stringf("%s" "assign ", indent.c_str());
828 dump_sigspec(f, sig_q);
829 f << stringf(" = %s;\n", reg_name.c_str());
830 }
831
832 return true;
833 }
834
835 if (cell->type == "$dff" || cell->type == "$adff" || cell->type == "$dffe")
836 {
837 RTLIL::SigSpec sig_clk, sig_arst, sig_en, val_arst;
838 bool pol_clk, pol_arst = false, pol_en = false;
839
840 sig_clk = cell->getPort("\\CLK");
841 pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
842
843 if (cell->type == "$adff") {
844 sig_arst = cell->getPort("\\ARST");
845 pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool();
846 val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
847 }
848
849 if (cell->type == "$dffe") {
850 sig_en = cell->getPort("\\EN");
851 pol_en = cell->parameters["\\EN_POLARITY"].as_bool();
852 }
853
854 std::string reg_name = cellname(cell);
855 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
856
857 if (!out_is_reg_wire) {
858 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
859 dump_reg_init(f, cell->getPort("\\Q"));
860 f << ";\n";
861 }
862
863 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
864 dump_sigspec(f, sig_clk);
865 if (cell->type == "$adff") {
866 f << stringf(" or %sedge ", pol_arst ? "pos" : "neg");
867 dump_sigspec(f, sig_arst);
868 }
869 f << stringf(")\n");
870
871 if (cell->type == "$adff") {
872 f << stringf("%s" " if (%s", indent.c_str(), pol_arst ? "" : "!");
873 dump_sigspec(f, sig_arst);
874 f << stringf(")\n");
875 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
876 dump_sigspec(f, val_arst);
877 f << stringf(";\n");
878 f << stringf("%s" " else\n", indent.c_str());
879 }
880
881 if (cell->type == "$dffe") {
882 f << stringf("%s" " if (%s", indent.c_str(), pol_en ? "" : "!");
883 dump_sigspec(f, sig_en);
884 f << stringf(")\n");
885 }
886
887 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
888 dump_cell_expr_port(f, cell, "D", false);
889 f << stringf(";\n");
890
891 if (!out_is_reg_wire) {
892 f << stringf("%s" "assign ", indent.c_str());
893 dump_sigspec(f, cell->getPort("\\Q"));
894 f << stringf(" = %s;\n", reg_name.c_str());
895 }
896
897 return true;
898 }
899
900 if (cell->type == "$mem")
901 {
902 RTLIL::IdString memid = cell->parameters["\\MEMID"].decode_string();
903 std::string mem_id = id(cell->parameters["\\MEMID"].decode_string());
904 int abits = cell->parameters["\\ABITS"].as_int();
905 int size = cell->parameters["\\SIZE"].as_int();
906 int width = cell->parameters["\\WIDTH"].as_int();
907 bool use_init = !(RTLIL::SigSpec(cell->parameters["\\INIT"]).is_fully_undef());
908
909 // for memory block make something like:
910 // reg [7:0] memid [3:0];
911 // initial begin
912 // memid[0] = ...
913 // end
914 f << stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent.c_str(), width-1, 0, mem_id.c_str(), size-1, 0);
915 if (use_init)
916 {
917 f << stringf("%s" "initial begin\n", indent.c_str());
918 for (int i=0; i<size; i++)
919 {
920 f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i);
921 dump_const(f, cell->parameters["\\INIT"].extract(i*width, width));
922 f << stringf(";\n");
923 }
924 f << stringf("%s" "end\n", indent.c_str());
925 }
926
927 // create a map : "edge clk" -> expressions within that clock domain
928 dict<std::string, std::vector<std::string>> clk_to_lof_body;
929 clk_to_lof_body[""] = std::vector<std::string>();
930 std::string clk_domain_str;
931 // create a list of reg declarations
932 std::vector<std::string> lof_reg_declarations;
933
934 int nread_ports = cell->parameters["\\RD_PORTS"].as_int();
935 RTLIL::SigSpec sig_rd_clk, sig_rd_en, sig_rd_data, sig_rd_addr;
936 bool use_rd_clk, rd_clk_posedge, rd_transparent;
937 // read ports
938 for (int i=0; i < nread_ports; i++)
939 {
940 sig_rd_clk = cell->getPort("\\RD_CLK").extract(i);
941 sig_rd_en = cell->getPort("\\RD_EN").extract(i);
942 sig_rd_data = cell->getPort("\\RD_DATA").extract(i*width, width);
943 sig_rd_addr = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
944 use_rd_clk = cell->parameters["\\RD_CLK_ENABLE"].extract(i).as_bool();
945 rd_clk_posedge = cell->parameters["\\RD_CLK_POLARITY"].extract(i).as_bool();
946 rd_transparent = cell->parameters["\\RD_TRANSPARENT"].extract(i).as_bool();
947 {
948 std::ostringstream os;
949 dump_sigspec(os, sig_rd_clk);
950 clk_domain_str = stringf("%sedge %s", rd_clk_posedge ? "pos" : "neg", os.str().c_str());
951 if( clk_to_lof_body.count(clk_domain_str) == 0 )
952 clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
953 }
954 if (use_rd_clk && !rd_transparent)
955 {
956 // for clocked read ports make something like:
957 // reg [..] temp_id;
958 // always @(posedge clk)
959 // if (rd_en) temp_id <= array_reg[r_addr];
960 // assign r_data = temp_id;
961 std::string temp_id = next_auto_id();
962 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data.size() - 1, temp_id.c_str()) );
963 {
964 std::ostringstream os;
965 if (sig_rd_en != RTLIL::SigBit(true))
966 {
967 os << stringf("if (");
968 dump_sigspec(os, sig_rd_en);
969 os << stringf(") ");
970 }
971 os << stringf("%s <= %s[", temp_id.c_str(), mem_id.c_str());
972 dump_sigspec(os, sig_rd_addr);
973 os << stringf("];\n");
974 clk_to_lof_body[clk_domain_str].push_back(os.str());
975 }
976 {
977 std::ostringstream os;
978 dump_sigspec(os, sig_rd_data);
979 std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
980 clk_to_lof_body[""].push_back(line);
981 }
982 } else {
983 if (rd_transparent) {
984 // for rd-transparent read-ports make something like:
985 // reg [..] temp_id;
986 // always @(posedge clk)
987 // temp_id <= r_addr;
988 // assign r_data = array_reg[temp_id];
989 std::string temp_id = next_auto_id();
990 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr.size() - 1, temp_id.c_str()) );
991 {
992 std::ostringstream os;
993 dump_sigspec(os, sig_rd_addr);
994 std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str());
995 clk_to_lof_body[clk_domain_str].push_back(line);
996 }
997 {
998 std::ostringstream os;
999 dump_sigspec(os, sig_rd_data);
1000 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), temp_id.c_str());
1001 clk_to_lof_body[""].push_back(line);
1002 }
1003 } else {
1004 // for non-clocked read-ports make something like:
1005 // assign r_data = array_reg[r_addr];
1006 std::ostringstream os, os2;
1007 dump_sigspec(os, sig_rd_data);
1008 dump_sigspec(os2, sig_rd_addr);
1009 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
1010 clk_to_lof_body[""].push_back(line);
1011 }
1012 }
1013 }
1014
1015 int nwrite_ports = cell->parameters["\\WR_PORTS"].as_int();
1016 RTLIL::SigSpec sig_wr_clk, sig_wr_data, sig_wr_addr, sig_wr_en;
1017 bool wr_clk_posedge;
1018
1019 // write ports
1020 for (int i=0; i < nwrite_ports; i++)
1021 {
1022 sig_wr_clk = cell->getPort("\\WR_CLK").extract(i);
1023 sig_wr_data = cell->getPort("\\WR_DATA").extract(i*width, width);
1024 sig_wr_addr = cell->getPort("\\WR_ADDR").extract(i*abits, abits);
1025 sig_wr_en = cell->getPort("\\WR_EN").extract(i*width, width);
1026 wr_clk_posedge = cell->parameters["\\WR_CLK_POLARITY"].extract(i).as_bool();
1027 {
1028 std::ostringstream os;
1029 dump_sigspec(os, sig_wr_clk);
1030 clk_domain_str = stringf("%sedge %s", wr_clk_posedge ? "pos" : "neg", os.str().c_str());
1031 if( clk_to_lof_body.count(clk_domain_str) == 0 )
1032 clk_to_lof_body[clk_domain_str] = std::vector<std::string>();
1033 }
1034 // make something like:
1035 // always @(posedge clk)
1036 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1037 // ...
1038 for (int i = 0; i < GetSize(sig_wr_en); i++)
1039 {
1040 int start_i = i, width = 1;
1041 SigBit wen_bit = sig_wr_en[i];
1042
1043 while (i+1 < GetSize(sig_wr_en) && active_sigmap(sig_wr_en[i+1]) == active_sigmap(wen_bit))
1044 i++, width++;
1045
1046 if (wen_bit == State::S0)
1047 continue;
1048
1049 std::ostringstream os;
1050 if (wen_bit != State::S1)
1051 {
1052 os << stringf("if (");
1053 dump_sigspec(os, wen_bit);
1054 os << stringf(") ");
1055 }
1056 os << stringf("%s[", mem_id.c_str());
1057 dump_sigspec(os, sig_wr_addr);
1058 if (width == GetSize(sig_wr_en))
1059 os << stringf("] <= ");
1060 else
1061 os << stringf("][%d:%d] <= ", i, start_i);
1062 dump_sigspec(os, sig_wr_data.extract(start_i, width));
1063 os << stringf(";\n");
1064 clk_to_lof_body[clk_domain_str].push_back(os.str());
1065 }
1066 }
1067 // Output Verilog that looks something like this:
1068 // reg [..] _3_;
1069 // always @(posedge CLK2) begin
1070 // _3_ <= memory[D1ADDR];
1071 // if (A1EN)
1072 // memory[A1ADDR] <= A1DATA;
1073 // if (A2EN)
1074 // memory[A2ADDR] <= A2DATA;
1075 // ...
1076 // end
1077 // always @(negedge CLK1) begin
1078 // if (C1EN)
1079 // memory[C1ADDR] <= C1DATA;
1080 // end
1081 // ...
1082 // assign D1DATA = _3_;
1083 // assign D2DATA <= memory[D2ADDR];
1084
1085 // the reg ... definitions
1086 for(auto &reg : lof_reg_declarations)
1087 {
1088 f << stringf("%s" "%s", indent.c_str(), reg.c_str());
1089 }
1090 // the block of expressions by clock domain
1091 for(auto &pair : clk_to_lof_body)
1092 {
1093 std::string clk_domain = pair.first;
1094 std::vector<std::string> lof_lines = pair.second;
1095 if( clk_domain != "")
1096 {
1097 f << stringf("%s" "always @(%s) begin\n", indent.c_str(), clk_domain.c_str());
1098 for(auto &line : lof_lines)
1099 f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str());
1100 f << stringf("%s" "end\n", indent.c_str());
1101 }
1102 else
1103 {
1104 // the non-clocked assignments
1105 for(auto &line : lof_lines)
1106 f << stringf("%s" "%s", indent.c_str(), line.c_str());
1107 }
1108 }
1109
1110 return true;
1111 }
1112
1113 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1114 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1115
1116 return false;
1117 }
1118
1119 void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
1120 {
1121 if (cell->type[0] == '$' && !noexpr) {
1122 if (dump_cell_expr(f, indent, cell))
1123 return;
1124 }
1125
1126 dump_attributes(f, indent, cell->attributes);
1127 f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
1128
1129 if (!defparam && cell->parameters.size() > 0) {
1130 f << stringf(" #(");
1131 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1132 if (it != cell->parameters.begin())
1133 f << stringf(",");
1134 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1135 bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
1136 dump_const(f, it->second, -1, 0, false, is_signed);
1137 f << stringf(")");
1138 }
1139 f << stringf("\n%s" ")", indent.c_str());
1140 }
1141
1142 std::string cell_name = cellname(cell);
1143 if (cell_name != id(cell->name))
1144 f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
1145 else
1146 f << stringf(" %s (", cell_name.c_str());
1147
1148 bool first_arg = true;
1149 std::set<RTLIL::IdString> numbered_ports;
1150 for (int i = 1; true; i++) {
1151 char str[16];
1152 snprintf(str, 16, "$%d", i);
1153 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1154 if (it->first != str)
1155 continue;
1156 if (!first_arg)
1157 f << stringf(",");
1158 first_arg = false;
1159 f << stringf("\n%s ", indent.c_str());
1160 dump_sigspec(f, it->second);
1161 numbered_ports.insert(it->first);
1162 goto found_numbered_port;
1163 }
1164 break;
1165 found_numbered_port:;
1166 }
1167 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1168 if (numbered_ports.count(it->first))
1169 continue;
1170 if (!first_arg)
1171 f << stringf(",");
1172 first_arg = false;
1173 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1174 if (it->second.size() > 0)
1175 dump_sigspec(f, it->second);
1176 f << stringf(")");
1177 }
1178 f << stringf("\n%s" ");\n", indent.c_str());
1179
1180 if (defparam && cell->parameters.size() > 0) {
1181 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1182 f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
1183 bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
1184 dump_const(f, it->second, -1, 0, false, is_signed);
1185 f << stringf(";\n");
1186 }
1187 }
1188
1189 }
1190
1191 void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
1192 {
1193 f << stringf("%s" "assign ", indent.c_str());
1194 dump_sigspec(f, left);
1195 f << stringf(" = ");
1196 dump_sigspec(f, right);
1197 f << stringf(";\n");
1198 }
1199
1200 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
1201
1202 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
1203 {
1204 int number_of_stmts = cs->switches.size() + cs->actions.size();
1205
1206 if (!omit_trailing_begin && number_of_stmts >= 2)
1207 f << stringf("%s" "begin\n", indent.c_str());
1208
1209 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1210 if (it->first.size() == 0)
1211 continue;
1212 f << stringf("%s ", indent.c_str());
1213 dump_sigspec(f, it->first);
1214 f << stringf(" = ");
1215 dump_sigspec(f, it->second);
1216 f << stringf(";\n");
1217 }
1218
1219 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1220 dump_proc_switch(f, indent + " ", *it);
1221
1222 if (!omit_trailing_begin && number_of_stmts == 0)
1223 f << stringf("%s /* empty */;\n", indent.c_str());
1224
1225 if (omit_trailing_begin || number_of_stmts >= 2)
1226 f << stringf("%s" "end\n", indent.c_str());
1227 }
1228
1229 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
1230 {
1231 if (sw->signal.size() == 0) {
1232 f << stringf("%s" "begin\n", indent.c_str());
1233 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1234 if ((*it)->compare.size() == 0)
1235 dump_case_body(f, indent + " ", *it);
1236 }
1237 f << stringf("%s" "end\n", indent.c_str());
1238 return;
1239 }
1240
1241 f << stringf("%s" "casez (", indent.c_str());
1242 dump_sigspec(f, sw->signal);
1243 f << stringf(")\n");
1244
1245 bool got_default = false;
1246 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1247 if ((*it)->compare.size() == 0) {
1248 if (got_default)
1249 continue;
1250 f << stringf("%s default", indent.c_str());
1251 got_default = true;
1252 } else {
1253 f << stringf("%s ", indent.c_str());
1254 for (size_t i = 0; i < (*it)->compare.size(); i++) {
1255 if (i > 0)
1256 f << stringf(", ");
1257 dump_sigspec(f, (*it)->compare[i]);
1258 }
1259 }
1260 f << stringf(":\n");
1261 dump_case_body(f, indent + " ", *it);
1262 }
1263
1264 f << stringf("%s" "endcase\n", indent.c_str());
1265 }
1266
1267 void case_body_find_regs(RTLIL::CaseRule *cs)
1268 {
1269 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1270 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
1271 case_body_find_regs(*it2);
1272
1273 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1274 for (auto &c : it->first.chunks())
1275 if (c.wire != NULL)
1276 reg_wires.insert(c.wire->name);
1277 }
1278 }
1279
1280 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
1281 {
1282 if (find_regs) {
1283 case_body_find_regs(&proc->root_case);
1284 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
1285 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
1286 for (auto &c : it2->first.chunks())
1287 if (c.wire != NULL)
1288 reg_wires.insert(c.wire->name);
1289 }
1290 return;
1291 }
1292
1293 f << stringf("%s" "always @* begin\n", indent.c_str());
1294 dump_case_body(f, indent, &proc->root_case, true);
1295
1296 std::string backup_indent = indent;
1297
1298 for (size_t i = 0; i < proc->syncs.size(); i++)
1299 {
1300 RTLIL::SyncRule *sync = proc->syncs[i];
1301 indent = backup_indent;
1302
1303 if (sync->type == RTLIL::STa) {
1304 f << stringf("%s" "always @* begin\n", indent.c_str());
1305 } else {
1306 f << stringf("%s" "always @(", indent.c_str());
1307 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
1308 f << stringf("posedge ");
1309 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
1310 f << stringf("negedge ");
1311 dump_sigspec(f, sync->signal);
1312 f << stringf(") begin\n");
1313 }
1314 std::string ends = indent + "end\n";
1315 indent += " ";
1316
1317 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
1318 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
1319 dump_sigspec(f, sync->signal);
1320 f << stringf(") begin\n");
1321 ends = indent + "end\n" + ends;
1322 indent += " ";
1323 }
1324
1325 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
1326 for (size_t j = 0; j < proc->syncs.size(); j++) {
1327 RTLIL::SyncRule *sync2 = proc->syncs[j];
1328 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
1329 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
1330 dump_sigspec(f, sync2->signal);
1331 f << stringf(") begin\n");
1332 ends = indent + "end\n" + ends;
1333 indent += " ";
1334 }
1335 }
1336 }
1337
1338 for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
1339 if (it->first.size() == 0)
1340 continue;
1341 f << stringf("%s ", indent.c_str());
1342 dump_sigspec(f, it->first);
1343 f << stringf(" <= ");
1344 dump_sigspec(f, it->second);
1345 f << stringf(";\n");
1346 }
1347
1348 f << stringf("%s", ends.c_str());
1349 }
1350 }
1351
1352 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
1353 {
1354 reg_wires.clear();
1355 reset_auto_counter(module);
1356 active_module = module;
1357 active_sigmap.set(module);
1358 active_initdata.clear();
1359
1360 for (auto wire : module->wires())
1361 if (wire->attributes.count("\\init")) {
1362 SigSpec sig = active_sigmap(wire);
1363 Const val = wire->attributes.at("\\init");
1364 for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
1365 active_initdata[sig[i]] = val.bits.at(i);
1366 }
1367
1368 if (!module->processes.empty())
1369 log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
1370 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1371 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1372 "processes to logic networks and registers.", log_id(module));
1373
1374 f << stringf("\n");
1375 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1376 dump_process(f, indent + " ", it->second, true);
1377
1378 if (!noexpr)
1379 {
1380 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
1381 for (auto &it : module->cells_)
1382 {
1383 RTLIL::Cell *cell = it.second;
1384 if (!reg_ct.count(cell->type) || !cell->hasPort("\\Q"))
1385 continue;
1386
1387 RTLIL::SigSpec sig = cell->getPort("\\Q");
1388
1389 if (sig.is_chunk()) {
1390 RTLIL::SigChunk chunk = sig.as_chunk();
1391 if (chunk.wire != NULL)
1392 for (int i = 0; i < chunk.width; i++)
1393 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
1394 }
1395 }
1396 for (auto &it : module->wires_)
1397 {
1398 RTLIL::Wire *wire = it.second;
1399 for (int i = 0; i < wire->width; i++)
1400 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
1401 goto this_wire_aint_reg;
1402 if (wire->width)
1403 reg_wires.insert(wire->name);
1404 this_wire_aint_reg:;
1405 }
1406 }
1407
1408 dump_attributes(f, indent, module->attributes, '\n', true);
1409 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
1410 bool keep_running = true;
1411 for (int port_id = 1; keep_running; port_id++) {
1412 keep_running = false;
1413 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it) {
1414 RTLIL::Wire *wire = it->second;
1415 if (wire->port_id == port_id) {
1416 if (port_id != 1)
1417 f << stringf(", ");
1418 f << stringf("%s", id(wire->name).c_str());
1419 keep_running = true;
1420 continue;
1421 }
1422 }
1423 }
1424 f << stringf(");\n");
1425
1426 for (auto it = module->wires_.begin(); it != module->wires_.end(); ++it)
1427 dump_wire(f, indent + " ", it->second);
1428
1429 for (auto it = module->memories.begin(); it != module->memories.end(); ++it)
1430 dump_memory(f, indent + " ", it->second);
1431
1432 for (auto it = module->cells_.begin(); it != module->cells_.end(); ++it)
1433 dump_cell(f, indent + " ", it->second);
1434
1435 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
1436 dump_process(f, indent + " ", it->second);
1437
1438 for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
1439 dump_conn(f, indent + " ", it->first, it->second);
1440
1441 f << stringf("%s" "endmodule\n", indent.c_str());
1442 active_module = NULL;
1443 active_sigmap.clear();
1444 active_initdata.clear();
1445 }
1446
1447 struct VerilogBackend : public Backend {
1448 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1449 virtual void help()
1450 {
1451 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1452 log("\n");
1453 log(" write_verilog [options] [filename]\n");
1454 log("\n");
1455 log("Write the current design to a Verilog file.\n");
1456 log("\n");
1457 log(" -norename\n");
1458 log(" without this option all internal object names (the ones with a dollar\n");
1459 log(" instead of a backslash prefix) are changed to short names in the\n");
1460 log(" format '_<number>_'.\n");
1461 log("\n");
1462 log(" -renameprefix <prefix>\n");
1463 log(" insert this prefix in front of auto-generated instance names\n");
1464 log("\n");
1465 log(" -noattr\n");
1466 log(" with this option no attributes are included in the output\n");
1467 log("\n");
1468 log(" -attr2comment\n");
1469 log(" with this option attributes are included as comments in the output\n");
1470 log("\n");
1471 log(" -noexpr\n");
1472 log(" without this option all internal cells are converted to Verilog\n");
1473 log(" expressions.\n");
1474 log("\n");
1475 log(" -nodec\n");
1476 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1477 log(" not bit pattern. This option decativates this feature and instead\n");
1478 log(" will write out all constants in binary.\n");
1479 log("\n");
1480 log(" -decimal\n");
1481 log(" dump 32-bit constants in decimal and without size and radix\n");
1482 log("\n");
1483 log(" -nohex\n");
1484 log(" constant values that are compatible with hex output are usually\n");
1485 log(" dumped as hex values. This option decativates this feature and\n");
1486 log(" instead will write out all constants in binary.\n");
1487 log("\n");
1488 log(" -nostr\n");
1489 log(" Parameters and attributes that are specified as strings in the\n");
1490 log(" original input will be output as strings by this back-end. This\n");
1491 log(" decativates this feature and instead will write string constants\n");
1492 log(" as binary numbers.\n");
1493 log("\n");
1494 log(" -defparam\n");
1495 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1496 log(" cell parameters.\n");
1497 log("\n");
1498 log(" -blackboxes\n");
1499 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1500 log(" this option set only the modules with the 'blackbox' attribute\n");
1501 log(" are written to the output file.\n");
1502 log("\n");
1503 log(" -selected\n");
1504 log(" only write selected modules. modules must be selected entirely or\n");
1505 log(" not at all.\n");
1506 log("\n");
1507 log(" -v\n");
1508 log(" verbose output (print new names of all renamed wires and cells)\n");
1509 log("\n");
1510 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1511 log("always blocks. This frontend should only be used to export an RTLIL\n");
1512 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1513 log("processes to logic networks and registers. A warning is generated when\n");
1514 log("this command is called on a design with RTLIL processes.\n");
1515 log("\n");
1516 }
1517 virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
1518 {
1519 log_header(design, "Executing Verilog backend.\n");
1520
1521 verbose = false;
1522 norename = false;
1523 noattr = false;
1524 attr2comment = false;
1525 noexpr = false;
1526 nodec = false;
1527 nohex = false;
1528 nostr = false;
1529 defparam = false;
1530 decimal = false;
1531 auto_prefix = "";
1532
1533 bool blackboxes = false;
1534 bool selected = false;
1535
1536 reg_ct.clear();
1537
1538 reg_ct.insert("$dff");
1539 reg_ct.insert("$adff");
1540
1541 reg_ct.insert("$_DFF_N_");
1542 reg_ct.insert("$_DFF_P_");
1543
1544 reg_ct.insert("$_DFF_NN0_");
1545 reg_ct.insert("$_DFF_NN1_");
1546 reg_ct.insert("$_DFF_NP0_");
1547 reg_ct.insert("$_DFF_NP1_");
1548 reg_ct.insert("$_DFF_PN0_");
1549 reg_ct.insert("$_DFF_PN1_");
1550 reg_ct.insert("$_DFF_PP0_");
1551 reg_ct.insert("$_DFF_PP1_");
1552
1553 reg_ct.insert("$_DFFSR_NNN_");
1554 reg_ct.insert("$_DFFSR_NNP_");
1555 reg_ct.insert("$_DFFSR_NPN_");
1556 reg_ct.insert("$_DFFSR_NPP_");
1557 reg_ct.insert("$_DFFSR_PNN_");
1558 reg_ct.insert("$_DFFSR_PNP_");
1559 reg_ct.insert("$_DFFSR_PPN_");
1560 reg_ct.insert("$_DFFSR_PPP_");
1561
1562 size_t argidx;
1563 for (argidx = 1; argidx < args.size(); argidx++) {
1564 std::string arg = args[argidx];
1565 if (arg == "-norename") {
1566 norename = true;
1567 continue;
1568 }
1569 if (arg == "-renameprefix" && argidx+1 < args.size()) {
1570 auto_prefix = args[++argidx];
1571 continue;
1572 }
1573 if (arg == "-noattr") {
1574 noattr = true;
1575 continue;
1576 }
1577 if (arg == "-attr2comment") {
1578 attr2comment = true;
1579 continue;
1580 }
1581 if (arg == "-noexpr") {
1582 noexpr = true;
1583 continue;
1584 }
1585 if (arg == "-nodec") {
1586 nodec = true;
1587 continue;
1588 }
1589 if (arg == "-nohex") {
1590 nohex = true;
1591 continue;
1592 }
1593 if (arg == "-nostr") {
1594 nostr = true;
1595 continue;
1596 }
1597 if (arg == "-defparam") {
1598 defparam = true;
1599 continue;
1600 }
1601 if (arg == "-decimal") {
1602 decimal = true;
1603 continue;
1604 }
1605 if (arg == "-blackboxes") {
1606 blackboxes = true;
1607 continue;
1608 }
1609 if (arg == "-selected") {
1610 selected = true;
1611 continue;
1612 }
1613 if (arg == "-v") {
1614 verbose = true;
1615 continue;
1616 }
1617 break;
1618 }
1619 extra_args(f, filename, args, argidx);
1620
1621 design->sort();
1622
1623 *f << stringf("/* Generated by %s */\n", yosys_version_str);
1624 for (auto it = design->modules_.begin(); it != design->modules_.end(); ++it) {
1625 if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
1626 continue;
1627 if (selected && !design->selected_whole_module(it->first)) {
1628 if (design->selected_module(it->first))
1629 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it->first));
1630 continue;
1631 }
1632 log("Dumping module `%s'.\n", it->first.c_str());
1633 dump_module(*f, "", it->second);
1634 }
1635
1636 reg_ct.clear();
1637 }
1638 } VerilogBackend;
1639
1640 PRIVATE_NAMESPACE_END