2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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.
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.
20 * A simple and straightforward verilog backend.
22 * Note that RTLIL processes can't always be mapped easily to a Verilog
23 * process. Therefore this frontend should only be used to export a
24 * Verilog netlist (i.e. after the "proc" pass has converted all processes
25 * to logic networks and registers).
29 #include "kernel/register.h"
30 #include "kernel/celltypes.h"
31 #include "kernel/log.h"
32 #include "kernel/sigtools.h"
40 PRIVATE_NAMESPACE_BEGIN
42 bool norename
, noattr
, attr2comment
, noexpr
;
43 int auto_name_counter
, auto_name_offset
, auto_name_digits
;
44 std::map
<RTLIL::IdString
, int> auto_name_map
;
45 std::set
<RTLIL::IdString
> reg_wires
, reg_ct
;
47 RTLIL::Module
*active_module
;
49 void reset_auto_counter_id(RTLIL::IdString id
, bool may_rename
)
51 const char *str
= id
.c_str();
53 if (*str
== '$' && may_rename
&& !norename
)
54 auto_name_map
[id
] = auto_name_counter
++;
56 if (str
[0] != '\\' || str
[1] != '_' || str
[2] == 0)
59 for (int i
= 2; str
[i
] != 0; i
++) {
60 if (str
[i
] == '_' && str
[i
+1] == 0)
62 if (str
[i
] < '0' || str
[i
] > '9')
66 int num
= atoi(str
+2);
67 if (num
>= auto_name_offset
)
68 auto_name_offset
= num
+ 1;
71 void reset_auto_counter(RTLIL::Module
*module
)
73 auto_name_map
.clear();
74 auto_name_counter
= 0;
77 reset_auto_counter_id(module
->name
, false);
79 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
80 reset_auto_counter_id(it
->second
->name
, true);
82 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
) {
83 reset_auto_counter_id(it
->second
->name
, true);
84 reset_auto_counter_id(it
->second
->type
, false);
87 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
88 reset_auto_counter_id(it
->second
->name
, false);
91 for (size_t i
= 10; i
< auto_name_offset
+ auto_name_map
.size(); i
= i
*10)
94 for (auto it
= auto_name_map
.begin(); it
!= auto_name_map
.end(); ++it
)
95 log(" renaming `%s' to `_%0*d_'.\n", it
->first
.c_str(), auto_name_digits
, auto_name_offset
+ it
->second
);
98 std::string
id(RTLIL::IdString internal_id
, bool may_rename
= true)
100 const char *str
= internal_id
.c_str();
101 bool do_escape
= false;
103 if (may_rename
&& auto_name_map
.count(internal_id
) != 0) {
105 snprintf(buffer
, 100, "_%0*d_", auto_name_digits
, auto_name_offset
+ auto_name_map
[internal_id
]);
106 return std::string(buffer
);
112 if ('0' <= *str
&& *str
<= '9')
115 for (int i
= 0; str
[i
]; i
++)
117 if ('0' <= str
[i
] && str
[i
] <= '9')
119 if ('a' <= str
[i
] && str
[i
] <= 'z')
121 if ('A' <= str
[i
] && str
[i
] <= 'Z')
130 return "\\" + std::string(str
) + " ";
131 return std::string(str
);
134 bool is_reg_wire(RTLIL::SigSpec sig
, std::string
®_name
)
136 if (!sig
.is_chunk() || sig
.as_chunk().wire
== NULL
)
139 RTLIL::SigChunk chunk
= sig
.as_chunk();
141 if (reg_wires
.count(chunk
.wire
->name
) == 0)
144 reg_name
= id(chunk
.wire
->name
);
145 if (sig
.size() != chunk
.wire
->width
) {
147 reg_name
+= stringf("[%d]", chunk
.wire
->start_offset
+ chunk
.offset
);
149 reg_name
+= stringf("[%d:%d]", chunk
.wire
->start_offset
+ chunk
.offset
+ chunk
.width
- 1,
150 chunk
.wire
->start_offset
+ chunk
.offset
);
156 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)
159 width
= data
.bits
.size() - offset
;
160 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
161 if (width
== 32 && !no_decimal
) {
163 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
164 log_assert(i
< (int)data
.bits
.size());
165 if (data
.bits
[i
] != RTLIL::S0
&& data
.bits
[i
] != RTLIL::S1
)
167 if (data
.bits
[i
] == RTLIL::S1
&& (i
- offset
) == 31)
169 if (data
.bits
[i
] == RTLIL::S1
)
170 val
|= 1 << (i
- offset
);
172 f
<< stringf("32'%sd %d", set_signed
? "s" : "", val
);
175 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
178 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
179 log_assert(i
< (int)data
.bits
.size());
180 switch (data
.bits
[i
]) {
181 case RTLIL::S0
: f
<< stringf("0"); break;
182 case RTLIL::S1
: f
<< stringf("1"); break;
183 case RTLIL::Sx
: f
<< stringf("x"); break;
184 case RTLIL::Sz
: f
<< stringf("z"); break;
185 case RTLIL::Sa
: f
<< stringf("z"); break;
186 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
192 std::string str
= data
.decode_string();
193 for (size_t i
= 0; i
< str
.size(); i
++) {
196 else if (str
[i
] == '\t')
198 else if (str
[i
] < 32)
199 f
<< stringf("\\%03o", str
[i
]);
200 else if (str
[i
] == '"')
201 f
<< stringf("\\\"");
202 else if (str
[i
] == '\\')
203 f
<< stringf("\\\\");
204 else if (str
[i
] == '/' && escape_comment
&& i
> 0 && str
[i
-1] == '*')
213 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
215 if (chunk
.wire
== NULL
) {
216 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
218 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0) {
219 f
<< stringf("%s", id(chunk
.wire
->name
).c_str());
220 } else if (chunk
.width
== 1) {
221 if (chunk
.wire
->upto
)
222 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
224 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
226 if (chunk
.wire
->upto
)
227 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
228 (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
229 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
231 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
232 (chunk
.offset
+ chunk
.width
- 1) + chunk
.wire
->start_offset
,
233 chunk
.offset
+ chunk
.wire
->start_offset
);
238 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
240 if (sig
.is_chunk()) {
241 dump_sigchunk(f
, sig
.as_chunk());
244 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
245 if (it
!= sig
.chunks().rbegin())
247 dump_sigchunk(f
, *it
, true);
253 void dump_attributes(std::ostream
&f
, std::string indent
, dict
<RTLIL::IdString
, RTLIL::Const
> &attributes
, char term
= '\n', bool modattr
= false)
257 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
258 f
<< stringf("%s" "%s %s", indent
.c_str(), attr2comment
? "/*" : "(*", id(it
->first
).c_str());
260 if (modattr
&& (it
->second
== Const(0, 1) || it
->second
== Const(0)))
262 else if (modattr
&& (it
->second
== Const(1, 1) || it
->second
== Const(1)))
265 dump_const(f
, it
->second
, -1, 0, false, false, attr2comment
);
266 f
<< stringf(" %s%c", attr2comment
? "*/" : "*)", term
);
270 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
272 dump_attributes(f
, indent
, wire
->attributes
);
274 if (wire
->port_input
&& !wire
->port_output
)
275 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
276 else if (!wire
->port_input
&& wire
->port_output
)
277 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
278 else if (wire
->port_input
&& wire
->port_output
)
279 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
281 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
282 if (wire
->width
!= 1)
283 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
284 f
<< stringf("%s;\n", id(wire
->name
).c_str());
286 // do not use Verilog-2k "outut reg" syntax in verilog export
287 std::string range
= "";
288 if (wire
->width
!= 1) {
290 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
292 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
294 if (wire
->port_input
&& !wire
->port_output
)
295 f
<< stringf("%s" "input%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
296 if (!wire
->port_input
&& wire
->port_output
)
297 f
<< stringf("%s" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
298 if (wire
->port_input
&& wire
->port_output
)
299 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
300 if (reg_wires
.count(wire
->name
)) {
301 f
<< stringf("%s" "reg%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
302 if (wire
->attributes
.count("\\init")) {
303 f
<< stringf("%s" "initial %s = ", indent
.c_str(), id(wire
->name
).c_str());
304 dump_const(f
, wire
->attributes
.at("\\init"));
307 } else if (!wire
->port_input
&& !wire
->port_output
)
308 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
312 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
314 dump_attributes(f
, indent
, memory
->attributes
);
315 f
<< stringf("%s" "reg [%d:0] %s [%d:0];\n", indent
.c_str(), memory
->width
-1, id(memory
->name
).c_str(), memory
->size
-1);
318 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
320 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
321 f
<< stringf("$signed(");
322 dump_sigspec(f
, cell
->getPort("\\" + port
));
325 dump_sigspec(f
, cell
->getPort("\\" + port
));
328 std::string
cellname(RTLIL::Cell
*cell
)
330 if (!norename
&& cell
->name
[0] == '$' && reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q"))
332 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
333 if (GetSize(sig
) != 1 || sig
.is_fully_const())
334 goto no_special_reg_name
;
336 RTLIL::Wire
*wire
= sig
[0].wire
;
338 if (wire
->name
[0] != '\\')
339 goto no_special_reg_name
;
341 std::string cell_name
= wire
->name
.str();
343 size_t pos
= cell_name
.find('[');
344 if (pos
!= std::string::npos
)
345 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
347 cell_name
= cell_name
+ "_reg";
349 if (wire
->width
!= 1)
350 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
352 if (active_module
&& active_module
->count_id(cell_name
) > 0)
353 goto no_special_reg_name
;
355 return id(cell_name
);
360 return id(cell
->name
).c_str();
364 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
366 f
<< stringf("%s" "assign ", indent
.c_str());
367 dump_sigspec(f
, cell
->getPort("\\Y"));
368 f
<< stringf(" = %s ", op
.c_str());
369 dump_attributes(f
, "", cell
->attributes
, ' ');
370 dump_cell_expr_port(f
, cell
, "A", true);
374 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
376 f
<< stringf("%s" "assign ", indent
.c_str());
377 dump_sigspec(f
, cell
->getPort("\\Y"));
379 dump_cell_expr_port(f
, cell
, "A", true);
380 f
<< stringf(" %s ", op
.c_str());
381 dump_attributes(f
, "", cell
->attributes
, ' ');
382 dump_cell_expr_port(f
, cell
, "B", true);
386 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
388 if (cell
->type
== "$_NOT_") {
389 f
<< stringf("%s" "assign ", indent
.c_str());
390 dump_sigspec(f
, cell
->getPort("\\Y"));
393 dump_attributes(f
, "", cell
->attributes
, ' ');
394 dump_cell_expr_port(f
, cell
, "A", false);
399 if (cell
->type
.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) {
400 f
<< stringf("%s" "assign ", indent
.c_str());
401 dump_sigspec(f
, cell
->getPort("\\Y"));
403 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
405 dump_cell_expr_port(f
, cell
, "A", false);
407 if (cell
->type
.in("$_AND_", "$_NAND_"))
409 if (cell
->type
.in("$_OR_", "$_NOR_"))
411 if (cell
->type
.in("$_XOR_", "$_XNOR_"))
413 dump_attributes(f
, "", cell
->attributes
, ' ');
415 dump_cell_expr_port(f
, cell
, "B", false);
416 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
422 if (cell
->type
== "$_MUX_") {
423 f
<< stringf("%s" "assign ", indent
.c_str());
424 dump_sigspec(f
, cell
->getPort("\\Y"));
426 dump_cell_expr_port(f
, cell
, "S", false);
428 dump_attributes(f
, "", cell
->attributes
, ' ');
429 dump_cell_expr_port(f
, cell
, "B", false);
431 dump_cell_expr_port(f
, cell
, "A", false);
436 if (cell
->type
.in("$_AOI3_", "$_OAI3_")) {
437 f
<< stringf("%s" "assign ", indent
.c_str());
438 dump_sigspec(f
, cell
->getPort("\\Y"));
439 f
<< stringf(" = ~((");
440 dump_cell_expr_port(f
, cell
, "A", false);
441 f
<< stringf(cell
->type
== "$_AOI3_" ? " & " : " | ");
442 dump_cell_expr_port(f
, cell
, "B", false);
443 f
<< stringf(cell
->type
== "$_AOI3_" ? ") |" : ") &");
444 dump_attributes(f
, "", cell
->attributes
, ' ');
446 dump_cell_expr_port(f
, cell
, "C", false);
447 f
<< stringf(");\n");
451 if (cell
->type
.in("$_AOI4_", "$_OAI4_")) {
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", false);
456 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
457 dump_cell_expr_port(f
, cell
, "B", false);
458 f
<< stringf(cell
->type
== "$_AOI4_" ? ") |" : ") &");
459 dump_attributes(f
, "", cell
->attributes
, ' ');
461 dump_cell_expr_port(f
, cell
, "C", false);
462 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
463 dump_cell_expr_port(f
, cell
, "D", false);
464 f
<< stringf("));\n");
468 if (cell
->type
.substr(0, 6) == "$_DFF_")
470 std::string reg_name
= cellname(cell
);
471 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
473 if (!out_is_reg_wire
)
474 f
<< stringf("%s" "reg %s;\n", indent
.c_str(), reg_name
.c_str());
476 dump_attributes(f
, indent
, cell
->attributes
);
477 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), cell
->type
[6] == 'P' ? "pos" : "neg");
478 dump_sigspec(f
, cell
->getPort("\\C"));
479 if (cell
->type
[7] != '_') {
480 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
481 dump_sigspec(f
, cell
->getPort("\\R"));
485 if (cell
->type
[7] != '_') {
486 f
<< stringf("%s" " if (%s", indent
.c_str(), cell
->type
[7] == 'P' ? "" : "!");
487 dump_sigspec(f
, cell
->getPort("\\R"));
489 f
<< stringf("%s" " %s <= %c;\n", indent
.c_str(), reg_name
.c_str(), cell
->type
[8]);
490 f
<< stringf("%s" " else\n", indent
.c_str());
493 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
494 dump_cell_expr_port(f
, cell
, "D", false);
497 if (!out_is_reg_wire
) {
498 f
<< stringf("%s" "assign ", indent
.c_str());
499 dump_sigspec(f
, cell
->getPort("\\Q"));
500 f
<< stringf(" = %s;\n", reg_name
.c_str());
506 if (cell
->type
.substr(0, 8) == "$_DFFSR_")
508 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
510 std::string reg_name
= cellname(cell
);
511 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
513 if (!out_is_reg_wire
)
514 f
<< stringf("%s" "reg %s;\n", indent
.c_str(), reg_name
.c_str());
516 dump_attributes(f
, indent
, cell
->attributes
);
517 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_c
== 'P' ? "pos" : "neg");
518 dump_sigspec(f
, cell
->getPort("\\C"));
519 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
520 dump_sigspec(f
, cell
->getPort("\\S"));
521 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
522 dump_sigspec(f
, cell
->getPort("\\R"));
525 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
526 dump_sigspec(f
, cell
->getPort("\\R"));
528 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
530 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
531 dump_sigspec(f
, cell
->getPort("\\S"));
533 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
535 f
<< stringf("%s" " else\n", indent
.c_str());
536 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
537 dump_cell_expr_port(f
, cell
, "D", false);
540 if (!out_is_reg_wire
) {
541 f
<< stringf("%s" "assign ", indent
.c_str());
542 dump_sigspec(f
, cell
->getPort("\\Q"));
543 f
<< stringf(" = %s;\n", reg_name
.c_str());
549 #define HANDLE_UNIOP(_type, _operator) \
550 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
551 #define HANDLE_BINOP(_type, _operator) \
552 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
554 HANDLE_UNIOP("$not", "~")
555 HANDLE_UNIOP("$pos", "+")
556 HANDLE_UNIOP("$neg", "-")
558 HANDLE_BINOP("$and", "&")
559 HANDLE_BINOP("$or", "|")
560 HANDLE_BINOP("$xor", "^")
561 HANDLE_BINOP("$xnor", "~^")
563 HANDLE_UNIOP("$reduce_and", "&")
564 HANDLE_UNIOP("$reduce_or", "|")
565 HANDLE_UNIOP("$reduce_xor", "^")
566 HANDLE_UNIOP("$reduce_xnor", "~^")
567 HANDLE_UNIOP("$reduce_bool", "|")
569 HANDLE_BINOP("$shl", "<<")
570 HANDLE_BINOP("$shr", ">>")
571 HANDLE_BINOP("$sshl", "<<<")
572 HANDLE_BINOP("$sshr", ">>>")
574 HANDLE_BINOP("$lt", "<")
575 HANDLE_BINOP("$le", "<=")
576 HANDLE_BINOP("$eq", "==")
577 HANDLE_BINOP("$ne", "!=")
578 HANDLE_BINOP("$eqx", "===")
579 HANDLE_BINOP("$nex", "!==")
580 HANDLE_BINOP("$ge", ">=")
581 HANDLE_BINOP("$gt", ">")
583 HANDLE_BINOP("$add", "+")
584 HANDLE_BINOP("$sub", "-")
585 HANDLE_BINOP("$mul", "*")
586 HANDLE_BINOP("$div", "/")
587 HANDLE_BINOP("$mod", "%")
588 HANDLE_BINOP("$pow", "**")
590 HANDLE_UNIOP("$logic_not", "!")
591 HANDLE_BINOP("$logic_and", "&&")
592 HANDLE_BINOP("$logic_or", "||")
597 if (cell
->type
== "$mux")
599 f
<< stringf("%s" "assign ", indent
.c_str());
600 dump_sigspec(f
, cell
->getPort("\\Y"));
602 dump_sigspec(f
, cell
->getPort("\\S"));
604 dump_attributes(f
, "", cell
->attributes
, ' ');
605 dump_sigspec(f
, cell
->getPort("\\B"));
607 dump_sigspec(f
, cell
->getPort("\\A"));
612 if (cell
->type
== "$pmux" || cell
->type
== "$pmux_safe")
614 int width
= cell
->parameters
["\\WIDTH"].as_int();
615 int s_width
= cell
->getPort("\\S").size();
616 std::string func_name
= cellname(cell
);
618 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
619 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
620 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
621 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
623 dump_attributes(f
, indent
+ " ", cell
->attributes
);
624 if (cell
->type
!= "$pmux_safe" && !noattr
)
625 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
626 f
<< stringf("%s" " casez (s)", indent
.c_str());
627 if (cell
->type
!= "$pmux_safe")
628 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
630 for (int i
= 0; i
< s_width
; i
++)
632 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
634 for (int j
= s_width
-1; j
>= 0; j
--)
635 f
<< stringf("%c", j
== i
? '1' : cell
->type
== "$pmux_safe" ? '0' : '?');
638 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
641 f
<< stringf("%s" " default:\n", indent
.c_str());
642 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
644 f
<< stringf("%s" " endcase\n", indent
.c_str());
645 f
<< stringf("%s" "endfunction\n", indent
.c_str());
647 f
<< stringf("%s" "assign ", indent
.c_str());
648 dump_sigspec(f
, cell
->getPort("\\Y"));
649 f
<< stringf(" = %s(", func_name
.c_str());
650 dump_sigspec(f
, cell
->getPort("\\A"));
652 dump_sigspec(f
, cell
->getPort("\\B"));
654 dump_sigspec(f
, cell
->getPort("\\S"));
655 f
<< stringf(");\n");
659 if (cell
->type
== "$slice")
661 f
<< stringf("%s" "assign ", indent
.c_str());
662 dump_sigspec(f
, cell
->getPort("\\Y"));
664 dump_sigspec(f
, cell
->getPort("\\A"));
665 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
669 if (cell
->type
== "$concat")
671 f
<< stringf("%s" "assign ", indent
.c_str());
672 dump_sigspec(f
, cell
->getPort("\\Y"));
673 f
<< stringf(" = { ");
674 dump_sigspec(f
, cell
->getPort("\\B"));
676 dump_sigspec(f
, cell
->getPort("\\A"));
677 f
<< stringf(" };\n");
681 if (cell
->type
== "$dffsr")
683 SigSpec sig_clk
= cell
->getPort("\\CLK");
684 SigSpec sig_set
= cell
->getPort("\\SET");
685 SigSpec sig_clr
= cell
->getPort("\\CLR");
686 SigSpec sig_d
= cell
->getPort("\\D");
687 SigSpec sig_q
= cell
->getPort("\\Q");
689 int width
= cell
->parameters
["\\WIDTH"].as_int();
690 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
691 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
692 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
694 std::string reg_name
= cellname(cell
);
695 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
697 if (!out_is_reg_wire
)
698 f
<< stringf("%s" "reg [%d:0] %s;\n", indent
.c_str(), width
-1, reg_name
.c_str());
700 for (int i
= 0; i
< width
; i
++) {
701 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
702 dump_sigspec(f
, sig_clk
);
703 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
704 dump_sigspec(f
, sig_set
);
705 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
706 dump_sigspec(f
, sig_clr
);
709 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
710 dump_sigspec(f
, sig_clr
);
711 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
713 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
714 dump_sigspec(f
, sig_set
);
715 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
717 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
718 dump_sigspec(f
, sig_d
[i
]);
722 if (!out_is_reg_wire
) {
723 f
<< stringf("%s" "assign ", indent
.c_str());
724 dump_sigspec(f
, sig_q
);
725 f
<< stringf(" = %s;\n", reg_name
.c_str());
731 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
733 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
734 bool pol_clk
, pol_arst
= false, pol_en
= false;
736 sig_clk
= cell
->getPort("\\CLK");
737 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
739 if (cell
->type
== "$adff") {
740 sig_arst
= cell
->getPort("\\ARST");
741 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
742 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
745 if (cell
->type
== "$dffe") {
746 sig_en
= cell
->getPort("\\EN");
747 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
750 std::string reg_name
= cellname(cell
);
751 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
753 if (!out_is_reg_wire
)
754 f
<< stringf("%s" "reg [%d:0] %s;\n", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
756 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
757 dump_sigspec(f
, sig_clk
);
758 if (cell
->type
== "$adff") {
759 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
760 dump_sigspec(f
, sig_arst
);
764 if (cell
->type
== "$adff") {
765 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
766 dump_sigspec(f
, sig_arst
);
768 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
769 dump_sigspec(f
, val_arst
);
771 f
<< stringf("%s" " else\n", indent
.c_str());
774 if (cell
->type
== "$dffe") {
775 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
776 dump_sigspec(f
, sig_en
);
780 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
781 dump_cell_expr_port(f
, cell
, "D", false);
784 if (!out_is_reg_wire
) {
785 f
<< stringf("%s" "assign ", indent
.c_str());
786 dump_sigspec(f
, cell
->getPort("\\Q"));
787 f
<< stringf(" = %s;\n", reg_name
.c_str());
793 if (cell
->type
== "$mem")
795 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
796 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
797 int abits
= cell
->parameters
["\\ABITS"].as_int();
798 int size
= cell
->parameters
["\\SIZE"].as_int();
799 int width
= cell
->parameters
["\\WIDTH"].as_int();
800 int offset
= cell
->parameters
["\\OFFSET"].as_int();
801 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
803 // for memory block make something like:
804 // reg [7:0] memid [3:0];
809 RTLIL::Memory memory
;
811 memory
.width
= width
;
812 memory
.start_offset
= offset
;
814 dump_memory(f
, indent
.c_str(), &memory
);
817 f
<< stringf("%s" "initial begin\n", indent
.c_str());
818 for (int i
=0; i
<size
; i
++)
820 mem_val
= cell
->parameters
["\\INIT"].extract(i
*width
, width
).as_int();
821 f
<< stringf("%s" " %s[%d] <= %d'd%d;\n", indent
.c_str(), mem_id
.c_str(), i
, width
, mem_val
);
823 f
<< stringf("%s" "end\n", indent
.c_str());
826 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
827 RTLIL::SigSpec sig_rd_clk
, sig_rd_data
, sig_rd_addr
;
828 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
829 RTLIL::IdString new_id
;
831 for (int i
=0; i
< nread_ports
; i
++)
833 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
834 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
835 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
836 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
837 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
838 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
839 if (use_rd_clk
&& !rd_transparent
)
841 // for clocked read ports make something like:
842 // always @(posedge clk)
843 // r_data <= array_reg[r_addr];
844 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), rd_clk_posedge
? "pos" : "neg");
845 dump_sigspec(f
, sig_rd_clk
);
847 f
<< stringf("%s" " ", indent
.c_str());
848 dump_sigspec(f
, sig_rd_data
);
849 f
<< stringf(" <= %s[", mem_id
.c_str());
850 dump_sigspec(f
, sig_rd_addr
);
851 f
<< stringf("];\n");
853 if (rd_transparent
) {
854 // for rd-transparent read-ports make something like:
856 // always @(posedge clk)
858 // assign r_data = array_reg[new-id];
859 new_id
= RTLIL::IdString(stringf("$%d", (int)time(NULL
)));
860 reset_auto_counter_id(new_id
, true);
861 f
<< stringf("%s" "reg [%d:0] %s;\n", indent
.c_str(), sig_rd_addr
.size() - 1, id(new_id
).c_str());
862 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), rd_clk_posedge
? "pos" : "neg");
863 dump_sigspec(f
, sig_rd_clk
);
865 f
<< stringf("%s" " %s <= ", indent
.c_str(), id(new_id
).c_str());
866 dump_sigspec(f
, sig_rd_addr
);
868 f
<< stringf("%s" "assign ", indent
.c_str());
869 dump_sigspec(f
, sig_rd_data
);
870 f
<< stringf(" = %s[%s];\n", mem_id
.c_str(), id(new_id
).c_str());
872 // for non-clocked read-ports make something like:
873 // assign r_data = array_reg[r_addr];
874 f
<< stringf("%s" "assign ", indent
.c_str());
875 dump_sigspec(f
, sig_rd_data
);
876 f
<< stringf(" = %s[", mem_id
.c_str());
877 dump_sigspec(f
, sig_rd_addr
);
878 f
<< stringf("];\n");
883 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
884 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
, sig_wr_en_bit
;
885 RTLIL::SigBit last_bit
, current_bit
;
887 RTLIL::SigSpec lof_wen
;
888 dict
<RTLIL::SigSpec
, int> wen_to_width
;
889 SigMap
sigmap(active_module
);
892 for (int i
=0; i
< nwrite_ports
; i
++)
894 // for write-ports make something like:
895 // always @(posedge clk)
897 // memid[w_addr] <= w_data;
898 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
899 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
900 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
901 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
902 sig_wr_en_bit
= sig_wr_en
.extract(0);
903 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
904 // group the wen bits
905 last_bit
= sig_wr_en
.extract(0);
906 lof_wen
= RTLIL::SigSpec(last_bit
);
907 wen_to_width
.clear();
908 wen_to_width
[last_bit
] = 0;
909 for (int j
=0; j
<width
; j
++)
911 current_bit
= sig_wr_en
.extract(j
);
912 if (sigmap(current_bit
) == sigmap(last_bit
)){
913 wen_to_width
[current_bit
] += 1;
915 lof_wen
.append_bit(current_bit
);
916 wen_to_width
[current_bit
] = 1;
918 last_bit
= current_bit
;
920 // make something like:
921 // always @(posedge clk)
923 // memid[w_addr][??] <= w_data[??];
926 for (auto &wen_bit
: lof_wen
) {
927 wen_width
= wen_to_width
[wen_bit
];
928 if (!(wen_bit
== RTLIL::SigBit(false)))
930 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), wr_clk_posedge
? "pos" : "neg");
931 dump_sigspec(f
, sig_wr_clk
);
933 if (!(wen_bit
== RTLIL::SigBit(true)))
935 f
<< stringf("%s" " if (", indent
.c_str());
936 dump_sigspec(f
, wen_bit
);
937 f
<< stringf(")\n ");
939 f
<< stringf("%s" " %s[", indent
.c_str(), mem_id
.c_str());
940 dump_sigspec(f
, sig_wr_addr
);
941 if (wen_width
== width
)
942 f
<< stringf("] <= ");
944 f
<< stringf("][%d:%d] <= ", n
+wen_width
-1, n
);
945 dump_sigspec(f
, sig_wr_data
.extract(n
, wen_width
));
955 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
956 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
961 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
963 if (cell
->type
[0] == '$' && !noexpr
) {
964 if (dump_cell_expr(f
, indent
, cell
))
968 dump_attributes(f
, indent
, cell
->attributes
);
969 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
971 if (cell
->parameters
.size() > 0) {
973 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
974 if (it
!= cell
->parameters
.begin())
976 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
977 bool is_signed
= (it
->second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
978 dump_const(f
, it
->second
, -1, 0, false, is_signed
);
981 f
<< stringf("\n%s" ")", indent
.c_str());
984 std::string cell_name
= cellname(cell
);
985 if (cell_name
!= id(cell
->name
))
986 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
988 f
<< stringf(" %s (", cell_name
.c_str());
990 bool first_arg
= true;
991 std::set
<RTLIL::IdString
> numbered_ports
;
992 for (int i
= 1; true; i
++) {
994 snprintf(str
, 16, "$%d", i
);
995 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
996 if (it
->first
!= str
)
1001 f
<< stringf("\n%s ", indent
.c_str());
1002 dump_sigspec(f
, it
->second
);
1003 numbered_ports
.insert(it
->first
);
1004 goto found_numbered_port
;
1007 found_numbered_port
:;
1009 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1010 if (numbered_ports
.count(it
->first
))
1015 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1016 if (it
->second
.size() > 0)
1017 dump_sigspec(f
, it
->second
);
1020 f
<< stringf("\n%s" ");\n", indent
.c_str());
1023 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1025 f
<< stringf("%s" "assign ", indent
.c_str());
1026 dump_sigspec(f
, left
);
1027 f
<< stringf(" = ");
1028 dump_sigspec(f
, right
);
1029 f
<< stringf(";\n");
1032 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1034 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1036 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1038 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1039 f
<< stringf("%s" "begin\n", indent
.c_str());
1041 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1042 if (it
->first
.size() == 0)
1044 f
<< stringf("%s ", indent
.c_str());
1045 dump_sigspec(f
, it
->first
);
1046 f
<< stringf(" = ");
1047 dump_sigspec(f
, it
->second
);
1048 f
<< stringf(";\n");
1051 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1052 dump_proc_switch(f
, indent
+ " ", *it
);
1054 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1055 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1057 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1058 f
<< stringf("%s" "end\n", indent
.c_str());
1061 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1063 if (sw
->signal
.size() == 0) {
1064 f
<< stringf("%s" "begin\n", indent
.c_str());
1065 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1066 if ((*it
)->compare
.size() == 0)
1067 dump_case_body(f
, indent
+ " ", *it
);
1069 f
<< stringf("%s" "end\n", indent
.c_str());
1073 f
<< stringf("%s" "casez (", indent
.c_str());
1074 dump_sigspec(f
, sw
->signal
);
1075 f
<< stringf(")\n");
1077 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1078 f
<< stringf("%s ", indent
.c_str());
1079 if ((*it
)->compare
.size() == 0)
1080 f
<< stringf("default");
1082 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1085 dump_sigspec(f
, (*it
)->compare
[i
]);
1088 f
<< stringf(":\n");
1089 dump_case_body(f
, indent
+ " ", *it
);
1092 f
<< stringf("%s" "endcase\n", indent
.c_str());
1095 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1097 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1098 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1099 case_body_find_regs(*it2
);
1101 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1102 for (auto &c
: it
->first
.chunks())
1104 reg_wires
.insert(c
.wire
->name
);
1108 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1111 case_body_find_regs(&proc
->root_case
);
1112 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1113 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1114 for (auto &c
: it2
->first
.chunks())
1116 reg_wires
.insert(c
.wire
->name
);
1121 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1122 dump_case_body(f
, indent
, &proc
->root_case
, true);
1124 std::string backup_indent
= indent
;
1126 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1128 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1129 indent
= backup_indent
;
1131 if (sync
->type
== RTLIL::STa
) {
1132 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1134 f
<< stringf("%s" "always @(", indent
.c_str());
1135 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1136 f
<< stringf("posedge ");
1137 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1138 f
<< stringf("negedge ");
1139 dump_sigspec(f
, sync
->signal
);
1140 f
<< stringf(") begin\n");
1142 std::string ends
= indent
+ "end\n";
1145 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1146 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1147 dump_sigspec(f
, sync
->signal
);
1148 f
<< stringf(") begin\n");
1149 ends
= indent
+ "end\n" + ends
;
1153 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1154 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1155 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1156 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1157 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1158 dump_sigspec(f
, sync2
->signal
);
1159 f
<< stringf(") begin\n");
1160 ends
= indent
+ "end\n" + ends
;
1166 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1167 if (it
->first
.size() == 0)
1169 f
<< stringf("%s ", indent
.c_str());
1170 dump_sigspec(f
, it
->first
);
1171 f
<< stringf(" <= ");
1172 dump_sigspec(f
, it
->second
);
1173 f
<< stringf(";\n");
1176 f
<< stringf("%s", ends
.c_str());
1180 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1183 reset_auto_counter(module
);
1184 active_module
= module
;
1187 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1188 dump_process(f
, indent
+ " ", it
->second
, true);
1192 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1193 for (auto &it
: module
->cells_
)
1195 RTLIL::Cell
*cell
= it
.second
;
1196 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1199 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1201 if (sig
.is_chunk()) {
1202 RTLIL::SigChunk chunk
= sig
.as_chunk();
1203 if (chunk
.wire
!= NULL
)
1204 for (int i
= 0; i
< chunk
.width
; i
++)
1205 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1208 for (auto &it
: module
->wires_
)
1210 RTLIL::Wire
*wire
= it
.second
;
1211 for (int i
= 0; i
< wire
->width
; i
++)
1212 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1213 goto this_wire_aint_reg
;
1215 reg_wires
.insert(wire
->name
);
1216 this_wire_aint_reg
:;
1220 dump_attributes(f
, indent
, module
->attributes
, '\n', true);
1221 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1222 bool keep_running
= true;
1223 for (int port_id
= 1; keep_running
; port_id
++) {
1224 keep_running
= false;
1225 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1226 RTLIL::Wire
*wire
= it
->second
;
1227 if (wire
->port_id
== port_id
) {
1230 f
<< stringf("%s", id(wire
->name
).c_str());
1231 keep_running
= true;
1236 f
<< stringf(");\n");
1238 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1239 dump_wire(f
, indent
+ " ", it
->second
);
1241 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1242 dump_memory(f
, indent
+ " ", it
->second
);
1244 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1245 dump_cell(f
, indent
+ " ", it
->second
);
1247 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1248 dump_process(f
, indent
+ " ", it
->second
);
1250 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1251 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1253 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1254 active_module
= NULL
;
1257 struct VerilogBackend
: public Backend
{
1258 VerilogBackend() : Backend("verilog", "write design to verilog file") { }
1261 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1263 log(" write_verilog [options] [filename]\n");
1265 log("Write the current design to a verilog file.\n");
1267 log(" -norename\n");
1268 log(" without this option all internal object names (the ones with a dollar\n");
1269 log(" instead of a backslash prefix) are changed to short names in the\n");
1270 log(" format '_<number>_'.\n");
1273 log(" with this option no attributes are included in the output\n");
1275 log(" -attr2comment\n");
1276 log(" with this option attributes are included as comments in the output\n");
1279 log(" without this option all internal cells are converted to verilog\n");
1280 log(" expressions.\n");
1282 log(" -blackboxes\n");
1283 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1284 log(" this option set only the modules with the 'blackbox' attribute\n");
1285 log(" are written to the output file.\n");
1287 log(" -selected\n");
1288 log(" only write selected modules. modules must be selected entirely or\n");
1289 log(" not at all.\n");
1292 virtual void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
)
1294 log_header("Executing Verilog backend.\n");
1298 attr2comment
= false;
1301 bool blackboxes
= false;
1302 bool selected
= false;
1306 reg_ct
.insert("$dff");
1307 reg_ct
.insert("$adff");
1309 reg_ct
.insert("$_DFF_N_");
1310 reg_ct
.insert("$_DFF_P_");
1312 reg_ct
.insert("$_DFF_NN0_");
1313 reg_ct
.insert("$_DFF_NN1_");
1314 reg_ct
.insert("$_DFF_NP0_");
1315 reg_ct
.insert("$_DFF_NP1_");
1316 reg_ct
.insert("$_DFF_PN0_");
1317 reg_ct
.insert("$_DFF_PN1_");
1318 reg_ct
.insert("$_DFF_PP0_");
1319 reg_ct
.insert("$_DFF_PP1_");
1321 reg_ct
.insert("$_DFFSR_NNN_");
1322 reg_ct
.insert("$_DFFSR_NNP_");
1323 reg_ct
.insert("$_DFFSR_NPN_");
1324 reg_ct
.insert("$_DFFSR_NPP_");
1325 reg_ct
.insert("$_DFFSR_PNN_");
1326 reg_ct
.insert("$_DFFSR_PNP_");
1327 reg_ct
.insert("$_DFFSR_PPN_");
1328 reg_ct
.insert("$_DFFSR_PPP_");
1331 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1332 std::string arg
= args
[argidx
];
1333 if (arg
== "-norename") {
1337 if (arg
== "-noattr") {
1341 if (arg
== "-attr2comment") {
1342 attr2comment
= true;
1345 if (arg
== "-noexpr") {
1349 if (arg
== "-blackboxes") {
1353 if (arg
== "-selected") {
1359 extra_args(f
, filename
, args
, argidx
);
1363 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1364 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1365 if (it
->second
->get_bool_attribute("\\blackbox") != blackboxes
)
1367 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1368 if (design
->selected_module(it
->first
))
1369 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1372 log("Dumping module `%s'.\n", it
->first
.c_str());
1373 dump_module(*f
, "", it
->second
);
1380 PRIVATE_NAMESPACE_END