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
;
192 // See IEEE 1364-2005 Clause 5.1.14.
198 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
199 if (width
== 32 && !no_decimal
&& !nodec
) {
201 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
202 log_assert(i
< (int)data
.bits
.size());
203 if (data
.bits
[i
] != RTLIL::S0
&& data
.bits
[i
] != RTLIL::S1
)
205 if (data
.bits
[i
] == RTLIL::S1
)
206 val
|= 1 << (i
- offset
);
209 f
<< stringf("%d", val
);
210 else if (set_signed
&& val
< 0)
211 f
<< stringf("-32'sd%u", -val
);
213 f
<< stringf("32'%sd%u", set_signed
? "s" : "", val
);
218 vector
<char> bin_digits
, hex_digits
;
219 for (int i
= offset
; i
< offset
+width
; i
++) {
220 log_assert(i
< (int)data
.bits
.size());
221 switch (data
.bits
[i
]) {
222 case RTLIL::S0
: bin_digits
.push_back('0'); break;
223 case RTLIL::S1
: bin_digits
.push_back('1'); break;
224 case RTLIL::Sx
: bin_digits
.push_back('x'); break;
225 case RTLIL::Sz
: bin_digits
.push_back('z'); break;
226 case RTLIL::Sa
: bin_digits
.push_back('?'); break;
227 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
230 if (GetSize(bin_digits
) == 0)
232 while (GetSize(bin_digits
) % 4 != 0)
233 if (bin_digits
.back() == '1')
234 bin_digits
.push_back('0');
236 bin_digits
.push_back(bin_digits
.back());
237 for (int i
= 0; i
< GetSize(bin_digits
); i
+= 4)
239 char bit_3
= bin_digits
[i
+3];
240 char bit_2
= bin_digits
[i
+2];
241 char bit_1
= bin_digits
[i
+1];
242 char bit_0
= bin_digits
[i
+0];
243 if (bit_3
== 'x' || bit_2
== 'x' || bit_1
== 'x' || bit_0
== 'x') {
244 if (bit_3
!= 'x' || bit_2
!= 'x' || bit_1
!= 'x' || bit_0
!= 'x')
246 hex_digits
.push_back('x');
249 if (bit_3
== 'z' || bit_2
== 'z' || bit_1
== 'z' || bit_0
== 'z') {
250 if (bit_3
!= 'z' || bit_2
!= 'z' || bit_1
!= 'z' || bit_0
!= 'z')
252 hex_digits
.push_back('z');
255 if (bit_3
== '?' || bit_2
== '?' || bit_1
== '?' || bit_0
== '?') {
256 if (bit_3
!= '?' || bit_2
!= '?' || bit_1
!= '?' || bit_0
!= '?')
258 hex_digits
.push_back('?');
261 int val
= 8*(bit_3
- '0') + 4*(bit_2
- '0') + 2*(bit_1
- '0') + (bit_0
- '0');
262 hex_digits
.push_back(val
< 10 ? '0' + val
: 'a' + val
- 10);
264 f
<< stringf("%d'%sh", width
, set_signed
? "s" : "");
265 for (int i
= GetSize(hex_digits
)-1; i
>= 0; i
--)
270 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
273 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
274 log_assert(i
< (int)data
.bits
.size());
275 switch (data
.bits
[i
]) {
276 case RTLIL::S0
: f
<< stringf("0"); break;
277 case RTLIL::S1
: f
<< stringf("1"); break;
278 case RTLIL::Sx
: f
<< stringf("x"); break;
279 case RTLIL::Sz
: f
<< stringf("z"); break;
280 case RTLIL::Sa
: f
<< stringf("?"); break;
281 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
286 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
288 std::string str
= data
.decode_string();
289 for (size_t i
= 0; i
< str
.size(); i
++) {
292 else if (str
[i
] == '\t')
294 else if (str
[i
] < 32)
295 f
<< stringf("\\%03o", str
[i
]);
296 else if (str
[i
] == '"')
297 f
<< stringf("\\\"");
298 else if (str
[i
] == '\\')
299 f
<< stringf("\\\\");
300 else if (str
[i
] == '/' && escape_comment
&& i
> 0 && str
[i
-1] == '*')
305 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
310 void dump_reg_init(std::ostream
&f
, SigSpec sig
)
313 bool gotinit
= false;
315 for (auto bit
: active_sigmap(sig
)) {
316 if (active_initdata
.count(bit
)) {
317 initval
.bits
.push_back(active_initdata
.at(bit
));
320 initval
.bits
.push_back(State::Sx
);
326 dump_const(f
, initval
);
330 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
332 if (chunk
.wire
== NULL
) {
333 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
335 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0) {
336 f
<< stringf("%s", id(chunk
.wire
->name
).c_str());
337 } else if (chunk
.width
== 1) {
338 if (chunk
.wire
->upto
)
339 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
341 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
343 if (chunk
.wire
->upto
)
344 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
345 (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
346 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
348 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
349 (chunk
.offset
+ chunk
.width
- 1) + chunk
.wire
->start_offset
,
350 chunk
.offset
+ chunk
.wire
->start_offset
);
355 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
357 if (GetSize(sig
) == 0) {
361 if (sig
.is_chunk()) {
362 dump_sigchunk(f
, sig
.as_chunk());
365 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
366 if (it
!= sig
.chunks().rbegin())
368 dump_sigchunk(f
, *it
, true);
374 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)
380 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
381 f
<< stringf("%s" "%s %s", indent
.c_str(), as_comment
? "/*" : "(*", id(it
->first
).c_str());
383 if (modattr
&& (it
->second
== Const(0, 1) || it
->second
== Const(0)))
385 else if (modattr
&& (it
->second
== Const(1, 1) || it
->second
== Const(1)))
388 dump_const(f
, it
->second
, -1, 0, false, as_comment
);
389 f
<< stringf(" %s%c", as_comment
? "*/" : "*)", term
);
393 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
395 dump_attributes(f
, indent
, wire
->attributes
);
397 if (wire
->port_input
&& !wire
->port_output
)
398 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
399 else if (!wire
->port_input
&& wire
->port_output
)
400 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
401 else if (wire
->port_input
&& wire
->port_output
)
402 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
404 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
405 if (wire
->width
!= 1)
406 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
407 f
<< stringf("%s;\n", id(wire
->name
).c_str());
409 // do not use Verilog-2k "output reg" syntax in Verilog export
410 std::string range
= "";
411 if (wire
->width
!= 1) {
413 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
415 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
417 if (wire
->port_input
&& !wire
->port_output
)
418 f
<< stringf("%s" "input%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
419 if (!wire
->port_input
&& wire
->port_output
)
420 f
<< stringf("%s" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
421 if (wire
->port_input
&& wire
->port_output
)
422 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
423 if (reg_wires
.count(wire
->name
)) {
424 f
<< stringf("%s" "reg%s %s", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
425 if (wire
->attributes
.count("\\init")) {
427 dump_const(f
, wire
->attributes
.at("\\init"));
430 } else if (!wire
->port_input
&& !wire
->port_output
)
431 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
435 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
437 dump_attributes(f
, indent
, memory
->attributes
);
438 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
);
441 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
443 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
444 f
<< stringf("$signed(");
445 dump_sigspec(f
, cell
->getPort("\\" + port
));
448 dump_sigspec(f
, cell
->getPort("\\" + port
));
451 std::string
cellname(RTLIL::Cell
*cell
)
453 if (!norename
&& cell
->name
[0] == '$' && reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q"))
455 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
456 if (GetSize(sig
) != 1 || sig
.is_fully_const())
457 goto no_special_reg_name
;
459 RTLIL::Wire
*wire
= sig
[0].wire
;
461 if (wire
->name
[0] != '\\')
462 goto no_special_reg_name
;
464 std::string cell_name
= wire
->name
.str();
466 size_t pos
= cell_name
.find('[');
467 if (pos
!= std::string::npos
)
468 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
470 cell_name
= cell_name
+ "_reg";
472 if (wire
->width
!= 1)
473 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
475 if (active_module
&& active_module
->count_id(cell_name
) > 0)
476 goto no_special_reg_name
;
478 return id(cell_name
);
483 return id(cell
->name
).c_str();
487 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
489 f
<< stringf("%s" "assign ", indent
.c_str());
490 dump_sigspec(f
, cell
->getPort("\\Y"));
491 f
<< stringf(" = %s ", op
.c_str());
492 dump_attributes(f
, "", cell
->attributes
, ' ');
493 dump_cell_expr_port(f
, cell
, "A", true);
497 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
499 f
<< stringf("%s" "assign ", indent
.c_str());
500 dump_sigspec(f
, cell
->getPort("\\Y"));
502 dump_cell_expr_port(f
, cell
, "A", true);
503 f
<< stringf(" %s ", op
.c_str());
504 dump_attributes(f
, "", cell
->attributes
, ' ');
505 dump_cell_expr_port(f
, cell
, "B", true);
509 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
511 if (cell
->type
== "$_NOT_") {
512 f
<< stringf("%s" "assign ", indent
.c_str());
513 dump_sigspec(f
, cell
->getPort("\\Y"));
516 dump_attributes(f
, "", cell
->attributes
, ' ');
517 dump_cell_expr_port(f
, cell
, "A", false);
522 if (cell
->type
.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
523 f
<< stringf("%s" "assign ", indent
.c_str());
524 dump_sigspec(f
, cell
->getPort("\\Y"));
526 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
528 dump_cell_expr_port(f
, cell
, "A", false);
530 if (cell
->type
.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
532 if (cell
->type
.in("$_OR_", "$_NOR_", "$_ORNOT_"))
534 if (cell
->type
.in("$_XOR_", "$_XNOR_"))
536 dump_attributes(f
, "", cell
->attributes
, ' ');
538 if (cell
->type
.in("$_ANDNOT_", "$_ORNOT_"))
540 dump_cell_expr_port(f
, cell
, "B", false);
541 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
547 if (cell
->type
== "$_MUX_") {
548 f
<< stringf("%s" "assign ", indent
.c_str());
549 dump_sigspec(f
, cell
->getPort("\\Y"));
551 dump_cell_expr_port(f
, cell
, "S", false);
553 dump_attributes(f
, "", cell
->attributes
, ' ');
554 dump_cell_expr_port(f
, cell
, "B", false);
556 dump_cell_expr_port(f
, cell
, "A", false);
561 if (cell
->type
.in("$_AOI3_", "$_OAI3_")) {
562 f
<< stringf("%s" "assign ", indent
.c_str());
563 dump_sigspec(f
, cell
->getPort("\\Y"));
564 f
<< stringf(" = ~((");
565 dump_cell_expr_port(f
, cell
, "A", false);
566 f
<< stringf(cell
->type
== "$_AOI3_" ? " & " : " | ");
567 dump_cell_expr_port(f
, cell
, "B", false);
568 f
<< stringf(cell
->type
== "$_AOI3_" ? ") |" : ") &");
569 dump_attributes(f
, "", cell
->attributes
, ' ');
571 dump_cell_expr_port(f
, cell
, "C", false);
572 f
<< stringf(");\n");
576 if (cell
->type
.in("$_AOI4_", "$_OAI4_")) {
577 f
<< stringf("%s" "assign ", indent
.c_str());
578 dump_sigspec(f
, cell
->getPort("\\Y"));
579 f
<< stringf(" = ~((");
580 dump_cell_expr_port(f
, cell
, "A", false);
581 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
582 dump_cell_expr_port(f
, cell
, "B", false);
583 f
<< stringf(cell
->type
== "$_AOI4_" ? ") |" : ") &");
584 dump_attributes(f
, "", cell
->attributes
, ' ');
586 dump_cell_expr_port(f
, cell
, "C", false);
587 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
588 dump_cell_expr_port(f
, cell
, "D", false);
589 f
<< stringf("));\n");
593 if (cell
->type
.substr(0, 6) == "$_DFF_")
595 std::string reg_name
= cellname(cell
);
596 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
598 if (!out_is_reg_wire
) {
599 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
600 dump_reg_init(f
, cell
->getPort("\\Q"));
604 dump_attributes(f
, indent
, cell
->attributes
);
605 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), cell
->type
[6] == 'P' ? "pos" : "neg");
606 dump_sigspec(f
, cell
->getPort("\\C"));
607 if (cell
->type
[7] != '_') {
608 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
609 dump_sigspec(f
, cell
->getPort("\\R"));
613 if (cell
->type
[7] != '_') {
614 f
<< stringf("%s" " if (%s", indent
.c_str(), cell
->type
[7] == 'P' ? "" : "!");
615 dump_sigspec(f
, cell
->getPort("\\R"));
617 f
<< stringf("%s" " %s <= %c;\n", indent
.c_str(), reg_name
.c_str(), cell
->type
[8]);
618 f
<< stringf("%s" " else\n", indent
.c_str());
621 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
622 dump_cell_expr_port(f
, cell
, "D", false);
625 if (!out_is_reg_wire
) {
626 f
<< stringf("%s" "assign ", indent
.c_str());
627 dump_sigspec(f
, cell
->getPort("\\Q"));
628 f
<< stringf(" = %s;\n", reg_name
.c_str());
634 if (cell
->type
.substr(0, 8) == "$_DFFSR_")
636 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
638 std::string reg_name
= cellname(cell
);
639 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
641 if (!out_is_reg_wire
) {
642 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
643 dump_reg_init(f
, cell
->getPort("\\Q"));
647 dump_attributes(f
, indent
, cell
->attributes
);
648 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_c
== 'P' ? "pos" : "neg");
649 dump_sigspec(f
, cell
->getPort("\\C"));
650 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
651 dump_sigspec(f
, cell
->getPort("\\S"));
652 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
653 dump_sigspec(f
, cell
->getPort("\\R"));
656 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
657 dump_sigspec(f
, cell
->getPort("\\R"));
659 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
661 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
662 dump_sigspec(f
, cell
->getPort("\\S"));
664 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
666 f
<< stringf("%s" " else\n", indent
.c_str());
667 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
668 dump_cell_expr_port(f
, cell
, "D", false);
671 if (!out_is_reg_wire
) {
672 f
<< stringf("%s" "assign ", indent
.c_str());
673 dump_sigspec(f
, cell
->getPort("\\Q"));
674 f
<< stringf(" = %s;\n", reg_name
.c_str());
680 #define HANDLE_UNIOP(_type, _operator) \
681 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
682 #define HANDLE_BINOP(_type, _operator) \
683 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
685 HANDLE_UNIOP("$not", "~")
686 HANDLE_UNIOP("$pos", "+")
687 HANDLE_UNIOP("$neg", "-")
689 HANDLE_BINOP("$and", "&")
690 HANDLE_BINOP("$or", "|")
691 HANDLE_BINOP("$xor", "^")
692 HANDLE_BINOP("$xnor", "~^")
694 HANDLE_UNIOP("$reduce_and", "&")
695 HANDLE_UNIOP("$reduce_or", "|")
696 HANDLE_UNIOP("$reduce_xor", "^")
697 HANDLE_UNIOP("$reduce_xnor", "~^")
698 HANDLE_UNIOP("$reduce_bool", "|")
700 HANDLE_BINOP("$shl", "<<")
701 HANDLE_BINOP("$shr", ">>")
702 HANDLE_BINOP("$sshl", "<<<")
703 HANDLE_BINOP("$sshr", ">>>")
705 HANDLE_BINOP("$lt", "<")
706 HANDLE_BINOP("$le", "<=")
707 HANDLE_BINOP("$eq", "==")
708 HANDLE_BINOP("$ne", "!=")
709 HANDLE_BINOP("$eqx", "===")
710 HANDLE_BINOP("$nex", "!==")
711 HANDLE_BINOP("$ge", ">=")
712 HANDLE_BINOP("$gt", ">")
714 HANDLE_BINOP("$add", "+")
715 HANDLE_BINOP("$sub", "-")
716 HANDLE_BINOP("$mul", "*")
717 HANDLE_BINOP("$div", "/")
718 HANDLE_BINOP("$mod", "%")
719 HANDLE_BINOP("$pow", "**")
721 HANDLE_UNIOP("$logic_not", "!")
722 HANDLE_BINOP("$logic_and", "&&")
723 HANDLE_BINOP("$logic_or", "||")
728 if (cell
->type
== "$shift")
730 f
<< stringf("%s" "assign ", indent
.c_str());
731 dump_sigspec(f
, cell
->getPort("\\Y"));
733 if (cell
->getParam("\\B_SIGNED").as_bool())
735 f
<< stringf("$signed(");
736 dump_sigspec(f
, cell
->getPort("\\B"));
738 f
<< stringf(" < 0 ? ");
739 dump_sigspec(f
, cell
->getPort("\\A"));
740 f
<< stringf(" << - ");
741 dump_sigspec(f
, cell
->getPort("\\B"));
743 dump_sigspec(f
, cell
->getPort("\\A"));
744 f
<< stringf(" >> ");
745 dump_sigspec(f
, cell
->getPort("\\B"));
749 dump_sigspec(f
, cell
->getPort("\\A"));
750 f
<< stringf(" >> ");
751 dump_sigspec(f
, cell
->getPort("\\B"));
757 if (cell
->type
== "$shiftx")
759 std::string temp_id
= next_auto_id();
760 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort("\\A"))-1, temp_id
.c_str());
761 dump_sigspec(f
, cell
->getPort("\\A"));
764 f
<< stringf("%s" "assign ", indent
.c_str());
765 dump_sigspec(f
, cell
->getPort("\\Y"));
766 f
<< stringf(" = %s[", temp_id
.c_str());
767 if (cell
->getParam("\\B_SIGNED").as_bool())
768 f
<< stringf("$signed(");
769 dump_sigspec(f
, cell
->getPort("\\B"));
770 if (cell
->getParam("\\B_SIGNED").as_bool())
772 f
<< stringf(" +: %d", cell
->getParam("\\Y_WIDTH").as_int());
773 f
<< stringf("];\n");
777 if (cell
->type
== "$mux")
779 f
<< stringf("%s" "assign ", indent
.c_str());
780 dump_sigspec(f
, cell
->getPort("\\Y"));
782 dump_sigspec(f
, cell
->getPort("\\S"));
784 dump_attributes(f
, "", cell
->attributes
, ' ');
785 dump_sigspec(f
, cell
->getPort("\\B"));
787 dump_sigspec(f
, cell
->getPort("\\A"));
792 if (cell
->type
== "$pmux")
794 int width
= cell
->parameters
["\\WIDTH"].as_int();
795 int s_width
= cell
->getPort("\\S").size();
796 std::string func_name
= cellname(cell
);
798 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
799 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
800 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
801 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
803 dump_attributes(f
, indent
+ " ", cell
->attributes
);
805 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
806 f
<< stringf("%s" " casez (s)", indent
.c_str());
807 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
809 for (int i
= 0; i
< s_width
; i
++)
811 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
813 for (int j
= s_width
-1; j
>= 0; j
--)
814 f
<< stringf("%c", j
== i
? '1' : '?');
817 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
820 f
<< stringf("%s" " default:\n", indent
.c_str());
821 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
823 f
<< stringf("%s" " endcase\n", indent
.c_str());
824 f
<< stringf("%s" "endfunction\n", indent
.c_str());
826 f
<< stringf("%s" "assign ", indent
.c_str());
827 dump_sigspec(f
, cell
->getPort("\\Y"));
828 f
<< stringf(" = %s(", func_name
.c_str());
829 dump_sigspec(f
, cell
->getPort("\\A"));
831 dump_sigspec(f
, cell
->getPort("\\B"));
833 dump_sigspec(f
, cell
->getPort("\\S"));
834 f
<< stringf(");\n");
838 if (cell
->type
== "$tribuf")
840 f
<< stringf("%s" "assign ", indent
.c_str());
841 dump_sigspec(f
, cell
->getPort("\\Y"));
843 dump_sigspec(f
, cell
->getPort("\\EN"));
845 dump_sigspec(f
, cell
->getPort("\\A"));
846 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at("\\WIDTH").as_int());
850 if (cell
->type
== "$slice")
852 f
<< stringf("%s" "assign ", indent
.c_str());
853 dump_sigspec(f
, cell
->getPort("\\Y"));
855 dump_sigspec(f
, cell
->getPort("\\A"));
856 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
860 if (cell
->type
== "$concat")
862 f
<< stringf("%s" "assign ", indent
.c_str());
863 dump_sigspec(f
, cell
->getPort("\\Y"));
864 f
<< stringf(" = { ");
865 dump_sigspec(f
, cell
->getPort("\\B"));
867 dump_sigspec(f
, cell
->getPort("\\A"));
868 f
<< stringf(" };\n");
872 if (cell
->type
== "$lut")
874 f
<< stringf("%s" "assign ", indent
.c_str());
875 dump_sigspec(f
, cell
->getPort("\\Y"));
877 dump_const(f
, cell
->parameters
.at("\\LUT"));
878 f
<< stringf(" >> ");
879 dump_attributes(f
, "", cell
->attributes
, ' ');
880 dump_sigspec(f
, cell
->getPort("\\A"));
885 if (cell
->type
== "$dffsr")
887 SigSpec sig_clk
= cell
->getPort("\\CLK");
888 SigSpec sig_set
= cell
->getPort("\\SET");
889 SigSpec sig_clr
= cell
->getPort("\\CLR");
890 SigSpec sig_d
= cell
->getPort("\\D");
891 SigSpec sig_q
= cell
->getPort("\\Q");
893 int width
= cell
->parameters
["\\WIDTH"].as_int();
894 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
895 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
896 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
898 std::string reg_name
= cellname(cell
);
899 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
901 if (!out_is_reg_wire
) {
902 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
903 dump_reg_init(f
, sig_q
);
907 for (int i
= 0; i
< width
; i
++) {
908 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
909 dump_sigspec(f
, sig_clk
);
910 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
911 dump_sigspec(f
, sig_set
);
912 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
913 dump_sigspec(f
, sig_clr
);
916 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
917 dump_sigspec(f
, sig_clr
);
918 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
920 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
921 dump_sigspec(f
, sig_set
);
922 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
924 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
925 dump_sigspec(f
, sig_d
[i
]);
929 if (!out_is_reg_wire
) {
930 f
<< stringf("%s" "assign ", indent
.c_str());
931 dump_sigspec(f
, sig_q
);
932 f
<< stringf(" = %s;\n", reg_name
.c_str());
938 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
940 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
941 bool pol_clk
, pol_arst
= false, pol_en
= false;
943 sig_clk
= cell
->getPort("\\CLK");
944 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
946 if (cell
->type
== "$adff") {
947 sig_arst
= cell
->getPort("\\ARST");
948 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
949 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
952 if (cell
->type
== "$dffe") {
953 sig_en
= cell
->getPort("\\EN");
954 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
957 std::string reg_name
= cellname(cell
);
958 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
960 if (!out_is_reg_wire
) {
961 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
962 dump_reg_init(f
, cell
->getPort("\\Q"));
966 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
967 dump_sigspec(f
, sig_clk
);
968 if (cell
->type
== "$adff") {
969 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
970 dump_sigspec(f
, sig_arst
);
974 if (cell
->type
== "$adff") {
975 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
976 dump_sigspec(f
, sig_arst
);
978 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
979 dump_sigspec(f
, val_arst
);
981 f
<< stringf("%s" " else\n", indent
.c_str());
984 if (cell
->type
== "$dffe") {
985 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
986 dump_sigspec(f
, sig_en
);
990 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
991 dump_cell_expr_port(f
, cell
, "D", false);
994 if (!out_is_reg_wire
) {
995 f
<< stringf("%s" "assign ", indent
.c_str());
996 dump_sigspec(f
, cell
->getPort("\\Q"));
997 f
<< stringf(" = %s;\n", reg_name
.c_str());
1003 if (cell
->type
== "$dlatch")
1005 RTLIL::SigSpec sig_en
;
1006 bool pol_en
= false;
1008 sig_en
= cell
->getPort("\\EN");
1009 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
1011 std::string reg_name
= cellname(cell
);
1012 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
1014 if (!out_is_reg_wire
) {
1015 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
1016 dump_reg_init(f
, cell
->getPort("\\Q"));
1020 f
<< stringf("%s" "always @*\n", indent
.c_str());
1022 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1023 dump_sigspec(f
, sig_en
);
1024 f
<< stringf(")\n");
1026 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
1027 dump_cell_expr_port(f
, cell
, "D", false);
1028 f
<< stringf(";\n");
1030 if (!out_is_reg_wire
) {
1031 f
<< stringf("%s" "assign ", indent
.c_str());
1032 dump_sigspec(f
, cell
->getPort("\\Q"));
1033 f
<< stringf(" = %s;\n", reg_name
.c_str());
1039 if (cell
->type
== "$mem")
1041 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
1042 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
1043 int abits
= cell
->parameters
["\\ABITS"].as_int();
1044 int size
= cell
->parameters
["\\SIZE"].as_int();
1045 int offset
= cell
->parameters
["\\OFFSET"].as_int();
1046 int width
= cell
->parameters
["\\WIDTH"].as_int();
1047 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
1049 // for memory block make something like:
1050 // reg [7:0] memid [3:0];
1054 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1057 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1058 for (int i
=0; i
<size
; i
++)
1060 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1061 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1062 f
<< stringf(";\n");
1064 f
<< stringf("%s" "end\n", indent
.c_str());
1067 // create a map : "edge clk" -> expressions within that clock domain
1068 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1069 clk_to_lof_body
[""] = std::vector
<std::string
>();
1070 std::string clk_domain_str
;
1071 // create a list of reg declarations
1072 std::vector
<std::string
> lof_reg_declarations
;
1074 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1075 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1076 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1078 for (int i
=0; i
< nread_ports
; i
++)
1080 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1081 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1082 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1083 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1084 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1085 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1086 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1090 std::ostringstream os
;
1091 dump_sigspec(os
, sig_rd_clk
);
1092 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1093 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1094 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1096 if (!rd_transparent
)
1098 // for clocked read ports make something like:
1099 // reg [..] temp_id;
1100 // always @(posedge clk)
1101 // if (rd_en) temp_id <= array_reg[r_addr];
1102 // assign r_data = temp_id;
1103 std::string temp_id
= next_auto_id();
1104 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1106 std::ostringstream os
;
1107 if (sig_rd_en
!= RTLIL::SigBit(true))
1109 os
<< stringf("if (");
1110 dump_sigspec(os
, sig_rd_en
);
1111 os
<< stringf(") ");
1113 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1114 dump_sigspec(os
, sig_rd_addr
);
1115 os
<< stringf("];\n");
1116 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1119 std::ostringstream os
;
1120 dump_sigspec(os
, sig_rd_data
);
1121 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1122 clk_to_lof_body
[""].push_back(line
);
1127 // for rd-transparent read-ports make something like:
1128 // reg [..] temp_id;
1129 // always @(posedge clk)
1130 // temp_id <= r_addr;
1131 // assign r_data = array_reg[temp_id];
1132 std::string temp_id
= next_auto_id();
1133 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1135 std::ostringstream os
;
1136 dump_sigspec(os
, sig_rd_addr
);
1137 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1138 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1141 std::ostringstream os
;
1142 dump_sigspec(os
, sig_rd_data
);
1143 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1144 clk_to_lof_body
[""].push_back(line
);
1148 // for non-clocked read-ports make something like:
1149 // assign r_data = array_reg[r_addr];
1150 std::ostringstream os
, os2
;
1151 dump_sigspec(os
, sig_rd_data
);
1152 dump_sigspec(os2
, sig_rd_addr
);
1153 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1154 clk_to_lof_body
[""].push_back(line
);
1158 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1159 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1160 bool wr_clk_posedge
;
1163 for (int i
=0; i
< nwrite_ports
; i
++)
1165 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1166 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1167 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1168 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1169 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1171 std::ostringstream os
;
1172 dump_sigspec(os
, sig_wr_clk
);
1173 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1174 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1175 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1177 // make something like:
1178 // always @(posedge clk)
1179 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1181 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1183 int start_i
= i
, width
= 1;
1184 SigBit wen_bit
= sig_wr_en
[i
];
1186 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1189 if (wen_bit
== State::S0
)
1192 std::ostringstream os
;
1193 if (wen_bit
!= State::S1
)
1195 os
<< stringf("if (");
1196 dump_sigspec(os
, wen_bit
);
1197 os
<< stringf(") ");
1199 os
<< stringf("%s[", mem_id
.c_str());
1200 dump_sigspec(os
, sig_wr_addr
);
1201 if (width
== GetSize(sig_wr_en
))
1202 os
<< stringf("] <= ");
1204 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1205 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1206 os
<< stringf(";\n");
1207 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1210 // Output Verilog that looks something like this:
1212 // always @(posedge CLK2) begin
1213 // _3_ <= memory[D1ADDR];
1215 // memory[A1ADDR] <= A1DATA;
1217 // memory[A2ADDR] <= A2DATA;
1220 // always @(negedge CLK1) begin
1222 // memory[C1ADDR] <= C1DATA;
1225 // assign D1DATA = _3_;
1226 // assign D2DATA <= memory[D2ADDR];
1228 // the reg ... definitions
1229 for(auto ®
: lof_reg_declarations
)
1231 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1233 // the block of expressions by clock domain
1234 for(auto &pair
: clk_to_lof_body
)
1236 std::string clk_domain
= pair
.first
;
1237 std::vector
<std::string
> lof_lines
= pair
.second
;
1238 if( clk_domain
!= "")
1240 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1241 for(auto &line
: lof_lines
)
1242 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1243 f
<< stringf("%s" "end\n", indent
.c_str());
1247 // the non-clocked assignments
1248 for(auto &line
: lof_lines
)
1249 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1256 if (cell
->type
.in("$assert", "$assume", "$cover"))
1258 f
<< stringf("%s" "always @* if (", indent
.c_str());
1259 dump_sigspec(f
, cell
->getPort("\\EN"));
1260 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1261 dump_sigspec(f
, cell
->getPort("\\A"));
1262 f
<< stringf(");\n");
1266 if (cell
->type
.in("$specify2", "$specify3"))
1268 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1270 SigSpec en
= cell
->getPort("\\EN");
1271 if (en
!= State::S1
) {
1272 f
<< stringf("if (");
1273 dump_sigspec(f
, cell
->getPort("\\EN"));
1278 if (cell
->type
== "$specify3" && cell
->getParam("\\EDGE_EN").as_bool())
1279 f
<< (cell
->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1281 dump_sigspec(f
, cell
->getPort("\\SRC"));
1284 if (cell
->getParam("\\SRC_DST_PEN").as_bool())
1285 f
<< (cell
->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1286 f
<< (cell
->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1288 if (cell
->type
== "$specify3") {
1290 dump_sigspec(f
, cell
->getPort("\\DST"));
1292 if (cell
->getParam("\\DAT_DST_PEN").as_bool())
1293 f
<< (cell
->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1295 dump_sigspec(f
, cell
->getPort("\\DAT"));
1298 dump_sigspec(f
, cell
->getPort("\\DST"));
1301 bool bak_decimal
= decimal
;
1305 dump_const(f
, cell
->getParam("\\T_RISE_MIN"));
1307 dump_const(f
, cell
->getParam("\\T_RISE_TYP"));
1309 dump_const(f
, cell
->getParam("\\T_RISE_MAX"));
1311 dump_const(f
, cell
->getParam("\\T_FALL_MIN"));
1313 dump_const(f
, cell
->getParam("\\T_FALL_TYP"));
1315 dump_const(f
, cell
->getParam("\\T_FALL_MAX"));
1318 decimal
= bak_decimal
;
1320 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1324 if (cell
->type
== "$specrule")
1326 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1328 string spec_type
= cell
->getParam("\\TYPE").decode_string();
1329 f
<< stringf("%s(", spec_type
.c_str());
1331 if (cell
->getParam("\\SRC_PEN").as_bool())
1332 f
<< (cell
->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1333 dump_sigspec(f
, cell
->getPort("\\SRC"));
1335 if (cell
->getPort("\\SRC_EN") != State::S1
) {
1337 dump_sigspec(f
, cell
->getPort("\\SRC_EN"));
1341 if (cell
->getParam("\\DST_PEN").as_bool())
1342 f
<< (cell
->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1343 dump_sigspec(f
, cell
->getPort("\\DST"));
1345 if (cell
->getPort("\\DST_EN") != State::S1
) {
1347 dump_sigspec(f
, cell
->getPort("\\DST_EN"));
1350 bool bak_decimal
= decimal
;
1354 dump_const(f
, cell
->getParam("\\T_LIMIT"));
1356 if (spec_type
== "$setuphold" || spec_type
== "$recrem" || spec_type
== "$fullskew") {
1358 dump_const(f
, cell
->getParam("\\T_LIMIT2"));
1362 decimal
= bak_decimal
;
1364 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1368 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1369 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1374 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1376 if (cell
->type
[0] == '$' && !noexpr
) {
1377 if (dump_cell_expr(f
, indent
, cell
))
1381 dump_attributes(f
, indent
, cell
->attributes
);
1382 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1384 if (!defparam
&& cell
->parameters
.size() > 0) {
1385 f
<< stringf(" #(");
1386 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1387 if (it
!= cell
->parameters
.begin())
1389 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1390 dump_const(f
, it
->second
);
1393 f
<< stringf("\n%s" ")", indent
.c_str());
1396 std::string cell_name
= cellname(cell
);
1397 if (cell_name
!= id(cell
->name
))
1398 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1400 f
<< stringf(" %s (", cell_name
.c_str());
1402 bool first_arg
= true;
1403 std::set
<RTLIL::IdString
> numbered_ports
;
1404 for (int i
= 1; true; i
++) {
1406 snprintf(str
, 16, "$%d", i
);
1407 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1408 if (it
->first
!= str
)
1413 f
<< stringf("\n%s ", indent
.c_str());
1414 dump_sigspec(f
, it
->second
);
1415 numbered_ports
.insert(it
->first
);
1416 goto found_numbered_port
;
1419 found_numbered_port
:;
1421 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1422 if (numbered_ports
.count(it
->first
))
1427 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1428 if (it
->second
.size() > 0)
1429 dump_sigspec(f
, it
->second
);
1432 f
<< stringf("\n%s" ");\n", indent
.c_str());
1434 if (defparam
&& cell
->parameters
.size() > 0) {
1435 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1436 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1437 dump_const(f
, it
->second
);
1438 f
<< stringf(";\n");
1442 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q")) {
1443 std::stringstream ss
;
1444 dump_reg_init(ss
, cell
->getPort("\\Q"));
1445 if (!ss
.str().empty()) {
1446 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1453 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1455 f
<< stringf("%s" "assign ", indent
.c_str());
1456 dump_sigspec(f
, left
);
1457 f
<< stringf(" = ");
1458 dump_sigspec(f
, right
);
1459 f
<< stringf(";\n");
1462 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1464 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1466 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1468 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1469 f
<< stringf("%s" "begin\n", indent
.c_str());
1471 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1472 if (it
->first
.size() == 0)
1474 f
<< stringf("%s ", indent
.c_str());
1475 dump_sigspec(f
, it
->first
);
1476 f
<< stringf(" = ");
1477 dump_sigspec(f
, it
->second
);
1478 f
<< stringf(";\n");
1481 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1482 dump_proc_switch(f
, indent
+ " ", *it
);
1484 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1485 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1487 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1488 f
<< stringf("%s" "end\n", indent
.c_str());
1491 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1493 if (sw
->signal
.size() == 0) {
1494 f
<< stringf("%s" "begin\n", indent
.c_str());
1495 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1496 if ((*it
)->compare
.size() == 0)
1497 dump_case_body(f
, indent
+ " ", *it
);
1499 f
<< stringf("%s" "end\n", indent
.c_str());
1503 dump_attributes(f
, indent
, sw
->attributes
);
1504 f
<< stringf("%s" "casez (", indent
.c_str());
1505 dump_sigspec(f
, sw
->signal
);
1506 f
<< stringf(")\n");
1508 bool got_default
= false;
1509 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1510 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*as_comment=*/true);
1511 if ((*it
)->compare
.size() == 0) {
1514 f
<< stringf("%s default", indent
.c_str());
1517 f
<< stringf("%s ", indent
.c_str());
1518 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1521 dump_sigspec(f
, (*it
)->compare
[i
]);
1524 f
<< stringf(":\n");
1525 dump_case_body(f
, indent
+ " ", *it
);
1528 f
<< stringf("%s" "endcase\n", indent
.c_str());
1531 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1533 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1534 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1535 case_body_find_regs(*it2
);
1537 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1538 for (auto &c
: it
->first
.chunks())
1540 reg_wires
.insert(c
.wire
->name
);
1544 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1547 case_body_find_regs(&proc
->root_case
);
1548 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1549 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1550 for (auto &c
: it2
->first
.chunks())
1552 reg_wires
.insert(c
.wire
->name
);
1557 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1558 dump_case_body(f
, indent
, &proc
->root_case
, true);
1560 std::string backup_indent
= indent
;
1562 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1564 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1565 indent
= backup_indent
;
1567 if (sync
->type
== RTLIL::STa
) {
1568 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1569 } else if (sync
->type
== RTLIL::STi
) {
1570 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1572 f
<< stringf("%s" "always @(", indent
.c_str());
1573 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1574 f
<< stringf("posedge ");
1575 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1576 f
<< stringf("negedge ");
1577 dump_sigspec(f
, sync
->signal
);
1578 f
<< stringf(") begin\n");
1580 std::string ends
= indent
+ "end\n";
1583 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1584 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1585 dump_sigspec(f
, sync
->signal
);
1586 f
<< stringf(") begin\n");
1587 ends
= indent
+ "end\n" + ends
;
1591 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1592 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1593 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1594 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1595 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1596 dump_sigspec(f
, sync2
->signal
);
1597 f
<< stringf(") begin\n");
1598 ends
= indent
+ "end\n" + ends
;
1604 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1605 if (it
->first
.size() == 0)
1607 f
<< stringf("%s ", indent
.c_str());
1608 dump_sigspec(f
, it
->first
);
1609 f
<< stringf(" <= ");
1610 dump_sigspec(f
, it
->second
);
1611 f
<< stringf(";\n");
1614 f
<< stringf("%s", ends
.c_str());
1618 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1621 reset_auto_counter(module
);
1622 active_module
= module
;
1623 active_sigmap
.set(module
);
1624 active_initdata
.clear();
1626 for (auto wire
: module
->wires())
1627 if (wire
->attributes
.count("\\init")) {
1628 SigSpec sig
= active_sigmap(wire
);
1629 Const val
= wire
->attributes
.at("\\init");
1630 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1631 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1632 active_initdata
[sig
[i
]] = val
[i
];
1635 if (!module
->processes
.empty())
1636 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1637 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1638 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1639 "processes to logic networks and registers.\n", log_id(module
));
1642 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1643 dump_process(f
, indent
+ " ", it
->second
, true);
1647 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1648 for (auto &it
: module
->cells_
)
1650 RTLIL::Cell
*cell
= it
.second
;
1651 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1654 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1656 if (sig
.is_chunk()) {
1657 RTLIL::SigChunk chunk
= sig
.as_chunk();
1658 if (chunk
.wire
!= NULL
)
1659 for (int i
= 0; i
< chunk
.width
; i
++)
1660 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1663 for (auto &it
: module
->wires_
)
1665 RTLIL::Wire
*wire
= it
.second
;
1666 for (int i
= 0; i
< wire
->width
; i
++)
1667 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1668 goto this_wire_aint_reg
;
1670 reg_wires
.insert(wire
->name
);
1671 this_wire_aint_reg
:;
1675 dump_attributes(f
, indent
, module
->attributes
, '\n', /*attr2comment=*/true);
1676 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1677 bool keep_running
= true;
1678 for (int port_id
= 1; keep_running
; port_id
++) {
1679 keep_running
= false;
1680 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1681 RTLIL::Wire
*wire
= it
->second
;
1682 if (wire
->port_id
== port_id
) {
1685 f
<< stringf("%s", id(wire
->name
).c_str());
1686 keep_running
= true;
1691 f
<< stringf(");\n");
1693 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1694 dump_wire(f
, indent
+ " ", it
->second
);
1696 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1697 dump_memory(f
, indent
+ " ", it
->second
);
1699 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1700 dump_cell(f
, indent
+ " ", it
->second
);
1702 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1703 dump_process(f
, indent
+ " ", it
->second
);
1705 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1706 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1708 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1709 active_module
= NULL
;
1710 active_sigmap
.clear();
1711 active_initdata
.clear();
1714 struct VerilogBackend
: public Backend
{
1715 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1716 void help() YS_OVERRIDE
1718 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1720 log(" write_verilog [options] [filename]\n");
1722 log("Write the current design to a Verilog file.\n");
1724 log(" -norename\n");
1725 log(" without this option all internal object names (the ones with a dollar\n");
1726 log(" instead of a backslash prefix) are changed to short names in the\n");
1727 log(" format '_<number>_'.\n");
1729 log(" -renameprefix <prefix>\n");
1730 log(" insert this prefix in front of auto-generated instance names\n");
1733 log(" with this option no attributes are included in the output\n");
1735 log(" -attr2comment\n");
1736 log(" with this option attributes are included as comments in the output\n");
1739 log(" without this option all internal cells are converted to Verilog\n");
1740 log(" expressions.\n");
1743 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1744 log(" in -noexpr mode.\n");
1747 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1748 log(" not bit pattern. This option deactivates this feature and instead\n");
1749 log(" will write out all constants in binary.\n");
1752 log(" dump 32-bit constants in decimal and without size and radix\n");
1755 log(" constant values that are compatible with hex output are usually\n");
1756 log(" dumped as hex values. This option deactivates this feature and\n");
1757 log(" instead will write out all constants in binary.\n");
1760 log(" Parameters and attributes that are specified as strings in the\n");
1761 log(" original input will be output as strings by this back-end. This\n");
1762 log(" deactivates this feature and instead will write string constants\n");
1763 log(" as binary numbers.\n");
1765 log(" -defparam\n");
1766 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1767 log(" cell parameters.\n");
1769 log(" -blackboxes\n");
1770 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1771 log(" this option set only the modules with the 'blackbox' attribute\n");
1772 log(" are written to the output file.\n");
1774 log(" -selected\n");
1775 log(" only write selected modules. modules must be selected entirely or\n");
1776 log(" not at all.\n");
1779 log(" verbose output (print new names of all renamed wires and cells)\n");
1781 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1782 log("always blocks. This frontend should only be used to export an RTLIL\n");
1783 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1784 log("processes to logic networks and registers. A warning is generated when\n");
1785 log("this command is called on a design with RTLIL processes.\n");
1788 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1790 log_header(design
, "Executing Verilog backend.\n");
1795 attr2comment
= false;
1805 bool blackboxes
= false;
1806 bool selected
= false;
1808 auto_name_map
.clear();
1812 reg_ct
.insert("$dff");
1813 reg_ct
.insert("$adff");
1814 reg_ct
.insert("$dffe");
1815 reg_ct
.insert("$dlatch");
1817 reg_ct
.insert("$_DFF_N_");
1818 reg_ct
.insert("$_DFF_P_");
1820 reg_ct
.insert("$_DFF_NN0_");
1821 reg_ct
.insert("$_DFF_NN1_");
1822 reg_ct
.insert("$_DFF_NP0_");
1823 reg_ct
.insert("$_DFF_NP1_");
1824 reg_ct
.insert("$_DFF_PN0_");
1825 reg_ct
.insert("$_DFF_PN1_");
1826 reg_ct
.insert("$_DFF_PP0_");
1827 reg_ct
.insert("$_DFF_PP1_");
1829 reg_ct
.insert("$_DFFSR_NNN_");
1830 reg_ct
.insert("$_DFFSR_NNP_");
1831 reg_ct
.insert("$_DFFSR_NPN_");
1832 reg_ct
.insert("$_DFFSR_NPP_");
1833 reg_ct
.insert("$_DFFSR_PNN_");
1834 reg_ct
.insert("$_DFFSR_PNP_");
1835 reg_ct
.insert("$_DFFSR_PPN_");
1836 reg_ct
.insert("$_DFFSR_PPP_");
1839 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1840 std::string arg
= args
[argidx
];
1841 if (arg
== "-norename") {
1845 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1846 auto_prefix
= args
[++argidx
];
1849 if (arg
== "-noattr") {
1853 if (arg
== "-attr2comment") {
1854 attr2comment
= true;
1857 if (arg
== "-noexpr") {
1861 if (arg
== "-nodec") {
1865 if (arg
== "-nohex") {
1869 if (arg
== "-nostr") {
1873 if (arg
== "-defparam") {
1877 if (arg
== "-decimal") {
1881 if (arg
== "-siminit") {
1885 if (arg
== "-blackboxes") {
1889 if (arg
== "-selected") {
1899 extra_args(f
, filename
, args
, argidx
);
1903 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1904 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1905 if (it
->second
->get_blackbox_attribute() != blackboxes
)
1907 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1908 if (design
->selected_module(it
->first
))
1909 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1912 log("Dumping module `%s'.\n", it
->first
.c_str());
1913 dump_module(*f
, "", it
->second
);
1916 auto_name_map
.clear();
1922 PRIVATE_NAMESPACE_END