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
, siminit
;
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')
129 const pool
<string
> keywords
= {
130 // IEEE 1800-2017 Annex B
131 "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
132 "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
133 "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
134 "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
135 "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
136 "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
137 "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
138 "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
139 "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
140 "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
141 "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
142 "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
143 "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
144 "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
145 "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
146 "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
147 "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
148 "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
149 "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
150 "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
151 "wildcard", "wire", "with", "within", "wor", "xnor", "xor",
153 if (keywords
.count(str
))
157 return "\\" + std::string(str
) + " ";
158 return std::string(str
);
161 bool is_reg_wire(RTLIL::SigSpec sig
, std::string
®_name
)
163 if (!sig
.is_chunk() || sig
.as_chunk().wire
== NULL
)
166 RTLIL::SigChunk chunk
= sig
.as_chunk();
168 if (reg_wires
.count(chunk
.wire
->name
) == 0)
171 reg_name
= id(chunk
.wire
->name
);
172 if (sig
.size() != chunk
.wire
->width
) {
174 reg_name
+= stringf("[%d]", chunk
.wire
->start_offset
+ chunk
.offset
);
175 else if (chunk
.wire
->upto
)
176 reg_name
+= stringf("[%d:%d]", (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
177 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
179 reg_name
+= stringf("[%d:%d]", chunk
.wire
->start_offset
+ chunk
.offset
+ chunk
.width
- 1,
180 chunk
.wire
->start_offset
+ chunk
.offset
);
186 void dump_const(std::ostream
&f
, const RTLIL::Const
&data
, int width
= -1, int offset
= 0, bool no_decimal
= false, bool escape_comment
= false)
188 bool set_signed
= (data
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
190 width
= data
.bits
.size() - offset
;
197 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
198 if (width
== 32 && !no_decimal
&& !nodec
) {
200 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
201 log_assert(i
< (int)data
.bits
.size());
202 if (data
.bits
[i
] != RTLIL::S0
&& data
.bits
[i
] != RTLIL::S1
)
204 if (data
.bits
[i
] == RTLIL::S1
)
205 val
|= 1 << (i
- offset
);
208 f
<< stringf("%d", val
);
209 else if (set_signed
&& val
< 0)
210 f
<< stringf("-32'sd%u", -val
);
212 f
<< stringf("32'%sd%u", set_signed
? "s" : "", val
);
217 vector
<char> bin_digits
, hex_digits
;
218 for (int i
= offset
; i
< offset
+width
; i
++) {
219 log_assert(i
< (int)data
.bits
.size());
220 switch (data
.bits
[i
]) {
221 case RTLIL::S0
: bin_digits
.push_back('0'); break;
222 case RTLIL::S1
: bin_digits
.push_back('1'); break;
223 case RTLIL::Sx
: bin_digits
.push_back('x'); break;
224 case RTLIL::Sz
: bin_digits
.push_back('z'); break;
225 case RTLIL::Sa
: bin_digits
.push_back('z'); break;
226 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
229 if (GetSize(bin_digits
) == 0)
231 while (GetSize(bin_digits
) % 4 != 0)
232 if (bin_digits
.back() == '1')
233 bin_digits
.push_back('0');
235 bin_digits
.push_back(bin_digits
.back());
236 for (int i
= 0; i
< GetSize(bin_digits
); i
+= 4)
238 char bit_3
= bin_digits
[i
+3];
239 char bit_2
= bin_digits
[i
+2];
240 char bit_1
= bin_digits
[i
+1];
241 char bit_0
= bin_digits
[i
+0];
242 if (bit_3
== 'x' || bit_2
== 'x' || bit_1
== 'x' || bit_0
== 'x') {
243 if (bit_3
!= 'x' || bit_2
!= 'x' || bit_1
!= 'x' || bit_0
!= 'x')
245 hex_digits
.push_back('x');
248 if (bit_3
== 'z' || bit_2
== 'z' || bit_1
== 'z' || bit_0
== 'z') {
249 if (bit_3
!= 'z' || bit_2
!= 'z' || bit_1
!= 'z' || bit_0
!= 'z')
251 hex_digits
.push_back('z');
254 int val
= 8*(bit_3
- '0') + 4*(bit_2
- '0') + 2*(bit_1
- '0') + (bit_0
- '0');
255 hex_digits
.push_back(val
< 10 ? '0' + val
: 'a' + val
- 10);
257 f
<< stringf("%d'%sh", width
, set_signed
? "s" : "");
258 for (int i
= GetSize(hex_digits
)-1; i
>= 0; i
--)
263 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
266 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
267 log_assert(i
< (int)data
.bits
.size());
268 switch (data
.bits
[i
]) {
269 case RTLIL::S0
: f
<< stringf("0"); break;
270 case RTLIL::S1
: f
<< stringf("1"); break;
271 case RTLIL::Sx
: f
<< stringf("x"); break;
272 case RTLIL::Sz
: f
<< stringf("z"); break;
273 case RTLIL::Sa
: f
<< stringf("z"); break;
274 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
279 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
281 std::string str
= data
.decode_string();
282 for (size_t i
= 0; i
< str
.size(); i
++) {
285 else if (str
[i
] == '\t')
287 else if (str
[i
] < 32)
288 f
<< stringf("\\%03o", str
[i
]);
289 else if (str
[i
] == '"')
290 f
<< stringf("\\\"");
291 else if (str
[i
] == '\\')
292 f
<< stringf("\\\\");
293 else if (str
[i
] == '/' && escape_comment
&& i
> 0 && str
[i
-1] == '*')
298 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
303 void dump_reg_init(std::ostream
&f
, SigSpec sig
)
306 bool gotinit
= false;
308 for (auto bit
: active_sigmap(sig
)) {
309 if (active_initdata
.count(bit
)) {
310 initval
.bits
.push_back(active_initdata
.at(bit
));
313 initval
.bits
.push_back(State::Sx
);
319 dump_const(f
, initval
);
323 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
325 if (chunk
.wire
== NULL
) {
326 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
328 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0) {
329 f
<< stringf("%s", id(chunk
.wire
->name
).c_str());
330 } else if (chunk
.width
== 1) {
331 if (chunk
.wire
->upto
)
332 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
334 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
336 if (chunk
.wire
->upto
)
337 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
338 (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
339 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
341 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
342 (chunk
.offset
+ chunk
.width
- 1) + chunk
.wire
->start_offset
,
343 chunk
.offset
+ chunk
.wire
->start_offset
);
348 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
350 if (GetSize(sig
) == 0) {
354 if (sig
.is_chunk()) {
355 dump_sigchunk(f
, sig
.as_chunk());
358 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
359 if (it
!= sig
.chunks().rbegin())
361 dump_sigchunk(f
, *it
, true);
367 void dump_attributes(std::ostream
&f
, std::string indent
, dict
<RTLIL::IdString
, RTLIL::Const
> &attributes
, char term
= '\n', bool modattr
= false, bool as_comment
= false)
373 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
374 f
<< stringf("%s" "%s %s", indent
.c_str(), as_comment
? "/*" : "(*", id(it
->first
).c_str());
376 if (modattr
&& (it
->second
== Const(0, 1) || it
->second
== Const(0)))
378 else if (modattr
&& (it
->second
== Const(1, 1) || it
->second
== Const(1)))
381 dump_const(f
, it
->second
, -1, 0, false, as_comment
);
382 f
<< stringf(" %s%c", as_comment
? "*/" : "*)", term
);
386 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
388 dump_attributes(f
, indent
, wire
->attributes
);
390 if (wire
->port_input
&& !wire
->port_output
)
391 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
392 else if (!wire
->port_input
&& wire
->port_output
)
393 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
394 else if (wire
->port_input
&& wire
->port_output
)
395 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
397 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
398 if (wire
->width
!= 1)
399 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
400 f
<< stringf("%s;\n", id(wire
->name
).c_str());
402 // do not use Verilog-2k "output reg" syntax in Verilog export
403 std::string range
= "";
404 if (wire
->width
!= 1) {
406 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
408 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
410 if (wire
->port_input
&& !wire
->port_output
)
411 f
<< stringf("%s" "input%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
412 if (!wire
->port_input
&& wire
->port_output
)
413 f
<< stringf("%s" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
414 if (wire
->port_input
&& wire
->port_output
)
415 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
416 if (reg_wires
.count(wire
->name
)) {
417 f
<< stringf("%s" "reg%s %s", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
418 if (wire
->attributes
.count("\\init")) {
420 dump_const(f
, wire
->attributes
.at("\\init"));
423 } else if (!wire
->port_input
&& !wire
->port_output
)
424 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
428 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
430 dump_attributes(f
, indent
, memory
->attributes
);
431 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
);
434 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
436 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
437 f
<< stringf("$signed(");
438 dump_sigspec(f
, cell
->getPort("\\" + port
));
441 dump_sigspec(f
, cell
->getPort("\\" + port
));
444 std::string
cellname(RTLIL::Cell
*cell
)
446 if (!norename
&& cell
->name
[0] == '$' && reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q"))
448 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
449 if (GetSize(sig
) != 1 || sig
.is_fully_const())
450 goto no_special_reg_name
;
452 RTLIL::Wire
*wire
= sig
[0].wire
;
454 if (wire
->name
[0] != '\\')
455 goto no_special_reg_name
;
457 std::string cell_name
= wire
->name
.str();
459 size_t pos
= cell_name
.find('[');
460 if (pos
!= std::string::npos
)
461 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
463 cell_name
= cell_name
+ "_reg";
465 if (wire
->width
!= 1)
466 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
468 if (active_module
&& active_module
->count_id(cell_name
) > 0)
469 goto no_special_reg_name
;
471 return id(cell_name
);
476 return id(cell
->name
).c_str();
480 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
482 f
<< stringf("%s" "assign ", indent
.c_str());
483 dump_sigspec(f
, cell
->getPort("\\Y"));
484 f
<< stringf(" = %s ", op
.c_str());
485 dump_attributes(f
, "", cell
->attributes
, ' ');
486 dump_cell_expr_port(f
, cell
, "A", true);
490 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
492 f
<< stringf("%s" "assign ", indent
.c_str());
493 dump_sigspec(f
, cell
->getPort("\\Y"));
495 dump_cell_expr_port(f
, cell
, "A", true);
496 f
<< stringf(" %s ", op
.c_str());
497 dump_attributes(f
, "", cell
->attributes
, ' ');
498 dump_cell_expr_port(f
, cell
, "B", true);
502 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
504 if (cell
->type
== "$_NOT_") {
505 f
<< stringf("%s" "assign ", indent
.c_str());
506 dump_sigspec(f
, cell
->getPort("\\Y"));
509 dump_attributes(f
, "", cell
->attributes
, ' ');
510 dump_cell_expr_port(f
, cell
, "A", false);
515 if (cell
->type
.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
516 f
<< stringf("%s" "assign ", indent
.c_str());
517 dump_sigspec(f
, cell
->getPort("\\Y"));
519 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
521 dump_cell_expr_port(f
, cell
, "A", false);
523 if (cell
->type
.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
525 if (cell
->type
.in("$_OR_", "$_NOR_", "$_ORNOT_"))
527 if (cell
->type
.in("$_XOR_", "$_XNOR_"))
529 dump_attributes(f
, "", cell
->attributes
, ' ');
531 if (cell
->type
.in("$_ANDNOT_", "$_ORNOT_"))
533 dump_cell_expr_port(f
, cell
, "B", false);
534 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
540 if (cell
->type
== "$_MUX_") {
541 f
<< stringf("%s" "assign ", indent
.c_str());
542 dump_sigspec(f
, cell
->getPort("\\Y"));
544 dump_cell_expr_port(f
, cell
, "S", false);
546 dump_attributes(f
, "", cell
->attributes
, ' ');
547 dump_cell_expr_port(f
, cell
, "B", false);
549 dump_cell_expr_port(f
, cell
, "A", false);
554 if (cell
->type
.in("$_AOI3_", "$_OAI3_")) {
555 f
<< stringf("%s" "assign ", indent
.c_str());
556 dump_sigspec(f
, cell
->getPort("\\Y"));
557 f
<< stringf(" = ~((");
558 dump_cell_expr_port(f
, cell
, "A", false);
559 f
<< stringf(cell
->type
== "$_AOI3_" ? " & " : " | ");
560 dump_cell_expr_port(f
, cell
, "B", false);
561 f
<< stringf(cell
->type
== "$_AOI3_" ? ") |" : ") &");
562 dump_attributes(f
, "", cell
->attributes
, ' ');
564 dump_cell_expr_port(f
, cell
, "C", false);
565 f
<< stringf(");\n");
569 if (cell
->type
.in("$_AOI4_", "$_OAI4_")) {
570 f
<< stringf("%s" "assign ", indent
.c_str());
571 dump_sigspec(f
, cell
->getPort("\\Y"));
572 f
<< stringf(" = ~((");
573 dump_cell_expr_port(f
, cell
, "A", false);
574 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
575 dump_cell_expr_port(f
, cell
, "B", false);
576 f
<< stringf(cell
->type
== "$_AOI4_" ? ") |" : ") &");
577 dump_attributes(f
, "", cell
->attributes
, ' ');
579 dump_cell_expr_port(f
, cell
, "C", false);
580 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
581 dump_cell_expr_port(f
, cell
, "D", false);
582 f
<< stringf("));\n");
586 if (cell
->type
.substr(0, 6) == "$_DFF_")
588 std::string reg_name
= cellname(cell
);
589 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
591 if (!out_is_reg_wire
) {
592 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
593 dump_reg_init(f
, cell
->getPort("\\Q"));
597 dump_attributes(f
, indent
, cell
->attributes
);
598 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), cell
->type
[6] == 'P' ? "pos" : "neg");
599 dump_sigspec(f
, cell
->getPort("\\C"));
600 if (cell
->type
[7] != '_') {
601 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
602 dump_sigspec(f
, cell
->getPort("\\R"));
606 if (cell
->type
[7] != '_') {
607 f
<< stringf("%s" " if (%s", indent
.c_str(), cell
->type
[7] == 'P' ? "" : "!");
608 dump_sigspec(f
, cell
->getPort("\\R"));
610 f
<< stringf("%s" " %s <= %c;\n", indent
.c_str(), reg_name
.c_str(), cell
->type
[8]);
611 f
<< stringf("%s" " else\n", indent
.c_str());
614 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
615 dump_cell_expr_port(f
, cell
, "D", false);
618 if (!out_is_reg_wire
) {
619 f
<< stringf("%s" "assign ", indent
.c_str());
620 dump_sigspec(f
, cell
->getPort("\\Q"));
621 f
<< stringf(" = %s;\n", reg_name
.c_str());
627 if (cell
->type
.substr(0, 8) == "$_DFFSR_")
629 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
631 std::string reg_name
= cellname(cell
);
632 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
634 if (!out_is_reg_wire
) {
635 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
636 dump_reg_init(f
, cell
->getPort("\\Q"));
640 dump_attributes(f
, indent
, cell
->attributes
);
641 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_c
== 'P' ? "pos" : "neg");
642 dump_sigspec(f
, cell
->getPort("\\C"));
643 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
644 dump_sigspec(f
, cell
->getPort("\\S"));
645 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
646 dump_sigspec(f
, cell
->getPort("\\R"));
649 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
650 dump_sigspec(f
, cell
->getPort("\\R"));
652 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
654 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
655 dump_sigspec(f
, cell
->getPort("\\S"));
657 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
659 f
<< stringf("%s" " else\n", indent
.c_str());
660 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
661 dump_cell_expr_port(f
, cell
, "D", false);
664 if (!out_is_reg_wire
) {
665 f
<< stringf("%s" "assign ", indent
.c_str());
666 dump_sigspec(f
, cell
->getPort("\\Q"));
667 f
<< stringf(" = %s;\n", reg_name
.c_str());
673 #define HANDLE_UNIOP(_type, _operator) \
674 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
675 #define HANDLE_BINOP(_type, _operator) \
676 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
678 HANDLE_UNIOP("$not", "~")
679 HANDLE_UNIOP("$pos", "+")
680 HANDLE_UNIOP("$neg", "-")
682 HANDLE_BINOP("$and", "&")
683 HANDLE_BINOP("$or", "|")
684 HANDLE_BINOP("$xor", "^")
685 HANDLE_BINOP("$xnor", "~^")
687 HANDLE_UNIOP("$reduce_and", "&")
688 HANDLE_UNIOP("$reduce_or", "|")
689 HANDLE_UNIOP("$reduce_xor", "^")
690 HANDLE_UNIOP("$reduce_xnor", "~^")
691 HANDLE_UNIOP("$reduce_bool", "|")
693 HANDLE_BINOP("$shl", "<<")
694 HANDLE_BINOP("$shr", ">>")
695 HANDLE_BINOP("$sshl", "<<<")
696 HANDLE_BINOP("$sshr", ">>>")
698 HANDLE_BINOP("$lt", "<")
699 HANDLE_BINOP("$le", "<=")
700 HANDLE_BINOP("$eq", "==")
701 HANDLE_BINOP("$ne", "!=")
702 HANDLE_BINOP("$eqx", "===")
703 HANDLE_BINOP("$nex", "!==")
704 HANDLE_BINOP("$ge", ">=")
705 HANDLE_BINOP("$gt", ">")
707 HANDLE_BINOP("$add", "+")
708 HANDLE_BINOP("$sub", "-")
709 HANDLE_BINOP("$mul", "*")
710 HANDLE_BINOP("$div", "/")
711 HANDLE_BINOP("$mod", "%")
712 HANDLE_BINOP("$pow", "**")
714 HANDLE_UNIOP("$logic_not", "!")
715 HANDLE_BINOP("$logic_and", "&&")
716 HANDLE_BINOP("$logic_or", "||")
721 if (cell
->type
== "$shift")
723 f
<< stringf("%s" "assign ", indent
.c_str());
724 dump_sigspec(f
, cell
->getPort("\\Y"));
726 if (cell
->getParam("\\B_SIGNED").as_bool())
728 f
<< stringf("$signed(");
729 dump_sigspec(f
, cell
->getPort("\\B"));
731 f
<< stringf(" < 0 ? ");
732 dump_sigspec(f
, cell
->getPort("\\A"));
733 f
<< stringf(" << - ");
734 dump_sigspec(f
, cell
->getPort("\\B"));
736 dump_sigspec(f
, cell
->getPort("\\A"));
737 f
<< stringf(" >> ");
738 dump_sigspec(f
, cell
->getPort("\\B"));
742 dump_sigspec(f
, cell
->getPort("\\A"));
743 f
<< stringf(" >> ");
744 dump_sigspec(f
, cell
->getPort("\\B"));
750 if (cell
->type
== "$shiftx")
752 std::string temp_id
= next_auto_id();
753 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort("\\A"))-1, temp_id
.c_str());
754 dump_sigspec(f
, cell
->getPort("\\A"));
757 f
<< stringf("%s" "assign ", indent
.c_str());
758 dump_sigspec(f
, cell
->getPort("\\Y"));
759 f
<< stringf(" = %s[", temp_id
.c_str());
760 if (cell
->getParam("\\B_SIGNED").as_bool())
761 f
<< stringf("$signed(");
762 dump_sigspec(f
, cell
->getPort("\\B"));
763 if (cell
->getParam("\\B_SIGNED").as_bool())
765 f
<< stringf(" +: %d", cell
->getParam("\\Y_WIDTH").as_int());
766 f
<< stringf("];\n");
770 if (cell
->type
== "$mux")
772 f
<< stringf("%s" "assign ", indent
.c_str());
773 dump_sigspec(f
, cell
->getPort("\\Y"));
775 dump_sigspec(f
, cell
->getPort("\\S"));
777 dump_attributes(f
, "", cell
->attributes
, ' ');
778 dump_sigspec(f
, cell
->getPort("\\B"));
780 dump_sigspec(f
, cell
->getPort("\\A"));
785 if (cell
->type
== "$pmux" || cell
->type
== "$pmux_safe")
787 int width
= cell
->parameters
["\\WIDTH"].as_int();
788 int s_width
= cell
->getPort("\\S").size();
789 std::string func_name
= cellname(cell
);
791 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
792 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
793 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
794 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
796 dump_attributes(f
, indent
+ " ", cell
->attributes
);
797 if (cell
->type
!= "$pmux_safe" && !noattr
)
798 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
799 f
<< stringf("%s" " casez (s)", indent
.c_str());
800 if (cell
->type
!= "$pmux_safe")
801 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
803 for (int i
= 0; i
< s_width
; i
++)
805 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
807 for (int j
= s_width
-1; j
>= 0; j
--)
808 f
<< stringf("%c", j
== i
? '1' : cell
->type
== "$pmux_safe" ? '0' : '?');
811 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
814 f
<< stringf("%s" " default:\n", indent
.c_str());
815 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
817 f
<< stringf("%s" " endcase\n", indent
.c_str());
818 f
<< stringf("%s" "endfunction\n", indent
.c_str());
820 f
<< stringf("%s" "assign ", indent
.c_str());
821 dump_sigspec(f
, cell
->getPort("\\Y"));
822 f
<< stringf(" = %s(", func_name
.c_str());
823 dump_sigspec(f
, cell
->getPort("\\A"));
825 dump_sigspec(f
, cell
->getPort("\\B"));
827 dump_sigspec(f
, cell
->getPort("\\S"));
828 f
<< stringf(");\n");
832 if (cell
->type
== "$tribuf")
834 f
<< stringf("%s" "assign ", indent
.c_str());
835 dump_sigspec(f
, cell
->getPort("\\Y"));
837 dump_sigspec(f
, cell
->getPort("\\EN"));
839 dump_sigspec(f
, cell
->getPort("\\A"));
840 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at("\\WIDTH").as_int());
844 if (cell
->type
== "$slice")
846 f
<< stringf("%s" "assign ", indent
.c_str());
847 dump_sigspec(f
, cell
->getPort("\\Y"));
849 dump_sigspec(f
, cell
->getPort("\\A"));
850 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
854 if (cell
->type
== "$concat")
856 f
<< stringf("%s" "assign ", indent
.c_str());
857 dump_sigspec(f
, cell
->getPort("\\Y"));
858 f
<< stringf(" = { ");
859 dump_sigspec(f
, cell
->getPort("\\B"));
861 dump_sigspec(f
, cell
->getPort("\\A"));
862 f
<< stringf(" };\n");
866 if (cell
->type
== "$lut")
868 f
<< stringf("%s" "assign ", indent
.c_str());
869 dump_sigspec(f
, cell
->getPort("\\Y"));
871 dump_const(f
, cell
->parameters
.at("\\LUT"));
872 f
<< stringf(" >> ");
873 dump_attributes(f
, "", cell
->attributes
, ' ');
874 dump_sigspec(f
, cell
->getPort("\\A"));
879 if (cell
->type
== "$dffsr")
881 SigSpec sig_clk
= cell
->getPort("\\CLK");
882 SigSpec sig_set
= cell
->getPort("\\SET");
883 SigSpec sig_clr
= cell
->getPort("\\CLR");
884 SigSpec sig_d
= cell
->getPort("\\D");
885 SigSpec sig_q
= cell
->getPort("\\Q");
887 int width
= cell
->parameters
["\\WIDTH"].as_int();
888 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
889 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
890 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
892 std::string reg_name
= cellname(cell
);
893 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
895 if (!out_is_reg_wire
) {
896 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
897 dump_reg_init(f
, sig_q
);
901 for (int i
= 0; i
< width
; i
++) {
902 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
903 dump_sigspec(f
, sig_clk
);
904 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
905 dump_sigspec(f
, sig_set
);
906 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
907 dump_sigspec(f
, sig_clr
);
910 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
911 dump_sigspec(f
, sig_clr
);
912 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
914 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
915 dump_sigspec(f
, sig_set
);
916 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
918 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
919 dump_sigspec(f
, sig_d
[i
]);
923 if (!out_is_reg_wire
) {
924 f
<< stringf("%s" "assign ", indent
.c_str());
925 dump_sigspec(f
, sig_q
);
926 f
<< stringf(" = %s;\n", reg_name
.c_str());
932 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
934 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
935 bool pol_clk
, pol_arst
= false, pol_en
= false;
937 sig_clk
= cell
->getPort("\\CLK");
938 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
940 if (cell
->type
== "$adff") {
941 sig_arst
= cell
->getPort("\\ARST");
942 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
943 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
946 if (cell
->type
== "$dffe") {
947 sig_en
= cell
->getPort("\\EN");
948 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
951 std::string reg_name
= cellname(cell
);
952 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
954 if (!out_is_reg_wire
) {
955 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
956 dump_reg_init(f
, cell
->getPort("\\Q"));
960 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
961 dump_sigspec(f
, sig_clk
);
962 if (cell
->type
== "$adff") {
963 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
964 dump_sigspec(f
, sig_arst
);
968 if (cell
->type
== "$adff") {
969 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
970 dump_sigspec(f
, sig_arst
);
972 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
973 dump_sigspec(f
, val_arst
);
975 f
<< stringf("%s" " else\n", indent
.c_str());
978 if (cell
->type
== "$dffe") {
979 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
980 dump_sigspec(f
, sig_en
);
984 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
985 dump_cell_expr_port(f
, cell
, "D", false);
988 if (!out_is_reg_wire
) {
989 f
<< stringf("%s" "assign ", indent
.c_str());
990 dump_sigspec(f
, cell
->getPort("\\Q"));
991 f
<< stringf(" = %s;\n", reg_name
.c_str());
997 if (cell
->type
== "$dlatch")
999 RTLIL::SigSpec sig_en
;
1000 bool pol_en
= false;
1002 sig_en
= cell
->getPort("\\EN");
1003 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
1005 std::string reg_name
= cellname(cell
);
1006 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
1008 if (!out_is_reg_wire
) {
1009 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
1010 dump_reg_init(f
, cell
->getPort("\\Q"));
1014 f
<< stringf("%s" "always @*\n", indent
.c_str());
1016 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1017 dump_sigspec(f
, sig_en
);
1018 f
<< stringf(")\n");
1020 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
1021 dump_cell_expr_port(f
, cell
, "D", false);
1022 f
<< stringf(";\n");
1024 if (!out_is_reg_wire
) {
1025 f
<< stringf("%s" "assign ", indent
.c_str());
1026 dump_sigspec(f
, cell
->getPort("\\Q"));
1027 f
<< stringf(" = %s;\n", reg_name
.c_str());
1033 if (cell
->type
== "$mem")
1035 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
1036 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
1037 int abits
= cell
->parameters
["\\ABITS"].as_int();
1038 int size
= cell
->parameters
["\\SIZE"].as_int();
1039 int offset
= cell
->parameters
["\\OFFSET"].as_int();
1040 int width
= cell
->parameters
["\\WIDTH"].as_int();
1041 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
1043 // for memory block make something like:
1044 // reg [7:0] memid [3:0];
1048 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1051 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1052 for (int i
=0; i
<size
; i
++)
1054 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1055 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1056 f
<< stringf(";\n");
1058 f
<< stringf("%s" "end\n", indent
.c_str());
1061 // create a map : "edge clk" -> expressions within that clock domain
1062 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1063 clk_to_lof_body
[""] = std::vector
<std::string
>();
1064 std::string clk_domain_str
;
1065 // create a list of reg declarations
1066 std::vector
<std::string
> lof_reg_declarations
;
1068 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1069 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1070 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1072 for (int i
=0; i
< nread_ports
; i
++)
1074 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1075 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1076 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1077 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1078 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1079 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1080 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1084 std::ostringstream os
;
1085 dump_sigspec(os
, sig_rd_clk
);
1086 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1087 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1088 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1090 if (!rd_transparent
)
1092 // for clocked read ports make something like:
1093 // reg [..] temp_id;
1094 // always @(posedge clk)
1095 // if (rd_en) temp_id <= array_reg[r_addr];
1096 // assign r_data = temp_id;
1097 std::string temp_id
= next_auto_id();
1098 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1100 std::ostringstream os
;
1101 if (sig_rd_en
!= RTLIL::SigBit(true))
1103 os
<< stringf("if (");
1104 dump_sigspec(os
, sig_rd_en
);
1105 os
<< stringf(") ");
1107 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1108 dump_sigspec(os
, sig_rd_addr
);
1109 os
<< stringf("];\n");
1110 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1113 std::ostringstream os
;
1114 dump_sigspec(os
, sig_rd_data
);
1115 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1116 clk_to_lof_body
[""].push_back(line
);
1121 // for rd-transparent read-ports make something like:
1122 // reg [..] temp_id;
1123 // always @(posedge clk)
1124 // temp_id <= r_addr;
1125 // assign r_data = array_reg[temp_id];
1126 std::string temp_id
= next_auto_id();
1127 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1129 std::ostringstream os
;
1130 dump_sigspec(os
, sig_rd_addr
);
1131 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1132 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1135 std::ostringstream os
;
1136 dump_sigspec(os
, sig_rd_data
);
1137 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1138 clk_to_lof_body
[""].push_back(line
);
1142 // for non-clocked read-ports make something like:
1143 // assign r_data = array_reg[r_addr];
1144 std::ostringstream os
, os2
;
1145 dump_sigspec(os
, sig_rd_data
);
1146 dump_sigspec(os2
, sig_rd_addr
);
1147 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1148 clk_to_lof_body
[""].push_back(line
);
1152 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1153 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1154 bool wr_clk_posedge
;
1157 for (int i
=0; i
< nwrite_ports
; i
++)
1159 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1160 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1161 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1162 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1163 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1165 std::ostringstream os
;
1166 dump_sigspec(os
, sig_wr_clk
);
1167 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1168 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1169 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1171 // make something like:
1172 // always @(posedge clk)
1173 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1175 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1177 int start_i
= i
, width
= 1;
1178 SigBit wen_bit
= sig_wr_en
[i
];
1180 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1183 if (wen_bit
== State::S0
)
1186 std::ostringstream os
;
1187 if (wen_bit
!= State::S1
)
1189 os
<< stringf("if (");
1190 dump_sigspec(os
, wen_bit
);
1191 os
<< stringf(") ");
1193 os
<< stringf("%s[", mem_id
.c_str());
1194 dump_sigspec(os
, sig_wr_addr
);
1195 if (width
== GetSize(sig_wr_en
))
1196 os
<< stringf("] <= ");
1198 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1199 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1200 os
<< stringf(";\n");
1201 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1204 // Output Verilog that looks something like this:
1206 // always @(posedge CLK2) begin
1207 // _3_ <= memory[D1ADDR];
1209 // memory[A1ADDR] <= A1DATA;
1211 // memory[A2ADDR] <= A2DATA;
1214 // always @(negedge CLK1) begin
1216 // memory[C1ADDR] <= C1DATA;
1219 // assign D1DATA = _3_;
1220 // assign D2DATA <= memory[D2ADDR];
1222 // the reg ... definitions
1223 for(auto ®
: lof_reg_declarations
)
1225 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1227 // the block of expressions by clock domain
1228 for(auto &pair
: clk_to_lof_body
)
1230 std::string clk_domain
= pair
.first
;
1231 std::vector
<std::string
> lof_lines
= pair
.second
;
1232 if( clk_domain
!= "")
1234 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1235 for(auto &line
: lof_lines
)
1236 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1237 f
<< stringf("%s" "end\n", indent
.c_str());
1241 // the non-clocked assignments
1242 for(auto &line
: lof_lines
)
1243 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1250 if (cell
->type
.in("$assert", "$assume", "$cover"))
1252 f
<< stringf("%s" "always @* if (", indent
.c_str());
1253 dump_sigspec(f
, cell
->getPort("\\EN"));
1254 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1255 dump_sigspec(f
, cell
->getPort("\\A"));
1256 f
<< stringf(");\n");
1260 if (cell
->type
.in("$specify2", "$specify3"))
1262 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1264 SigSpec en
= cell
->getPort("\\EN");
1265 if (en
!= State::S1
) {
1266 f
<< stringf("if (");
1267 dump_sigspec(f
, cell
->getPort("\\EN"));
1272 if (cell
->type
== "$specify3" && cell
->getParam("\\EDGE_EN").as_bool())
1273 f
<< (cell
->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1275 dump_sigspec(f
, cell
->getPort("\\SRC"));
1278 if (cell
->getParam("\\SRC_DST_PEN").as_bool())
1279 f
<< (cell
->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1280 f
<< (cell
->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1282 if (cell
->type
== "$specify3") {
1284 dump_sigspec(f
, cell
->getPort("\\DST"));
1286 if (cell
->getParam("\\DAT_DST_PEN").as_bool())
1287 f
<< (cell
->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1289 dump_sigspec(f
, cell
->getPort("\\DAT"));
1292 dump_sigspec(f
, cell
->getPort("\\DST"));
1295 bool bak_decimal
= decimal
;
1299 dump_const(f
, cell
->getParam("\\T_RISE_MIN"));
1301 dump_const(f
, cell
->getParam("\\T_RISE_TYP"));
1303 dump_const(f
, cell
->getParam("\\T_RISE_MAX"));
1305 dump_const(f
, cell
->getParam("\\T_FALL_MIN"));
1307 dump_const(f
, cell
->getParam("\\T_FALL_TYP"));
1309 dump_const(f
, cell
->getParam("\\T_FALL_MAX"));
1312 decimal
= bak_decimal
;
1314 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1318 if (cell
->type
== "$specrule")
1320 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1322 string spec_type
= cell
->getParam("\\TYPE").decode_string();
1323 f
<< stringf("%s(", spec_type
.c_str());
1325 if (cell
->getParam("\\SRC_PEN").as_bool())
1326 f
<< (cell
->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1327 dump_sigspec(f
, cell
->getPort("\\SRC"));
1329 if (cell
->getPort("\\SRC_EN") != State::S1
) {
1331 dump_sigspec(f
, cell
->getPort("\\SRC_EN"));
1335 if (cell
->getParam("\\DST_PEN").as_bool())
1336 f
<< (cell
->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1337 dump_sigspec(f
, cell
->getPort("\\DST"));
1339 if (cell
->getPort("\\DST_EN") != State::S1
) {
1341 dump_sigspec(f
, cell
->getPort("\\DST_EN"));
1344 bool bak_decimal
= decimal
;
1348 dump_const(f
, cell
->getParam("\\T_LIMIT"));
1350 if (spec_type
== "$setuphold" || spec_type
== "$recrem" || spec_type
== "$fullskew") {
1352 dump_const(f
, cell
->getParam("\\T_LIMIT2"));
1356 decimal
= bak_decimal
;
1358 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1362 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1363 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1368 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1370 if (cell
->type
[0] == '$' && !noexpr
) {
1371 if (dump_cell_expr(f
, indent
, cell
))
1375 dump_attributes(f
, indent
, cell
->attributes
);
1376 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1378 if (!defparam
&& cell
->parameters
.size() > 0) {
1379 f
<< stringf(" #(");
1380 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1381 if (it
!= cell
->parameters
.begin())
1383 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1384 dump_const(f
, it
->second
);
1387 f
<< stringf("\n%s" ")", indent
.c_str());
1390 std::string cell_name
= cellname(cell
);
1391 if (cell_name
!= id(cell
->name
))
1392 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1394 f
<< stringf(" %s (", cell_name
.c_str());
1396 bool first_arg
= true;
1397 std::set
<RTLIL::IdString
> numbered_ports
;
1398 for (int i
= 1; true; i
++) {
1400 snprintf(str
, 16, "$%d", i
);
1401 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1402 if (it
->first
!= str
)
1407 f
<< stringf("\n%s ", indent
.c_str());
1408 dump_sigspec(f
, it
->second
);
1409 numbered_ports
.insert(it
->first
);
1410 goto found_numbered_port
;
1413 found_numbered_port
:;
1415 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1416 if (numbered_ports
.count(it
->first
))
1421 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1422 if (it
->second
.size() > 0)
1423 dump_sigspec(f
, it
->second
);
1426 f
<< stringf("\n%s" ");\n", indent
.c_str());
1428 if (defparam
&& cell
->parameters
.size() > 0) {
1429 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1430 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1431 dump_const(f
, it
->second
);
1432 f
<< stringf(";\n");
1436 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q")) {
1437 std::stringstream ss
;
1438 dump_reg_init(ss
, cell
->getPort("\\Q"));
1439 if (!ss
.str().empty()) {
1440 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1447 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1449 f
<< stringf("%s" "assign ", indent
.c_str());
1450 dump_sigspec(f
, left
);
1451 f
<< stringf(" = ");
1452 dump_sigspec(f
, right
);
1453 f
<< stringf(";\n");
1456 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1458 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1460 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1462 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1463 f
<< stringf("%s" "begin\n", indent
.c_str());
1465 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1466 if (it
->first
.size() == 0)
1468 f
<< stringf("%s ", indent
.c_str());
1469 dump_sigspec(f
, it
->first
);
1470 f
<< stringf(" = ");
1471 dump_sigspec(f
, it
->second
);
1472 f
<< stringf(";\n");
1475 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1476 dump_proc_switch(f
, indent
+ " ", *it
);
1478 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1479 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1481 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1482 f
<< stringf("%s" "end\n", indent
.c_str());
1485 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1487 if (sw
->signal
.size() == 0) {
1488 f
<< stringf("%s" "begin\n", indent
.c_str());
1489 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1490 if ((*it
)->compare
.size() == 0)
1491 dump_case_body(f
, indent
+ " ", *it
);
1493 f
<< stringf("%s" "end\n", indent
.c_str());
1497 dump_attributes(f
, indent
, sw
->attributes
);
1498 f
<< stringf("%s" "casez (", indent
.c_str());
1499 dump_sigspec(f
, sw
->signal
);
1500 f
<< stringf(")\n");
1502 bool got_default
= false;
1503 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1504 if ((*it
)->compare
.size() == 0) {
1507 f
<< stringf("%s default", indent
.c_str());
1510 f
<< stringf("%s ", indent
.c_str());
1511 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1514 dump_sigspec(f
, (*it
)->compare
[i
]);
1518 dump_attributes(f
, indent
, (*it
)->attributes
, ' ', /*modattr=*/false, /*as_comment=*/true);
1520 dump_case_body(f
, indent
+ " ", *it
);
1523 f
<< stringf("%s" "endcase\n", indent
.c_str());
1526 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1528 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1529 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1530 case_body_find_regs(*it2
);
1532 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1533 for (auto &c
: it
->first
.chunks())
1535 reg_wires
.insert(c
.wire
->name
);
1539 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1542 case_body_find_regs(&proc
->root_case
);
1543 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1544 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1545 for (auto &c
: it2
->first
.chunks())
1547 reg_wires
.insert(c
.wire
->name
);
1552 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1553 dump_case_body(f
, indent
, &proc
->root_case
, true);
1555 std::string backup_indent
= indent
;
1557 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1559 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1560 indent
= backup_indent
;
1562 if (sync
->type
== RTLIL::STa
) {
1563 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1564 } else if (sync
->type
== RTLIL::STi
) {
1565 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1567 f
<< stringf("%s" "always @(", indent
.c_str());
1568 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1569 f
<< stringf("posedge ");
1570 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1571 f
<< stringf("negedge ");
1572 dump_sigspec(f
, sync
->signal
);
1573 f
<< stringf(") begin\n");
1575 std::string ends
= indent
+ "end\n";
1578 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1579 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1580 dump_sigspec(f
, sync
->signal
);
1581 f
<< stringf(") begin\n");
1582 ends
= indent
+ "end\n" + ends
;
1586 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1587 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1588 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1589 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1590 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1591 dump_sigspec(f
, sync2
->signal
);
1592 f
<< stringf(") begin\n");
1593 ends
= indent
+ "end\n" + ends
;
1599 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1600 if (it
->first
.size() == 0)
1602 f
<< stringf("%s ", indent
.c_str());
1603 dump_sigspec(f
, it
->first
);
1604 f
<< stringf(" <= ");
1605 dump_sigspec(f
, it
->second
);
1606 f
<< stringf(";\n");
1609 f
<< stringf("%s", ends
.c_str());
1613 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1616 reset_auto_counter(module
);
1617 active_module
= module
;
1618 active_sigmap
.set(module
);
1619 active_initdata
.clear();
1621 for (auto wire
: module
->wires())
1622 if (wire
->attributes
.count("\\init")) {
1623 SigSpec sig
= active_sigmap(wire
);
1624 Const val
= wire
->attributes
.at("\\init");
1625 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1626 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1627 active_initdata
[sig
[i
]] = val
[i
];
1630 if (!module
->processes
.empty())
1631 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1632 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1633 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1634 "processes to logic networks and registers.\n", log_id(module
));
1637 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1638 dump_process(f
, indent
+ " ", it
->second
, true);
1642 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1643 for (auto &it
: module
->cells_
)
1645 RTLIL::Cell
*cell
= it
.second
;
1646 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1649 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1651 if (sig
.is_chunk()) {
1652 RTLIL::SigChunk chunk
= sig
.as_chunk();
1653 if (chunk
.wire
!= NULL
)
1654 for (int i
= 0; i
< chunk
.width
; i
++)
1655 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1658 for (auto &it
: module
->wires_
)
1660 RTLIL::Wire
*wire
= it
.second
;
1661 for (int i
= 0; i
< wire
->width
; i
++)
1662 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1663 goto this_wire_aint_reg
;
1665 reg_wires
.insert(wire
->name
);
1666 this_wire_aint_reg
:;
1670 dump_attributes(f
, indent
, module
->attributes
, '\n', /*attr2comment=*/true);
1671 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1672 bool keep_running
= true;
1673 for (int port_id
= 1; keep_running
; port_id
++) {
1674 keep_running
= false;
1675 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1676 RTLIL::Wire
*wire
= it
->second
;
1677 if (wire
->port_id
== port_id
) {
1680 f
<< stringf("%s", id(wire
->name
).c_str());
1681 keep_running
= true;
1686 f
<< stringf(");\n");
1688 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1689 dump_wire(f
, indent
+ " ", it
->second
);
1691 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1692 dump_memory(f
, indent
+ " ", it
->second
);
1694 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1695 dump_cell(f
, indent
+ " ", it
->second
);
1697 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1698 dump_process(f
, indent
+ " ", it
->second
);
1700 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1701 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1703 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1704 active_module
= NULL
;
1705 active_sigmap
.clear();
1706 active_initdata
.clear();
1709 struct VerilogBackend
: public Backend
{
1710 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1711 void help() YS_OVERRIDE
1713 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1715 log(" write_verilog [options] [filename]\n");
1717 log("Write the current design to a Verilog file.\n");
1719 log(" -norename\n");
1720 log(" without this option all internal object names (the ones with a dollar\n");
1721 log(" instead of a backslash prefix) are changed to short names in the\n");
1722 log(" format '_<number>_'.\n");
1724 log(" -renameprefix <prefix>\n");
1725 log(" insert this prefix in front of auto-generated instance names\n");
1728 log(" with this option no attributes are included in the output\n");
1730 log(" -attr2comment\n");
1731 log(" with this option attributes are included as comments in the output\n");
1734 log(" without this option all internal cells are converted to Verilog\n");
1735 log(" expressions.\n");
1738 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1739 log(" in -noexpr mode.\n");
1742 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1743 log(" not bit pattern. This option deactivates this feature and instead\n");
1744 log(" will write out all constants in binary.\n");
1747 log(" dump 32-bit constants in decimal and without size and radix\n");
1750 log(" constant values that are compatible with hex output are usually\n");
1751 log(" dumped as hex values. This option deactivates this feature and\n");
1752 log(" instead will write out all constants in binary.\n");
1755 log(" Parameters and attributes that are specified as strings in the\n");
1756 log(" original input will be output as strings by this back-end. This\n");
1757 log(" deactivates this feature and instead will write string constants\n");
1758 log(" as binary numbers.\n");
1760 log(" -defparam\n");
1761 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1762 log(" cell parameters.\n");
1764 log(" -blackboxes\n");
1765 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1766 log(" this option set only the modules with the 'blackbox' attribute\n");
1767 log(" are written to the output file.\n");
1769 log(" -selected\n");
1770 log(" only write selected modules. modules must be selected entirely or\n");
1771 log(" not at all.\n");
1774 log(" verbose output (print new names of all renamed wires and cells)\n");
1776 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1777 log("always blocks. This frontend should only be used to export an RTLIL\n");
1778 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1779 log("processes to logic networks and registers. A warning is generated when\n");
1780 log("this command is called on a design with RTLIL processes.\n");
1783 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1785 log_header(design
, "Executing Verilog backend.\n");
1790 attr2comment
= false;
1800 bool blackboxes
= false;
1801 bool selected
= false;
1803 auto_name_map
.clear();
1807 reg_ct
.insert("$dff");
1808 reg_ct
.insert("$adff");
1809 reg_ct
.insert("$dffe");
1810 reg_ct
.insert("$dlatch");
1812 reg_ct
.insert("$_DFF_N_");
1813 reg_ct
.insert("$_DFF_P_");
1815 reg_ct
.insert("$_DFF_NN0_");
1816 reg_ct
.insert("$_DFF_NN1_");
1817 reg_ct
.insert("$_DFF_NP0_");
1818 reg_ct
.insert("$_DFF_NP1_");
1819 reg_ct
.insert("$_DFF_PN0_");
1820 reg_ct
.insert("$_DFF_PN1_");
1821 reg_ct
.insert("$_DFF_PP0_");
1822 reg_ct
.insert("$_DFF_PP1_");
1824 reg_ct
.insert("$_DFFSR_NNN_");
1825 reg_ct
.insert("$_DFFSR_NNP_");
1826 reg_ct
.insert("$_DFFSR_NPN_");
1827 reg_ct
.insert("$_DFFSR_NPP_");
1828 reg_ct
.insert("$_DFFSR_PNN_");
1829 reg_ct
.insert("$_DFFSR_PNP_");
1830 reg_ct
.insert("$_DFFSR_PPN_");
1831 reg_ct
.insert("$_DFFSR_PPP_");
1834 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1835 std::string arg
= args
[argidx
];
1836 if (arg
== "-norename") {
1840 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1841 auto_prefix
= args
[++argidx
];
1844 if (arg
== "-noattr") {
1848 if (arg
== "-attr2comment") {
1849 attr2comment
= true;
1852 if (arg
== "-noexpr") {
1856 if (arg
== "-nodec") {
1860 if (arg
== "-nohex") {
1864 if (arg
== "-nostr") {
1868 if (arg
== "-defparam") {
1872 if (arg
== "-decimal") {
1876 if (arg
== "-siminit") {
1880 if (arg
== "-blackboxes") {
1884 if (arg
== "-selected") {
1894 extra_args(f
, filename
, args
, argidx
);
1898 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1899 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1900 if (it
->second
->get_blackbox_attribute() != blackboxes
)
1902 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1903 if (design
->selected_module(it
->first
))
1904 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1907 log("Dumping module `%s'.\n", it
->first
.c_str());
1908 dump_module(*f
, "", it
->second
);
1911 auto_name_map
.clear();
1917 PRIVATE_NAMESPACE_END