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"
38 PRIVATE_NAMESPACE_BEGIN
40 bool norename
, noattr
, attr2comment
, noexpr
;
41 int auto_name_counter
, auto_name_offset
, auto_name_digits
;
42 std::map
<RTLIL::IdString
, int> auto_name_map
;
43 std::set
<RTLIL::IdString
> reg_wires
, reg_ct
;
45 RTLIL::Module
*active_module
;
47 void reset_auto_counter_id(RTLIL::IdString id
, bool may_rename
)
49 const char *str
= id
.c_str();
51 if (*str
== '$' && may_rename
&& !norename
)
52 auto_name_map
[id
] = auto_name_counter
++;
54 if (str
[0] != '_' && str
[1] != 0)
56 for (int i
= 0; str
[i
] != 0; i
++) {
59 if (str
[i
] < '0' || str
[i
] > '9')
63 int num
= atoi(str
+1);
64 if (num
>= auto_name_offset
)
65 auto_name_offset
= num
+ 1;
68 void reset_auto_counter(RTLIL::Module
*module
)
70 auto_name_map
.clear();
71 auto_name_counter
= 0;
74 reset_auto_counter_id(module
->name
, false);
76 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); it
++)
77 reset_auto_counter_id(it
->second
->name
, true);
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);
84 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); it
++)
85 reset_auto_counter_id(it
->second
->name
, false);
88 for (size_t i
= 10; i
< auto_name_offset
+ auto_name_map
.size(); i
= i
*10)
91 for (auto it
= auto_name_map
.begin(); it
!= auto_name_map
.end(); it
++)
92 log(" renaming `%s' to `_%0*d_'.\n", it
->first
.c_str(), auto_name_digits
, auto_name_offset
+ it
->second
);
95 std::string
id(RTLIL::IdString internal_id
, bool may_rename
= true)
97 const char *str
= internal_id
.c_str();
98 bool do_escape
= false;
100 if (may_rename
&& auto_name_map
.count(internal_id
) != 0) {
102 snprintf(buffer
, 100, "_%0*d_", auto_name_digits
, auto_name_offset
+ auto_name_map
[internal_id
]);
103 return std::string(buffer
);
109 if ('0' <= *str
&& *str
<= '9')
112 for (int i
= 0; str
[i
]; i
++)
114 if ('0' <= str
[i
] && str
[i
] <= '9')
116 if ('a' <= str
[i
] && str
[i
] <= 'z')
118 if ('A' <= str
[i
] && str
[i
] <= 'Z')
127 return "\\" + std::string(str
) + " ";
128 return std::string(str
);
131 bool is_reg_wire(RTLIL::SigSpec sig
, std::string
®_name
)
133 if (!sig
.is_chunk() || sig
.as_chunk().wire
== NULL
)
136 RTLIL::SigChunk chunk
= sig
.as_chunk();
138 if (reg_wires
.count(chunk
.wire
->name
) == 0)
141 reg_name
= id(chunk
.wire
->name
);
142 if (sig
.size() != chunk
.wire
->width
) {
144 reg_name
+= stringf("[%d]", chunk
.wire
->start_offset
+ chunk
.offset
);
146 reg_name
+= stringf("[%d:%d]", chunk
.wire
->start_offset
+ chunk
.offset
+ chunk
.width
- 1,
147 chunk
.wire
->start_offset
+ chunk
.offset
);
153 void dump_const(std::ostream
&f
, const RTLIL::Const
&data
, int width
= -1, int offset
= 0, bool no_decimal
= false, bool set_signed
= false)
156 width
= data
.bits
.size() - offset
;
157 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
158 if (width
== 32 && !no_decimal
) {
160 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
161 log_assert(i
< (int)data
.bits
.size());
162 if (data
.bits
[i
] != RTLIL::S0
&& data
.bits
[i
] != RTLIL::S1
)
164 if (data
.bits
[i
] == RTLIL::S1
&& (i
- offset
) == 31)
166 if (data
.bits
[i
] == RTLIL::S1
)
167 val
|= 1 << (i
- offset
);
169 f
<< stringf("32'%sd%d", set_signed
? "s" : "", val
);
172 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
175 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
176 log_assert(i
< (int)data
.bits
.size());
177 switch (data
.bits
[i
]) {
178 case RTLIL::S0
: f
<< stringf("0"); break;
179 case RTLIL::S1
: f
<< stringf("1"); break;
180 case RTLIL::Sx
: f
<< stringf("x"); break;
181 case RTLIL::Sz
: f
<< stringf("z"); break;
182 case RTLIL::Sa
: f
<< stringf("z"); break;
183 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
189 std::string str
= data
.decode_string();
190 for (size_t i
= 0; i
< str
.size(); i
++) {
193 else if (str
[i
] == '\t')
195 else if (str
[i
] < 32)
196 f
<< stringf("\\%03o", str
[i
]);
197 else if (str
[i
] == '"')
198 f
<< stringf("\\\"");
199 else if (str
[i
] == '\\')
200 f
<< stringf("\\\\");
208 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
210 if (chunk
.wire
== NULL
) {
211 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
213 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0) {
214 f
<< stringf("%s", id(chunk
.wire
->name
).c_str());
215 } else if (chunk
.width
== 1) {
216 if (chunk
.wire
->upto
)
217 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
219 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
221 if (chunk
.wire
->upto
)
222 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
223 (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
224 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
226 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
227 (chunk
.offset
+ chunk
.width
- 1) + chunk
.wire
->start_offset
,
228 chunk
.offset
+ chunk
.wire
->start_offset
);
233 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
235 if (sig
.is_chunk()) {
236 dump_sigchunk(f
, sig
.as_chunk());
239 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); it
++) {
240 if (it
!= sig
.chunks().rbegin())
242 dump_sigchunk(f
, *it
, true);
248 void dump_attributes(std::ostream
&f
, std::string indent
, std::map
<RTLIL::IdString
, RTLIL::Const
> &attributes
, char term
= '\n')
252 for (auto it
= attributes
.begin(); it
!= attributes
.end(); it
++) {
253 f
<< stringf("%s" "%s %s", indent
.c_str(), attr2comment
? "/*" : "(*", id(it
->first
).c_str());
255 dump_const(f
, it
->second
);
256 f
<< stringf(" %s%c", attr2comment
? "*/" : "*)", term
);
260 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
262 dump_attributes(f
, indent
, wire
->attributes
);
264 if (wire
->port_input
&& !wire
->port_output
)
265 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
266 else if (!wire
->port_input
&& wire
->port_output
)
267 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
268 else if (wire
->port_input
&& wire
->port_output
)
269 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
271 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
272 if (wire
->width
!= 1)
273 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
274 f
<< stringf("%s;\n", id(wire
->name
).c_str());
276 // do not use Verilog-2k "outut reg" syntax in verilog export
277 std::string range
= "";
278 if (wire
->width
!= 1) {
280 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
282 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
284 if (wire
->port_input
&& !wire
->port_output
)
285 f
<< stringf("%s" "input%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
286 if (!wire
->port_input
&& wire
->port_output
)
287 f
<< stringf("%s" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
288 if (wire
->port_input
&& wire
->port_output
)
289 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
290 if (reg_wires
.count(wire
->name
))
291 f
<< stringf("%s" "reg%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
292 else if (!wire
->port_input
&& !wire
->port_output
)
293 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
297 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
299 dump_attributes(f
, indent
, memory
->attributes
);
300 f
<< stringf("%s" "reg [%d:0] %s [%d:0];\n", indent
.c_str(), memory
->width
-1, id(memory
->name
).c_str(), memory
->size
-1);
303 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
305 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
306 f
<< stringf("$signed(");
307 dump_sigspec(f
, cell
->getPort("\\" + port
));
310 dump_sigspec(f
, cell
->getPort("\\" + port
));
313 std::string
cellname(RTLIL::Cell
*cell
)
315 if (!norename
&& cell
->name
[0] == '$' && reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q"))
317 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
318 if (SIZE(sig
) != 1 || sig
.is_fully_const())
319 goto no_special_reg_name
;
321 RTLIL::Wire
*wire
= sig
[0].wire
;
323 if (wire
->name
[0] != '\\')
324 goto no_special_reg_name
;
326 std::string cell_name
= wire
->name
.str();
328 size_t pos
= cell_name
.find('[');
329 if (pos
!= std::string::npos
)
330 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
332 cell_name
= cell_name
+ "_reg";
334 if (wire
->width
!= 1)
335 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
337 if (active_module
&& active_module
->count_id(cell_name
) > 0)
338 goto no_special_reg_name
;
340 return id(cell_name
);
345 return id(cell
->name
).c_str();
349 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
351 f
<< stringf("%s" "assign ", indent
.c_str());
352 dump_sigspec(f
, cell
->getPort("\\Y"));
353 f
<< stringf(" = %s ", op
.c_str());
354 dump_attributes(f
, "", cell
->attributes
, ' ');
355 dump_cell_expr_port(f
, cell
, "A", true);
359 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
361 f
<< stringf("%s" "assign ", indent
.c_str());
362 dump_sigspec(f
, cell
->getPort("\\Y"));
364 dump_cell_expr_port(f
, cell
, "A", true);
365 f
<< stringf(" %s ", op
.c_str());
366 dump_attributes(f
, "", cell
->attributes
, ' ');
367 dump_cell_expr_port(f
, cell
, "B", true);
371 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
373 if (cell
->type
== "$_NOT_") {
374 f
<< stringf("%s" "assign ", indent
.c_str());
375 dump_sigspec(f
, cell
->getPort("\\Y"));
378 dump_attributes(f
, "", cell
->attributes
, ' ');
379 dump_cell_expr_port(f
, cell
, "A", false);
384 if (cell
->type
.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) {
385 f
<< stringf("%s" "assign ", indent
.c_str());
386 dump_sigspec(f
, cell
->getPort("\\Y"));
388 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
390 dump_cell_expr_port(f
, cell
, "A", false);
392 if (cell
->type
.in("$_AND_", "$_NAND_"))
394 if (cell
->type
.in("$_OR_", "$_NOR_"))
396 if (cell
->type
.in("$_XOR_", "$_XNOR_"))
398 dump_attributes(f
, "", cell
->attributes
, ' ');
400 dump_cell_expr_port(f
, cell
, "B", false);
401 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
407 if (cell
->type
== "$_MUX_") {
408 f
<< stringf("%s" "assign ", indent
.c_str());
409 dump_sigspec(f
, cell
->getPort("\\Y"));
411 dump_cell_expr_port(f
, cell
, "S", false);
413 dump_attributes(f
, "", cell
->attributes
, ' ');
414 dump_cell_expr_port(f
, cell
, "B", false);
416 dump_cell_expr_port(f
, cell
, "A", false);
421 if (cell
->type
.in("$_AOI3_", "$_OAI3_")) {
422 f
<< stringf("%s" "assign ", indent
.c_str());
423 dump_sigspec(f
, cell
->getPort("\\Y"));
424 f
<< stringf(" = ~((");
425 dump_cell_expr_port(f
, cell
, "A", false);
426 f
<< stringf(cell
->type
== "$_AOI3_" ? " & " : " | ");
427 dump_cell_expr_port(f
, cell
, "B", false);
428 f
<< stringf(cell
->type
== "$_AOI3_" ? ") |" : ") &");
429 dump_attributes(f
, "", cell
->attributes
, ' ');
431 dump_cell_expr_port(f
, cell
, "C", false);
432 f
<< stringf(");\n");
436 if (cell
->type
.in("$_AOI4_", "$_OAI4_")) {
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
== "$_AOI4_" ? " & " : " | ");
442 dump_cell_expr_port(f
, cell
, "B", false);
443 f
<< stringf(cell
->type
== "$_AOI4_" ? ") |" : ") &");
444 dump_attributes(f
, "", cell
->attributes
, ' ');
446 dump_cell_expr_port(f
, cell
, "C", false);
447 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
448 dump_cell_expr_port(f
, cell
, "D", false);
449 f
<< stringf("));\n");
453 if (cell
->type
.substr(0, 6) == "$_DFF_")
455 std::string reg_name
= cellname(cell
);
456 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
458 if (!out_is_reg_wire
)
459 f
<< stringf("%s" "reg %s;\n", indent
.c_str(), reg_name
.c_str());
461 dump_attributes(f
, indent
, cell
->attributes
);
462 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), cell
->type
[6] == 'P' ? "pos" : "neg");
463 dump_sigspec(f
, cell
->getPort("\\C"));
464 if (cell
->type
[7] != '_') {
465 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
466 dump_sigspec(f
, cell
->getPort("\\R"));
470 if (cell
->type
[7] != '_') {
471 f
<< stringf("%s" " if (%s", indent
.c_str(), cell
->type
[7] == 'P' ? "" : "!");
472 dump_sigspec(f
, cell
->getPort("\\R"));
474 f
<< stringf("%s" " %s <= %c;\n", indent
.c_str(), reg_name
.c_str(), cell
->type
[8]);
475 f
<< stringf("%s" " else\n", indent
.c_str());
478 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
479 dump_cell_expr_port(f
, cell
, "D", false);
482 if (!out_is_reg_wire
) {
483 f
<< stringf("%s" "assign ", indent
.c_str());
484 dump_sigspec(f
, cell
->getPort("\\Q"));
485 f
<< stringf(" = %s;\n", reg_name
.c_str());
491 if (cell
->type
.substr(0, 8) == "$_DFFSR_")
493 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
495 std::string reg_name
= cellname(cell
);
496 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
498 if (!out_is_reg_wire
)
499 f
<< stringf("%s" "reg %s;\n", indent
.c_str(), reg_name
.c_str());
501 dump_attributes(f
, indent
, cell
->attributes
);
502 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_c
== 'P' ? "pos" : "neg");
503 dump_sigspec(f
, cell
->getPort("\\C"));
504 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
505 dump_sigspec(f
, cell
->getPort("\\S"));
506 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
507 dump_sigspec(f
, cell
->getPort("\\R"));
510 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
511 dump_sigspec(f
, cell
->getPort("\\R"));
513 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
515 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
516 dump_sigspec(f
, cell
->getPort("\\S"));
518 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
520 f
<< stringf("%s" " else\n", indent
.c_str());
521 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
522 dump_cell_expr_port(f
, cell
, "D", false);
525 if (!out_is_reg_wire
) {
526 f
<< stringf("%s" "assign ", indent
.c_str());
527 dump_sigspec(f
, cell
->getPort("\\Q"));
528 f
<< stringf(" = %s;\n", reg_name
.c_str());
534 #define HANDLE_UNIOP(_type, _operator) \
535 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
536 #define HANDLE_BINOP(_type, _operator) \
537 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
539 HANDLE_UNIOP("$not", "~")
540 HANDLE_UNIOP("$pos", "+")
541 HANDLE_UNIOP("$neg", "-")
543 HANDLE_BINOP("$and", "&")
544 HANDLE_BINOP("$or", "|")
545 HANDLE_BINOP("$xor", "^")
546 HANDLE_BINOP("$xnor", "~^")
548 HANDLE_UNIOP("$reduce_and", "&")
549 HANDLE_UNIOP("$reduce_or", "|")
550 HANDLE_UNIOP("$reduce_xor", "^")
551 HANDLE_UNIOP("$reduce_xnor", "~^")
552 HANDLE_UNIOP("$reduce_bool", "|")
554 HANDLE_BINOP("$shl", "<<")
555 HANDLE_BINOP("$shr", ">>")
556 HANDLE_BINOP("$sshl", "<<<")
557 HANDLE_BINOP("$sshr", ">>>")
559 HANDLE_BINOP("$lt", "<")
560 HANDLE_BINOP("$le", "<=")
561 HANDLE_BINOP("$eq", "==")
562 HANDLE_BINOP("$ne", "!=")
563 HANDLE_BINOP("$eqx", "===")
564 HANDLE_BINOP("$nex", "!==")
565 HANDLE_BINOP("$ge", ">=")
566 HANDLE_BINOP("$gt", ">")
568 HANDLE_BINOP("$add", "+")
569 HANDLE_BINOP("$sub", "-")
570 HANDLE_BINOP("$mul", "*")
571 HANDLE_BINOP("$div", "/")
572 HANDLE_BINOP("$mod", "%")
573 HANDLE_BINOP("$pow", "**")
575 HANDLE_UNIOP("$logic_not", "!")
576 HANDLE_BINOP("$logic_and", "&&")
577 HANDLE_BINOP("$logic_or", "||")
582 if (cell
->type
== "$mux")
584 f
<< stringf("%s" "assign ", indent
.c_str());
585 dump_sigspec(f
, cell
->getPort("\\Y"));
587 dump_sigspec(f
, cell
->getPort("\\S"));
589 dump_attributes(f
, "", cell
->attributes
, ' ');
590 dump_sigspec(f
, cell
->getPort("\\B"));
592 dump_sigspec(f
, cell
->getPort("\\A"));
597 if (cell
->type
== "$pmux" || cell
->type
== "$pmux_safe")
599 int width
= cell
->parameters
["\\WIDTH"].as_int();
600 int s_width
= cell
->getPort("\\S").size();
601 std::string func_name
= cellname(cell
);
603 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
604 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
605 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
606 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
608 dump_attributes(f
, indent
+ " ", cell
->attributes
);
609 if (cell
->type
!= "$pmux_safe" && !noattr
)
610 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
611 f
<< stringf("%s" " casez (s)", indent
.c_str());
612 if (cell
->type
!= "$pmux_safe")
613 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
615 for (int i
= 0; i
< s_width
; i
++)
617 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
619 for (int j
= s_width
-1; j
>= 0; j
--)
620 f
<< stringf("%c", j
== i
? '1' : cell
->type
== "$pmux_safe" ? '0' : '?');
623 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
626 f
<< stringf("%s" " default:\n", indent
.c_str());
627 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
629 f
<< stringf("%s" " endcase\n", indent
.c_str());
630 f
<< stringf("%s" "endfunction\n", indent
.c_str());
632 f
<< stringf("%s" "assign ", indent
.c_str());
633 dump_sigspec(f
, cell
->getPort("\\Y"));
634 f
<< stringf(" = %s(", func_name
.c_str());
635 dump_sigspec(f
, cell
->getPort("\\A"));
637 dump_sigspec(f
, cell
->getPort("\\B"));
639 dump_sigspec(f
, cell
->getPort("\\S"));
640 f
<< stringf(");\n");
644 if (cell
->type
== "$slice")
646 f
<< stringf("%s" "assign ", indent
.c_str());
647 dump_sigspec(f
, cell
->getPort("\\Y"));
649 dump_sigspec(f
, cell
->getPort("\\A"));
650 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
654 if (cell
->type
== "$concat")
656 f
<< stringf("%s" "assign ", indent
.c_str());
657 dump_sigspec(f
, cell
->getPort("\\Y"));
658 f
<< stringf(" = { ");
659 dump_sigspec(f
, cell
->getPort("\\B"));
661 dump_sigspec(f
, cell
->getPort("\\A"));
662 f
<< stringf(" };\n");
666 if (cell
->type
== "$dff" || cell
->type
== "$adff")
668 RTLIL::SigSpec sig_clk
, sig_arst
, val_arst
;
669 bool pol_clk
, pol_arst
= false;
671 sig_clk
= cell
->getPort("\\CLK");
672 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
674 if (cell
->type
== "$adff") {
675 sig_arst
= cell
->getPort("\\ARST");
676 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
677 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
680 std::string reg_name
= cellname(cell
);
681 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
683 if (!out_is_reg_wire
)
684 f
<< stringf("%s" "reg [%d:0] %s;\n", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
686 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
687 dump_sigspec(f
, sig_clk
);
688 if (cell
->type
== "$adff") {
689 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
690 dump_sigspec(f
, sig_arst
);
694 if (cell
->type
== "$adff") {
695 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
696 dump_sigspec(f
, sig_arst
);
698 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
699 dump_sigspec(f
, val_arst
);
701 f
<< stringf("%s" " else\n", indent
.c_str());
704 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
705 dump_cell_expr_port(f
, cell
, "D", false);
708 if (!out_is_reg_wire
) {
709 f
<< stringf("%s" "assign ", indent
.c_str());
710 dump_sigspec(f
, cell
->getPort("\\Q"));
711 f
<< stringf(" = %s;\n", reg_name
.c_str());
717 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
718 // FIXME: $sr, $dffsr, $dlatch, $memrd, $memwr, $mem, $fsm
723 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
725 if (cell
->type
[0] == '$' && !noexpr
) {
726 if (dump_cell_expr(f
, indent
, cell
))
730 dump_attributes(f
, indent
, cell
->attributes
);
731 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
733 if (cell
->parameters
.size() > 0) {
735 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); it
++) {
736 if (it
!= cell
->parameters
.begin())
738 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
739 bool is_signed
= (it
->second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
740 dump_const(f
, it
->second
, -1, 0, !is_signed
, is_signed
);
743 f
<< stringf("\n%s" ")", indent
.c_str());
746 std::string cell_name
= cellname(cell
);
747 if (cell_name
!= id(cell
->name
))
748 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
750 f
<< stringf(" %s (", cell_name
.c_str());
752 bool first_arg
= true;
753 std::set
<RTLIL::IdString
> numbered_ports
;
754 for (int i
= 1; true; i
++) {
756 snprintf(str
, 16, "$%d", i
);
757 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); it
++) {
758 if (it
->first
!= str
)
763 f
<< stringf("\n%s ", indent
.c_str());
764 dump_sigspec(f
, it
->second
);
765 numbered_ports
.insert(it
->first
);
766 goto found_numbered_port
;
769 found_numbered_port
:;
771 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); it
++) {
772 if (numbered_ports
.count(it
->first
))
777 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
778 if (it
->second
.size() > 0)
779 dump_sigspec(f
, it
->second
);
782 f
<< stringf("\n%s" ");\n", indent
.c_str());
785 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
787 f
<< stringf("%s" "assign ", indent
.c_str());
788 dump_sigspec(f
, left
);
790 dump_sigspec(f
, right
);
794 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
796 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
798 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
800 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
801 f
<< stringf("%s" "begin\n", indent
.c_str());
803 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); it
++) {
804 if (it
->first
.size() == 0)
806 f
<< stringf("%s ", indent
.c_str());
807 dump_sigspec(f
, it
->first
);
809 dump_sigspec(f
, it
->second
);
813 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); it
++)
814 dump_proc_switch(f
, indent
+ " ", *it
);
816 if (!omit_trailing_begin
&& number_of_stmts
== 0)
817 f
<< stringf("%s /* empty */;\n", indent
.c_str());
819 if (omit_trailing_begin
|| number_of_stmts
>= 2)
820 f
<< stringf("%s" "end\n", indent
.c_str());
823 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
825 if (sw
->signal
.size() == 0) {
826 f
<< stringf("%s" "begin\n", indent
.c_str());
827 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); it
++) {
828 if ((*it
)->compare
.size() == 0)
829 dump_case_body(f
, indent
+ " ", *it
);
831 f
<< stringf("%s" "end\n", indent
.c_str());
835 f
<< stringf("%s" "casez (", indent
.c_str());
836 dump_sigspec(f
, sw
->signal
);
839 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); it
++) {
840 f
<< stringf("%s ", indent
.c_str());
841 if ((*it
)->compare
.size() == 0)
842 f
<< stringf("default");
844 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
847 dump_sigspec(f
, (*it
)->compare
[i
]);
851 dump_case_body(f
, indent
+ " ", *it
);
854 f
<< stringf("%s" "endcase\n", indent
.c_str());
857 void case_body_find_regs(RTLIL::CaseRule
*cs
)
859 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); it
++)
860 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
861 case_body_find_regs(*it2
);
863 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); it
++) {
864 for (auto &c
: it
->first
.chunks())
866 reg_wires
.insert(c
.wire
->name
);
870 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
873 case_body_find_regs(&proc
->root_case
);
874 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); it
++)
875 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
876 for (auto &c
: it2
->first
.chunks())
878 reg_wires
.insert(c
.wire
->name
);
883 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
884 dump_case_body(f
, indent
, &proc
->root_case
, true);
886 std::string backup_indent
= indent
;
888 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
890 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
891 indent
= backup_indent
;
893 if (sync
->type
== RTLIL::STa
) {
894 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
896 f
<< stringf("%s" "always @(", indent
.c_str());
897 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
898 f
<< stringf("posedge ");
899 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
900 f
<< stringf("negedge ");
901 dump_sigspec(f
, sync
->signal
);
902 f
<< stringf(") begin\n");
904 std::string ends
= indent
+ "end\n";
907 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
908 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
909 dump_sigspec(f
, sync
->signal
);
910 f
<< stringf(") begin\n");
911 ends
= indent
+ "end\n" + ends
;
915 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
916 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
917 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
918 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
919 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
920 dump_sigspec(f
, sync2
->signal
);
921 f
<< stringf(") begin\n");
922 ends
= indent
+ "end\n" + ends
;
928 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); it
++) {
929 if (it
->first
.size() == 0)
931 f
<< stringf("%s ", indent
.c_str());
932 dump_sigspec(f
, it
->first
);
933 f
<< stringf(" <= ");
934 dump_sigspec(f
, it
->second
);
938 f
<< stringf("%s", ends
.c_str());
942 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
945 reset_auto_counter(module
);
946 active_module
= module
;
949 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); it
++)
950 dump_process(f
, indent
+ " ", it
->second
, true);
954 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
955 for (auto &it
: module
->cells_
)
957 RTLIL::Cell
*cell
= it
.second
;
958 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
961 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
963 if (sig
.is_chunk()) {
964 RTLIL::SigChunk chunk
= sig
.as_chunk();
965 if (chunk
.wire
!= NULL
)
966 for (int i
= 0; i
< chunk
.width
; i
++)
967 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
970 for (auto &it
: module
->wires_
)
972 RTLIL::Wire
*wire
= it
.second
;
973 for (int i
= 0; i
< wire
->width
; i
++)
974 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
975 goto this_wire_aint_reg
;
977 reg_wires
.insert(wire
->name
);
982 dump_attributes(f
, indent
, module
->attributes
);
983 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
984 bool keep_running
= true;
985 for (int port_id
= 1; keep_running
; port_id
++) {
986 keep_running
= false;
987 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); it
++) {
988 RTLIL::Wire
*wire
= it
->second
;
989 if (wire
->port_id
== port_id
) {
992 f
<< stringf("%s", id(wire
->name
).c_str());
998 f
<< stringf(");\n");
1000 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); it
++)
1001 dump_wire(f
, indent
+ " ", it
->second
);
1003 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); it
++)
1004 dump_memory(f
, indent
+ " ", it
->second
);
1006 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); it
++)
1007 dump_cell(f
, indent
+ " ", it
->second
);
1009 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); it
++)
1010 dump_process(f
, indent
+ " ", it
->second
);
1012 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); it
++)
1013 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1015 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1016 active_module
= NULL
;
1019 struct VerilogBackend
: public Backend
{
1020 VerilogBackend() : Backend("verilog", "write design to verilog file") { }
1023 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1025 log(" write_verilog [options] [filename]\n");
1027 log("Write the current design to a verilog file.\n");
1029 log(" -norename\n");
1030 log(" without this option all internal object names (the ones with a dollar\n");
1031 log(" instead of a backslash prefix) are changed to short names in the\n");
1032 log(" format '_<number>_'.\n");
1035 log(" with this option no attributes are included in the output\n");
1037 log(" -attr2comment\n");
1038 log(" with this option attributes are included as comments in the output\n");
1041 log(" without this option all internal cells are converted to verilog\n");
1042 log(" expressions.\n");
1044 log(" -blackboxes\n");
1045 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1046 log(" this option set only the modules with the 'blackbox' attribute\n");
1047 log(" are written to the output file.\n");
1049 log(" -selected\n");
1050 log(" only write selected modules. modules must be selected entirely or\n");
1051 log(" not at all.\n");
1054 virtual void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
)
1056 log_header("Executing Verilog backend.\n");
1060 attr2comment
= false;
1063 bool blackboxes
= false;
1064 bool selected
= false;
1068 reg_ct
.insert("$dff");
1069 reg_ct
.insert("$adff");
1071 reg_ct
.insert("$_DFF_N_");
1072 reg_ct
.insert("$_DFF_P_");
1074 reg_ct
.insert("$_DFF_NN0_");
1075 reg_ct
.insert("$_DFF_NN1_");
1076 reg_ct
.insert("$_DFF_NP0_");
1077 reg_ct
.insert("$_DFF_NP1_");
1078 reg_ct
.insert("$_DFF_PN0_");
1079 reg_ct
.insert("$_DFF_PN1_");
1080 reg_ct
.insert("$_DFF_PP0_");
1081 reg_ct
.insert("$_DFF_PP1_");
1083 reg_ct
.insert("$_DFFSR_NNN_");
1084 reg_ct
.insert("$_DFFSR_NNP_");
1085 reg_ct
.insert("$_DFFSR_NPN_");
1086 reg_ct
.insert("$_DFFSR_NPP_");
1087 reg_ct
.insert("$_DFFSR_PNN_");
1088 reg_ct
.insert("$_DFFSR_PNP_");
1089 reg_ct
.insert("$_DFFSR_PPN_");
1090 reg_ct
.insert("$_DFFSR_PPP_");
1093 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1094 std::string arg
= args
[argidx
];
1095 if (arg
== "-norename") {
1099 if (arg
== "-noattr") {
1103 if (arg
== "-attr2comment") {
1104 attr2comment
= true;
1107 if (arg
== "-noexpr") {
1111 if (arg
== "-blackboxes") {
1115 if (arg
== "-selected") {
1121 extra_args(f
, filename
, args
, argidx
);
1123 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1124 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); it
++) {
1125 if (it
->second
->get_bool_attribute("\\blackbox") != blackboxes
)
1127 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1128 if (design
->selected_module(it
->first
))
1129 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1132 log("Dumping module `%s'.\n", it
->first
.c_str());
1133 dump_module(*f
, "", it
->second
);
1140 PRIVATE_NAMESPACE_END