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" || cell
->type
== "$pmux_safe")
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
);
804 if (cell
->type
!= "$pmux_safe" && !noattr
)
805 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
806 f
<< stringf("%s" " casez (s)", indent
.c_str());
807 if (cell
->type
!= "$pmux_safe")
808 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
810 for (int i
= 0; i
< s_width
; i
++)
812 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
814 for (int j
= s_width
-1; j
>= 0; j
--)
815 f
<< stringf("%c", j
== i
? '1' : cell
->type
== "$pmux_safe" ? '0' : '?');
818 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
821 f
<< stringf("%s" " default:\n", indent
.c_str());
822 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
824 f
<< stringf("%s" " endcase\n", indent
.c_str());
825 f
<< stringf("%s" "endfunction\n", indent
.c_str());
827 f
<< stringf("%s" "assign ", indent
.c_str());
828 dump_sigspec(f
, cell
->getPort("\\Y"));
829 f
<< stringf(" = %s(", func_name
.c_str());
830 dump_sigspec(f
, cell
->getPort("\\A"));
832 dump_sigspec(f
, cell
->getPort("\\B"));
834 dump_sigspec(f
, cell
->getPort("\\S"));
835 f
<< stringf(");\n");
839 if (cell
->type
== "$tribuf")
841 f
<< stringf("%s" "assign ", indent
.c_str());
842 dump_sigspec(f
, cell
->getPort("\\Y"));
844 dump_sigspec(f
, cell
->getPort("\\EN"));
846 dump_sigspec(f
, cell
->getPort("\\A"));
847 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at("\\WIDTH").as_int());
851 if (cell
->type
== "$slice")
853 f
<< stringf("%s" "assign ", indent
.c_str());
854 dump_sigspec(f
, cell
->getPort("\\Y"));
856 dump_sigspec(f
, cell
->getPort("\\A"));
857 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
861 if (cell
->type
== "$concat")
863 f
<< stringf("%s" "assign ", indent
.c_str());
864 dump_sigspec(f
, cell
->getPort("\\Y"));
865 f
<< stringf(" = { ");
866 dump_sigspec(f
, cell
->getPort("\\B"));
868 dump_sigspec(f
, cell
->getPort("\\A"));
869 f
<< stringf(" };\n");
873 if (cell
->type
== "$lut")
875 f
<< stringf("%s" "assign ", indent
.c_str());
876 dump_sigspec(f
, cell
->getPort("\\Y"));
878 dump_const(f
, cell
->parameters
.at("\\LUT"));
879 f
<< stringf(" >> ");
880 dump_attributes(f
, "", cell
->attributes
, ' ');
881 dump_sigspec(f
, cell
->getPort("\\A"));
886 if (cell
->type
== "$dffsr")
888 SigSpec sig_clk
= cell
->getPort("\\CLK");
889 SigSpec sig_set
= cell
->getPort("\\SET");
890 SigSpec sig_clr
= cell
->getPort("\\CLR");
891 SigSpec sig_d
= cell
->getPort("\\D");
892 SigSpec sig_q
= cell
->getPort("\\Q");
894 int width
= cell
->parameters
["\\WIDTH"].as_int();
895 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
896 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
897 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
899 std::string reg_name
= cellname(cell
);
900 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
902 if (!out_is_reg_wire
) {
903 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
904 dump_reg_init(f
, sig_q
);
908 for (int i
= 0; i
< width
; i
++) {
909 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
910 dump_sigspec(f
, sig_clk
);
911 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
912 dump_sigspec(f
, sig_set
);
913 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
914 dump_sigspec(f
, sig_clr
);
917 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
918 dump_sigspec(f
, sig_clr
);
919 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
921 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
922 dump_sigspec(f
, sig_set
);
923 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
925 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
926 dump_sigspec(f
, sig_d
[i
]);
930 if (!out_is_reg_wire
) {
931 f
<< stringf("%s" "assign ", indent
.c_str());
932 dump_sigspec(f
, sig_q
);
933 f
<< stringf(" = %s;\n", reg_name
.c_str());
939 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
941 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
942 bool pol_clk
, pol_arst
= false, pol_en
= false;
944 sig_clk
= cell
->getPort("\\CLK");
945 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
947 if (cell
->type
== "$adff") {
948 sig_arst
= cell
->getPort("\\ARST");
949 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
950 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
953 if (cell
->type
== "$dffe") {
954 sig_en
= cell
->getPort("\\EN");
955 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
958 std::string reg_name
= cellname(cell
);
959 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
961 if (!out_is_reg_wire
) {
962 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
963 dump_reg_init(f
, cell
->getPort("\\Q"));
967 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
968 dump_sigspec(f
, sig_clk
);
969 if (cell
->type
== "$adff") {
970 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
971 dump_sigspec(f
, sig_arst
);
975 if (cell
->type
== "$adff") {
976 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
977 dump_sigspec(f
, sig_arst
);
979 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
980 dump_sigspec(f
, val_arst
);
982 f
<< stringf("%s" " else\n", indent
.c_str());
985 if (cell
->type
== "$dffe") {
986 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
987 dump_sigspec(f
, sig_en
);
991 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
992 dump_cell_expr_port(f
, cell
, "D", false);
995 if (!out_is_reg_wire
) {
996 f
<< stringf("%s" "assign ", indent
.c_str());
997 dump_sigspec(f
, cell
->getPort("\\Q"));
998 f
<< stringf(" = %s;\n", reg_name
.c_str());
1004 if (cell
->type
== "$dlatch")
1006 RTLIL::SigSpec sig_en
;
1007 bool pol_en
= false;
1009 sig_en
= cell
->getPort("\\EN");
1010 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
1012 std::string reg_name
= cellname(cell
);
1013 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
1015 if (!out_is_reg_wire
) {
1016 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
1017 dump_reg_init(f
, cell
->getPort("\\Q"));
1021 f
<< stringf("%s" "always @*\n", indent
.c_str());
1023 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1024 dump_sigspec(f
, sig_en
);
1025 f
<< stringf(")\n");
1027 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
1028 dump_cell_expr_port(f
, cell
, "D", false);
1029 f
<< stringf(";\n");
1031 if (!out_is_reg_wire
) {
1032 f
<< stringf("%s" "assign ", indent
.c_str());
1033 dump_sigspec(f
, cell
->getPort("\\Q"));
1034 f
<< stringf(" = %s;\n", reg_name
.c_str());
1040 if (cell
->type
== "$mem")
1042 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
1043 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
1044 int abits
= cell
->parameters
["\\ABITS"].as_int();
1045 int size
= cell
->parameters
["\\SIZE"].as_int();
1046 int offset
= cell
->parameters
["\\OFFSET"].as_int();
1047 int width
= cell
->parameters
["\\WIDTH"].as_int();
1048 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
1050 // for memory block make something like:
1051 // reg [7:0] memid [3:0];
1055 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1058 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1059 for (int i
=0; i
<size
; i
++)
1061 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1062 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1063 f
<< stringf(";\n");
1065 f
<< stringf("%s" "end\n", indent
.c_str());
1068 // create a map : "edge clk" -> expressions within that clock domain
1069 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1070 clk_to_lof_body
[""] = std::vector
<std::string
>();
1071 std::string clk_domain_str
;
1072 // create a list of reg declarations
1073 std::vector
<std::string
> lof_reg_declarations
;
1075 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1076 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1077 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1079 for (int i
=0; i
< nread_ports
; i
++)
1081 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1082 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1083 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1084 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1085 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1086 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1087 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1091 std::ostringstream os
;
1092 dump_sigspec(os
, sig_rd_clk
);
1093 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1094 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1095 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1097 if (!rd_transparent
)
1099 // for clocked read ports make something like:
1100 // reg [..] temp_id;
1101 // always @(posedge clk)
1102 // if (rd_en) temp_id <= array_reg[r_addr];
1103 // assign r_data = temp_id;
1104 std::string temp_id
= next_auto_id();
1105 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1107 std::ostringstream os
;
1108 if (sig_rd_en
!= RTLIL::SigBit(true))
1110 os
<< stringf("if (");
1111 dump_sigspec(os
, sig_rd_en
);
1112 os
<< stringf(") ");
1114 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1115 dump_sigspec(os
, sig_rd_addr
);
1116 os
<< stringf("];\n");
1117 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1120 std::ostringstream os
;
1121 dump_sigspec(os
, sig_rd_data
);
1122 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1123 clk_to_lof_body
[""].push_back(line
);
1128 // for rd-transparent read-ports make something like:
1129 // reg [..] temp_id;
1130 // always @(posedge clk)
1131 // temp_id <= r_addr;
1132 // assign r_data = array_reg[temp_id];
1133 std::string temp_id
= next_auto_id();
1134 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1136 std::ostringstream os
;
1137 dump_sigspec(os
, sig_rd_addr
);
1138 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1139 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1142 std::ostringstream os
;
1143 dump_sigspec(os
, sig_rd_data
);
1144 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1145 clk_to_lof_body
[""].push_back(line
);
1149 // for non-clocked read-ports make something like:
1150 // assign r_data = array_reg[r_addr];
1151 std::ostringstream os
, os2
;
1152 dump_sigspec(os
, sig_rd_data
);
1153 dump_sigspec(os2
, sig_rd_addr
);
1154 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1155 clk_to_lof_body
[""].push_back(line
);
1159 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1160 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1161 bool wr_clk_posedge
;
1164 for (int i
=0; i
< nwrite_ports
; i
++)
1166 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1167 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1168 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1169 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1170 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1172 std::ostringstream os
;
1173 dump_sigspec(os
, sig_wr_clk
);
1174 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1175 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1176 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1178 // make something like:
1179 // always @(posedge clk)
1180 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1182 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1184 int start_i
= i
, width
= 1;
1185 SigBit wen_bit
= sig_wr_en
[i
];
1187 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1190 if (wen_bit
== State::S0
)
1193 std::ostringstream os
;
1194 if (wen_bit
!= State::S1
)
1196 os
<< stringf("if (");
1197 dump_sigspec(os
, wen_bit
);
1198 os
<< stringf(") ");
1200 os
<< stringf("%s[", mem_id
.c_str());
1201 dump_sigspec(os
, sig_wr_addr
);
1202 if (width
== GetSize(sig_wr_en
))
1203 os
<< stringf("] <= ");
1205 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1206 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1207 os
<< stringf(";\n");
1208 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1211 // Output Verilog that looks something like this:
1213 // always @(posedge CLK2) begin
1214 // _3_ <= memory[D1ADDR];
1216 // memory[A1ADDR] <= A1DATA;
1218 // memory[A2ADDR] <= A2DATA;
1221 // always @(negedge CLK1) begin
1223 // memory[C1ADDR] <= C1DATA;
1226 // assign D1DATA = _3_;
1227 // assign D2DATA <= memory[D2ADDR];
1229 // the reg ... definitions
1230 for(auto ®
: lof_reg_declarations
)
1232 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1234 // the block of expressions by clock domain
1235 for(auto &pair
: clk_to_lof_body
)
1237 std::string clk_domain
= pair
.first
;
1238 std::vector
<std::string
> lof_lines
= pair
.second
;
1239 if( clk_domain
!= "")
1241 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1242 for(auto &line
: lof_lines
)
1243 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1244 f
<< stringf("%s" "end\n", indent
.c_str());
1248 // the non-clocked assignments
1249 for(auto &line
: lof_lines
)
1250 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1257 if (cell
->type
.in("$assert", "$assume", "$cover"))
1259 f
<< stringf("%s" "always @* if (", indent
.c_str());
1260 dump_sigspec(f
, cell
->getPort("\\EN"));
1261 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1262 dump_sigspec(f
, cell
->getPort("\\A"));
1263 f
<< stringf(");\n");
1267 if (cell
->type
.in("$specify2", "$specify3"))
1269 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1271 SigSpec en
= cell
->getPort("\\EN");
1272 if (en
!= State::S1
) {
1273 f
<< stringf("if (");
1274 dump_sigspec(f
, cell
->getPort("\\EN"));
1279 if (cell
->type
== "$specify3" && cell
->getParam("\\EDGE_EN").as_bool())
1280 f
<< (cell
->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1282 dump_sigspec(f
, cell
->getPort("\\SRC"));
1285 if (cell
->getParam("\\SRC_DST_PEN").as_bool())
1286 f
<< (cell
->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1287 f
<< (cell
->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1289 if (cell
->type
== "$specify3") {
1291 dump_sigspec(f
, cell
->getPort("\\DST"));
1293 if (cell
->getParam("\\DAT_DST_PEN").as_bool())
1294 f
<< (cell
->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1296 dump_sigspec(f
, cell
->getPort("\\DAT"));
1299 dump_sigspec(f
, cell
->getPort("\\DST"));
1302 bool bak_decimal
= decimal
;
1306 dump_const(f
, cell
->getParam("\\T_RISE_MIN"));
1308 dump_const(f
, cell
->getParam("\\T_RISE_TYP"));
1310 dump_const(f
, cell
->getParam("\\T_RISE_MAX"));
1312 dump_const(f
, cell
->getParam("\\T_FALL_MIN"));
1314 dump_const(f
, cell
->getParam("\\T_FALL_TYP"));
1316 dump_const(f
, cell
->getParam("\\T_FALL_MAX"));
1319 decimal
= bak_decimal
;
1321 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1325 if (cell
->type
== "$specrule")
1327 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1329 string spec_type
= cell
->getParam("\\TYPE").decode_string();
1330 f
<< stringf("%s(", spec_type
.c_str());
1332 if (cell
->getParam("\\SRC_PEN").as_bool())
1333 f
<< (cell
->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1334 dump_sigspec(f
, cell
->getPort("\\SRC"));
1336 if (cell
->getPort("\\SRC_EN") != State::S1
) {
1338 dump_sigspec(f
, cell
->getPort("\\SRC_EN"));
1342 if (cell
->getParam("\\DST_PEN").as_bool())
1343 f
<< (cell
->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1344 dump_sigspec(f
, cell
->getPort("\\DST"));
1346 if (cell
->getPort("\\DST_EN") != State::S1
) {
1348 dump_sigspec(f
, cell
->getPort("\\DST_EN"));
1351 bool bak_decimal
= decimal
;
1355 dump_const(f
, cell
->getParam("\\T_LIMIT"));
1357 if (spec_type
== "$setuphold" || spec_type
== "$recrem" || spec_type
== "$fullskew") {
1359 dump_const(f
, cell
->getParam("\\T_LIMIT2"));
1363 decimal
= bak_decimal
;
1365 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1369 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1370 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1375 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1377 if (cell
->type
[0] == '$' && !noexpr
) {
1378 if (dump_cell_expr(f
, indent
, cell
))
1382 dump_attributes(f
, indent
, cell
->attributes
);
1383 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1385 if (!defparam
&& cell
->parameters
.size() > 0) {
1386 f
<< stringf(" #(");
1387 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1388 if (it
!= cell
->parameters
.begin())
1390 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1391 dump_const(f
, it
->second
);
1394 f
<< stringf("\n%s" ")", indent
.c_str());
1397 std::string cell_name
= cellname(cell
);
1398 if (cell_name
!= id(cell
->name
))
1399 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1401 f
<< stringf(" %s (", cell_name
.c_str());
1403 bool first_arg
= true;
1404 std::set
<RTLIL::IdString
> numbered_ports
;
1405 for (int i
= 1; true; i
++) {
1407 snprintf(str
, 16, "$%d", i
);
1408 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1409 if (it
->first
!= str
)
1414 f
<< stringf("\n%s ", indent
.c_str());
1415 dump_sigspec(f
, it
->second
);
1416 numbered_ports
.insert(it
->first
);
1417 goto found_numbered_port
;
1420 found_numbered_port
:;
1422 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1423 if (numbered_ports
.count(it
->first
))
1428 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1429 if (it
->second
.size() > 0)
1430 dump_sigspec(f
, it
->second
);
1433 f
<< stringf("\n%s" ");\n", indent
.c_str());
1435 if (defparam
&& cell
->parameters
.size() > 0) {
1436 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1437 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1438 dump_const(f
, it
->second
);
1439 f
<< stringf(";\n");
1443 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q")) {
1444 std::stringstream ss
;
1445 dump_reg_init(ss
, cell
->getPort("\\Q"));
1446 if (!ss
.str().empty()) {
1447 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1454 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1456 f
<< stringf("%s" "assign ", indent
.c_str());
1457 dump_sigspec(f
, left
);
1458 f
<< stringf(" = ");
1459 dump_sigspec(f
, right
);
1460 f
<< stringf(";\n");
1463 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1465 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1467 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1469 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1470 f
<< stringf("%s" "begin\n", indent
.c_str());
1472 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1473 if (it
->first
.size() == 0)
1475 f
<< stringf("%s ", indent
.c_str());
1476 dump_sigspec(f
, it
->first
);
1477 f
<< stringf(" = ");
1478 dump_sigspec(f
, it
->second
);
1479 f
<< stringf(";\n");
1482 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1483 dump_proc_switch(f
, indent
+ " ", *it
);
1485 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1486 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1488 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1489 f
<< stringf("%s" "end\n", indent
.c_str());
1492 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1494 if (sw
->signal
.size() == 0) {
1495 f
<< stringf("%s" "begin\n", indent
.c_str());
1496 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1497 if ((*it
)->compare
.size() == 0)
1498 dump_case_body(f
, indent
+ " ", *it
);
1500 f
<< stringf("%s" "end\n", indent
.c_str());
1504 dump_attributes(f
, indent
, sw
->attributes
);
1505 f
<< stringf("%s" "casez (", indent
.c_str());
1506 dump_sigspec(f
, sw
->signal
);
1507 f
<< stringf(")\n");
1509 bool got_default
= false;
1510 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1511 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*as_comment=*/true);
1512 if ((*it
)->compare
.size() == 0) {
1515 f
<< stringf("%s default", indent
.c_str());
1518 f
<< stringf("%s ", indent
.c_str());
1519 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1522 dump_sigspec(f
, (*it
)->compare
[i
]);
1525 f
<< stringf(":\n");
1526 dump_case_body(f
, indent
+ " ", *it
);
1529 f
<< stringf("%s" "endcase\n", indent
.c_str());
1532 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1534 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1535 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1536 case_body_find_regs(*it2
);
1538 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1539 for (auto &c
: it
->first
.chunks())
1541 reg_wires
.insert(c
.wire
->name
);
1545 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1548 case_body_find_regs(&proc
->root_case
);
1549 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1550 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1551 for (auto &c
: it2
->first
.chunks())
1553 reg_wires
.insert(c
.wire
->name
);
1558 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1559 dump_case_body(f
, indent
, &proc
->root_case
, true);
1561 std::string backup_indent
= indent
;
1563 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1565 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1566 indent
= backup_indent
;
1568 if (sync
->type
== RTLIL::STa
) {
1569 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1570 } else if (sync
->type
== RTLIL::STi
) {
1571 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1573 f
<< stringf("%s" "always @(", indent
.c_str());
1574 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1575 f
<< stringf("posedge ");
1576 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1577 f
<< stringf("negedge ");
1578 dump_sigspec(f
, sync
->signal
);
1579 f
<< stringf(") begin\n");
1581 std::string ends
= indent
+ "end\n";
1584 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1585 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1586 dump_sigspec(f
, sync
->signal
);
1587 f
<< stringf(") begin\n");
1588 ends
= indent
+ "end\n" + ends
;
1592 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1593 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1594 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1595 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1596 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1597 dump_sigspec(f
, sync2
->signal
);
1598 f
<< stringf(") begin\n");
1599 ends
= indent
+ "end\n" + ends
;
1605 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1606 if (it
->first
.size() == 0)
1608 f
<< stringf("%s ", indent
.c_str());
1609 dump_sigspec(f
, it
->first
);
1610 f
<< stringf(" <= ");
1611 dump_sigspec(f
, it
->second
);
1612 f
<< stringf(";\n");
1615 f
<< stringf("%s", ends
.c_str());
1619 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1622 reset_auto_counter(module
);
1623 active_module
= module
;
1624 active_sigmap
.set(module
);
1625 active_initdata
.clear();
1627 for (auto wire
: module
->wires())
1628 if (wire
->attributes
.count("\\init")) {
1629 SigSpec sig
= active_sigmap(wire
);
1630 Const val
= wire
->attributes
.at("\\init");
1631 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1632 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1633 active_initdata
[sig
[i
]] = val
[i
];
1636 if (!module
->processes
.empty())
1637 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1638 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1639 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1640 "processes to logic networks and registers.\n", log_id(module
));
1643 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1644 dump_process(f
, indent
+ " ", it
->second
, true);
1648 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1649 for (auto &it
: module
->cells_
)
1651 RTLIL::Cell
*cell
= it
.second
;
1652 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1655 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1657 if (sig
.is_chunk()) {
1658 RTLIL::SigChunk chunk
= sig
.as_chunk();
1659 if (chunk
.wire
!= NULL
)
1660 for (int i
= 0; i
< chunk
.width
; i
++)
1661 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1664 for (auto &it
: module
->wires_
)
1666 RTLIL::Wire
*wire
= it
.second
;
1667 for (int i
= 0; i
< wire
->width
; i
++)
1668 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1669 goto this_wire_aint_reg
;
1671 reg_wires
.insert(wire
->name
);
1672 this_wire_aint_reg
:;
1676 dump_attributes(f
, indent
, module
->attributes
, '\n', /*attr2comment=*/true);
1677 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1678 bool keep_running
= true;
1679 for (int port_id
= 1; keep_running
; port_id
++) {
1680 keep_running
= false;
1681 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1682 RTLIL::Wire
*wire
= it
->second
;
1683 if (wire
->port_id
== port_id
) {
1686 f
<< stringf("%s", id(wire
->name
).c_str());
1687 keep_running
= true;
1692 f
<< stringf(");\n");
1694 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1695 dump_wire(f
, indent
+ " ", it
->second
);
1697 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1698 dump_memory(f
, indent
+ " ", it
->second
);
1700 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1701 dump_cell(f
, indent
+ " ", it
->second
);
1703 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1704 dump_process(f
, indent
+ " ", it
->second
);
1706 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1707 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1709 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1710 active_module
= NULL
;
1711 active_sigmap
.clear();
1712 active_initdata
.clear();
1715 struct VerilogBackend
: public Backend
{
1716 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1717 void help() YS_OVERRIDE
1719 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1721 log(" write_verilog [options] [filename]\n");
1723 log("Write the current design to a Verilog file.\n");
1725 log(" -norename\n");
1726 log(" without this option all internal object names (the ones with a dollar\n");
1727 log(" instead of a backslash prefix) are changed to short names in the\n");
1728 log(" format '_<number>_'.\n");
1730 log(" -renameprefix <prefix>\n");
1731 log(" insert this prefix in front of auto-generated instance names\n");
1734 log(" with this option no attributes are included in the output\n");
1736 log(" -attr2comment\n");
1737 log(" with this option attributes are included as comments in the output\n");
1740 log(" without this option all internal cells are converted to Verilog\n");
1741 log(" expressions.\n");
1744 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1745 log(" in -noexpr mode.\n");
1748 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1749 log(" not bit pattern. This option deactivates this feature and instead\n");
1750 log(" will write out all constants in binary.\n");
1753 log(" dump 32-bit constants in decimal and without size and radix\n");
1756 log(" constant values that are compatible with hex output are usually\n");
1757 log(" dumped as hex values. This option deactivates this feature and\n");
1758 log(" instead will write out all constants in binary.\n");
1761 log(" Parameters and attributes that are specified as strings in the\n");
1762 log(" original input will be output as strings by this back-end. This\n");
1763 log(" deactivates this feature and instead will write string constants\n");
1764 log(" as binary numbers.\n");
1766 log(" -defparam\n");
1767 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1768 log(" cell parameters.\n");
1770 log(" -blackboxes\n");
1771 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1772 log(" this option set only the modules with the 'blackbox' attribute\n");
1773 log(" are written to the output file.\n");
1775 log(" -selected\n");
1776 log(" only write selected modules. modules must be selected entirely or\n");
1777 log(" not at all.\n");
1780 log(" verbose output (print new names of all renamed wires and cells)\n");
1782 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1783 log("always blocks. This frontend should only be used to export an RTLIL\n");
1784 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1785 log("processes to logic networks and registers. A warning is generated when\n");
1786 log("this command is called on a design with RTLIL processes.\n");
1789 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1791 log_header(design
, "Executing Verilog backend.\n");
1796 attr2comment
= false;
1806 bool blackboxes
= false;
1807 bool selected
= false;
1809 auto_name_map
.clear();
1813 reg_ct
.insert("$dff");
1814 reg_ct
.insert("$adff");
1815 reg_ct
.insert("$dffe");
1816 reg_ct
.insert("$dlatch");
1818 reg_ct
.insert("$_DFF_N_");
1819 reg_ct
.insert("$_DFF_P_");
1821 reg_ct
.insert("$_DFF_NN0_");
1822 reg_ct
.insert("$_DFF_NN1_");
1823 reg_ct
.insert("$_DFF_NP0_");
1824 reg_ct
.insert("$_DFF_NP1_");
1825 reg_ct
.insert("$_DFF_PN0_");
1826 reg_ct
.insert("$_DFF_PN1_");
1827 reg_ct
.insert("$_DFF_PP0_");
1828 reg_ct
.insert("$_DFF_PP1_");
1830 reg_ct
.insert("$_DFFSR_NNN_");
1831 reg_ct
.insert("$_DFFSR_NNP_");
1832 reg_ct
.insert("$_DFFSR_NPN_");
1833 reg_ct
.insert("$_DFFSR_NPP_");
1834 reg_ct
.insert("$_DFFSR_PNN_");
1835 reg_ct
.insert("$_DFFSR_PNP_");
1836 reg_ct
.insert("$_DFFSR_PPN_");
1837 reg_ct
.insert("$_DFFSR_PPP_");
1840 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1841 std::string arg
= args
[argidx
];
1842 if (arg
== "-norename") {
1846 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1847 auto_prefix
= args
[++argidx
];
1850 if (arg
== "-noattr") {
1854 if (arg
== "-attr2comment") {
1855 attr2comment
= true;
1858 if (arg
== "-noexpr") {
1862 if (arg
== "-nodec") {
1866 if (arg
== "-nohex") {
1870 if (arg
== "-nostr") {
1874 if (arg
== "-defparam") {
1878 if (arg
== "-decimal") {
1882 if (arg
== "-siminit") {
1886 if (arg
== "-blackboxes") {
1890 if (arg
== "-selected") {
1900 extra_args(f
, filename
, args
, argidx
);
1904 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1905 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1906 if (it
->second
->get_blackbox_attribute() != blackboxes
)
1908 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1909 if (design
->selected_module(it
->first
))
1910 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1913 log("Dumping module `%s'.\n", it
->first
.c_str());
1914 dump_module(*f
, "", it
->second
);
1917 auto_name_map
.clear();
1923 PRIVATE_NAMESPACE_END