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.
24 #include "kernel/register.h"
25 #include "kernel/celltypes.h"
26 #include "kernel/log.h"
27 #include "kernel/sigtools.h"
34 PRIVATE_NAMESPACE_BEGIN
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
;
42 RTLIL::Module
*active_module
;
43 dict
<RTLIL::SigBit
, RTLIL::State
> active_initdata
;
46 void reset_auto_counter_id(RTLIL::IdString id
, bool may_rename
)
48 const char *str
= id
.c_str();
50 if (*str
== '$' && may_rename
&& !norename
)
51 auto_name_map
[id
] = auto_name_counter
++;
53 if (str
[0] != '\\' || str
[1] != '_' || str
[2] == 0)
56 for (int i
= 2; str
[i
] != 0; i
++) {
57 if (str
[i
] == '_' && str
[i
+1] == 0)
59 if (str
[i
] < '0' || str
[i
] > '9')
63 int num
= atoi(str
+2);
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)
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
);
96 std::string
next_auto_id()
98 return stringf("%s_%0*d_", auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ auto_name_counter
++);
101 std::string
id(RTLIL::IdString internal_id
, bool may_rename
= true)
103 const char *str
= internal_id
.c_str();
104 bool do_escape
= false;
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
]);
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
);
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
);
152 reg_name
+= stringf("[%d:%d]", chunk
.wire
->start_offset
+ chunk
.offset
+ chunk
.width
- 1,
153 chunk
.wire
->start_offset
+ chunk
.offset
);
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)
162 width
= data
.bits
.size() - offset
;
165 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
166 if (width
== 32 && !no_decimal
&& !nodec
) {
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
)
172 if (data
.bits
[i
] == RTLIL::S1
)
173 val
|= 1 << (i
- offset
);
176 f
<< stringf("%d", val
);
177 else if (set_signed
&& val
< 0)
178 f
<< stringf("-32'sd%u", -val
);
180 f
<< stringf("32'%sd%u", set_signed
? "s" : "", val
);
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.");
197 if (GetSize(bin_digits
) == 0)
199 while (GetSize(bin_digits
) % 4 != 0)
200 if (bin_digits
.back() == '1')
201 bin_digits
.push_back('0');
203 bin_digits
.push_back(bin_digits
.back());
204 for (int i
= 0; i
< GetSize(bin_digits
); i
+= 4)
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')
213 hex_digits
.push_back('x');
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')
219 hex_digits
.push_back('z');
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);
225 f
<< stringf("%d'%sh", width
, set_signed
? "s" : "");
226 for (int i
= GetSize(hex_digits
)-1; i
>= 0; i
--)
231 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
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.");
248 std::string str
= data
.decode_string();
249 for (size_t i
= 0; i
< str
.size(); i
++) {
252 else if (str
[i
] == '\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] == '*')
269 void dump_reg_init(std::ostream
&f
, SigSpec sig
)
272 bool gotinit
= false;
274 for (auto bit
: active_sigmap(sig
)) {
275 if (active_initdata
.count(bit
)) {
276 initval
.bits
.push_back(active_initdata
.at(bit
));
279 initval
.bits
.push_back(State::Sx
);
285 dump_const(f
, initval
);
289 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
291 if (chunk
.wire
== NULL
) {
292 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
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
);
300 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
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
);
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
);
314 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
316 if (sig
.is_chunk()) {
317 dump_sigchunk(f
, sig
.as_chunk());
320 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
321 if (it
!= sig
.chunks().rbegin())
323 dump_sigchunk(f
, *it
, true);
329 void dump_attributes(std::ostream
&f
, std::string indent
, dict
<RTLIL::IdString
, RTLIL::Const
> &attributes
, char term
= '\n', bool modattr
= false)
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());
336 if (modattr
&& (it
->second
== Const(0, 1) || it
->second
== Const(0)))
338 else if (modattr
&& (it
->second
== Const(1, 1) || it
->second
== Const(1)))
341 dump_const(f
, it
->second
, -1, 0, false, false, attr2comment
);
342 f
<< stringf(" %s%c", attr2comment
? "*/" : "*)", term
);
346 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
348 dump_attributes(f
, indent
, wire
->attributes
);
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 " : "");
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());
362 // do not use Verilog-2k "output reg" syntax in Verilog export
363 std::string range
= "";
364 if (wire
->width
!= 1) {
366 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
368 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
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")) {
380 dump_const(f
, wire
->attributes
.at("\\init"));
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());
388 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
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);
394 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
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
));
401 dump_sigspec(f
, cell
->getPort("\\" + port
));
404 std::string
cellname(RTLIL::Cell
*cell
)
406 if (!norename
&& cell
->name
[0] == '$' && reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q"))
408 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
409 if (GetSize(sig
) != 1 || sig
.is_fully_const())
410 goto no_special_reg_name
;
412 RTLIL::Wire
*wire
= sig
[0].wire
;
414 if (wire
->name
[0] != '\\')
415 goto no_special_reg_name
;
417 std::string cell_name
= wire
->name
.str();
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
);
423 cell_name
= cell_name
+ "_reg";
425 if (wire
->width
!= 1)
426 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
428 if (active_module
&& active_module
->count_id(cell_name
) > 0)
429 goto no_special_reg_name
;
431 return id(cell_name
);
436 return id(cell
->name
).c_str();
440 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
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);
450 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
452 f
<< stringf("%s" "assign ", indent
.c_str());
453 dump_sigspec(f
, cell
->getPort("\\Y"));
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);
462 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
464 if (cell
->type
== "$_NOT_") {
465 f
<< stringf("%s" "assign ", indent
.c_str());
466 dump_sigspec(f
, cell
->getPort("\\Y"));
469 dump_attributes(f
, "", cell
->attributes
, ' ');
470 dump_cell_expr_port(f
, cell
, "A", false);
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"));
479 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
481 dump_cell_expr_port(f
, cell
, "A", false);
483 if (cell
->type
.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
485 if (cell
->type
.in("$_OR_", "$_NOR_", "$_ORNOT_"))
487 if (cell
->type
.in("$_XOR_", "$_XNOR_"))
489 dump_attributes(f
, "", cell
->attributes
, ' ');
491 if (cell
->type
.in("$_ANDNOT_", "$_ORNOT_"))
493 dump_cell_expr_port(f
, cell
, "B", false);
494 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
500 if (cell
->type
== "$_MUX_") {
501 f
<< stringf("%s" "assign ", indent
.c_str());
502 dump_sigspec(f
, cell
->getPort("\\Y"));
504 dump_cell_expr_port(f
, cell
, "S", false);
506 dump_attributes(f
, "", cell
->attributes
, ' ');
507 dump_cell_expr_port(f
, cell
, "B", false);
509 dump_cell_expr_port(f
, cell
, "A", false);
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
, ' ');
524 dump_cell_expr_port(f
, cell
, "C", false);
525 f
<< stringf(");\n");
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
, ' ');
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");
546 if (cell
->type
.substr(0, 6) == "$_DFF_")
548 std::string reg_name
= cellname(cell
);
549 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
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"));
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"));
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"));
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());
574 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
575 dump_cell_expr_port(f
, cell
, "D", false);
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());
587 if (cell
->type
.substr(0, 8) == "$_DFFSR_")
589 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
591 std::string reg_name
= cellname(cell
);
592 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
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"));
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"));
609 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
610 dump_sigspec(f
, cell
->getPort("\\R"));
612 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
614 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
615 dump_sigspec(f
, cell
->getPort("\\S"));
617 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
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);
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());
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; }
638 HANDLE_UNIOP("$not", "~")
639 HANDLE_UNIOP("$pos", "+")
640 HANDLE_UNIOP("$neg", "-")
642 HANDLE_BINOP("$and", "&")
643 HANDLE_BINOP("$or", "|")
644 HANDLE_BINOP("$xor", "^")
645 HANDLE_BINOP("$xnor", "~^")
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", "|")
653 HANDLE_BINOP("$shl", "<<")
654 HANDLE_BINOP("$shr", ">>")
655 HANDLE_BINOP("$sshl", "<<<")
656 HANDLE_BINOP("$sshr", ">>>")
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", ">")
667 HANDLE_BINOP("$add", "+")
668 HANDLE_BINOP("$sub", "-")
669 HANDLE_BINOP("$mul", "*")
670 HANDLE_BINOP("$div", "/")
671 HANDLE_BINOP("$mod", "%")
672 HANDLE_BINOP("$pow", "**")
674 HANDLE_UNIOP("$logic_not", "!")
675 HANDLE_BINOP("$logic_and", "&&")
676 HANDLE_BINOP("$logic_or", "||")
681 if (cell
->type
== "$shiftx")
683 f
<< stringf("%s" "assign ", indent
.c_str());
684 dump_sigspec(f
, cell
->getPort("\\Y"));
686 dump_sigspec(f
, cell
->getPort("\\A"));
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())
693 f
<< stringf(" +: %d", cell
->getParam("\\Y_WIDTH").as_int());
694 f
<< stringf("];\n");
698 if (cell
->type
== "$mux")
700 f
<< stringf("%s" "assign ", indent
.c_str());
701 dump_sigspec(f
, cell
->getPort("\\Y"));
703 dump_sigspec(f
, cell
->getPort("\\S"));
705 dump_attributes(f
, "", cell
->attributes
, ' ');
706 dump_sigspec(f
, cell
->getPort("\\B"));
708 dump_sigspec(f
, cell
->getPort("\\A"));
713 if (cell
->type
== "$pmux" || cell
->type
== "$pmux_safe")
715 int width
= cell
->parameters
["\\WIDTH"].as_int();
716 int s_width
= cell
->getPort("\\S").size();
717 std::string func_name
= cellname(cell
);
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);
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");
731 for (int i
= 0; i
< s_width
; i
++)
733 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
735 for (int j
= s_width
-1; j
>= 0; j
--)
736 f
<< stringf("%c", j
== i
? '1' : cell
->type
== "$pmux_safe" ? '0' : '?');
739 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
742 f
<< stringf("%s" " default:\n", indent
.c_str());
743 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
745 f
<< stringf("%s" " endcase\n", indent
.c_str());
746 f
<< stringf("%s" "endfunction\n", indent
.c_str());
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"));
753 dump_sigspec(f
, cell
->getPort("\\B"));
755 dump_sigspec(f
, cell
->getPort("\\S"));
756 f
<< stringf(");\n");
760 if (cell
->type
== "$slice")
762 f
<< stringf("%s" "assign ", indent
.c_str());
763 dump_sigspec(f
, cell
->getPort("\\Y"));
765 dump_sigspec(f
, cell
->getPort("\\A"));
766 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
770 if (cell
->type
== "$concat")
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"));
777 dump_sigspec(f
, cell
->getPort("\\A"));
778 f
<< stringf(" };\n");
782 if (cell
->type
== "$dffsr")
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");
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();
795 std::string reg_name
= cellname(cell
);
796 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
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
);
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
);
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
);
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
);
821 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
822 dump_sigspec(f
, sig_d
[i
]);
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());
835 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
837 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
838 bool pol_clk
, pol_arst
= false, pol_en
= false;
840 sig_clk
= cell
->getPort("\\CLK");
841 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
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"]);
849 if (cell
->type
== "$dffe") {
850 sig_en
= cell
->getPort("\\EN");
851 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
854 std::string reg_name
= cellname(cell
);
855 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
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"));
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
);
871 if (cell
->type
== "$adff") {
872 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
873 dump_sigspec(f
, sig_arst
);
875 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
876 dump_sigspec(f
, val_arst
);
878 f
<< stringf("%s" " else\n", indent
.c_str());
881 if (cell
->type
== "$dffe") {
882 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
883 dump_sigspec(f
, sig_en
);
887 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
888 dump_cell_expr_port(f
, cell
, "D", false);
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());
900 if (cell
->type
== "$mem")
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());
909 // for memory block make something like:
910 // reg [7:0] memid [3:0];
914 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
-1, 0);
917 f
<< stringf("%s" "initial begin\n", indent
.c_str());
918 for (int i
=0; i
<size
; i
++)
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
));
924 f
<< stringf("%s" "end\n", indent
.c_str());
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
;
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
;
938 for (int i
=0; i
< nread_ports
; i
++)
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();
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
>();
954 if (use_rd_clk
&& !rd_transparent
)
956 // for clocked read ports make something like:
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()) );
964 std::ostringstream os
;
965 if (sig_rd_en
!= RTLIL::SigBit(true))
967 os
<< stringf("if (");
968 dump_sigspec(os
, sig_rd_en
);
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());
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
);
983 if (rd_transparent
) {
984 // for rd-transparent read-ports make something like:
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()) );
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
);
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
);
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
);
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
;
1020 for (int i
=0; i
< nwrite_ports
; i
++)
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();
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
>();
1034 // make something like:
1035 // always @(posedge clk)
1036 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1038 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1040 int start_i
= i
, width
= 1;
1041 SigBit wen_bit
= sig_wr_en
[i
];
1043 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1046 if (wen_bit
== State::S0
)
1049 std::ostringstream os
;
1050 if (wen_bit
!= State::S1
)
1052 os
<< stringf("if (");
1053 dump_sigspec(os
, wen_bit
);
1054 os
<< stringf(") ");
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("] <= ");
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());
1067 // Output Verilog that looks something like this:
1069 // always @(posedge CLK2) begin
1070 // _3_ <= memory[D1ADDR];
1072 // memory[A1ADDR] <= A1DATA;
1074 // memory[A2ADDR] <= A2DATA;
1077 // always @(negedge CLK1) begin
1079 // memory[C1ADDR] <= C1DATA;
1082 // assign D1DATA = _3_;
1083 // assign D2DATA <= memory[D2ADDR];
1085 // the reg ... definitions
1086 for(auto ®
: lof_reg_declarations
)
1088 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1090 // the block of expressions by clock domain
1091 for(auto &pair
: clk_to_lof_body
)
1093 std::string clk_domain
= pair
.first
;
1094 std::vector
<std::string
> lof_lines
= pair
.second
;
1095 if( clk_domain
!= "")
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());
1104 // the non-clocked assignments
1105 for(auto &line
: lof_lines
)
1106 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1113 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1114 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1119 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1121 if (cell
->type
[0] == '$' && !noexpr
) {
1122 if (dump_cell_expr(f
, indent
, cell
))
1126 dump_attributes(f
, indent
, cell
->attributes
);
1127 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
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())
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
);
1139 f
<< stringf("\n%s" ")", indent
.c_str());
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());
1146 f
<< stringf(" %s (", cell_name
.c_str());
1148 bool first_arg
= true;
1149 std::set
<RTLIL::IdString
> numbered_ports
;
1150 for (int i
= 1; true; i
++) {
1152 snprintf(str
, 16, "$%d", i
);
1153 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1154 if (it
->first
!= str
)
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
;
1165 found_numbered_port
:;
1167 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1168 if (numbered_ports
.count(it
->first
))
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
);
1178 f
<< stringf("\n%s" ");\n", indent
.c_str());
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");
1191 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
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");
1200 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1202 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1204 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1206 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1207 f
<< stringf("%s" "begin\n", indent
.c_str());
1209 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1210 if (it
->first
.size() == 0)
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");
1219 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1220 dump_proc_switch(f
, indent
+ " ", *it
);
1222 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1223 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1225 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1226 f
<< stringf("%s" "end\n", indent
.c_str());
1229 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
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
);
1237 f
<< stringf("%s" "end\n", indent
.c_str());
1241 f
<< stringf("%s" "casez (", indent
.c_str());
1242 dump_sigspec(f
, sw
->signal
);
1243 f
<< stringf(")\n");
1245 bool got_default
= false;
1246 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1247 if ((*it
)->compare
.size() == 0) {
1250 f
<< stringf("%s default", indent
.c_str());
1253 f
<< stringf("%s ", indent
.c_str());
1254 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1257 dump_sigspec(f
, (*it
)->compare
[i
]);
1260 f
<< stringf(":\n");
1261 dump_case_body(f
, indent
+ " ", *it
);
1264 f
<< stringf("%s" "endcase\n", indent
.c_str());
1267 void case_body_find_regs(RTLIL::CaseRule
*cs
)
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
);
1273 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1274 for (auto &c
: it
->first
.chunks())
1276 reg_wires
.insert(c
.wire
->name
);
1280 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
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())
1288 reg_wires
.insert(c
.wire
->name
);
1293 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1294 dump_case_body(f
, indent
, &proc
->root_case
, true);
1296 std::string backup_indent
= indent
;
1298 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1300 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1301 indent
= backup_indent
;
1303 if (sync
->type
== RTLIL::STa
) {
1304 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
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");
1314 std::string ends
= indent
+ "end\n";
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
;
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
;
1338 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1339 if (it
->first
.size() == 0)
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");
1348 f
<< stringf("%s", ends
.c_str());
1352 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1355 reset_auto_counter(module
);
1356 active_module
= module
;
1357 active_sigmap
.set(module
);
1358 active_initdata
.clear();
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
);
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
));
1375 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1376 dump_process(f
, indent
+ " ", it
->second
, true);
1380 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1381 for (auto &it
: module
->cells_
)
1383 RTLIL::Cell
*cell
= it
.second
;
1384 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1387 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
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
));
1396 for (auto &it
: module
->wires_
)
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
;
1403 reg_wires
.insert(wire
->name
);
1404 this_wire_aint_reg
:;
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
) {
1418 f
<< stringf("%s", id(wire
->name
).c_str());
1419 keep_running
= true;
1424 f
<< stringf(");\n");
1426 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1427 dump_wire(f
, indent
+ " ", it
->second
);
1429 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1430 dump_memory(f
, indent
+ " ", it
->second
);
1432 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1433 dump_cell(f
, indent
+ " ", it
->second
);
1435 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1436 dump_process(f
, indent
+ " ", it
->second
);
1438 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1439 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1441 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1442 active_module
= NULL
;
1443 active_sigmap
.clear();
1444 active_initdata
.clear();
1447 struct VerilogBackend
: public Backend
{
1448 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1451 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1453 log(" write_verilog [options] [filename]\n");
1455 log("Write the current design to a Verilog file.\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");
1462 log(" -renameprefix <prefix>\n");
1463 log(" insert this prefix in front of auto-generated instance names\n");
1466 log(" with this option no attributes are included in the output\n");
1468 log(" -attr2comment\n");
1469 log(" with this option attributes are included as comments in the output\n");
1472 log(" without this option all internal cells are converted to Verilog\n");
1473 log(" expressions.\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");
1481 log(" dump 32-bit constants in decimal and without size and radix\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");
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");
1494 log(" -defparam\n");
1495 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1496 log(" cell parameters.\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");
1503 log(" -selected\n");
1504 log(" only write selected modules. modules must be selected entirely or\n");
1505 log(" not at all.\n");
1508 log(" verbose output (print new names of all renamed wires and cells)\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");
1517 virtual void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
)
1519 log_header(design
, "Executing Verilog backend.\n");
1524 attr2comment
= false;
1533 bool blackboxes
= false;
1534 bool selected
= false;
1538 reg_ct
.insert("$dff");
1539 reg_ct
.insert("$adff");
1541 reg_ct
.insert("$_DFF_N_");
1542 reg_ct
.insert("$_DFF_P_");
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_");
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_");
1563 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1564 std::string arg
= args
[argidx
];
1565 if (arg
== "-norename") {
1569 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1570 auto_prefix
= args
[++argidx
];
1573 if (arg
== "-noattr") {
1577 if (arg
== "-attr2comment") {
1578 attr2comment
= true;
1581 if (arg
== "-noexpr") {
1585 if (arg
== "-nodec") {
1589 if (arg
== "-nohex") {
1593 if (arg
== "-nostr") {
1597 if (arg
== "-defparam") {
1601 if (arg
== "-decimal") {
1605 if (arg
== "-blackboxes") {
1609 if (arg
== "-selected") {
1619 extra_args(f
, filename
, args
, argidx
);
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
)
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
));
1632 log("Dumping module `%s'.\n", it
->first
.c_str());
1633 dump_module(*f
, "", it
->second
);
1640 PRIVATE_NAMESPACE_END