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:%d];\n", indent
.c_str(), memory
->width
-1, id(memory
->name
).c_str(), memory
->size
+memory
->start_offset
-1, memory
->start_offset
);
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
== "$lut")
784 f
<< stringf("%s" "assign ", indent
.c_str());
785 dump_sigspec(f
, cell
->getPort("\\Y"));
787 dump_const(f
, cell
->parameters
.at("\\LUT"));
788 f
<< stringf(" >> ");
789 dump_attributes(f
, "", cell
->attributes
, ' ');
790 dump_sigspec(f
, cell
->getPort("\\A"));
795 if (cell
->type
== "$dffsr")
797 SigSpec sig_clk
= cell
->getPort("\\CLK");
798 SigSpec sig_set
= cell
->getPort("\\SET");
799 SigSpec sig_clr
= cell
->getPort("\\CLR");
800 SigSpec sig_d
= cell
->getPort("\\D");
801 SigSpec sig_q
= cell
->getPort("\\Q");
803 int width
= cell
->parameters
["\\WIDTH"].as_int();
804 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
805 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
806 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
808 std::string reg_name
= cellname(cell
);
809 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
811 if (!out_is_reg_wire
) {
812 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
813 dump_reg_init(f
, sig_q
);
817 for (int i
= 0; i
< width
; i
++) {
818 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
819 dump_sigspec(f
, sig_clk
);
820 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
821 dump_sigspec(f
, sig_set
);
822 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
823 dump_sigspec(f
, sig_clr
);
826 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
827 dump_sigspec(f
, sig_clr
);
828 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
830 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
831 dump_sigspec(f
, sig_set
);
832 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
834 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
835 dump_sigspec(f
, sig_d
[i
]);
839 if (!out_is_reg_wire
) {
840 f
<< stringf("%s" "assign ", indent
.c_str());
841 dump_sigspec(f
, sig_q
);
842 f
<< stringf(" = %s;\n", reg_name
.c_str());
848 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
850 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
851 bool pol_clk
, pol_arst
= false, pol_en
= false;
853 sig_clk
= cell
->getPort("\\CLK");
854 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
856 if (cell
->type
== "$adff") {
857 sig_arst
= cell
->getPort("\\ARST");
858 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
859 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
862 if (cell
->type
== "$dffe") {
863 sig_en
= cell
->getPort("\\EN");
864 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
867 std::string reg_name
= cellname(cell
);
868 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
870 if (!out_is_reg_wire
) {
871 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
872 dump_reg_init(f
, cell
->getPort("\\Q"));
876 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
877 dump_sigspec(f
, sig_clk
);
878 if (cell
->type
== "$adff") {
879 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
880 dump_sigspec(f
, sig_arst
);
884 if (cell
->type
== "$adff") {
885 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
886 dump_sigspec(f
, sig_arst
);
888 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
889 dump_sigspec(f
, val_arst
);
891 f
<< stringf("%s" " else\n", indent
.c_str());
894 if (cell
->type
== "$dffe") {
895 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
896 dump_sigspec(f
, sig_en
);
900 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
901 dump_cell_expr_port(f
, cell
, "D", false);
904 if (!out_is_reg_wire
) {
905 f
<< stringf("%s" "assign ", indent
.c_str());
906 dump_sigspec(f
, cell
->getPort("\\Q"));
907 f
<< stringf(" = %s;\n", reg_name
.c_str());
913 if (cell
->type
== "$dlatch")
915 RTLIL::SigSpec sig_en
;
918 sig_en
= cell
->getPort("\\EN");
919 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
921 std::string reg_name
= cellname(cell
);
922 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
924 if (!out_is_reg_wire
) {
925 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
926 dump_reg_init(f
, cell
->getPort("\\Q"));
930 f
<< stringf("%s" "always @*\n", indent
.c_str());
932 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
933 dump_sigspec(f
, sig_en
);
936 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
937 dump_cell_expr_port(f
, cell
, "D", false);
940 if (!out_is_reg_wire
) {
941 f
<< stringf("%s" "assign ", indent
.c_str());
942 dump_sigspec(f
, cell
->getPort("\\Q"));
943 f
<< stringf(" = %s;\n", reg_name
.c_str());
949 if (cell
->type
== "$mem")
951 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
952 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
953 int abits
= cell
->parameters
["\\ABITS"].as_int();
954 int size
= cell
->parameters
["\\SIZE"].as_int();
955 int offset
= cell
->parameters
["\\OFFSET"].as_int();
956 int width
= cell
->parameters
["\\WIDTH"].as_int();
957 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
959 // for memory block make something like:
960 // reg [7:0] memid [3:0];
964 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
967 f
<< stringf("%s" "initial begin\n", indent
.c_str());
968 for (int i
=0; i
<size
; i
++)
970 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
971 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
974 f
<< stringf("%s" "end\n", indent
.c_str());
977 // create a map : "edge clk" -> expressions within that clock domain
978 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
979 clk_to_lof_body
[""] = std::vector
<std::string
>();
980 std::string clk_domain_str
;
981 // create a list of reg declarations
982 std::vector
<std::string
> lof_reg_declarations
;
984 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
985 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
986 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
988 for (int i
=0; i
< nread_ports
; i
++)
990 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
991 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
992 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
993 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
994 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
995 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
996 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
998 std::ostringstream os
;
999 dump_sigspec(os
, sig_rd_clk
);
1000 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1001 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1002 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1004 if (use_rd_clk
&& !rd_transparent
)
1006 // for clocked read ports make something like:
1007 // reg [..] temp_id;
1008 // always @(posedge clk)
1009 // if (rd_en) temp_id <= array_reg[r_addr];
1010 // assign r_data = temp_id;
1011 std::string temp_id
= next_auto_id();
1012 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1014 std::ostringstream os
;
1015 if (sig_rd_en
!= RTLIL::SigBit(true))
1017 os
<< stringf("if (");
1018 dump_sigspec(os
, sig_rd_en
);
1019 os
<< stringf(") ");
1021 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1022 dump_sigspec(os
, sig_rd_addr
);
1023 os
<< stringf("];\n");
1024 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1027 std::ostringstream os
;
1028 dump_sigspec(os
, sig_rd_data
);
1029 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1030 clk_to_lof_body
[""].push_back(line
);
1033 if (rd_transparent
) {
1034 // for rd-transparent read-ports make something like:
1035 // reg [..] temp_id;
1036 // always @(posedge clk)
1037 // temp_id <= r_addr;
1038 // assign r_data = array_reg[temp_id];
1039 std::string temp_id
= next_auto_id();
1040 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1042 std::ostringstream os
;
1043 dump_sigspec(os
, sig_rd_addr
);
1044 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1045 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1048 std::ostringstream os
;
1049 dump_sigspec(os
, sig_rd_data
);
1050 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1051 clk_to_lof_body
[""].push_back(line
);
1054 // for non-clocked read-ports make something like:
1055 // assign r_data = array_reg[r_addr];
1056 std::ostringstream os
, os2
;
1057 dump_sigspec(os
, sig_rd_data
);
1058 dump_sigspec(os2
, sig_rd_addr
);
1059 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1060 clk_to_lof_body
[""].push_back(line
);
1065 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1066 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1067 bool wr_clk_posedge
;
1070 for (int i
=0; i
< nwrite_ports
; i
++)
1072 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1073 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1074 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1075 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1076 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1078 std::ostringstream os
;
1079 dump_sigspec(os
, sig_wr_clk
);
1080 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1081 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1082 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1084 // make something like:
1085 // always @(posedge clk)
1086 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1088 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1090 int start_i
= i
, width
= 1;
1091 SigBit wen_bit
= sig_wr_en
[i
];
1093 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1096 if (wen_bit
== State::S0
)
1099 std::ostringstream os
;
1100 if (wen_bit
!= State::S1
)
1102 os
<< stringf("if (");
1103 dump_sigspec(os
, wen_bit
);
1104 os
<< stringf(") ");
1106 os
<< stringf("%s[", mem_id
.c_str());
1107 dump_sigspec(os
, sig_wr_addr
);
1108 if (width
== GetSize(sig_wr_en
))
1109 os
<< stringf("] <= ");
1111 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1112 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1113 os
<< stringf(";\n");
1114 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1117 // Output Verilog that looks something like this:
1119 // always @(posedge CLK2) begin
1120 // _3_ <= memory[D1ADDR];
1122 // memory[A1ADDR] <= A1DATA;
1124 // memory[A2ADDR] <= A2DATA;
1127 // always @(negedge CLK1) begin
1129 // memory[C1ADDR] <= C1DATA;
1132 // assign D1DATA = _3_;
1133 // assign D2DATA <= memory[D2ADDR];
1135 // the reg ... definitions
1136 for(auto ®
: lof_reg_declarations
)
1138 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1140 // the block of expressions by clock domain
1141 for(auto &pair
: clk_to_lof_body
)
1143 std::string clk_domain
= pair
.first
;
1144 std::vector
<std::string
> lof_lines
= pair
.second
;
1145 if( clk_domain
!= "")
1147 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1148 for(auto &line
: lof_lines
)
1149 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1150 f
<< stringf("%s" "end\n", indent
.c_str());
1154 // the non-clocked assignments
1155 for(auto &line
: lof_lines
)
1156 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1163 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1164 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1169 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1171 if (cell
->type
[0] == '$' && !noexpr
) {
1172 if (dump_cell_expr(f
, indent
, cell
))
1176 dump_attributes(f
, indent
, cell
->attributes
);
1177 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1179 if (!defparam
&& cell
->parameters
.size() > 0) {
1180 f
<< stringf(" #(");
1181 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1182 if (it
!= cell
->parameters
.begin())
1184 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1185 bool is_signed
= (it
->second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
1186 dump_const(f
, it
->second
, -1, 0, false, is_signed
);
1189 f
<< stringf("\n%s" ")", indent
.c_str());
1192 std::string cell_name
= cellname(cell
);
1193 if (cell_name
!= id(cell
->name
))
1194 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1196 f
<< stringf(" %s (", cell_name
.c_str());
1198 bool first_arg
= true;
1199 std::set
<RTLIL::IdString
> numbered_ports
;
1200 for (int i
= 1; true; i
++) {
1202 snprintf(str
, 16, "$%d", i
);
1203 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1204 if (it
->first
!= str
)
1209 f
<< stringf("\n%s ", indent
.c_str());
1210 dump_sigspec(f
, it
->second
);
1211 numbered_ports
.insert(it
->first
);
1212 goto found_numbered_port
;
1215 found_numbered_port
:;
1217 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1218 if (numbered_ports
.count(it
->first
))
1223 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1224 if (it
->second
.size() > 0)
1225 dump_sigspec(f
, it
->second
);
1228 f
<< stringf("\n%s" ");\n", indent
.c_str());
1230 if (defparam
&& cell
->parameters
.size() > 0) {
1231 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1232 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1233 bool is_signed
= (it
->second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
1234 dump_const(f
, it
->second
, -1, 0, false, is_signed
);
1235 f
<< stringf(";\n");
1241 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1243 f
<< stringf("%s" "assign ", indent
.c_str());
1244 dump_sigspec(f
, left
);
1245 f
<< stringf(" = ");
1246 dump_sigspec(f
, right
);
1247 f
<< stringf(";\n");
1250 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1252 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1254 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1256 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1257 f
<< stringf("%s" "begin\n", indent
.c_str());
1259 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1260 if (it
->first
.size() == 0)
1262 f
<< stringf("%s ", indent
.c_str());
1263 dump_sigspec(f
, it
->first
);
1264 f
<< stringf(" = ");
1265 dump_sigspec(f
, it
->second
);
1266 f
<< stringf(";\n");
1269 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1270 dump_proc_switch(f
, indent
+ " ", *it
);
1272 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1273 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1275 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1276 f
<< stringf("%s" "end\n", indent
.c_str());
1279 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1281 if (sw
->signal
.size() == 0) {
1282 f
<< stringf("%s" "begin\n", indent
.c_str());
1283 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1284 if ((*it
)->compare
.size() == 0)
1285 dump_case_body(f
, indent
+ " ", *it
);
1287 f
<< stringf("%s" "end\n", indent
.c_str());
1291 f
<< stringf("%s" "casez (", indent
.c_str());
1292 dump_sigspec(f
, sw
->signal
);
1293 f
<< stringf(")\n");
1295 bool got_default
= false;
1296 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1297 if ((*it
)->compare
.size() == 0) {
1300 f
<< stringf("%s default", indent
.c_str());
1303 f
<< stringf("%s ", indent
.c_str());
1304 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1307 dump_sigspec(f
, (*it
)->compare
[i
]);
1310 f
<< stringf(":\n");
1311 dump_case_body(f
, indent
+ " ", *it
);
1314 f
<< stringf("%s" "endcase\n", indent
.c_str());
1317 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1319 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1320 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1321 case_body_find_regs(*it2
);
1323 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1324 for (auto &c
: it
->first
.chunks())
1326 reg_wires
.insert(c
.wire
->name
);
1330 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1333 case_body_find_regs(&proc
->root_case
);
1334 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1335 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1336 for (auto &c
: it2
->first
.chunks())
1338 reg_wires
.insert(c
.wire
->name
);
1343 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1344 dump_case_body(f
, indent
, &proc
->root_case
, true);
1346 std::string backup_indent
= indent
;
1348 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1350 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1351 indent
= backup_indent
;
1353 if (sync
->type
== RTLIL::STa
) {
1354 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1356 f
<< stringf("%s" "always @(", indent
.c_str());
1357 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1358 f
<< stringf("posedge ");
1359 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1360 f
<< stringf("negedge ");
1361 dump_sigspec(f
, sync
->signal
);
1362 f
<< stringf(") begin\n");
1364 std::string ends
= indent
+ "end\n";
1367 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1368 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1369 dump_sigspec(f
, sync
->signal
);
1370 f
<< stringf(") begin\n");
1371 ends
= indent
+ "end\n" + ends
;
1375 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1376 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1377 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1378 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1379 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1380 dump_sigspec(f
, sync2
->signal
);
1381 f
<< stringf(") begin\n");
1382 ends
= indent
+ "end\n" + ends
;
1388 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1389 if (it
->first
.size() == 0)
1391 f
<< stringf("%s ", indent
.c_str());
1392 dump_sigspec(f
, it
->first
);
1393 f
<< stringf(" <= ");
1394 dump_sigspec(f
, it
->second
);
1395 f
<< stringf(";\n");
1398 f
<< stringf("%s", ends
.c_str());
1402 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1405 reset_auto_counter(module
);
1406 active_module
= module
;
1407 active_sigmap
.set(module
);
1408 active_initdata
.clear();
1410 for (auto wire
: module
->wires())
1411 if (wire
->attributes
.count("\\init")) {
1412 SigSpec sig
= active_sigmap(wire
);
1413 Const val
= wire
->attributes
.at("\\init");
1414 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1415 active_initdata
[sig
[i
]] = val
.bits
.at(i
);
1418 if (!module
->processes
.empty())
1419 log_warning("Module %s contains unmapped RTLIL proccesses. RTLIL processes\n"
1420 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1421 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1422 "processes to logic networks and registers.", log_id(module
));
1425 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1426 dump_process(f
, indent
+ " ", it
->second
, true);
1430 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1431 for (auto &it
: module
->cells_
)
1433 RTLIL::Cell
*cell
= it
.second
;
1434 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1437 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1439 if (sig
.is_chunk()) {
1440 RTLIL::SigChunk chunk
= sig
.as_chunk();
1441 if (chunk
.wire
!= NULL
)
1442 for (int i
= 0; i
< chunk
.width
; i
++)
1443 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1446 for (auto &it
: module
->wires_
)
1448 RTLIL::Wire
*wire
= it
.second
;
1449 for (int i
= 0; i
< wire
->width
; i
++)
1450 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1451 goto this_wire_aint_reg
;
1453 reg_wires
.insert(wire
->name
);
1454 this_wire_aint_reg
:;
1458 dump_attributes(f
, indent
, module
->attributes
, '\n', true);
1459 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1460 bool keep_running
= true;
1461 for (int port_id
= 1; keep_running
; port_id
++) {
1462 keep_running
= false;
1463 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1464 RTLIL::Wire
*wire
= it
->second
;
1465 if (wire
->port_id
== port_id
) {
1468 f
<< stringf("%s", id(wire
->name
).c_str());
1469 keep_running
= true;
1474 f
<< stringf(");\n");
1476 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1477 dump_wire(f
, indent
+ " ", it
->second
);
1479 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1480 dump_memory(f
, indent
+ " ", it
->second
);
1482 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1483 dump_cell(f
, indent
+ " ", it
->second
);
1485 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1486 dump_process(f
, indent
+ " ", it
->second
);
1488 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1489 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1491 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1492 active_module
= NULL
;
1493 active_sigmap
.clear();
1494 active_initdata
.clear();
1497 struct VerilogBackend
: public Backend
{
1498 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1499 void help() YS_OVERRIDE
1501 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1503 log(" write_verilog [options] [filename]\n");
1505 log("Write the current design to a Verilog file.\n");
1507 log(" -norename\n");
1508 log(" without this option all internal object names (the ones with a dollar\n");
1509 log(" instead of a backslash prefix) are changed to short names in the\n");
1510 log(" format '_<number>_'.\n");
1512 log(" -renameprefix <prefix>\n");
1513 log(" insert this prefix in front of auto-generated instance names\n");
1516 log(" with this option no attributes are included in the output\n");
1518 log(" -attr2comment\n");
1519 log(" with this option attributes are included as comments in the output\n");
1522 log(" without this option all internal cells are converted to Verilog\n");
1523 log(" expressions.\n");
1526 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1527 log(" not bit pattern. This option deactivates this feature and instead\n");
1528 log(" will write out all constants in binary.\n");
1531 log(" dump 32-bit constants in decimal and without size and radix\n");
1534 log(" constant values that are compatible with hex output are usually\n");
1535 log(" dumped as hex values. This option deactivates this feature and\n");
1536 log(" instead will write out all constants in binary.\n");
1539 log(" Parameters and attributes that are specified as strings in the\n");
1540 log(" original input will be output as strings by this back-end. This\n");
1541 log(" deactivates this feature and instead will write string constants\n");
1542 log(" as binary numbers.\n");
1544 log(" -defparam\n");
1545 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1546 log(" cell parameters.\n");
1548 log(" -blackboxes\n");
1549 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1550 log(" this option set only the modules with the 'blackbox' attribute\n");
1551 log(" are written to the output file.\n");
1553 log(" -selected\n");
1554 log(" only write selected modules. modules must be selected entirely or\n");
1555 log(" not at all.\n");
1558 log(" verbose output (print new names of all renamed wires and cells)\n");
1560 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1561 log("always blocks. This frontend should only be used to export an RTLIL\n");
1562 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1563 log("processes to logic networks and registers. A warning is generated when\n");
1564 log("this command is called on a design with RTLIL processes.\n");
1567 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1569 log_header(design
, "Executing Verilog backend.\n");
1574 attr2comment
= false;
1583 bool blackboxes
= false;
1584 bool selected
= false;
1588 reg_ct
.insert("$dff");
1589 reg_ct
.insert("$adff");
1590 reg_ct
.insert("$dffe");
1591 reg_ct
.insert("$dlatch");
1593 reg_ct
.insert("$_DFF_N_");
1594 reg_ct
.insert("$_DFF_P_");
1596 reg_ct
.insert("$_DFF_NN0_");
1597 reg_ct
.insert("$_DFF_NN1_");
1598 reg_ct
.insert("$_DFF_NP0_");
1599 reg_ct
.insert("$_DFF_NP1_");
1600 reg_ct
.insert("$_DFF_PN0_");
1601 reg_ct
.insert("$_DFF_PN1_");
1602 reg_ct
.insert("$_DFF_PP0_");
1603 reg_ct
.insert("$_DFF_PP1_");
1605 reg_ct
.insert("$_DFFSR_NNN_");
1606 reg_ct
.insert("$_DFFSR_NNP_");
1607 reg_ct
.insert("$_DFFSR_NPN_");
1608 reg_ct
.insert("$_DFFSR_NPP_");
1609 reg_ct
.insert("$_DFFSR_PNN_");
1610 reg_ct
.insert("$_DFFSR_PNP_");
1611 reg_ct
.insert("$_DFFSR_PPN_");
1612 reg_ct
.insert("$_DFFSR_PPP_");
1615 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1616 std::string arg
= args
[argidx
];
1617 if (arg
== "-norename") {
1621 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1622 auto_prefix
= args
[++argidx
];
1625 if (arg
== "-noattr") {
1629 if (arg
== "-attr2comment") {
1630 attr2comment
= true;
1633 if (arg
== "-noexpr") {
1637 if (arg
== "-nodec") {
1641 if (arg
== "-nohex") {
1645 if (arg
== "-nostr") {
1649 if (arg
== "-defparam") {
1653 if (arg
== "-decimal") {
1657 if (arg
== "-blackboxes") {
1661 if (arg
== "-selected") {
1671 extra_args(f
, filename
, args
, argidx
);
1675 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1676 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1677 if (it
->second
->get_bool_attribute("\\blackbox") != blackboxes
)
1679 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1680 if (design
->selected_module(it
->first
))
1681 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1684 log("Dumping module `%s'.\n", it
->first
.c_str());
1685 dump_module(*f
, "", it
->second
);
1692 PRIVATE_NAMESPACE_END