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('?'); 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 if (bit_3
== '?' || bit_2
== '?' || bit_1
== '?' || bit_0
== '?') {
255 if (bit_3
!= '?' || bit_2
!= '?' || bit_1
!= '?' || bit_0
!= '?')
257 hex_digits
.push_back('?');
260 int val
= 8*(bit_3
- '0') + 4*(bit_2
- '0') + 2*(bit_1
- '0') + (bit_0
- '0');
261 hex_digits
.push_back(val
< 10 ? '0' + val
: 'a' + val
- 10);
263 f
<< stringf("%d'%sh", width
, set_signed
? "s" : "");
264 for (int i
= GetSize(hex_digits
)-1; i
>= 0; i
--)
269 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
272 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
273 log_assert(i
< (int)data
.bits
.size());
274 switch (data
.bits
[i
]) {
275 case RTLIL::S0
: f
<< stringf("0"); break;
276 case RTLIL::S1
: f
<< stringf("1"); break;
277 case RTLIL::Sx
: f
<< stringf("x"); break;
278 case RTLIL::Sz
: f
<< stringf("z"); break;
279 case RTLIL::Sa
: f
<< stringf("?"); break;
280 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
285 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
287 std::string str
= data
.decode_string();
288 for (size_t i
= 0; i
< str
.size(); i
++) {
291 else if (str
[i
] == '\t')
293 else if (str
[i
] < 32)
294 f
<< stringf("\\%03o", str
[i
]);
295 else if (str
[i
] == '"')
296 f
<< stringf("\\\"");
297 else if (str
[i
] == '\\')
298 f
<< stringf("\\\\");
299 else if (str
[i
] == '/' && escape_comment
&& i
> 0 && str
[i
-1] == '*')
304 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
309 void dump_reg_init(std::ostream
&f
, SigSpec sig
)
312 bool gotinit
= false;
314 for (auto bit
: active_sigmap(sig
)) {
315 if (active_initdata
.count(bit
)) {
316 initval
.bits
.push_back(active_initdata
.at(bit
));
319 initval
.bits
.push_back(State::Sx
);
325 dump_const(f
, initval
);
329 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
331 if (chunk
.wire
== NULL
) {
332 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
334 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0) {
335 f
<< stringf("%s", id(chunk
.wire
->name
).c_str());
336 } else if (chunk
.width
== 1) {
337 if (chunk
.wire
->upto
)
338 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
340 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
342 if (chunk
.wire
->upto
)
343 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
344 (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
345 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
347 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
348 (chunk
.offset
+ chunk
.width
- 1) + chunk
.wire
->start_offset
,
349 chunk
.offset
+ chunk
.wire
->start_offset
);
354 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
356 if (GetSize(sig
) == 0) {
360 if (sig
.is_chunk()) {
361 dump_sigchunk(f
, sig
.as_chunk());
364 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
365 if (it
!= sig
.chunks().rbegin())
367 dump_sigchunk(f
, *it
, true);
373 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)
379 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
380 f
<< stringf("%s" "%s %s", indent
.c_str(), as_comment
? "/*" : "(*", id(it
->first
).c_str());
382 if (modattr
&& (it
->second
== Const(0, 1) || it
->second
== Const(0)))
384 else if (modattr
&& (it
->second
== Const(1, 1) || it
->second
== Const(1)))
387 dump_const(f
, it
->second
, -1, 0, false, as_comment
);
388 f
<< stringf(" %s%c", as_comment
? "*/" : "*)", term
);
392 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
394 dump_attributes(f
, indent
, wire
->attributes
);
396 if (wire
->port_input
&& !wire
->port_output
)
397 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
398 else if (!wire
->port_input
&& wire
->port_output
)
399 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
400 else if (wire
->port_input
&& wire
->port_output
)
401 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
403 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
404 if (wire
->width
!= 1)
405 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
406 f
<< stringf("%s;\n", id(wire
->name
).c_str());
408 // do not use Verilog-2k "output reg" syntax in Verilog export
409 std::string range
= "";
410 if (wire
->width
!= 1) {
412 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
414 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
416 if (wire
->port_input
&& !wire
->port_output
)
417 f
<< stringf("%s" "input%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
418 if (!wire
->port_input
&& wire
->port_output
)
419 f
<< stringf("%s" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
420 if (wire
->port_input
&& wire
->port_output
)
421 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
422 if (reg_wires
.count(wire
->name
)) {
423 f
<< stringf("%s" "reg%s %s", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
424 if (wire
->attributes
.count("\\init")) {
426 dump_const(f
, wire
->attributes
.at("\\init"));
429 } else if (!wire
->port_input
&& !wire
->port_output
)
430 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
434 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
436 dump_attributes(f
, indent
, memory
->attributes
);
437 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
);
440 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
442 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
443 f
<< stringf("$signed(");
444 dump_sigspec(f
, cell
->getPort("\\" + port
));
447 dump_sigspec(f
, cell
->getPort("\\" + port
));
450 std::string
cellname(RTLIL::Cell
*cell
)
452 if (!norename
&& cell
->name
[0] == '$' && reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q"))
454 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
455 if (GetSize(sig
) != 1 || sig
.is_fully_const())
456 goto no_special_reg_name
;
458 RTLIL::Wire
*wire
= sig
[0].wire
;
460 if (wire
->name
[0] != '\\')
461 goto no_special_reg_name
;
463 std::string cell_name
= wire
->name
.str();
465 size_t pos
= cell_name
.find('[');
466 if (pos
!= std::string::npos
)
467 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
469 cell_name
= cell_name
+ "_reg";
471 if (wire
->width
!= 1)
472 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
474 if (active_module
&& active_module
->count_id(cell_name
) > 0)
475 goto no_special_reg_name
;
477 return id(cell_name
);
482 return id(cell
->name
).c_str();
486 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
488 f
<< stringf("%s" "assign ", indent
.c_str());
489 dump_sigspec(f
, cell
->getPort("\\Y"));
490 f
<< stringf(" = %s ", op
.c_str());
491 dump_attributes(f
, "", cell
->attributes
, ' ');
492 dump_cell_expr_port(f
, cell
, "A", true);
496 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
498 f
<< stringf("%s" "assign ", indent
.c_str());
499 dump_sigspec(f
, cell
->getPort("\\Y"));
501 dump_cell_expr_port(f
, cell
, "A", true);
502 f
<< stringf(" %s ", op
.c_str());
503 dump_attributes(f
, "", cell
->attributes
, ' ');
504 dump_cell_expr_port(f
, cell
, "B", true);
508 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
510 if (cell
->type
== "$_NOT_") {
511 f
<< stringf("%s" "assign ", indent
.c_str());
512 dump_sigspec(f
, cell
->getPort("\\Y"));
515 dump_attributes(f
, "", cell
->attributes
, ' ');
516 dump_cell_expr_port(f
, cell
, "A", false);
521 if (cell
->type
.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
522 f
<< stringf("%s" "assign ", indent
.c_str());
523 dump_sigspec(f
, cell
->getPort("\\Y"));
525 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
527 dump_cell_expr_port(f
, cell
, "A", false);
529 if (cell
->type
.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
531 if (cell
->type
.in("$_OR_", "$_NOR_", "$_ORNOT_"))
533 if (cell
->type
.in("$_XOR_", "$_XNOR_"))
535 dump_attributes(f
, "", cell
->attributes
, ' ');
537 if (cell
->type
.in("$_ANDNOT_", "$_ORNOT_"))
539 dump_cell_expr_port(f
, cell
, "B", false);
540 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
546 if (cell
->type
== "$_MUX_") {
547 f
<< stringf("%s" "assign ", indent
.c_str());
548 dump_sigspec(f
, cell
->getPort("\\Y"));
550 dump_cell_expr_port(f
, cell
, "S", false);
552 dump_attributes(f
, "", cell
->attributes
, ' ');
553 dump_cell_expr_port(f
, cell
, "B", false);
555 dump_cell_expr_port(f
, cell
, "A", false);
560 if (cell
->type
.in("$_AOI3_", "$_OAI3_")) {
561 f
<< stringf("%s" "assign ", indent
.c_str());
562 dump_sigspec(f
, cell
->getPort("\\Y"));
563 f
<< stringf(" = ~((");
564 dump_cell_expr_port(f
, cell
, "A", false);
565 f
<< stringf(cell
->type
== "$_AOI3_" ? " & " : " | ");
566 dump_cell_expr_port(f
, cell
, "B", false);
567 f
<< stringf(cell
->type
== "$_AOI3_" ? ") |" : ") &");
568 dump_attributes(f
, "", cell
->attributes
, ' ');
570 dump_cell_expr_port(f
, cell
, "C", false);
571 f
<< stringf(");\n");
575 if (cell
->type
.in("$_AOI4_", "$_OAI4_")) {
576 f
<< stringf("%s" "assign ", indent
.c_str());
577 dump_sigspec(f
, cell
->getPort("\\Y"));
578 f
<< stringf(" = ~((");
579 dump_cell_expr_port(f
, cell
, "A", false);
580 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
581 dump_cell_expr_port(f
, cell
, "B", false);
582 f
<< stringf(cell
->type
== "$_AOI4_" ? ") |" : ") &");
583 dump_attributes(f
, "", cell
->attributes
, ' ');
585 dump_cell_expr_port(f
, cell
, "C", false);
586 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
587 dump_cell_expr_port(f
, cell
, "D", false);
588 f
<< stringf("));\n");
592 if (cell
->type
.substr(0, 6) == "$_DFF_")
594 std::string reg_name
= cellname(cell
);
595 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
597 if (!out_is_reg_wire
) {
598 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
599 dump_reg_init(f
, cell
->getPort("\\Q"));
603 dump_attributes(f
, indent
, cell
->attributes
);
604 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), cell
->type
[6] == 'P' ? "pos" : "neg");
605 dump_sigspec(f
, cell
->getPort("\\C"));
606 if (cell
->type
[7] != '_') {
607 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
608 dump_sigspec(f
, cell
->getPort("\\R"));
612 if (cell
->type
[7] != '_') {
613 f
<< stringf("%s" " if (%s", indent
.c_str(), cell
->type
[7] == 'P' ? "" : "!");
614 dump_sigspec(f
, cell
->getPort("\\R"));
616 f
<< stringf("%s" " %s <= %c;\n", indent
.c_str(), reg_name
.c_str(), cell
->type
[8]);
617 f
<< stringf("%s" " else\n", indent
.c_str());
620 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
621 dump_cell_expr_port(f
, cell
, "D", false);
624 if (!out_is_reg_wire
) {
625 f
<< stringf("%s" "assign ", indent
.c_str());
626 dump_sigspec(f
, cell
->getPort("\\Q"));
627 f
<< stringf(" = %s;\n", reg_name
.c_str());
633 if (cell
->type
.substr(0, 8) == "$_DFFSR_")
635 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
637 std::string reg_name
= cellname(cell
);
638 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
640 if (!out_is_reg_wire
) {
641 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
642 dump_reg_init(f
, cell
->getPort("\\Q"));
646 dump_attributes(f
, indent
, cell
->attributes
);
647 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_c
== 'P' ? "pos" : "neg");
648 dump_sigspec(f
, cell
->getPort("\\C"));
649 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
650 dump_sigspec(f
, cell
->getPort("\\S"));
651 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
652 dump_sigspec(f
, cell
->getPort("\\R"));
655 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
656 dump_sigspec(f
, cell
->getPort("\\R"));
658 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
660 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
661 dump_sigspec(f
, cell
->getPort("\\S"));
663 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
665 f
<< stringf("%s" " else\n", indent
.c_str());
666 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
667 dump_cell_expr_port(f
, cell
, "D", false);
670 if (!out_is_reg_wire
) {
671 f
<< stringf("%s" "assign ", indent
.c_str());
672 dump_sigspec(f
, cell
->getPort("\\Q"));
673 f
<< stringf(" = %s;\n", reg_name
.c_str());
679 #define HANDLE_UNIOP(_type, _operator) \
680 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
681 #define HANDLE_BINOP(_type, _operator) \
682 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
684 HANDLE_UNIOP("$not", "~")
685 HANDLE_UNIOP("$pos", "+")
686 HANDLE_UNIOP("$neg", "-")
688 HANDLE_BINOP("$and", "&")
689 HANDLE_BINOP("$or", "|")
690 HANDLE_BINOP("$xor", "^")
691 HANDLE_BINOP("$xnor", "~^")
693 HANDLE_UNIOP("$reduce_and", "&")
694 HANDLE_UNIOP("$reduce_or", "|")
695 HANDLE_UNIOP("$reduce_xor", "^")
696 HANDLE_UNIOP("$reduce_xnor", "~^")
697 HANDLE_UNIOP("$reduce_bool", "|")
699 HANDLE_BINOP("$shl", "<<")
700 HANDLE_BINOP("$shr", ">>")
701 HANDLE_BINOP("$sshl", "<<<")
702 HANDLE_BINOP("$sshr", ">>>")
704 HANDLE_BINOP("$lt", "<")
705 HANDLE_BINOP("$le", "<=")
706 HANDLE_BINOP("$eq", "==")
707 HANDLE_BINOP("$ne", "!=")
708 HANDLE_BINOP("$eqx", "===")
709 HANDLE_BINOP("$nex", "!==")
710 HANDLE_BINOP("$ge", ">=")
711 HANDLE_BINOP("$gt", ">")
713 HANDLE_BINOP("$add", "+")
714 HANDLE_BINOP("$sub", "-")
715 HANDLE_BINOP("$mul", "*")
716 HANDLE_BINOP("$div", "/")
717 HANDLE_BINOP("$mod", "%")
718 HANDLE_BINOP("$pow", "**")
720 HANDLE_UNIOP("$logic_not", "!")
721 HANDLE_BINOP("$logic_and", "&&")
722 HANDLE_BINOP("$logic_or", "||")
727 if (cell
->type
== "$shift")
729 f
<< stringf("%s" "assign ", indent
.c_str());
730 dump_sigspec(f
, cell
->getPort("\\Y"));
732 if (cell
->getParam("\\B_SIGNED").as_bool())
734 f
<< stringf("$signed(");
735 dump_sigspec(f
, cell
->getPort("\\B"));
737 f
<< stringf(" < 0 ? ");
738 dump_sigspec(f
, cell
->getPort("\\A"));
739 f
<< stringf(" << - ");
740 dump_sigspec(f
, cell
->getPort("\\B"));
742 dump_sigspec(f
, cell
->getPort("\\A"));
743 f
<< stringf(" >> ");
744 dump_sigspec(f
, cell
->getPort("\\B"));
748 dump_sigspec(f
, cell
->getPort("\\A"));
749 f
<< stringf(" >> ");
750 dump_sigspec(f
, cell
->getPort("\\B"));
756 if (cell
->type
== "$shiftx")
758 std::string temp_id
= next_auto_id();
759 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort("\\A"))-1, temp_id
.c_str());
760 dump_sigspec(f
, cell
->getPort("\\A"));
763 f
<< stringf("%s" "assign ", indent
.c_str());
764 dump_sigspec(f
, cell
->getPort("\\Y"));
765 f
<< stringf(" = %s[", temp_id
.c_str());
766 if (cell
->getParam("\\B_SIGNED").as_bool())
767 f
<< stringf("$signed(");
768 dump_sigspec(f
, cell
->getPort("\\B"));
769 if (cell
->getParam("\\B_SIGNED").as_bool())
771 f
<< stringf(" +: %d", cell
->getParam("\\Y_WIDTH").as_int());
772 f
<< stringf("];\n");
776 if (cell
->type
== "$mux")
778 f
<< stringf("%s" "assign ", indent
.c_str());
779 dump_sigspec(f
, cell
->getPort("\\Y"));
781 dump_sigspec(f
, cell
->getPort("\\S"));
783 dump_attributes(f
, "", cell
->attributes
, ' ');
784 dump_sigspec(f
, cell
->getPort("\\B"));
786 dump_sigspec(f
, cell
->getPort("\\A"));
791 if (cell
->type
== "$pmux")
793 int width
= cell
->parameters
["\\WIDTH"].as_int();
794 int s_width
= cell
->getPort("\\S").size();
795 std::string func_name
= cellname(cell
);
797 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
798 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
799 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
800 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
802 dump_attributes(f
, indent
+ " ", cell
->attributes
);
804 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
805 f
<< stringf("%s" " casez (s)", indent
.c_str());
806 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
808 for (int i
= 0; i
< s_width
; i
++)
810 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
812 for (int j
= s_width
-1; j
>= 0; j
--)
813 f
<< stringf("%c", j
== i
? '1' : '?');
816 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
819 f
<< stringf("%s" " default:\n", indent
.c_str());
820 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
822 f
<< stringf("%s" " endcase\n", indent
.c_str());
823 f
<< stringf("%s" "endfunction\n", indent
.c_str());
825 f
<< stringf("%s" "assign ", indent
.c_str());
826 dump_sigspec(f
, cell
->getPort("\\Y"));
827 f
<< stringf(" = %s(", func_name
.c_str());
828 dump_sigspec(f
, cell
->getPort("\\A"));
830 dump_sigspec(f
, cell
->getPort("\\B"));
832 dump_sigspec(f
, cell
->getPort("\\S"));
833 f
<< stringf(");\n");
837 if (cell
->type
== "$tribuf")
839 f
<< stringf("%s" "assign ", indent
.c_str());
840 dump_sigspec(f
, cell
->getPort("\\Y"));
842 dump_sigspec(f
, cell
->getPort("\\EN"));
844 dump_sigspec(f
, cell
->getPort("\\A"));
845 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at("\\WIDTH").as_int());
849 if (cell
->type
== "$slice")
851 f
<< stringf("%s" "assign ", indent
.c_str());
852 dump_sigspec(f
, cell
->getPort("\\Y"));
854 dump_sigspec(f
, cell
->getPort("\\A"));
855 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
859 if (cell
->type
== "$concat")
861 f
<< stringf("%s" "assign ", indent
.c_str());
862 dump_sigspec(f
, cell
->getPort("\\Y"));
863 f
<< stringf(" = { ");
864 dump_sigspec(f
, cell
->getPort("\\B"));
866 dump_sigspec(f
, cell
->getPort("\\A"));
867 f
<< stringf(" };\n");
871 if (cell
->type
== "$lut")
873 f
<< stringf("%s" "assign ", indent
.c_str());
874 dump_sigspec(f
, cell
->getPort("\\Y"));
876 dump_const(f
, cell
->parameters
.at("\\LUT"));
877 f
<< stringf(" >> ");
878 dump_attributes(f
, "", cell
->attributes
, ' ');
879 dump_sigspec(f
, cell
->getPort("\\A"));
884 if (cell
->type
== "$dffsr")
886 SigSpec sig_clk
= cell
->getPort("\\CLK");
887 SigSpec sig_set
= cell
->getPort("\\SET");
888 SigSpec sig_clr
= cell
->getPort("\\CLR");
889 SigSpec sig_d
= cell
->getPort("\\D");
890 SigSpec sig_q
= cell
->getPort("\\Q");
892 int width
= cell
->parameters
["\\WIDTH"].as_int();
893 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
894 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
895 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
897 std::string reg_name
= cellname(cell
);
898 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
900 if (!out_is_reg_wire
) {
901 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
902 dump_reg_init(f
, sig_q
);
906 for (int i
= 0; i
< width
; i
++) {
907 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
908 dump_sigspec(f
, sig_clk
);
909 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
910 dump_sigspec(f
, sig_set
);
911 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
912 dump_sigspec(f
, sig_clr
);
915 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
916 dump_sigspec(f
, sig_clr
);
917 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
919 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
920 dump_sigspec(f
, sig_set
);
921 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
923 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
924 dump_sigspec(f
, sig_d
[i
]);
928 if (!out_is_reg_wire
) {
929 f
<< stringf("%s" "assign ", indent
.c_str());
930 dump_sigspec(f
, sig_q
);
931 f
<< stringf(" = %s;\n", reg_name
.c_str());
937 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
939 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
940 bool pol_clk
, pol_arst
= false, pol_en
= false;
942 sig_clk
= cell
->getPort("\\CLK");
943 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
945 if (cell
->type
== "$adff") {
946 sig_arst
= cell
->getPort("\\ARST");
947 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
948 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
951 if (cell
->type
== "$dffe") {
952 sig_en
= cell
->getPort("\\EN");
953 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
956 std::string reg_name
= cellname(cell
);
957 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
959 if (!out_is_reg_wire
) {
960 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
961 dump_reg_init(f
, cell
->getPort("\\Q"));
965 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
966 dump_sigspec(f
, sig_clk
);
967 if (cell
->type
== "$adff") {
968 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
969 dump_sigspec(f
, sig_arst
);
973 if (cell
->type
== "$adff") {
974 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
975 dump_sigspec(f
, sig_arst
);
977 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
978 dump_sigspec(f
, val_arst
);
980 f
<< stringf("%s" " else\n", indent
.c_str());
983 if (cell
->type
== "$dffe") {
984 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
985 dump_sigspec(f
, sig_en
);
989 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
990 dump_cell_expr_port(f
, cell
, "D", false);
993 if (!out_is_reg_wire
) {
994 f
<< stringf("%s" "assign ", indent
.c_str());
995 dump_sigspec(f
, cell
->getPort("\\Q"));
996 f
<< stringf(" = %s;\n", reg_name
.c_str());
1002 if (cell
->type
== "$dlatch")
1004 RTLIL::SigSpec sig_en
;
1005 bool pol_en
= false;
1007 sig_en
= cell
->getPort("\\EN");
1008 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
1010 std::string reg_name
= cellname(cell
);
1011 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
1013 if (!out_is_reg_wire
) {
1014 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
1015 dump_reg_init(f
, cell
->getPort("\\Q"));
1019 f
<< stringf("%s" "always @*\n", indent
.c_str());
1021 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1022 dump_sigspec(f
, sig_en
);
1023 f
<< stringf(")\n");
1025 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
1026 dump_cell_expr_port(f
, cell
, "D", false);
1027 f
<< stringf(";\n");
1029 if (!out_is_reg_wire
) {
1030 f
<< stringf("%s" "assign ", indent
.c_str());
1031 dump_sigspec(f
, cell
->getPort("\\Q"));
1032 f
<< stringf(" = %s;\n", reg_name
.c_str());
1038 if (cell
->type
== "$mem")
1040 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
1041 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
1042 int abits
= cell
->parameters
["\\ABITS"].as_int();
1043 int size
= cell
->parameters
["\\SIZE"].as_int();
1044 int offset
= cell
->parameters
["\\OFFSET"].as_int();
1045 int width
= cell
->parameters
["\\WIDTH"].as_int();
1046 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
1048 // for memory block make something like:
1049 // reg [7:0] memid [3:0];
1053 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1056 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1057 for (int i
=0; i
<size
; i
++)
1059 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1060 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1061 f
<< stringf(";\n");
1063 f
<< stringf("%s" "end\n", indent
.c_str());
1066 // create a map : "edge clk" -> expressions within that clock domain
1067 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1068 clk_to_lof_body
[""] = std::vector
<std::string
>();
1069 std::string clk_domain_str
;
1070 // create a list of reg declarations
1071 std::vector
<std::string
> lof_reg_declarations
;
1073 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1074 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1075 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1077 for (int i
=0; i
< nread_ports
; i
++)
1079 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1080 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1081 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1082 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1083 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1084 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1085 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1089 std::ostringstream os
;
1090 dump_sigspec(os
, sig_rd_clk
);
1091 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1092 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1093 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1095 if (!rd_transparent
)
1097 // for clocked read ports make something like:
1098 // reg [..] temp_id;
1099 // always @(posedge clk)
1100 // if (rd_en) temp_id <= array_reg[r_addr];
1101 // assign r_data = temp_id;
1102 std::string temp_id
= next_auto_id();
1103 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1105 std::ostringstream os
;
1106 if (sig_rd_en
!= RTLIL::SigBit(true))
1108 os
<< stringf("if (");
1109 dump_sigspec(os
, sig_rd_en
);
1110 os
<< stringf(") ");
1112 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1113 dump_sigspec(os
, sig_rd_addr
);
1114 os
<< stringf("];\n");
1115 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1118 std::ostringstream os
;
1119 dump_sigspec(os
, sig_rd_data
);
1120 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1121 clk_to_lof_body
[""].push_back(line
);
1126 // for rd-transparent read-ports make something like:
1127 // reg [..] temp_id;
1128 // always @(posedge clk)
1129 // temp_id <= r_addr;
1130 // assign r_data = array_reg[temp_id];
1131 std::string temp_id
= next_auto_id();
1132 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1134 std::ostringstream os
;
1135 dump_sigspec(os
, sig_rd_addr
);
1136 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1137 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1140 std::ostringstream os
;
1141 dump_sigspec(os
, sig_rd_data
);
1142 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1143 clk_to_lof_body
[""].push_back(line
);
1147 // for non-clocked read-ports make something like:
1148 // assign r_data = array_reg[r_addr];
1149 std::ostringstream os
, os2
;
1150 dump_sigspec(os
, sig_rd_data
);
1151 dump_sigspec(os2
, sig_rd_addr
);
1152 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1153 clk_to_lof_body
[""].push_back(line
);
1157 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1158 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1159 bool wr_clk_posedge
;
1162 for (int i
=0; i
< nwrite_ports
; i
++)
1164 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1165 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1166 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1167 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1168 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1170 std::ostringstream os
;
1171 dump_sigspec(os
, sig_wr_clk
);
1172 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1173 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1174 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1176 // make something like:
1177 // always @(posedge clk)
1178 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1180 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1182 int start_i
= i
, width
= 1;
1183 SigBit wen_bit
= sig_wr_en
[i
];
1185 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1188 if (wen_bit
== State::S0
)
1191 std::ostringstream os
;
1192 if (wen_bit
!= State::S1
)
1194 os
<< stringf("if (");
1195 dump_sigspec(os
, wen_bit
);
1196 os
<< stringf(") ");
1198 os
<< stringf("%s[", mem_id
.c_str());
1199 dump_sigspec(os
, sig_wr_addr
);
1200 if (width
== GetSize(sig_wr_en
))
1201 os
<< stringf("] <= ");
1203 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1204 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1205 os
<< stringf(";\n");
1206 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1209 // Output Verilog that looks something like this:
1211 // always @(posedge CLK2) begin
1212 // _3_ <= memory[D1ADDR];
1214 // memory[A1ADDR] <= A1DATA;
1216 // memory[A2ADDR] <= A2DATA;
1219 // always @(negedge CLK1) begin
1221 // memory[C1ADDR] <= C1DATA;
1224 // assign D1DATA = _3_;
1225 // assign D2DATA <= memory[D2ADDR];
1227 // the reg ... definitions
1228 for(auto ®
: lof_reg_declarations
)
1230 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1232 // the block of expressions by clock domain
1233 for(auto &pair
: clk_to_lof_body
)
1235 std::string clk_domain
= pair
.first
;
1236 std::vector
<std::string
> lof_lines
= pair
.second
;
1237 if( clk_domain
!= "")
1239 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1240 for(auto &line
: lof_lines
)
1241 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1242 f
<< stringf("%s" "end\n", indent
.c_str());
1246 // the non-clocked assignments
1247 for(auto &line
: lof_lines
)
1248 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1255 if (cell
->type
.in("$assert", "$assume", "$cover"))
1257 f
<< stringf("%s" "always @* if (", indent
.c_str());
1258 dump_sigspec(f
, cell
->getPort("\\EN"));
1259 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1260 dump_sigspec(f
, cell
->getPort("\\A"));
1261 f
<< stringf(");\n");
1265 if (cell
->type
.in("$specify2", "$specify3"))
1267 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1269 SigSpec en
= cell
->getPort("\\EN");
1270 if (en
!= State::S1
) {
1271 f
<< stringf("if (");
1272 dump_sigspec(f
, cell
->getPort("\\EN"));
1277 if (cell
->type
== "$specify3" && cell
->getParam("\\EDGE_EN").as_bool())
1278 f
<< (cell
->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1280 dump_sigspec(f
, cell
->getPort("\\SRC"));
1283 if (cell
->getParam("\\SRC_DST_PEN").as_bool())
1284 f
<< (cell
->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1285 f
<< (cell
->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1287 if (cell
->type
== "$specify3") {
1289 dump_sigspec(f
, cell
->getPort("\\DST"));
1291 if (cell
->getParam("\\DAT_DST_PEN").as_bool())
1292 f
<< (cell
->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1294 dump_sigspec(f
, cell
->getPort("\\DAT"));
1297 dump_sigspec(f
, cell
->getPort("\\DST"));
1300 bool bak_decimal
= decimal
;
1304 dump_const(f
, cell
->getParam("\\T_RISE_MIN"));
1306 dump_const(f
, cell
->getParam("\\T_RISE_TYP"));
1308 dump_const(f
, cell
->getParam("\\T_RISE_MAX"));
1310 dump_const(f
, cell
->getParam("\\T_FALL_MIN"));
1312 dump_const(f
, cell
->getParam("\\T_FALL_TYP"));
1314 dump_const(f
, cell
->getParam("\\T_FALL_MAX"));
1317 decimal
= bak_decimal
;
1319 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1323 if (cell
->type
== "$specrule")
1325 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1327 string spec_type
= cell
->getParam("\\TYPE").decode_string();
1328 f
<< stringf("%s(", spec_type
.c_str());
1330 if (cell
->getParam("\\SRC_PEN").as_bool())
1331 f
<< (cell
->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1332 dump_sigspec(f
, cell
->getPort("\\SRC"));
1334 if (cell
->getPort("\\SRC_EN") != State::S1
) {
1336 dump_sigspec(f
, cell
->getPort("\\SRC_EN"));
1340 if (cell
->getParam("\\DST_PEN").as_bool())
1341 f
<< (cell
->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1342 dump_sigspec(f
, cell
->getPort("\\DST"));
1344 if (cell
->getPort("\\DST_EN") != State::S1
) {
1346 dump_sigspec(f
, cell
->getPort("\\DST_EN"));
1349 bool bak_decimal
= decimal
;
1353 dump_const(f
, cell
->getParam("\\T_LIMIT"));
1355 if (spec_type
== "$setuphold" || spec_type
== "$recrem" || spec_type
== "$fullskew") {
1357 dump_const(f
, cell
->getParam("\\T_LIMIT2"));
1361 decimal
= bak_decimal
;
1363 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1367 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1368 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1373 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1375 if (cell
->type
[0] == '$' && !noexpr
) {
1376 if (dump_cell_expr(f
, indent
, cell
))
1380 dump_attributes(f
, indent
, cell
->attributes
);
1381 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1383 if (!defparam
&& cell
->parameters
.size() > 0) {
1384 f
<< stringf(" #(");
1385 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1386 if (it
!= cell
->parameters
.begin())
1388 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1389 dump_const(f
, it
->second
);
1392 f
<< stringf("\n%s" ")", indent
.c_str());
1395 std::string cell_name
= cellname(cell
);
1396 if (cell_name
!= id(cell
->name
))
1397 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1399 f
<< stringf(" %s (", cell_name
.c_str());
1401 bool first_arg
= true;
1402 std::set
<RTLIL::IdString
> numbered_ports
;
1403 for (int i
= 1; true; i
++) {
1405 snprintf(str
, 16, "$%d", i
);
1406 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1407 if (it
->first
!= str
)
1412 f
<< stringf("\n%s ", indent
.c_str());
1413 dump_sigspec(f
, it
->second
);
1414 numbered_ports
.insert(it
->first
);
1415 goto found_numbered_port
;
1418 found_numbered_port
:;
1420 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1421 if (numbered_ports
.count(it
->first
))
1426 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1427 if (it
->second
.size() > 0)
1428 dump_sigspec(f
, it
->second
);
1431 f
<< stringf("\n%s" ");\n", indent
.c_str());
1433 if (defparam
&& cell
->parameters
.size() > 0) {
1434 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1435 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1436 dump_const(f
, it
->second
);
1437 f
<< stringf(";\n");
1441 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q")) {
1442 std::stringstream ss
;
1443 dump_reg_init(ss
, cell
->getPort("\\Q"));
1444 if (!ss
.str().empty()) {
1445 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1452 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1454 f
<< stringf("%s" "assign ", indent
.c_str());
1455 dump_sigspec(f
, left
);
1456 f
<< stringf(" = ");
1457 dump_sigspec(f
, right
);
1458 f
<< stringf(";\n");
1461 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1463 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1465 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1467 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1468 f
<< stringf("%s" "begin\n", indent
.c_str());
1470 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1471 if (it
->first
.size() == 0)
1473 f
<< stringf("%s ", indent
.c_str());
1474 dump_sigspec(f
, it
->first
);
1475 f
<< stringf(" = ");
1476 dump_sigspec(f
, it
->second
);
1477 f
<< stringf(";\n");
1480 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1481 dump_proc_switch(f
, indent
+ " ", *it
);
1483 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1484 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1486 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1487 f
<< stringf("%s" "end\n", indent
.c_str());
1490 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1492 if (sw
->signal
.size() == 0) {
1493 f
<< stringf("%s" "begin\n", indent
.c_str());
1494 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1495 if ((*it
)->compare
.size() == 0)
1496 dump_case_body(f
, indent
+ " ", *it
);
1498 f
<< stringf("%s" "end\n", indent
.c_str());
1502 dump_attributes(f
, indent
, sw
->attributes
);
1503 f
<< stringf("%s" "casez (", indent
.c_str());
1504 dump_sigspec(f
, sw
->signal
);
1505 f
<< stringf(")\n");
1507 bool got_default
= false;
1508 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1509 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*as_comment=*/true);
1510 if ((*it
)->compare
.size() == 0) {
1513 f
<< stringf("%s default", indent
.c_str());
1516 f
<< stringf("%s ", indent
.c_str());
1517 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1520 dump_sigspec(f
, (*it
)->compare
[i
]);
1523 f
<< stringf(":\n");
1524 dump_case_body(f
, indent
+ " ", *it
);
1527 f
<< stringf("%s" "endcase\n", indent
.c_str());
1530 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1532 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1533 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1534 case_body_find_regs(*it2
);
1536 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1537 for (auto &c
: it
->first
.chunks())
1539 reg_wires
.insert(c
.wire
->name
);
1543 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1546 case_body_find_regs(&proc
->root_case
);
1547 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1548 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1549 for (auto &c
: it2
->first
.chunks())
1551 reg_wires
.insert(c
.wire
->name
);
1556 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1557 dump_case_body(f
, indent
, &proc
->root_case
, true);
1559 std::string backup_indent
= indent
;
1561 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1563 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1564 indent
= backup_indent
;
1566 if (sync
->type
== RTLIL::STa
) {
1567 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1568 } else if (sync
->type
== RTLIL::STi
) {
1569 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1571 f
<< stringf("%s" "always @(", indent
.c_str());
1572 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1573 f
<< stringf("posedge ");
1574 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1575 f
<< stringf("negedge ");
1576 dump_sigspec(f
, sync
->signal
);
1577 f
<< stringf(") begin\n");
1579 std::string ends
= indent
+ "end\n";
1582 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1583 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1584 dump_sigspec(f
, sync
->signal
);
1585 f
<< stringf(") begin\n");
1586 ends
= indent
+ "end\n" + ends
;
1590 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1591 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1592 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1593 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1594 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1595 dump_sigspec(f
, sync2
->signal
);
1596 f
<< stringf(") begin\n");
1597 ends
= indent
+ "end\n" + ends
;
1603 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1604 if (it
->first
.size() == 0)
1606 f
<< stringf("%s ", indent
.c_str());
1607 dump_sigspec(f
, it
->first
);
1608 f
<< stringf(" <= ");
1609 dump_sigspec(f
, it
->second
);
1610 f
<< stringf(";\n");
1613 f
<< stringf("%s", ends
.c_str());
1617 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1620 reset_auto_counter(module
);
1621 active_module
= module
;
1622 active_sigmap
.set(module
);
1623 active_initdata
.clear();
1625 for (auto wire
: module
->wires())
1626 if (wire
->attributes
.count("\\init")) {
1627 SigSpec sig
= active_sigmap(wire
);
1628 Const val
= wire
->attributes
.at("\\init");
1629 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1630 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1631 active_initdata
[sig
[i
]] = val
[i
];
1634 if (!module
->processes
.empty())
1635 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1636 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1637 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1638 "processes to logic networks and registers.\n", log_id(module
));
1641 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1642 dump_process(f
, indent
+ " ", it
->second
, true);
1646 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1647 for (auto &it
: module
->cells_
)
1649 RTLIL::Cell
*cell
= it
.second
;
1650 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1653 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1655 if (sig
.is_chunk()) {
1656 RTLIL::SigChunk chunk
= sig
.as_chunk();
1657 if (chunk
.wire
!= NULL
)
1658 for (int i
= 0; i
< chunk
.width
; i
++)
1659 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1662 for (auto &it
: module
->wires_
)
1664 RTLIL::Wire
*wire
= it
.second
;
1665 for (int i
= 0; i
< wire
->width
; i
++)
1666 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1667 goto this_wire_aint_reg
;
1669 reg_wires
.insert(wire
->name
);
1670 this_wire_aint_reg
:;
1674 dump_attributes(f
, indent
, module
->attributes
, '\n', /*attr2comment=*/true);
1675 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1676 bool keep_running
= true;
1677 for (int port_id
= 1; keep_running
; port_id
++) {
1678 keep_running
= false;
1679 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1680 RTLIL::Wire
*wire
= it
->second
;
1681 if (wire
->port_id
== port_id
) {
1684 f
<< stringf("%s", id(wire
->name
).c_str());
1685 keep_running
= true;
1690 f
<< stringf(");\n");
1692 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1693 dump_wire(f
, indent
+ " ", it
->second
);
1695 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1696 dump_memory(f
, indent
+ " ", it
->second
);
1698 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1699 dump_cell(f
, indent
+ " ", it
->second
);
1701 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1702 dump_process(f
, indent
+ " ", it
->second
);
1704 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1705 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1707 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1708 active_module
= NULL
;
1709 active_sigmap
.clear();
1710 active_initdata
.clear();
1713 struct VerilogBackend
: public Backend
{
1714 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1715 void help() YS_OVERRIDE
1717 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1719 log(" write_verilog [options] [filename]\n");
1721 log("Write the current design to a Verilog file.\n");
1723 log(" -norename\n");
1724 log(" without this option all internal object names (the ones with a dollar\n");
1725 log(" instead of a backslash prefix) are changed to short names in the\n");
1726 log(" format '_<number>_'.\n");
1728 log(" -renameprefix <prefix>\n");
1729 log(" insert this prefix in front of auto-generated instance names\n");
1732 log(" with this option no attributes are included in the output\n");
1734 log(" -attr2comment\n");
1735 log(" with this option attributes are included as comments in the output\n");
1738 log(" without this option all internal cells are converted to Verilog\n");
1739 log(" expressions.\n");
1742 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1743 log(" in -noexpr mode.\n");
1746 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1747 log(" not bit pattern. This option deactivates this feature and instead\n");
1748 log(" will write out all constants in binary.\n");
1751 log(" dump 32-bit constants in decimal and without size and radix\n");
1754 log(" constant values that are compatible with hex output are usually\n");
1755 log(" dumped as hex values. This option deactivates this feature and\n");
1756 log(" instead will write out all constants in binary.\n");
1759 log(" Parameters and attributes that are specified as strings in the\n");
1760 log(" original input will be output as strings by this back-end. This\n");
1761 log(" deactivates this feature and instead will write string constants\n");
1762 log(" as binary numbers.\n");
1764 log(" -defparam\n");
1765 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1766 log(" cell parameters.\n");
1768 log(" -blackboxes\n");
1769 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1770 log(" this option set only the modules with the 'blackbox' attribute\n");
1771 log(" are written to the output file.\n");
1773 log(" -selected\n");
1774 log(" only write selected modules. modules must be selected entirely or\n");
1775 log(" not at all.\n");
1778 log(" verbose output (print new names of all renamed wires and cells)\n");
1780 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1781 log("always blocks. This frontend should only be used to export an RTLIL\n");
1782 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1783 log("processes to logic networks and registers. A warning is generated when\n");
1784 log("this command is called on a design with RTLIL processes.\n");
1787 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1789 log_header(design
, "Executing Verilog backend.\n");
1794 attr2comment
= false;
1804 bool blackboxes
= false;
1805 bool selected
= false;
1807 auto_name_map
.clear();
1811 reg_ct
.insert("$dff");
1812 reg_ct
.insert("$adff");
1813 reg_ct
.insert("$dffe");
1814 reg_ct
.insert("$dlatch");
1816 reg_ct
.insert("$_DFF_N_");
1817 reg_ct
.insert("$_DFF_P_");
1819 reg_ct
.insert("$_DFF_NN0_");
1820 reg_ct
.insert("$_DFF_NN1_");
1821 reg_ct
.insert("$_DFF_NP0_");
1822 reg_ct
.insert("$_DFF_NP1_");
1823 reg_ct
.insert("$_DFF_PN0_");
1824 reg_ct
.insert("$_DFF_PN1_");
1825 reg_ct
.insert("$_DFF_PP0_");
1826 reg_ct
.insert("$_DFF_PP1_");
1828 reg_ct
.insert("$_DFFSR_NNN_");
1829 reg_ct
.insert("$_DFFSR_NNP_");
1830 reg_ct
.insert("$_DFFSR_NPN_");
1831 reg_ct
.insert("$_DFFSR_NPP_");
1832 reg_ct
.insert("$_DFFSR_PNN_");
1833 reg_ct
.insert("$_DFFSR_PNP_");
1834 reg_ct
.insert("$_DFFSR_PPN_");
1835 reg_ct
.insert("$_DFFSR_PPP_");
1838 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1839 std::string arg
= args
[argidx
];
1840 if (arg
== "-norename") {
1844 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1845 auto_prefix
= args
[++argidx
];
1848 if (arg
== "-noattr") {
1852 if (arg
== "-attr2comment") {
1853 attr2comment
= true;
1856 if (arg
== "-noexpr") {
1860 if (arg
== "-nodec") {
1864 if (arg
== "-nohex") {
1868 if (arg
== "-nostr") {
1872 if (arg
== "-defparam") {
1876 if (arg
== "-decimal") {
1880 if (arg
== "-siminit") {
1884 if (arg
== "-blackboxes") {
1888 if (arg
== "-selected") {
1898 extra_args(f
, filename
, args
, argidx
);
1902 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1903 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1904 if (it
->second
->get_blackbox_attribute() != blackboxes
)
1906 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1907 if (design
->selected_module(it
->first
))
1908 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1911 log("Dumping module `%s'.\n", it
->first
.c_str());
1912 dump_module(*f
, "", it
->second
);
1915 auto_name_map
.clear();
1921 PRIVATE_NAMESPACE_END