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)
371 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
372 f
<< stringf("%s" "%s %s", indent
.c_str(), attr2comment
? "/*" : "(*", id(it
->first
).c_str());
374 if (modattr
&& (it
->second
== Const(0, 1) || it
->second
== Const(0)))
376 else if (modattr
&& (it
->second
== Const(1, 1) || it
->second
== Const(1)))
379 dump_const(f
, it
->second
, -1, 0, false, attr2comment
);
380 f
<< stringf(" %s%c", attr2comment
? "*/" : "*)", term
);
384 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
386 dump_attributes(f
, indent
, wire
->attributes
);
388 if (wire
->port_input
&& !wire
->port_output
)
389 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
390 else if (!wire
->port_input
&& wire
->port_output
)
391 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
392 else if (wire
->port_input
&& wire
->port_output
)
393 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
395 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
396 if (wire
->width
!= 1)
397 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
398 f
<< stringf("%s;\n", id(wire
->name
).c_str());
400 // do not use Verilog-2k "output reg" syntax in Verilog export
401 std::string range
= "";
402 if (wire
->width
!= 1) {
404 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
406 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
408 if (wire
->port_input
&& !wire
->port_output
)
409 f
<< stringf("%s" "input%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
410 if (!wire
->port_input
&& wire
->port_output
)
411 f
<< stringf("%s" "output%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" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
414 if (reg_wires
.count(wire
->name
)) {
415 f
<< stringf("%s" "reg%s %s", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
416 if (wire
->attributes
.count("\\init")) {
418 dump_const(f
, wire
->attributes
.at("\\init"));
421 } else if (!wire
->port_input
&& !wire
->port_output
)
422 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
426 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
428 dump_attributes(f
, indent
, memory
->attributes
);
429 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
);
432 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
434 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
435 f
<< stringf("$signed(");
436 dump_sigspec(f
, cell
->getPort("\\" + port
));
439 dump_sigspec(f
, cell
->getPort("\\" + port
));
442 std::string
cellname(RTLIL::Cell
*cell
)
444 if (!norename
&& cell
->name
[0] == '$' && reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q"))
446 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
447 if (GetSize(sig
) != 1 || sig
.is_fully_const())
448 goto no_special_reg_name
;
450 RTLIL::Wire
*wire
= sig
[0].wire
;
452 if (wire
->name
[0] != '\\')
453 goto no_special_reg_name
;
455 std::string cell_name
= wire
->name
.str();
457 size_t pos
= cell_name
.find('[');
458 if (pos
!= std::string::npos
)
459 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
461 cell_name
= cell_name
+ "_reg";
463 if (wire
->width
!= 1)
464 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
466 if (active_module
&& active_module
->count_id(cell_name
) > 0)
467 goto no_special_reg_name
;
469 return id(cell_name
);
474 return id(cell
->name
).c_str();
478 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
480 f
<< stringf("%s" "assign ", indent
.c_str());
481 dump_sigspec(f
, cell
->getPort("\\Y"));
482 f
<< stringf(" = %s ", op
.c_str());
483 dump_attributes(f
, "", cell
->attributes
, ' ');
484 dump_cell_expr_port(f
, cell
, "A", true);
488 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
490 f
<< stringf("%s" "assign ", indent
.c_str());
491 dump_sigspec(f
, cell
->getPort("\\Y"));
493 dump_cell_expr_port(f
, cell
, "A", true);
494 f
<< stringf(" %s ", op
.c_str());
495 dump_attributes(f
, "", cell
->attributes
, ' ');
496 dump_cell_expr_port(f
, cell
, "B", true);
500 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
502 if (cell
->type
== "$_NOT_") {
503 f
<< stringf("%s" "assign ", indent
.c_str());
504 dump_sigspec(f
, cell
->getPort("\\Y"));
507 dump_attributes(f
, "", cell
->attributes
, ' ');
508 dump_cell_expr_port(f
, cell
, "A", false);
513 if (cell
->type
.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
514 f
<< stringf("%s" "assign ", indent
.c_str());
515 dump_sigspec(f
, cell
->getPort("\\Y"));
517 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
519 dump_cell_expr_port(f
, cell
, "A", false);
521 if (cell
->type
.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
523 if (cell
->type
.in("$_OR_", "$_NOR_", "$_ORNOT_"))
525 if (cell
->type
.in("$_XOR_", "$_XNOR_"))
527 dump_attributes(f
, "", cell
->attributes
, ' ');
529 if (cell
->type
.in("$_ANDNOT_", "$_ORNOT_"))
531 dump_cell_expr_port(f
, cell
, "B", false);
532 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
538 if (cell
->type
== "$_MUX_") {
539 f
<< stringf("%s" "assign ", indent
.c_str());
540 dump_sigspec(f
, cell
->getPort("\\Y"));
542 dump_cell_expr_port(f
, cell
, "S", false);
544 dump_attributes(f
, "", cell
->attributes
, ' ');
545 dump_cell_expr_port(f
, cell
, "B", false);
547 dump_cell_expr_port(f
, cell
, "A", false);
552 if (cell
->type
.in("$_AOI3_", "$_OAI3_")) {
553 f
<< stringf("%s" "assign ", indent
.c_str());
554 dump_sigspec(f
, cell
->getPort("\\Y"));
555 f
<< stringf(" = ~((");
556 dump_cell_expr_port(f
, cell
, "A", false);
557 f
<< stringf(cell
->type
== "$_AOI3_" ? " & " : " | ");
558 dump_cell_expr_port(f
, cell
, "B", false);
559 f
<< stringf(cell
->type
== "$_AOI3_" ? ") |" : ") &");
560 dump_attributes(f
, "", cell
->attributes
, ' ');
562 dump_cell_expr_port(f
, cell
, "C", false);
563 f
<< stringf(");\n");
567 if (cell
->type
.in("$_AOI4_", "$_OAI4_")) {
568 f
<< stringf("%s" "assign ", indent
.c_str());
569 dump_sigspec(f
, cell
->getPort("\\Y"));
570 f
<< stringf(" = ~((");
571 dump_cell_expr_port(f
, cell
, "A", false);
572 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
573 dump_cell_expr_port(f
, cell
, "B", false);
574 f
<< stringf(cell
->type
== "$_AOI4_" ? ") |" : ") &");
575 dump_attributes(f
, "", cell
->attributes
, ' ');
577 dump_cell_expr_port(f
, cell
, "C", false);
578 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
579 dump_cell_expr_port(f
, cell
, "D", false);
580 f
<< stringf("));\n");
584 if (cell
->type
.substr(0, 6) == "$_DFF_")
586 std::string reg_name
= cellname(cell
);
587 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
589 if (!out_is_reg_wire
) {
590 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
591 dump_reg_init(f
, cell
->getPort("\\Q"));
595 dump_attributes(f
, indent
, cell
->attributes
);
596 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), cell
->type
[6] == 'P' ? "pos" : "neg");
597 dump_sigspec(f
, cell
->getPort("\\C"));
598 if (cell
->type
[7] != '_') {
599 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
600 dump_sigspec(f
, cell
->getPort("\\R"));
604 if (cell
->type
[7] != '_') {
605 f
<< stringf("%s" " if (%s", indent
.c_str(), cell
->type
[7] == 'P' ? "" : "!");
606 dump_sigspec(f
, cell
->getPort("\\R"));
608 f
<< stringf("%s" " %s <= %c;\n", indent
.c_str(), reg_name
.c_str(), cell
->type
[8]);
609 f
<< stringf("%s" " else\n", indent
.c_str());
612 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
613 dump_cell_expr_port(f
, cell
, "D", false);
616 if (!out_is_reg_wire
) {
617 f
<< stringf("%s" "assign ", indent
.c_str());
618 dump_sigspec(f
, cell
->getPort("\\Q"));
619 f
<< stringf(" = %s;\n", reg_name
.c_str());
625 if (cell
->type
.substr(0, 8) == "$_DFFSR_")
627 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
629 std::string reg_name
= cellname(cell
);
630 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
632 if (!out_is_reg_wire
) {
633 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
634 dump_reg_init(f
, cell
->getPort("\\Q"));
638 dump_attributes(f
, indent
, cell
->attributes
);
639 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_c
== 'P' ? "pos" : "neg");
640 dump_sigspec(f
, cell
->getPort("\\C"));
641 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
642 dump_sigspec(f
, cell
->getPort("\\S"));
643 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
644 dump_sigspec(f
, cell
->getPort("\\R"));
647 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
648 dump_sigspec(f
, cell
->getPort("\\R"));
650 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
652 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
653 dump_sigspec(f
, cell
->getPort("\\S"));
655 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
657 f
<< stringf("%s" " else\n", indent
.c_str());
658 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
659 dump_cell_expr_port(f
, cell
, "D", false);
662 if (!out_is_reg_wire
) {
663 f
<< stringf("%s" "assign ", indent
.c_str());
664 dump_sigspec(f
, cell
->getPort("\\Q"));
665 f
<< stringf(" = %s;\n", reg_name
.c_str());
671 #define HANDLE_UNIOP(_type, _operator) \
672 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
673 #define HANDLE_BINOP(_type, _operator) \
674 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
676 HANDLE_UNIOP("$not", "~")
677 HANDLE_UNIOP("$pos", "+")
678 HANDLE_UNIOP("$neg", "-")
680 HANDLE_BINOP("$and", "&")
681 HANDLE_BINOP("$or", "|")
682 HANDLE_BINOP("$xor", "^")
683 HANDLE_BINOP("$xnor", "~^")
685 HANDLE_UNIOP("$reduce_and", "&")
686 HANDLE_UNIOP("$reduce_or", "|")
687 HANDLE_UNIOP("$reduce_xor", "^")
688 HANDLE_UNIOP("$reduce_xnor", "~^")
689 HANDLE_UNIOP("$reduce_bool", "|")
691 HANDLE_BINOP("$shl", "<<")
692 HANDLE_BINOP("$shr", ">>")
693 HANDLE_BINOP("$sshl", "<<<")
694 HANDLE_BINOP("$sshr", ">>>")
696 HANDLE_BINOP("$lt", "<")
697 HANDLE_BINOP("$le", "<=")
698 HANDLE_BINOP("$eq", "==")
699 HANDLE_BINOP("$ne", "!=")
700 HANDLE_BINOP("$eqx", "===")
701 HANDLE_BINOP("$nex", "!==")
702 HANDLE_BINOP("$ge", ">=")
703 HANDLE_BINOP("$gt", ">")
705 HANDLE_BINOP("$add", "+")
706 HANDLE_BINOP("$sub", "-")
707 HANDLE_BINOP("$mul", "*")
708 HANDLE_BINOP("$div", "/")
709 HANDLE_BINOP("$mod", "%")
710 HANDLE_BINOP("$pow", "**")
712 HANDLE_UNIOP("$logic_not", "!")
713 HANDLE_BINOP("$logic_and", "&&")
714 HANDLE_BINOP("$logic_or", "||")
719 if (cell
->type
== "$shift")
721 f
<< stringf("%s" "assign ", indent
.c_str());
722 dump_sigspec(f
, cell
->getPort("\\Y"));
724 if (cell
->getParam("\\B_SIGNED").as_bool())
726 f
<< stringf("$signed(");
727 dump_sigspec(f
, cell
->getPort("\\B"));
729 f
<< stringf(" < 0 ? ");
730 dump_sigspec(f
, cell
->getPort("\\A"));
731 f
<< stringf(" << - ");
732 dump_sigspec(f
, cell
->getPort("\\B"));
734 dump_sigspec(f
, cell
->getPort("\\A"));
735 f
<< stringf(" >> ");
736 dump_sigspec(f
, cell
->getPort("\\B"));
740 dump_sigspec(f
, cell
->getPort("\\A"));
741 f
<< stringf(" >> ");
742 dump_sigspec(f
, cell
->getPort("\\B"));
748 if (cell
->type
== "$shiftx")
750 std::string temp_id
= next_auto_id();
751 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort("\\A"))-1, temp_id
.c_str());
752 dump_sigspec(f
, cell
->getPort("\\A"));
755 f
<< stringf("%s" "assign ", indent
.c_str());
756 dump_sigspec(f
, cell
->getPort("\\Y"));
757 f
<< stringf(" = %s[", temp_id
.c_str());
758 if (cell
->getParam("\\B_SIGNED").as_bool())
759 f
<< stringf("$signed(");
760 dump_sigspec(f
, cell
->getPort("\\B"));
761 if (cell
->getParam("\\B_SIGNED").as_bool())
763 f
<< stringf(" +: %d", cell
->getParam("\\Y_WIDTH").as_int());
764 f
<< stringf("];\n");
768 if (cell
->type
== "$mux")
770 f
<< stringf("%s" "assign ", indent
.c_str());
771 dump_sigspec(f
, cell
->getPort("\\Y"));
773 dump_sigspec(f
, cell
->getPort("\\S"));
775 dump_attributes(f
, "", cell
->attributes
, ' ');
776 dump_sigspec(f
, cell
->getPort("\\B"));
778 dump_sigspec(f
, cell
->getPort("\\A"));
783 if (cell
->type
== "$pmux" || cell
->type
== "$pmux_safe")
785 int width
= cell
->parameters
["\\WIDTH"].as_int();
786 int s_width
= cell
->getPort("\\S").size();
787 std::string func_name
= cellname(cell
);
789 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
790 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
791 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
792 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
794 dump_attributes(f
, indent
+ " ", cell
->attributes
);
795 if (cell
->type
!= "$pmux_safe" && !noattr
)
796 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
797 f
<< stringf("%s" " casez (s)", indent
.c_str());
798 if (cell
->type
!= "$pmux_safe")
799 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
801 for (int i
= 0; i
< s_width
; i
++)
803 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
805 for (int j
= s_width
-1; j
>= 0; j
--)
806 f
<< stringf("%c", j
== i
? '1' : cell
->type
== "$pmux_safe" ? '0' : '?');
809 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
812 f
<< stringf("%s" " default:\n", indent
.c_str());
813 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
815 f
<< stringf("%s" " endcase\n", indent
.c_str());
816 f
<< stringf("%s" "endfunction\n", indent
.c_str());
818 f
<< stringf("%s" "assign ", indent
.c_str());
819 dump_sigspec(f
, cell
->getPort("\\Y"));
820 f
<< stringf(" = %s(", func_name
.c_str());
821 dump_sigspec(f
, cell
->getPort("\\A"));
823 dump_sigspec(f
, cell
->getPort("\\B"));
825 dump_sigspec(f
, cell
->getPort("\\S"));
826 f
<< stringf(");\n");
830 if (cell
->type
== "$tribuf")
832 f
<< stringf("%s" "assign ", indent
.c_str());
833 dump_sigspec(f
, cell
->getPort("\\Y"));
835 dump_sigspec(f
, cell
->getPort("\\EN"));
837 dump_sigspec(f
, cell
->getPort("\\A"));
838 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at("\\WIDTH").as_int());
842 if (cell
->type
== "$slice")
844 f
<< stringf("%s" "assign ", indent
.c_str());
845 dump_sigspec(f
, cell
->getPort("\\Y"));
847 dump_sigspec(f
, cell
->getPort("\\A"));
848 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
852 if (cell
->type
== "$concat")
854 f
<< stringf("%s" "assign ", indent
.c_str());
855 dump_sigspec(f
, cell
->getPort("\\Y"));
856 f
<< stringf(" = { ");
857 dump_sigspec(f
, cell
->getPort("\\B"));
859 dump_sigspec(f
, cell
->getPort("\\A"));
860 f
<< stringf(" };\n");
864 if (cell
->type
== "$lut")
866 f
<< stringf("%s" "assign ", indent
.c_str());
867 dump_sigspec(f
, cell
->getPort("\\Y"));
869 dump_const(f
, cell
->parameters
.at("\\LUT"));
870 f
<< stringf(" >> ");
871 dump_attributes(f
, "", cell
->attributes
, ' ');
872 dump_sigspec(f
, cell
->getPort("\\A"));
877 if (cell
->type
== "$dffsr")
879 SigSpec sig_clk
= cell
->getPort("\\CLK");
880 SigSpec sig_set
= cell
->getPort("\\SET");
881 SigSpec sig_clr
= cell
->getPort("\\CLR");
882 SigSpec sig_d
= cell
->getPort("\\D");
883 SigSpec sig_q
= cell
->getPort("\\Q");
885 int width
= cell
->parameters
["\\WIDTH"].as_int();
886 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
887 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
888 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
890 std::string reg_name
= cellname(cell
);
891 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
893 if (!out_is_reg_wire
) {
894 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
895 dump_reg_init(f
, sig_q
);
899 for (int i
= 0; i
< width
; i
++) {
900 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
901 dump_sigspec(f
, sig_clk
);
902 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
903 dump_sigspec(f
, sig_set
);
904 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
905 dump_sigspec(f
, sig_clr
);
908 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
909 dump_sigspec(f
, sig_clr
);
910 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
912 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
913 dump_sigspec(f
, sig_set
);
914 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
916 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
917 dump_sigspec(f
, sig_d
[i
]);
921 if (!out_is_reg_wire
) {
922 f
<< stringf("%s" "assign ", indent
.c_str());
923 dump_sigspec(f
, sig_q
);
924 f
<< stringf(" = %s;\n", reg_name
.c_str());
930 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
932 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
933 bool pol_clk
, pol_arst
= false, pol_en
= false;
935 sig_clk
= cell
->getPort("\\CLK");
936 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
938 if (cell
->type
== "$adff") {
939 sig_arst
= cell
->getPort("\\ARST");
940 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
941 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
944 if (cell
->type
== "$dffe") {
945 sig_en
= cell
->getPort("\\EN");
946 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
949 std::string reg_name
= cellname(cell
);
950 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
952 if (!out_is_reg_wire
) {
953 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
954 dump_reg_init(f
, cell
->getPort("\\Q"));
958 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
959 dump_sigspec(f
, sig_clk
);
960 if (cell
->type
== "$adff") {
961 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
962 dump_sigspec(f
, sig_arst
);
966 if (cell
->type
== "$adff") {
967 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
968 dump_sigspec(f
, sig_arst
);
970 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
971 dump_sigspec(f
, val_arst
);
973 f
<< stringf("%s" " else\n", indent
.c_str());
976 if (cell
->type
== "$dffe") {
977 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
978 dump_sigspec(f
, sig_en
);
982 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
983 dump_cell_expr_port(f
, cell
, "D", false);
986 if (!out_is_reg_wire
) {
987 f
<< stringf("%s" "assign ", indent
.c_str());
988 dump_sigspec(f
, cell
->getPort("\\Q"));
989 f
<< stringf(" = %s;\n", reg_name
.c_str());
995 if (cell
->type
== "$dlatch")
997 RTLIL::SigSpec sig_en
;
1000 sig_en
= cell
->getPort("\\EN");
1001 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
1003 std::string reg_name
= cellname(cell
);
1004 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
1006 if (!out_is_reg_wire
) {
1007 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
1008 dump_reg_init(f
, cell
->getPort("\\Q"));
1012 f
<< stringf("%s" "always @*\n", indent
.c_str());
1014 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1015 dump_sigspec(f
, sig_en
);
1016 f
<< stringf(")\n");
1018 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
1019 dump_cell_expr_port(f
, cell
, "D", false);
1020 f
<< stringf(";\n");
1022 if (!out_is_reg_wire
) {
1023 f
<< stringf("%s" "assign ", indent
.c_str());
1024 dump_sigspec(f
, cell
->getPort("\\Q"));
1025 f
<< stringf(" = %s;\n", reg_name
.c_str());
1031 if (cell
->type
== "$mem")
1033 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
1034 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
1035 int abits
= cell
->parameters
["\\ABITS"].as_int();
1036 int size
= cell
->parameters
["\\SIZE"].as_int();
1037 int offset
= cell
->parameters
["\\OFFSET"].as_int();
1038 int width
= cell
->parameters
["\\WIDTH"].as_int();
1039 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
1041 // for memory block make something like:
1042 // reg [7:0] memid [3:0];
1046 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1049 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1050 for (int i
=0; i
<size
; i
++)
1052 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1053 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1054 f
<< stringf(";\n");
1056 f
<< stringf("%s" "end\n", indent
.c_str());
1059 // create a map : "edge clk" -> expressions within that clock domain
1060 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1061 clk_to_lof_body
[""] = std::vector
<std::string
>();
1062 std::string clk_domain_str
;
1063 // create a list of reg declarations
1064 std::vector
<std::string
> lof_reg_declarations
;
1066 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1067 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1068 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1070 for (int i
=0; i
< nread_ports
; i
++)
1072 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1073 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1074 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1075 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1076 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1077 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1078 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1082 std::ostringstream os
;
1083 dump_sigspec(os
, sig_rd_clk
);
1084 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1085 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1086 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1088 if (!rd_transparent
)
1090 // for clocked read ports make something like:
1091 // reg [..] temp_id;
1092 // always @(posedge clk)
1093 // if (rd_en) temp_id <= array_reg[r_addr];
1094 // assign r_data = temp_id;
1095 std::string temp_id
= next_auto_id();
1096 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1098 std::ostringstream os
;
1099 if (sig_rd_en
!= RTLIL::SigBit(true))
1101 os
<< stringf("if (");
1102 dump_sigspec(os
, sig_rd_en
);
1103 os
<< stringf(") ");
1105 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1106 dump_sigspec(os
, sig_rd_addr
);
1107 os
<< stringf("];\n");
1108 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1111 std::ostringstream os
;
1112 dump_sigspec(os
, sig_rd_data
);
1113 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1114 clk_to_lof_body
[""].push_back(line
);
1119 // for rd-transparent read-ports make something like:
1120 // reg [..] temp_id;
1121 // always @(posedge clk)
1122 // temp_id <= r_addr;
1123 // assign r_data = array_reg[temp_id];
1124 std::string temp_id
= next_auto_id();
1125 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1127 std::ostringstream os
;
1128 dump_sigspec(os
, sig_rd_addr
);
1129 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1130 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1133 std::ostringstream os
;
1134 dump_sigspec(os
, sig_rd_data
);
1135 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1136 clk_to_lof_body
[""].push_back(line
);
1140 // for non-clocked read-ports make something like:
1141 // assign r_data = array_reg[r_addr];
1142 std::ostringstream os
, os2
;
1143 dump_sigspec(os
, sig_rd_data
);
1144 dump_sigspec(os2
, sig_rd_addr
);
1145 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1146 clk_to_lof_body
[""].push_back(line
);
1150 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1151 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1152 bool wr_clk_posedge
;
1155 for (int i
=0; i
< nwrite_ports
; i
++)
1157 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1158 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1159 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1160 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1161 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1163 std::ostringstream os
;
1164 dump_sigspec(os
, sig_wr_clk
);
1165 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1166 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1167 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1169 // make something like:
1170 // always @(posedge clk)
1171 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1173 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1175 int start_i
= i
, width
= 1;
1176 SigBit wen_bit
= sig_wr_en
[i
];
1178 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1181 if (wen_bit
== State::S0
)
1184 std::ostringstream os
;
1185 if (wen_bit
!= State::S1
)
1187 os
<< stringf("if (");
1188 dump_sigspec(os
, wen_bit
);
1189 os
<< stringf(") ");
1191 os
<< stringf("%s[", mem_id
.c_str());
1192 dump_sigspec(os
, sig_wr_addr
);
1193 if (width
== GetSize(sig_wr_en
))
1194 os
<< stringf("] <= ");
1196 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1197 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1198 os
<< stringf(";\n");
1199 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1202 // Output Verilog that looks something like this:
1204 // always @(posedge CLK2) begin
1205 // _3_ <= memory[D1ADDR];
1207 // memory[A1ADDR] <= A1DATA;
1209 // memory[A2ADDR] <= A2DATA;
1212 // always @(negedge CLK1) begin
1214 // memory[C1ADDR] <= C1DATA;
1217 // assign D1DATA = _3_;
1218 // assign D2DATA <= memory[D2ADDR];
1220 // the reg ... definitions
1221 for(auto ®
: lof_reg_declarations
)
1223 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1225 // the block of expressions by clock domain
1226 for(auto &pair
: clk_to_lof_body
)
1228 std::string clk_domain
= pair
.first
;
1229 std::vector
<std::string
> lof_lines
= pair
.second
;
1230 if( clk_domain
!= "")
1232 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1233 for(auto &line
: lof_lines
)
1234 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1235 f
<< stringf("%s" "end\n", indent
.c_str());
1239 // the non-clocked assignments
1240 for(auto &line
: lof_lines
)
1241 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1248 if (cell
->type
.in("$assert", "$assume", "$cover"))
1250 f
<< stringf("%s" "always @* if (", indent
.c_str());
1251 dump_sigspec(f
, cell
->getPort("\\EN"));
1252 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1253 dump_sigspec(f
, cell
->getPort("\\A"));
1254 f
<< stringf(");\n");
1258 if (cell
->type
.in("$specify2", "$specify3"))
1260 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1262 SigSpec en
= cell
->getPort("\\EN");
1263 if (en
!= State::S1
) {
1264 f
<< stringf("if (");
1265 dump_sigspec(f
, cell
->getPort("\\EN"));
1270 if (cell
->type
== "$specify3" && cell
->getParam("\\EDGE_EN").as_bool())
1271 f
<< (cell
->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1273 dump_sigspec(f
, cell
->getPort("\\SRC"));
1276 if (cell
->getParam("\\SRC_DST_PEN").as_bool())
1277 f
<< (cell
->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1278 f
<< (cell
->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1280 if (cell
->type
== "$specify3") {
1282 dump_sigspec(f
, cell
->getPort("\\DST"));
1284 if (cell
->getParam("\\DAT_DST_PEN").as_bool())
1285 f
<< (cell
->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1287 dump_sigspec(f
, cell
->getPort("\\DAT"));
1290 dump_sigspec(f
, cell
->getPort("\\DST"));
1293 bool bak_decimal
= decimal
;
1297 dump_const(f
, cell
->getParam("\\T_RISE_MIN"));
1299 dump_const(f
, cell
->getParam("\\T_RISE_TYP"));
1301 dump_const(f
, cell
->getParam("\\T_RISE_MAX"));
1303 dump_const(f
, cell
->getParam("\\T_FALL_MIN"));
1305 dump_const(f
, cell
->getParam("\\T_FALL_TYP"));
1307 dump_const(f
, cell
->getParam("\\T_FALL_MAX"));
1310 decimal
= bak_decimal
;
1312 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1316 if (cell
->type
== "$specrule")
1318 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1320 string spec_type
= cell
->getParam("\\TYPE").decode_string();
1321 f
<< stringf("%s(", spec_type
.c_str());
1323 if (cell
->getParam("\\SRC_PEN").as_bool())
1324 f
<< (cell
->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1325 dump_sigspec(f
, cell
->getPort("\\SRC"));
1327 if (cell
->getPort("\\SRC_EN") != State::S1
) {
1329 dump_sigspec(f
, cell
->getPort("\\SRC_EN"));
1333 if (cell
->getParam("\\DST_PEN").as_bool())
1334 f
<< (cell
->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1335 dump_sigspec(f
, cell
->getPort("\\DST"));
1337 if (cell
->getPort("\\DST_EN") != State::S1
) {
1339 dump_sigspec(f
, cell
->getPort("\\DST_EN"));
1342 bool bak_decimal
= decimal
;
1346 dump_const(f
, cell
->getParam("\\T_LIMIT"));
1348 if (spec_type
== "$setuphold" || spec_type
== "$recrem" || spec_type
== "$fullskew") {
1350 dump_const(f
, cell
->getParam("\\T_LIMIT2"));
1354 decimal
= bak_decimal
;
1356 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1360 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1361 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1366 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1368 if (cell
->type
[0] == '$' && !noexpr
) {
1369 if (dump_cell_expr(f
, indent
, cell
))
1373 dump_attributes(f
, indent
, cell
->attributes
);
1374 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1376 if (!defparam
&& cell
->parameters
.size() > 0) {
1377 f
<< stringf(" #(");
1378 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1379 if (it
!= cell
->parameters
.begin())
1381 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1382 dump_const(f
, it
->second
);
1385 f
<< stringf("\n%s" ")", indent
.c_str());
1388 std::string cell_name
= cellname(cell
);
1389 if (cell_name
!= id(cell
->name
))
1390 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1392 f
<< stringf(" %s (", cell_name
.c_str());
1394 bool first_arg
= true;
1395 std::set
<RTLIL::IdString
> numbered_ports
;
1396 for (int i
= 1; true; i
++) {
1398 snprintf(str
, 16, "$%d", i
);
1399 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1400 if (it
->first
!= str
)
1405 f
<< stringf("\n%s ", indent
.c_str());
1406 dump_sigspec(f
, it
->second
);
1407 numbered_ports
.insert(it
->first
);
1408 goto found_numbered_port
;
1411 found_numbered_port
:;
1413 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1414 if (numbered_ports
.count(it
->first
))
1419 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1420 if (it
->second
.size() > 0)
1421 dump_sigspec(f
, it
->second
);
1424 f
<< stringf("\n%s" ");\n", indent
.c_str());
1426 if (defparam
&& cell
->parameters
.size() > 0) {
1427 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1428 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1429 dump_const(f
, it
->second
);
1430 f
<< stringf(";\n");
1434 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q")) {
1435 std::stringstream ss
;
1436 dump_reg_init(ss
, cell
->getPort("\\Q"));
1437 if (!ss
.str().empty()) {
1438 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1445 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1447 f
<< stringf("%s" "assign ", indent
.c_str());
1448 dump_sigspec(f
, left
);
1449 f
<< stringf(" = ");
1450 dump_sigspec(f
, right
);
1451 f
<< stringf(";\n");
1454 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1456 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1458 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1460 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1461 f
<< stringf("%s" "begin\n", indent
.c_str());
1463 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1464 if (it
->first
.size() == 0)
1466 f
<< stringf("%s ", indent
.c_str());
1467 dump_sigspec(f
, it
->first
);
1468 f
<< stringf(" = ");
1469 dump_sigspec(f
, it
->second
);
1470 f
<< stringf(";\n");
1473 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1474 dump_proc_switch(f
, indent
+ " ", *it
);
1476 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1477 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1479 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1480 f
<< stringf("%s" "end\n", indent
.c_str());
1483 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1485 if (sw
->signal
.size() == 0) {
1486 f
<< stringf("%s" "begin\n", indent
.c_str());
1487 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1488 if ((*it
)->compare
.size() == 0)
1489 dump_case_body(f
, indent
+ " ", *it
);
1491 f
<< stringf("%s" "end\n", indent
.c_str());
1495 f
<< stringf("%s" "casez (", indent
.c_str());
1496 dump_sigspec(f
, sw
->signal
);
1497 f
<< stringf(")\n");
1499 bool got_default
= false;
1500 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1501 if ((*it
)->compare
.size() == 0) {
1504 f
<< stringf("%s default", indent
.c_str());
1507 f
<< stringf("%s ", indent
.c_str());
1508 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1511 dump_sigspec(f
, (*it
)->compare
[i
]);
1514 f
<< stringf(":\n");
1515 dump_case_body(f
, indent
+ " ", *it
);
1518 f
<< stringf("%s" "endcase\n", indent
.c_str());
1521 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1523 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1524 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1525 case_body_find_regs(*it2
);
1527 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1528 for (auto &c
: it
->first
.chunks())
1530 reg_wires
.insert(c
.wire
->name
);
1534 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1537 case_body_find_regs(&proc
->root_case
);
1538 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1539 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1540 for (auto &c
: it2
->first
.chunks())
1542 reg_wires
.insert(c
.wire
->name
);
1547 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1548 dump_case_body(f
, indent
, &proc
->root_case
, true);
1550 std::string backup_indent
= indent
;
1552 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1554 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1555 indent
= backup_indent
;
1557 if (sync
->type
== RTLIL::STa
) {
1558 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1559 } else if (sync
->type
== RTLIL::STi
) {
1560 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1562 f
<< stringf("%s" "always @(", indent
.c_str());
1563 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1564 f
<< stringf("posedge ");
1565 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1566 f
<< stringf("negedge ");
1567 dump_sigspec(f
, sync
->signal
);
1568 f
<< stringf(") begin\n");
1570 std::string ends
= indent
+ "end\n";
1573 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1574 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1575 dump_sigspec(f
, sync
->signal
);
1576 f
<< stringf(") begin\n");
1577 ends
= indent
+ "end\n" + ends
;
1581 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1582 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1583 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1584 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1585 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1586 dump_sigspec(f
, sync2
->signal
);
1587 f
<< stringf(") begin\n");
1588 ends
= indent
+ "end\n" + ends
;
1594 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1595 if (it
->first
.size() == 0)
1597 f
<< stringf("%s ", indent
.c_str());
1598 dump_sigspec(f
, it
->first
);
1599 f
<< stringf(" <= ");
1600 dump_sigspec(f
, it
->second
);
1601 f
<< stringf(";\n");
1604 f
<< stringf("%s", ends
.c_str());
1608 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1611 reset_auto_counter(module
);
1612 active_module
= module
;
1613 active_sigmap
.set(module
);
1614 active_initdata
.clear();
1616 for (auto wire
: module
->wires())
1617 if (wire
->attributes
.count("\\init")) {
1618 SigSpec sig
= active_sigmap(wire
);
1619 Const val
= wire
->attributes
.at("\\init");
1620 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1621 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1622 active_initdata
[sig
[i
]] = val
[i
];
1625 if (!module
->processes
.empty())
1626 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1627 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1628 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1629 "processes to logic networks and registers.\n", log_id(module
));
1632 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1633 dump_process(f
, indent
+ " ", it
->second
, true);
1637 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1638 for (auto &it
: module
->cells_
)
1640 RTLIL::Cell
*cell
= it
.second
;
1641 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1644 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1646 if (sig
.is_chunk()) {
1647 RTLIL::SigChunk chunk
= sig
.as_chunk();
1648 if (chunk
.wire
!= NULL
)
1649 for (int i
= 0; i
< chunk
.width
; i
++)
1650 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1653 for (auto &it
: module
->wires_
)
1655 RTLIL::Wire
*wire
= it
.second
;
1656 for (int i
= 0; i
< wire
->width
; i
++)
1657 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1658 goto this_wire_aint_reg
;
1660 reg_wires
.insert(wire
->name
);
1661 this_wire_aint_reg
:;
1665 dump_attributes(f
, indent
, module
->attributes
, '\n', true);
1666 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1667 bool keep_running
= true;
1668 for (int port_id
= 1; keep_running
; port_id
++) {
1669 keep_running
= false;
1670 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1671 RTLIL::Wire
*wire
= it
->second
;
1672 if (wire
->port_id
== port_id
) {
1675 f
<< stringf("%s", id(wire
->name
).c_str());
1676 keep_running
= true;
1681 f
<< stringf(");\n");
1683 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1684 dump_wire(f
, indent
+ " ", it
->second
);
1686 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1687 dump_memory(f
, indent
+ " ", it
->second
);
1689 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1690 dump_cell(f
, indent
+ " ", it
->second
);
1692 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1693 dump_process(f
, indent
+ " ", it
->second
);
1695 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1696 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1698 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1699 active_module
= NULL
;
1700 active_sigmap
.clear();
1701 active_initdata
.clear();
1704 struct VerilogBackend
: public Backend
{
1705 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1706 void help() YS_OVERRIDE
1708 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1710 log(" write_verilog [options] [filename]\n");
1712 log("Write the current design to a Verilog file.\n");
1714 log(" -norename\n");
1715 log(" without this option all internal object names (the ones with a dollar\n");
1716 log(" instead of a backslash prefix) are changed to short names in the\n");
1717 log(" format '_<number>_'.\n");
1719 log(" -renameprefix <prefix>\n");
1720 log(" insert this prefix in front of auto-generated instance names\n");
1723 log(" with this option no attributes are included in the output\n");
1725 log(" -attr2comment\n");
1726 log(" with this option attributes are included as comments in the output\n");
1729 log(" without this option all internal cells are converted to Verilog\n");
1730 log(" expressions.\n");
1733 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1734 log(" in -noexpr mode.\n");
1737 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1738 log(" not bit pattern. This option deactivates this feature and instead\n");
1739 log(" will write out all constants in binary.\n");
1742 log(" dump 32-bit constants in decimal and without size and radix\n");
1745 log(" constant values that are compatible with hex output are usually\n");
1746 log(" dumped as hex values. This option deactivates this feature and\n");
1747 log(" instead will write out all constants in binary.\n");
1750 log(" Parameters and attributes that are specified as strings in the\n");
1751 log(" original input will be output as strings by this back-end. This\n");
1752 log(" deactivates this feature and instead will write string constants\n");
1753 log(" as binary numbers.\n");
1755 log(" -defparam\n");
1756 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1757 log(" cell parameters.\n");
1759 log(" -blackboxes\n");
1760 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1761 log(" this option set only the modules with the 'blackbox' attribute\n");
1762 log(" are written to the output file.\n");
1764 log(" -selected\n");
1765 log(" only write selected modules. modules must be selected entirely or\n");
1766 log(" not at all.\n");
1769 log(" verbose output (print new names of all renamed wires and cells)\n");
1771 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1772 log("always blocks. This frontend should only be used to export an RTLIL\n");
1773 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1774 log("processes to logic networks and registers. A warning is generated when\n");
1775 log("this command is called on a design with RTLIL processes.\n");
1778 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1780 log_header(design
, "Executing Verilog backend.\n");
1785 attr2comment
= false;
1795 bool blackboxes
= false;
1796 bool selected
= false;
1798 auto_name_map
.clear();
1802 reg_ct
.insert("$dff");
1803 reg_ct
.insert("$adff");
1804 reg_ct
.insert("$dffe");
1805 reg_ct
.insert("$dlatch");
1807 reg_ct
.insert("$_DFF_N_");
1808 reg_ct
.insert("$_DFF_P_");
1810 reg_ct
.insert("$_DFF_NN0_");
1811 reg_ct
.insert("$_DFF_NN1_");
1812 reg_ct
.insert("$_DFF_NP0_");
1813 reg_ct
.insert("$_DFF_NP1_");
1814 reg_ct
.insert("$_DFF_PN0_");
1815 reg_ct
.insert("$_DFF_PN1_");
1816 reg_ct
.insert("$_DFF_PP0_");
1817 reg_ct
.insert("$_DFF_PP1_");
1819 reg_ct
.insert("$_DFFSR_NNN_");
1820 reg_ct
.insert("$_DFFSR_NNP_");
1821 reg_ct
.insert("$_DFFSR_NPN_");
1822 reg_ct
.insert("$_DFFSR_NPP_");
1823 reg_ct
.insert("$_DFFSR_PNN_");
1824 reg_ct
.insert("$_DFFSR_PNP_");
1825 reg_ct
.insert("$_DFFSR_PPN_");
1826 reg_ct
.insert("$_DFFSR_PPP_");
1829 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1830 std::string arg
= args
[argidx
];
1831 if (arg
== "-norename") {
1835 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1836 auto_prefix
= args
[++argidx
];
1839 if (arg
== "-noattr") {
1843 if (arg
== "-attr2comment") {
1844 attr2comment
= true;
1847 if (arg
== "-noexpr") {
1851 if (arg
== "-nodec") {
1855 if (arg
== "-nohex") {
1859 if (arg
== "-nostr") {
1863 if (arg
== "-defparam") {
1867 if (arg
== "-decimal") {
1871 if (arg
== "-siminit") {
1875 if (arg
== "-blackboxes") {
1879 if (arg
== "-selected") {
1889 extra_args(f
, filename
, args
, argidx
);
1893 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1894 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1895 if (it
->second
->get_blackbox_attribute() != blackboxes
)
1897 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1898 if (design
->selected_module(it
->first
))
1899 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1902 log("Dumping module `%s'.\n", it
->first
.c_str());
1903 dump_module(*f
, "", it
->second
);
1906 auto_name_map
.clear();
1912 PRIVATE_NAMESPACE_END