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
== "$shift")
683 f
<< stringf("%s" "assign ", indent
.c_str());
684 dump_sigspec(f
, cell
->getPort("\\Y"));
686 if (cell
->getParam("\\B_SIGNED").as_bool())
688 f
<< stringf("$signed(");
689 dump_sigspec(f
, cell
->getPort("\\B"));
691 f
<< stringf(" < 0 ? ");
692 dump_sigspec(f
, cell
->getPort("\\A"));
693 f
<< stringf(" << - ");
694 dump_sigspec(f
, cell
->getPort("\\B"));
696 dump_sigspec(f
, cell
->getPort("\\A"));
697 f
<< stringf(" >> ");
698 dump_sigspec(f
, cell
->getPort("\\B"));
702 dump_sigspec(f
, cell
->getPort("\\A"));
703 f
<< stringf(" >> ");
704 dump_sigspec(f
, cell
->getPort("\\B"));
710 if (cell
->type
== "$shiftx")
712 std::string temp_id
= next_auto_id();
713 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort("\\A"))-1, temp_id
.c_str());
714 dump_sigspec(f
, cell
->getPort("\\A"));
717 f
<< stringf("%s" "assign ", indent
.c_str());
718 dump_sigspec(f
, cell
->getPort("\\Y"));
719 f
<< stringf(" = %s[", temp_id
.c_str());
720 if (cell
->getParam("\\B_SIGNED").as_bool())
721 f
<< stringf("$signed(");
722 dump_sigspec(f
, cell
->getPort("\\B"));
723 if (cell
->getParam("\\B_SIGNED").as_bool())
725 f
<< stringf(" +: %d", cell
->getParam("\\Y_WIDTH").as_int());
726 f
<< stringf("];\n");
730 if (cell
->type
== "$mux")
732 f
<< stringf("%s" "assign ", indent
.c_str());
733 dump_sigspec(f
, cell
->getPort("\\Y"));
735 dump_sigspec(f
, cell
->getPort("\\S"));
737 dump_attributes(f
, "", cell
->attributes
, ' ');
738 dump_sigspec(f
, cell
->getPort("\\B"));
740 dump_sigspec(f
, cell
->getPort("\\A"));
745 if (cell
->type
== "$pmux" || cell
->type
== "$pmux_safe")
747 int width
= cell
->parameters
["\\WIDTH"].as_int();
748 int s_width
= cell
->getPort("\\S").size();
749 std::string func_name
= cellname(cell
);
751 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
752 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
753 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
754 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
756 dump_attributes(f
, indent
+ " ", cell
->attributes
);
757 if (cell
->type
!= "$pmux_safe" && !noattr
)
758 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
759 f
<< stringf("%s" " casez (s)", indent
.c_str());
760 if (cell
->type
!= "$pmux_safe")
761 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
763 for (int i
= 0; i
< s_width
; i
++)
765 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
767 for (int j
= s_width
-1; j
>= 0; j
--)
768 f
<< stringf("%c", j
== i
? '1' : cell
->type
== "$pmux_safe" ? '0' : '?');
771 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
774 f
<< stringf("%s" " default:\n", indent
.c_str());
775 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
777 f
<< stringf("%s" " endcase\n", indent
.c_str());
778 f
<< stringf("%s" "endfunction\n", indent
.c_str());
780 f
<< stringf("%s" "assign ", indent
.c_str());
781 dump_sigspec(f
, cell
->getPort("\\Y"));
782 f
<< stringf(" = %s(", func_name
.c_str());
783 dump_sigspec(f
, cell
->getPort("\\A"));
785 dump_sigspec(f
, cell
->getPort("\\B"));
787 dump_sigspec(f
, cell
->getPort("\\S"));
788 f
<< stringf(");\n");
792 if (cell
->type
== "$tribuf")
794 f
<< stringf("%s" "assign ", indent
.c_str());
795 dump_sigspec(f
, cell
->getPort("\\Y"));
797 dump_sigspec(f
, cell
->getPort("\\EN"));
799 dump_sigspec(f
, cell
->getPort("\\A"));
800 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at("\\WIDTH").as_int());
804 if (cell
->type
== "$slice")
806 f
<< stringf("%s" "assign ", indent
.c_str());
807 dump_sigspec(f
, cell
->getPort("\\Y"));
809 dump_sigspec(f
, cell
->getPort("\\A"));
810 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
814 if (cell
->type
== "$concat")
816 f
<< stringf("%s" "assign ", indent
.c_str());
817 dump_sigspec(f
, cell
->getPort("\\Y"));
818 f
<< stringf(" = { ");
819 dump_sigspec(f
, cell
->getPort("\\B"));
821 dump_sigspec(f
, cell
->getPort("\\A"));
822 f
<< stringf(" };\n");
826 if (cell
->type
== "$lut")
828 f
<< stringf("%s" "assign ", indent
.c_str());
829 dump_sigspec(f
, cell
->getPort("\\Y"));
831 dump_const(f
, cell
->parameters
.at("\\LUT"));
832 f
<< stringf(" >> ");
833 dump_attributes(f
, "", cell
->attributes
, ' ');
834 dump_sigspec(f
, cell
->getPort("\\A"));
839 if (cell
->type
== "$dffsr")
841 SigSpec sig_clk
= cell
->getPort("\\CLK");
842 SigSpec sig_set
= cell
->getPort("\\SET");
843 SigSpec sig_clr
= cell
->getPort("\\CLR");
844 SigSpec sig_d
= cell
->getPort("\\D");
845 SigSpec sig_q
= cell
->getPort("\\Q");
847 int width
= cell
->parameters
["\\WIDTH"].as_int();
848 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
849 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
850 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
852 std::string reg_name
= cellname(cell
);
853 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
855 if (!out_is_reg_wire
) {
856 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
857 dump_reg_init(f
, sig_q
);
861 for (int i
= 0; i
< width
; i
++) {
862 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
863 dump_sigspec(f
, sig_clk
);
864 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
865 dump_sigspec(f
, sig_set
);
866 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
867 dump_sigspec(f
, sig_clr
);
870 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
871 dump_sigspec(f
, sig_clr
);
872 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
874 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
875 dump_sigspec(f
, sig_set
);
876 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
878 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
879 dump_sigspec(f
, sig_d
[i
]);
883 if (!out_is_reg_wire
) {
884 f
<< stringf("%s" "assign ", indent
.c_str());
885 dump_sigspec(f
, sig_q
);
886 f
<< stringf(" = %s;\n", reg_name
.c_str());
892 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
894 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
895 bool pol_clk
, pol_arst
= false, pol_en
= false;
897 sig_clk
= cell
->getPort("\\CLK");
898 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
900 if (cell
->type
== "$adff") {
901 sig_arst
= cell
->getPort("\\ARST");
902 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
903 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
906 if (cell
->type
== "$dffe") {
907 sig_en
= cell
->getPort("\\EN");
908 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
911 std::string reg_name
= cellname(cell
);
912 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
914 if (!out_is_reg_wire
) {
915 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
916 dump_reg_init(f
, cell
->getPort("\\Q"));
920 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
921 dump_sigspec(f
, sig_clk
);
922 if (cell
->type
== "$adff") {
923 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
924 dump_sigspec(f
, sig_arst
);
928 if (cell
->type
== "$adff") {
929 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
930 dump_sigspec(f
, sig_arst
);
932 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
933 dump_sigspec(f
, val_arst
);
935 f
<< stringf("%s" " else\n", indent
.c_str());
938 if (cell
->type
== "$dffe") {
939 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
940 dump_sigspec(f
, sig_en
);
944 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
945 dump_cell_expr_port(f
, cell
, "D", false);
948 if (!out_is_reg_wire
) {
949 f
<< stringf("%s" "assign ", indent
.c_str());
950 dump_sigspec(f
, cell
->getPort("\\Q"));
951 f
<< stringf(" = %s;\n", reg_name
.c_str());
957 if (cell
->type
== "$dlatch")
959 RTLIL::SigSpec sig_en
;
962 sig_en
= cell
->getPort("\\EN");
963 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
965 std::string reg_name
= cellname(cell
);
966 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
968 if (!out_is_reg_wire
) {
969 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
970 dump_reg_init(f
, cell
->getPort("\\Q"));
974 f
<< stringf("%s" "always @*\n", indent
.c_str());
976 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
977 dump_sigspec(f
, sig_en
);
980 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
981 dump_cell_expr_port(f
, cell
, "D", false);
984 if (!out_is_reg_wire
) {
985 f
<< stringf("%s" "assign ", indent
.c_str());
986 dump_sigspec(f
, cell
->getPort("\\Q"));
987 f
<< stringf(" = %s;\n", reg_name
.c_str());
993 if (cell
->type
== "$mem")
995 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
996 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
997 int abits
= cell
->parameters
["\\ABITS"].as_int();
998 int size
= cell
->parameters
["\\SIZE"].as_int();
999 int offset
= cell
->parameters
["\\OFFSET"].as_int();
1000 int width
= cell
->parameters
["\\WIDTH"].as_int();
1001 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
1003 // for memory block make something like:
1004 // reg [7:0] memid [3:0];
1008 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1011 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1012 for (int i
=0; i
<size
; i
++)
1014 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1015 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1016 f
<< stringf(";\n");
1018 f
<< stringf("%s" "end\n", indent
.c_str());
1021 // create a map : "edge clk" -> expressions within that clock domain
1022 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1023 clk_to_lof_body
[""] = std::vector
<std::string
>();
1024 std::string clk_domain_str
;
1025 // create a list of reg declarations
1026 std::vector
<std::string
> lof_reg_declarations
;
1028 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1029 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1030 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1032 for (int i
=0; i
< nread_ports
; i
++)
1034 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1035 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1036 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1037 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1038 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1039 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1040 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1042 std::ostringstream os
;
1043 dump_sigspec(os
, sig_rd_clk
);
1044 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1045 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1046 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1048 if (use_rd_clk
&& !rd_transparent
)
1050 // for clocked read ports make something like:
1051 // reg [..] temp_id;
1052 // always @(posedge clk)
1053 // if (rd_en) temp_id <= array_reg[r_addr];
1054 // assign r_data = temp_id;
1055 std::string temp_id
= next_auto_id();
1056 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1058 std::ostringstream os
;
1059 if (sig_rd_en
!= RTLIL::SigBit(true))
1061 os
<< stringf("if (");
1062 dump_sigspec(os
, sig_rd_en
);
1063 os
<< stringf(") ");
1065 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1066 dump_sigspec(os
, sig_rd_addr
);
1067 os
<< stringf("];\n");
1068 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1071 std::ostringstream os
;
1072 dump_sigspec(os
, sig_rd_data
);
1073 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1074 clk_to_lof_body
[""].push_back(line
);
1077 if (rd_transparent
) {
1078 // for rd-transparent read-ports make something like:
1079 // reg [..] temp_id;
1080 // always @(posedge clk)
1081 // temp_id <= r_addr;
1082 // assign r_data = array_reg[temp_id];
1083 std::string temp_id
= next_auto_id();
1084 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1086 std::ostringstream os
;
1087 dump_sigspec(os
, sig_rd_addr
);
1088 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1089 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1092 std::ostringstream os
;
1093 dump_sigspec(os
, sig_rd_data
);
1094 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1095 clk_to_lof_body
[""].push_back(line
);
1098 // for non-clocked read-ports make something like:
1099 // assign r_data = array_reg[r_addr];
1100 std::ostringstream os
, os2
;
1101 dump_sigspec(os
, sig_rd_data
);
1102 dump_sigspec(os2
, sig_rd_addr
);
1103 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1104 clk_to_lof_body
[""].push_back(line
);
1109 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1110 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1111 bool wr_clk_posedge
;
1114 for (int i
=0; i
< nwrite_ports
; i
++)
1116 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1117 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1118 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1119 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1120 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1122 std::ostringstream os
;
1123 dump_sigspec(os
, sig_wr_clk
);
1124 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1125 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1126 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1128 // make something like:
1129 // always @(posedge clk)
1130 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1132 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1134 int start_i
= i
, width
= 1;
1135 SigBit wen_bit
= sig_wr_en
[i
];
1137 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1140 if (wen_bit
== State::S0
)
1143 std::ostringstream os
;
1144 if (wen_bit
!= State::S1
)
1146 os
<< stringf("if (");
1147 dump_sigspec(os
, wen_bit
);
1148 os
<< stringf(") ");
1150 os
<< stringf("%s[", mem_id
.c_str());
1151 dump_sigspec(os
, sig_wr_addr
);
1152 if (width
== GetSize(sig_wr_en
))
1153 os
<< stringf("] <= ");
1155 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1156 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1157 os
<< stringf(";\n");
1158 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1161 // Output Verilog that looks something like this:
1163 // always @(posedge CLK2) begin
1164 // _3_ <= memory[D1ADDR];
1166 // memory[A1ADDR] <= A1DATA;
1168 // memory[A2ADDR] <= A2DATA;
1171 // always @(negedge CLK1) begin
1173 // memory[C1ADDR] <= C1DATA;
1176 // assign D1DATA = _3_;
1177 // assign D2DATA <= memory[D2ADDR];
1179 // the reg ... definitions
1180 for(auto ®
: lof_reg_declarations
)
1182 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1184 // the block of expressions by clock domain
1185 for(auto &pair
: clk_to_lof_body
)
1187 std::string clk_domain
= pair
.first
;
1188 std::vector
<std::string
> lof_lines
= pair
.second
;
1189 if( clk_domain
!= "")
1191 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1192 for(auto &line
: lof_lines
)
1193 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1194 f
<< stringf("%s" "end\n", indent
.c_str());
1198 // the non-clocked assignments
1199 for(auto &line
: lof_lines
)
1200 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1207 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1208 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1213 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1215 if (cell
->type
[0] == '$' && !noexpr
) {
1216 if (dump_cell_expr(f
, indent
, cell
))
1220 dump_attributes(f
, indent
, cell
->attributes
);
1221 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1223 if (!defparam
&& cell
->parameters
.size() > 0) {
1224 f
<< stringf(" #(");
1225 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1226 if (it
!= cell
->parameters
.begin())
1228 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1229 bool is_signed
= (it
->second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
1230 dump_const(f
, it
->second
, -1, 0, false, is_signed
);
1233 f
<< stringf("\n%s" ")", indent
.c_str());
1236 std::string cell_name
= cellname(cell
);
1237 if (cell_name
!= id(cell
->name
))
1238 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1240 f
<< stringf(" %s (", cell_name
.c_str());
1242 bool first_arg
= true;
1243 std::set
<RTLIL::IdString
> numbered_ports
;
1244 for (int i
= 1; true; i
++) {
1246 snprintf(str
, 16, "$%d", i
);
1247 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1248 if (it
->first
!= str
)
1253 f
<< stringf("\n%s ", indent
.c_str());
1254 dump_sigspec(f
, it
->second
);
1255 numbered_ports
.insert(it
->first
);
1256 goto found_numbered_port
;
1259 found_numbered_port
:;
1261 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1262 if (numbered_ports
.count(it
->first
))
1267 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1268 if (it
->second
.size() > 0)
1269 dump_sigspec(f
, it
->second
);
1272 f
<< stringf("\n%s" ");\n", indent
.c_str());
1274 if (defparam
&& cell
->parameters
.size() > 0) {
1275 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1276 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1277 bool is_signed
= (it
->second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
1278 dump_const(f
, it
->second
, -1, 0, false, is_signed
);
1279 f
<< stringf(";\n");
1285 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1287 f
<< stringf("%s" "assign ", indent
.c_str());
1288 dump_sigspec(f
, left
);
1289 f
<< stringf(" = ");
1290 dump_sigspec(f
, right
);
1291 f
<< stringf(";\n");
1294 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1296 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1298 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1300 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1301 f
<< stringf("%s" "begin\n", indent
.c_str());
1303 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1304 if (it
->first
.size() == 0)
1306 f
<< stringf("%s ", indent
.c_str());
1307 dump_sigspec(f
, it
->first
);
1308 f
<< stringf(" = ");
1309 dump_sigspec(f
, it
->second
);
1310 f
<< stringf(";\n");
1313 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1314 dump_proc_switch(f
, indent
+ " ", *it
);
1316 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1317 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1319 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1320 f
<< stringf("%s" "end\n", indent
.c_str());
1323 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1325 if (sw
->signal
.size() == 0) {
1326 f
<< stringf("%s" "begin\n", indent
.c_str());
1327 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1328 if ((*it
)->compare
.size() == 0)
1329 dump_case_body(f
, indent
+ " ", *it
);
1331 f
<< stringf("%s" "end\n", indent
.c_str());
1335 f
<< stringf("%s" "casez (", indent
.c_str());
1336 dump_sigspec(f
, sw
->signal
);
1337 f
<< stringf(")\n");
1339 bool got_default
= false;
1340 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1341 if ((*it
)->compare
.size() == 0) {
1344 f
<< stringf("%s default", indent
.c_str());
1347 f
<< stringf("%s ", indent
.c_str());
1348 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1351 dump_sigspec(f
, (*it
)->compare
[i
]);
1354 f
<< stringf(":\n");
1355 dump_case_body(f
, indent
+ " ", *it
);
1358 f
<< stringf("%s" "endcase\n", indent
.c_str());
1361 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1363 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1364 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1365 case_body_find_regs(*it2
);
1367 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1368 for (auto &c
: it
->first
.chunks())
1370 reg_wires
.insert(c
.wire
->name
);
1374 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1377 case_body_find_regs(&proc
->root_case
);
1378 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1379 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1380 for (auto &c
: it2
->first
.chunks())
1382 reg_wires
.insert(c
.wire
->name
);
1387 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1388 dump_case_body(f
, indent
, &proc
->root_case
, true);
1390 std::string backup_indent
= indent
;
1392 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1394 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1395 indent
= backup_indent
;
1397 if (sync
->type
== RTLIL::STa
) {
1398 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1399 } else if (sync
->type
== RTLIL::STi
) {
1400 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1402 f
<< stringf("%s" "always @(", indent
.c_str());
1403 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1404 f
<< stringf("posedge ");
1405 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1406 f
<< stringf("negedge ");
1407 dump_sigspec(f
, sync
->signal
);
1408 f
<< stringf(") begin\n");
1410 std::string ends
= indent
+ "end\n";
1413 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1414 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1415 dump_sigspec(f
, sync
->signal
);
1416 f
<< stringf(") begin\n");
1417 ends
= indent
+ "end\n" + ends
;
1421 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1422 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1423 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1424 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1425 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1426 dump_sigspec(f
, sync2
->signal
);
1427 f
<< stringf(") begin\n");
1428 ends
= indent
+ "end\n" + ends
;
1434 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1435 if (it
->first
.size() == 0)
1437 f
<< stringf("%s ", indent
.c_str());
1438 dump_sigspec(f
, it
->first
);
1439 f
<< stringf(" <= ");
1440 dump_sigspec(f
, it
->second
);
1441 f
<< stringf(";\n");
1444 f
<< stringf("%s", ends
.c_str());
1448 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1451 reset_auto_counter(module
);
1452 active_module
= module
;
1453 active_sigmap
.set(module
);
1454 active_initdata
.clear();
1456 for (auto wire
: module
->wires())
1457 if (wire
->attributes
.count("\\init")) {
1458 SigSpec sig
= active_sigmap(wire
);
1459 Const val
= wire
->attributes
.at("\\init");
1460 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1461 active_initdata
[sig
[i
]] = val
.bits
.at(i
);
1464 if (!module
->processes
.empty())
1465 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1466 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1467 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1468 "processes to logic networks and registers.\n", log_id(module
));
1471 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1472 dump_process(f
, indent
+ " ", it
->second
, true);
1476 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1477 for (auto &it
: module
->cells_
)
1479 RTLIL::Cell
*cell
= it
.second
;
1480 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1483 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1485 if (sig
.is_chunk()) {
1486 RTLIL::SigChunk chunk
= sig
.as_chunk();
1487 if (chunk
.wire
!= NULL
)
1488 for (int i
= 0; i
< chunk
.width
; i
++)
1489 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1492 for (auto &it
: module
->wires_
)
1494 RTLIL::Wire
*wire
= it
.second
;
1495 for (int i
= 0; i
< wire
->width
; i
++)
1496 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1497 goto this_wire_aint_reg
;
1499 reg_wires
.insert(wire
->name
);
1500 this_wire_aint_reg
:;
1504 dump_attributes(f
, indent
, module
->attributes
, '\n', true);
1505 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1506 bool keep_running
= true;
1507 for (int port_id
= 1; keep_running
; port_id
++) {
1508 keep_running
= false;
1509 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1510 RTLIL::Wire
*wire
= it
->second
;
1511 if (wire
->port_id
== port_id
) {
1514 f
<< stringf("%s", id(wire
->name
).c_str());
1515 keep_running
= true;
1520 f
<< stringf(");\n");
1522 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1523 dump_wire(f
, indent
+ " ", it
->second
);
1525 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1526 dump_memory(f
, indent
+ " ", it
->second
);
1528 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1529 dump_cell(f
, indent
+ " ", it
->second
);
1531 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1532 dump_process(f
, indent
+ " ", it
->second
);
1534 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1535 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1537 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1538 active_module
= NULL
;
1539 active_sigmap
.clear();
1540 active_initdata
.clear();
1543 struct VerilogBackend
: public Backend
{
1544 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1545 void help() YS_OVERRIDE
1547 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1549 log(" write_verilog [options] [filename]\n");
1551 log("Write the current design to a Verilog file.\n");
1553 log(" -norename\n");
1554 log(" without this option all internal object names (the ones with a dollar\n");
1555 log(" instead of a backslash prefix) are changed to short names in the\n");
1556 log(" format '_<number>_'.\n");
1558 log(" -renameprefix <prefix>\n");
1559 log(" insert this prefix in front of auto-generated instance names\n");
1562 log(" with this option no attributes are included in the output\n");
1564 log(" -attr2comment\n");
1565 log(" with this option attributes are included as comments in the output\n");
1568 log(" without this option all internal cells are converted to Verilog\n");
1569 log(" expressions.\n");
1572 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1573 log(" not bit pattern. This option deactivates this feature and instead\n");
1574 log(" will write out all constants in binary.\n");
1577 log(" dump 32-bit constants in decimal and without size and radix\n");
1580 log(" constant values that are compatible with hex output are usually\n");
1581 log(" dumped as hex values. This option deactivates this feature and\n");
1582 log(" instead will write out all constants in binary.\n");
1585 log(" Parameters and attributes that are specified as strings in the\n");
1586 log(" original input will be output as strings by this back-end. This\n");
1587 log(" deactivates this feature and instead will write string constants\n");
1588 log(" as binary numbers.\n");
1590 log(" -defparam\n");
1591 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1592 log(" cell parameters.\n");
1594 log(" -blackboxes\n");
1595 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1596 log(" this option set only the modules with the 'blackbox' attribute\n");
1597 log(" are written to the output file.\n");
1599 log(" -selected\n");
1600 log(" only write selected modules. modules must be selected entirely or\n");
1601 log(" not at all.\n");
1604 log(" verbose output (print new names of all renamed wires and cells)\n");
1606 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1607 log("always blocks. This frontend should only be used to export an RTLIL\n");
1608 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1609 log("processes to logic networks and registers. A warning is generated when\n");
1610 log("this command is called on a design with RTLIL processes.\n");
1613 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1615 log_header(design
, "Executing Verilog backend.\n");
1620 attr2comment
= false;
1629 bool blackboxes
= false;
1630 bool selected
= false;
1634 reg_ct
.insert("$dff");
1635 reg_ct
.insert("$adff");
1636 reg_ct
.insert("$dffe");
1637 reg_ct
.insert("$dlatch");
1639 reg_ct
.insert("$_DFF_N_");
1640 reg_ct
.insert("$_DFF_P_");
1642 reg_ct
.insert("$_DFF_NN0_");
1643 reg_ct
.insert("$_DFF_NN1_");
1644 reg_ct
.insert("$_DFF_NP0_");
1645 reg_ct
.insert("$_DFF_NP1_");
1646 reg_ct
.insert("$_DFF_PN0_");
1647 reg_ct
.insert("$_DFF_PN1_");
1648 reg_ct
.insert("$_DFF_PP0_");
1649 reg_ct
.insert("$_DFF_PP1_");
1651 reg_ct
.insert("$_DFFSR_NNN_");
1652 reg_ct
.insert("$_DFFSR_NNP_");
1653 reg_ct
.insert("$_DFFSR_NPN_");
1654 reg_ct
.insert("$_DFFSR_NPP_");
1655 reg_ct
.insert("$_DFFSR_PNN_");
1656 reg_ct
.insert("$_DFFSR_PNP_");
1657 reg_ct
.insert("$_DFFSR_PPN_");
1658 reg_ct
.insert("$_DFFSR_PPP_");
1661 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1662 std::string arg
= args
[argidx
];
1663 if (arg
== "-norename") {
1667 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1668 auto_prefix
= args
[++argidx
];
1671 if (arg
== "-noattr") {
1675 if (arg
== "-attr2comment") {
1676 attr2comment
= true;
1679 if (arg
== "-noexpr") {
1683 if (arg
== "-nodec") {
1687 if (arg
== "-nohex") {
1691 if (arg
== "-nostr") {
1695 if (arg
== "-defparam") {
1699 if (arg
== "-decimal") {
1703 if (arg
== "-blackboxes") {
1707 if (arg
== "-selected") {
1717 extra_args(f
, filename
, args
, argidx
);
1721 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1722 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1723 if (it
->second
->get_bool_attribute("\\blackbox") != blackboxes
)
1725 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1726 if (design
->selected_module(it
->first
))
1727 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1730 log("Dumping module `%s'.\n", it
->first
.c_str());
1731 dump_module(*f
, "", it
->second
);
1738 PRIVATE_NAMESPACE_END