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
== "$_NMUX_") {
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
, "S", false);
567 dump_attributes(f
, "", cell
->attributes
, ' ');
568 dump_cell_expr_port(f
, cell
, "B", false);
570 dump_cell_expr_port(f
, cell
, "A", false);
571 f
<< stringf(");\n");
575 if (cell
->type
.in("$_AOI3_", "$_OAI3_")) {
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
== "$_AOI3_" ? " & " : " | ");
581 dump_cell_expr_port(f
, cell
, "B", false);
582 f
<< stringf(cell
->type
== "$_AOI3_" ? ") |" : ") &");
583 dump_attributes(f
, "", cell
->attributes
, ' ');
585 dump_cell_expr_port(f
, cell
, "C", false);
586 f
<< stringf(");\n");
590 if (cell
->type
.in("$_AOI4_", "$_OAI4_")) {
591 f
<< stringf("%s" "assign ", indent
.c_str());
592 dump_sigspec(f
, cell
->getPort("\\Y"));
593 f
<< stringf(" = ~((");
594 dump_cell_expr_port(f
, cell
, "A", false);
595 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
596 dump_cell_expr_port(f
, cell
, "B", false);
597 f
<< stringf(cell
->type
== "$_AOI4_" ? ") |" : ") &");
598 dump_attributes(f
, "", cell
->attributes
, ' ');
600 dump_cell_expr_port(f
, cell
, "C", false);
601 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
602 dump_cell_expr_port(f
, cell
, "D", false);
603 f
<< stringf("));\n");
607 if (cell
->type
.substr(0, 6) == "$_DFF_")
609 std::string reg_name
= cellname(cell
);
610 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
612 if (!out_is_reg_wire
) {
613 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
614 dump_reg_init(f
, cell
->getPort("\\Q"));
618 dump_attributes(f
, indent
, cell
->attributes
);
619 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), cell
->type
[6] == 'P' ? "pos" : "neg");
620 dump_sigspec(f
, cell
->getPort("\\C"));
621 if (cell
->type
[7] != '_') {
622 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
623 dump_sigspec(f
, cell
->getPort("\\R"));
627 if (cell
->type
[7] != '_') {
628 f
<< stringf("%s" " if (%s", indent
.c_str(), cell
->type
[7] == 'P' ? "" : "!");
629 dump_sigspec(f
, cell
->getPort("\\R"));
631 f
<< stringf("%s" " %s <= %c;\n", indent
.c_str(), reg_name
.c_str(), cell
->type
[8]);
632 f
<< stringf("%s" " else\n", indent
.c_str());
635 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
636 dump_cell_expr_port(f
, cell
, "D", false);
639 if (!out_is_reg_wire
) {
640 f
<< stringf("%s" "assign ", indent
.c_str());
641 dump_sigspec(f
, cell
->getPort("\\Q"));
642 f
<< stringf(" = %s;\n", reg_name
.c_str());
648 if (cell
->type
.substr(0, 8) == "$_DFFSR_")
650 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
652 std::string reg_name
= cellname(cell
);
653 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
655 if (!out_is_reg_wire
) {
656 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
657 dump_reg_init(f
, cell
->getPort("\\Q"));
661 dump_attributes(f
, indent
, cell
->attributes
);
662 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_c
== 'P' ? "pos" : "neg");
663 dump_sigspec(f
, cell
->getPort("\\C"));
664 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
665 dump_sigspec(f
, cell
->getPort("\\S"));
666 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
667 dump_sigspec(f
, cell
->getPort("\\R"));
670 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
671 dump_sigspec(f
, cell
->getPort("\\R"));
673 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
675 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
676 dump_sigspec(f
, cell
->getPort("\\S"));
678 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
680 f
<< stringf("%s" " else\n", indent
.c_str());
681 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
682 dump_cell_expr_port(f
, cell
, "D", false);
685 if (!out_is_reg_wire
) {
686 f
<< stringf("%s" "assign ", indent
.c_str());
687 dump_sigspec(f
, cell
->getPort("\\Q"));
688 f
<< stringf(" = %s;\n", reg_name
.c_str());
694 #define HANDLE_UNIOP(_type, _operator) \
695 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
696 #define HANDLE_BINOP(_type, _operator) \
697 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
699 HANDLE_UNIOP("$not", "~")
700 HANDLE_UNIOP("$pos", "+")
701 HANDLE_UNIOP("$neg", "-")
703 HANDLE_BINOP("$and", "&")
704 HANDLE_BINOP("$or", "|")
705 HANDLE_BINOP("$xor", "^")
706 HANDLE_BINOP("$xnor", "~^")
708 HANDLE_UNIOP("$reduce_and", "&")
709 HANDLE_UNIOP("$reduce_or", "|")
710 HANDLE_UNIOP("$reduce_xor", "^")
711 HANDLE_UNIOP("$reduce_xnor", "~^")
712 HANDLE_UNIOP("$reduce_bool", "|")
714 HANDLE_BINOP("$shl", "<<")
715 HANDLE_BINOP("$shr", ">>")
716 HANDLE_BINOP("$sshl", "<<<")
717 HANDLE_BINOP("$sshr", ">>>")
719 HANDLE_BINOP("$lt", "<")
720 HANDLE_BINOP("$le", "<=")
721 HANDLE_BINOP("$eq", "==")
722 HANDLE_BINOP("$ne", "!=")
723 HANDLE_BINOP("$eqx", "===")
724 HANDLE_BINOP("$nex", "!==")
725 HANDLE_BINOP("$ge", ">=")
726 HANDLE_BINOP("$gt", ">")
728 HANDLE_BINOP("$add", "+")
729 HANDLE_BINOP("$sub", "-")
730 HANDLE_BINOP("$mul", "*")
731 HANDLE_BINOP("$div", "/")
732 HANDLE_BINOP("$mod", "%")
733 HANDLE_BINOP("$pow", "**")
735 HANDLE_UNIOP("$logic_not", "!")
736 HANDLE_BINOP("$logic_and", "&&")
737 HANDLE_BINOP("$logic_or", "||")
742 if (cell
->type
== "$shift")
744 f
<< stringf("%s" "assign ", indent
.c_str());
745 dump_sigspec(f
, cell
->getPort("\\Y"));
747 if (cell
->getParam("\\B_SIGNED").as_bool())
749 f
<< stringf("$signed(");
750 dump_sigspec(f
, cell
->getPort("\\B"));
752 f
<< stringf(" < 0 ? ");
753 dump_sigspec(f
, cell
->getPort("\\A"));
754 f
<< stringf(" << - ");
755 dump_sigspec(f
, cell
->getPort("\\B"));
757 dump_sigspec(f
, cell
->getPort("\\A"));
758 f
<< stringf(" >> ");
759 dump_sigspec(f
, cell
->getPort("\\B"));
763 dump_sigspec(f
, cell
->getPort("\\A"));
764 f
<< stringf(" >> ");
765 dump_sigspec(f
, cell
->getPort("\\B"));
771 if (cell
->type
== "$shiftx")
773 std::string temp_id
= next_auto_id();
774 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort("\\A"))-1, temp_id
.c_str());
775 dump_sigspec(f
, cell
->getPort("\\A"));
778 f
<< stringf("%s" "assign ", indent
.c_str());
779 dump_sigspec(f
, cell
->getPort("\\Y"));
780 f
<< stringf(" = %s[", temp_id
.c_str());
781 if (cell
->getParam("\\B_SIGNED").as_bool())
782 f
<< stringf("$signed(");
783 dump_sigspec(f
, cell
->getPort("\\B"));
784 if (cell
->getParam("\\B_SIGNED").as_bool())
786 f
<< stringf(" +: %d", cell
->getParam("\\Y_WIDTH").as_int());
787 f
<< stringf("];\n");
791 if (cell
->type
== "$mux")
793 f
<< stringf("%s" "assign ", indent
.c_str());
794 dump_sigspec(f
, cell
->getPort("\\Y"));
796 dump_sigspec(f
, cell
->getPort("\\S"));
798 dump_attributes(f
, "", cell
->attributes
, ' ');
799 dump_sigspec(f
, cell
->getPort("\\B"));
801 dump_sigspec(f
, cell
->getPort("\\A"));
806 if (cell
->type
== "$pmux")
808 int width
= cell
->parameters
["\\WIDTH"].as_int();
809 int s_width
= cell
->getPort("\\S").size();
810 std::string func_name
= cellname(cell
);
812 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
813 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
814 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
815 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
817 dump_attributes(f
, indent
+ " ", cell
->attributes
);
819 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
820 f
<< stringf("%s" " casez (s)", indent
.c_str());
821 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
823 for (int i
= 0; i
< s_width
; i
++)
825 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
827 for (int j
= s_width
-1; j
>= 0; j
--)
828 f
<< stringf("%c", j
== i
? '1' : '?');
831 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
834 f
<< stringf("%s" " default:\n", indent
.c_str());
835 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
837 f
<< stringf("%s" " endcase\n", indent
.c_str());
838 f
<< stringf("%s" "endfunction\n", indent
.c_str());
840 f
<< stringf("%s" "assign ", indent
.c_str());
841 dump_sigspec(f
, cell
->getPort("\\Y"));
842 f
<< stringf(" = %s(", func_name
.c_str());
843 dump_sigspec(f
, cell
->getPort("\\A"));
845 dump_sigspec(f
, cell
->getPort("\\B"));
847 dump_sigspec(f
, cell
->getPort("\\S"));
848 f
<< stringf(");\n");
852 if (cell
->type
== "$tribuf")
854 f
<< stringf("%s" "assign ", indent
.c_str());
855 dump_sigspec(f
, cell
->getPort("\\Y"));
857 dump_sigspec(f
, cell
->getPort("\\EN"));
859 dump_sigspec(f
, cell
->getPort("\\A"));
860 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at("\\WIDTH").as_int());
864 if (cell
->type
== "$slice")
866 f
<< stringf("%s" "assign ", indent
.c_str());
867 dump_sigspec(f
, cell
->getPort("\\Y"));
869 dump_sigspec(f
, cell
->getPort("\\A"));
870 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
874 if (cell
->type
== "$concat")
876 f
<< stringf("%s" "assign ", indent
.c_str());
877 dump_sigspec(f
, cell
->getPort("\\Y"));
878 f
<< stringf(" = { ");
879 dump_sigspec(f
, cell
->getPort("\\B"));
881 dump_sigspec(f
, cell
->getPort("\\A"));
882 f
<< stringf(" };\n");
886 if (cell
->type
== "$lut")
888 f
<< stringf("%s" "assign ", indent
.c_str());
889 dump_sigspec(f
, cell
->getPort("\\Y"));
891 dump_const(f
, cell
->parameters
.at("\\LUT"));
892 f
<< stringf(" >> ");
893 dump_attributes(f
, "", cell
->attributes
, ' ');
894 dump_sigspec(f
, cell
->getPort("\\A"));
899 if (cell
->type
== "$dffsr")
901 SigSpec sig_clk
= cell
->getPort("\\CLK");
902 SigSpec sig_set
= cell
->getPort("\\SET");
903 SigSpec sig_clr
= cell
->getPort("\\CLR");
904 SigSpec sig_d
= cell
->getPort("\\D");
905 SigSpec sig_q
= cell
->getPort("\\Q");
907 int width
= cell
->parameters
["\\WIDTH"].as_int();
908 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
909 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
910 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
912 std::string reg_name
= cellname(cell
);
913 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
915 if (!out_is_reg_wire
) {
916 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
917 dump_reg_init(f
, sig_q
);
921 for (int i
= 0; i
< width
; i
++) {
922 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
923 dump_sigspec(f
, sig_clk
);
924 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
925 dump_sigspec(f
, sig_set
);
926 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
927 dump_sigspec(f
, sig_clr
);
930 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
931 dump_sigspec(f
, sig_clr
);
932 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
934 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
935 dump_sigspec(f
, sig_set
);
936 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
938 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
939 dump_sigspec(f
, sig_d
[i
]);
943 if (!out_is_reg_wire
) {
944 f
<< stringf("%s" "assign ", indent
.c_str());
945 dump_sigspec(f
, sig_q
);
946 f
<< stringf(" = %s;\n", reg_name
.c_str());
952 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
954 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
955 bool pol_clk
, pol_arst
= false, pol_en
= false;
957 sig_clk
= cell
->getPort("\\CLK");
958 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
960 if (cell
->type
== "$adff") {
961 sig_arst
= cell
->getPort("\\ARST");
962 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
963 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
966 if (cell
->type
== "$dffe") {
967 sig_en
= cell
->getPort("\\EN");
968 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
971 std::string reg_name
= cellname(cell
);
972 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
974 if (!out_is_reg_wire
) {
975 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
976 dump_reg_init(f
, cell
->getPort("\\Q"));
980 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
981 dump_sigspec(f
, sig_clk
);
982 if (cell
->type
== "$adff") {
983 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
984 dump_sigspec(f
, sig_arst
);
988 if (cell
->type
== "$adff") {
989 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
990 dump_sigspec(f
, sig_arst
);
992 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
993 dump_sigspec(f
, val_arst
);
995 f
<< stringf("%s" " else\n", indent
.c_str());
998 if (cell
->type
== "$dffe") {
999 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1000 dump_sigspec(f
, sig_en
);
1001 f
<< stringf(")\n");
1004 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
1005 dump_cell_expr_port(f
, cell
, "D", false);
1006 f
<< stringf(";\n");
1008 if (!out_is_reg_wire
) {
1009 f
<< stringf("%s" "assign ", indent
.c_str());
1010 dump_sigspec(f
, cell
->getPort("\\Q"));
1011 f
<< stringf(" = %s;\n", reg_name
.c_str());
1017 if (cell
->type
== "$dlatch")
1019 RTLIL::SigSpec sig_en
;
1020 bool pol_en
= false;
1022 sig_en
= cell
->getPort("\\EN");
1023 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
1025 std::string reg_name
= cellname(cell
);
1026 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
1028 if (!out_is_reg_wire
) {
1029 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
1030 dump_reg_init(f
, cell
->getPort("\\Q"));
1034 f
<< stringf("%s" "always @*\n", indent
.c_str());
1036 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1037 dump_sigspec(f
, sig_en
);
1038 f
<< stringf(")\n");
1040 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
1041 dump_cell_expr_port(f
, cell
, "D", false);
1042 f
<< stringf(";\n");
1044 if (!out_is_reg_wire
) {
1045 f
<< stringf("%s" "assign ", indent
.c_str());
1046 dump_sigspec(f
, cell
->getPort("\\Q"));
1047 f
<< stringf(" = %s;\n", reg_name
.c_str());
1053 if (cell
->type
== "$mem")
1055 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
1056 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
1057 int abits
= cell
->parameters
["\\ABITS"].as_int();
1058 int size
= cell
->parameters
["\\SIZE"].as_int();
1059 int offset
= cell
->parameters
["\\OFFSET"].as_int();
1060 int width
= cell
->parameters
["\\WIDTH"].as_int();
1061 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
1063 // for memory block make something like:
1064 // reg [7:0] memid [3:0];
1068 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1071 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1072 for (int i
=0; i
<size
; i
++)
1074 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1075 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1076 f
<< stringf(";\n");
1078 f
<< stringf("%s" "end\n", indent
.c_str());
1081 // create a map : "edge clk" -> expressions within that clock domain
1082 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1083 clk_to_lof_body
[""] = std::vector
<std::string
>();
1084 std::string clk_domain_str
;
1085 // create a list of reg declarations
1086 std::vector
<std::string
> lof_reg_declarations
;
1088 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1089 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1090 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1092 for (int i
=0; i
< nread_ports
; i
++)
1094 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1095 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1096 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1097 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1098 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1099 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1100 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1104 std::ostringstream os
;
1105 dump_sigspec(os
, sig_rd_clk
);
1106 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1107 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1108 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1110 if (!rd_transparent
)
1112 // for clocked read ports make something like:
1113 // reg [..] temp_id;
1114 // always @(posedge clk)
1115 // if (rd_en) temp_id <= array_reg[r_addr];
1116 // assign r_data = temp_id;
1117 std::string temp_id
= next_auto_id();
1118 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1120 std::ostringstream os
;
1121 if (sig_rd_en
!= RTLIL::SigBit(true))
1123 os
<< stringf("if (");
1124 dump_sigspec(os
, sig_rd_en
);
1125 os
<< stringf(") ");
1127 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1128 dump_sigspec(os
, sig_rd_addr
);
1129 os
<< stringf("];\n");
1130 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1133 std::ostringstream os
;
1134 dump_sigspec(os
, sig_rd_data
);
1135 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1136 clk_to_lof_body
[""].push_back(line
);
1141 // for rd-transparent read-ports make something like:
1142 // reg [..] temp_id;
1143 // always @(posedge clk)
1144 // temp_id <= r_addr;
1145 // assign r_data = array_reg[temp_id];
1146 std::string temp_id
= next_auto_id();
1147 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1149 std::ostringstream os
;
1150 dump_sigspec(os
, sig_rd_addr
);
1151 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1152 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1155 std::ostringstream os
;
1156 dump_sigspec(os
, sig_rd_data
);
1157 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1158 clk_to_lof_body
[""].push_back(line
);
1162 // for non-clocked read-ports make something like:
1163 // assign r_data = array_reg[r_addr];
1164 std::ostringstream os
, os2
;
1165 dump_sigspec(os
, sig_rd_data
);
1166 dump_sigspec(os2
, sig_rd_addr
);
1167 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1168 clk_to_lof_body
[""].push_back(line
);
1172 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1173 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1174 bool wr_clk_posedge
;
1177 for (int i
=0; i
< nwrite_ports
; i
++)
1179 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1180 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1181 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1182 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1183 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1185 std::ostringstream os
;
1186 dump_sigspec(os
, sig_wr_clk
);
1187 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1188 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1189 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1191 // make something like:
1192 // always @(posedge clk)
1193 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1195 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1197 int start_i
= i
, width
= 1;
1198 SigBit wen_bit
= sig_wr_en
[i
];
1200 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1203 if (wen_bit
== State::S0
)
1206 std::ostringstream os
;
1207 if (wen_bit
!= State::S1
)
1209 os
<< stringf("if (");
1210 dump_sigspec(os
, wen_bit
);
1211 os
<< stringf(") ");
1213 os
<< stringf("%s[", mem_id
.c_str());
1214 dump_sigspec(os
, sig_wr_addr
);
1215 if (width
== GetSize(sig_wr_en
))
1216 os
<< stringf("] <= ");
1218 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1219 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1220 os
<< stringf(";\n");
1221 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1224 // Output Verilog that looks something like this:
1226 // always @(posedge CLK2) begin
1227 // _3_ <= memory[D1ADDR];
1229 // memory[A1ADDR] <= A1DATA;
1231 // memory[A2ADDR] <= A2DATA;
1234 // always @(negedge CLK1) begin
1236 // memory[C1ADDR] <= C1DATA;
1239 // assign D1DATA = _3_;
1240 // assign D2DATA <= memory[D2ADDR];
1242 // the reg ... definitions
1243 for(auto ®
: lof_reg_declarations
)
1245 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1247 // the block of expressions by clock domain
1248 for(auto &pair
: clk_to_lof_body
)
1250 std::string clk_domain
= pair
.first
;
1251 std::vector
<std::string
> lof_lines
= pair
.second
;
1252 if( clk_domain
!= "")
1254 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1255 for(auto &line
: lof_lines
)
1256 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1257 f
<< stringf("%s" "end\n", indent
.c_str());
1261 // the non-clocked assignments
1262 for(auto &line
: lof_lines
)
1263 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1270 if (cell
->type
.in("$assert", "$assume", "$cover"))
1272 f
<< stringf("%s" "always @* if (", indent
.c_str());
1273 dump_sigspec(f
, cell
->getPort("\\EN"));
1274 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1275 dump_sigspec(f
, cell
->getPort("\\A"));
1276 f
<< stringf(");\n");
1280 if (cell
->type
.in("$specify2", "$specify3"))
1282 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1284 SigSpec en
= cell
->getPort("\\EN");
1285 if (en
!= State::S1
) {
1286 f
<< stringf("if (");
1287 dump_sigspec(f
, cell
->getPort("\\EN"));
1292 if (cell
->type
== "$specify3" && cell
->getParam("\\EDGE_EN").as_bool())
1293 f
<< (cell
->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1295 dump_sigspec(f
, cell
->getPort("\\SRC"));
1298 if (cell
->getParam("\\SRC_DST_PEN").as_bool())
1299 f
<< (cell
->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1300 f
<< (cell
->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1302 if (cell
->type
== "$specify3") {
1304 dump_sigspec(f
, cell
->getPort("\\DST"));
1306 if (cell
->getParam("\\DAT_DST_PEN").as_bool())
1307 f
<< (cell
->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1309 dump_sigspec(f
, cell
->getPort("\\DAT"));
1312 dump_sigspec(f
, cell
->getPort("\\DST"));
1315 bool bak_decimal
= decimal
;
1319 dump_const(f
, cell
->getParam("\\T_RISE_MIN"));
1321 dump_const(f
, cell
->getParam("\\T_RISE_TYP"));
1323 dump_const(f
, cell
->getParam("\\T_RISE_MAX"));
1325 dump_const(f
, cell
->getParam("\\T_FALL_MIN"));
1327 dump_const(f
, cell
->getParam("\\T_FALL_TYP"));
1329 dump_const(f
, cell
->getParam("\\T_FALL_MAX"));
1332 decimal
= bak_decimal
;
1334 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1338 if (cell
->type
== "$specrule")
1340 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1342 string spec_type
= cell
->getParam("\\TYPE").decode_string();
1343 f
<< stringf("%s(", spec_type
.c_str());
1345 if (cell
->getParam("\\SRC_PEN").as_bool())
1346 f
<< (cell
->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1347 dump_sigspec(f
, cell
->getPort("\\SRC"));
1349 if (cell
->getPort("\\SRC_EN") != State::S1
) {
1351 dump_sigspec(f
, cell
->getPort("\\SRC_EN"));
1355 if (cell
->getParam("\\DST_PEN").as_bool())
1356 f
<< (cell
->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1357 dump_sigspec(f
, cell
->getPort("\\DST"));
1359 if (cell
->getPort("\\DST_EN") != State::S1
) {
1361 dump_sigspec(f
, cell
->getPort("\\DST_EN"));
1364 bool bak_decimal
= decimal
;
1368 dump_const(f
, cell
->getParam("\\T_LIMIT"));
1370 if (spec_type
== "$setuphold" || spec_type
== "$recrem" || spec_type
== "$fullskew") {
1372 dump_const(f
, cell
->getParam("\\T_LIMIT2"));
1376 decimal
= bak_decimal
;
1378 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1382 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1383 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1388 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1390 if (cell
->type
[0] == '$' && !noexpr
) {
1391 if (dump_cell_expr(f
, indent
, cell
))
1395 dump_attributes(f
, indent
, cell
->attributes
);
1396 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1398 if (!defparam
&& cell
->parameters
.size() > 0) {
1399 f
<< stringf(" #(");
1400 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1401 if (it
!= cell
->parameters
.begin())
1403 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1404 dump_const(f
, it
->second
);
1407 f
<< stringf("\n%s" ")", indent
.c_str());
1410 std::string cell_name
= cellname(cell
);
1411 if (cell_name
!= id(cell
->name
))
1412 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1414 f
<< stringf(" %s (", cell_name
.c_str());
1416 bool first_arg
= true;
1417 std::set
<RTLIL::IdString
> numbered_ports
;
1418 for (int i
= 1; true; i
++) {
1420 snprintf(str
, 16, "$%d", i
);
1421 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1422 if (it
->first
!= str
)
1427 f
<< stringf("\n%s ", indent
.c_str());
1428 dump_sigspec(f
, it
->second
);
1429 numbered_ports
.insert(it
->first
);
1430 goto found_numbered_port
;
1433 found_numbered_port
:;
1435 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1436 if (numbered_ports
.count(it
->first
))
1441 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1442 if (it
->second
.size() > 0)
1443 dump_sigspec(f
, it
->second
);
1446 f
<< stringf("\n%s" ");\n", indent
.c_str());
1448 if (defparam
&& cell
->parameters
.size() > 0) {
1449 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1450 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1451 dump_const(f
, it
->second
);
1452 f
<< stringf(";\n");
1456 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q")) {
1457 std::stringstream ss
;
1458 dump_reg_init(ss
, cell
->getPort("\\Q"));
1459 if (!ss
.str().empty()) {
1460 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1467 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1469 f
<< stringf("%s" "assign ", indent
.c_str());
1470 dump_sigspec(f
, left
);
1471 f
<< stringf(" = ");
1472 dump_sigspec(f
, right
);
1473 f
<< stringf(";\n");
1476 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1478 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1480 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1482 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1483 f
<< stringf("%s" "begin\n", indent
.c_str());
1485 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1486 if (it
->first
.size() == 0)
1488 f
<< stringf("%s ", indent
.c_str());
1489 dump_sigspec(f
, it
->first
);
1490 f
<< stringf(" = ");
1491 dump_sigspec(f
, it
->second
);
1492 f
<< stringf(";\n");
1495 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1496 dump_proc_switch(f
, indent
+ " ", *it
);
1498 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1499 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1501 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1502 f
<< stringf("%s" "end\n", indent
.c_str());
1505 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1507 if (sw
->signal
.size() == 0) {
1508 f
<< stringf("%s" "begin\n", indent
.c_str());
1509 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1510 if ((*it
)->compare
.size() == 0)
1511 dump_case_body(f
, indent
+ " ", *it
);
1513 f
<< stringf("%s" "end\n", indent
.c_str());
1517 dump_attributes(f
, indent
, sw
->attributes
);
1518 f
<< stringf("%s" "casez (", indent
.c_str());
1519 dump_sigspec(f
, sw
->signal
);
1520 f
<< stringf(")\n");
1522 bool got_default
= false;
1523 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1524 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*as_comment=*/true);
1525 if ((*it
)->compare
.size() == 0) {
1528 f
<< stringf("%s default", indent
.c_str());
1531 f
<< stringf("%s ", indent
.c_str());
1532 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1535 dump_sigspec(f
, (*it
)->compare
[i
]);
1538 f
<< stringf(":\n");
1539 dump_case_body(f
, indent
+ " ", *it
);
1542 f
<< stringf("%s" "endcase\n", indent
.c_str());
1545 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1547 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1548 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1549 case_body_find_regs(*it2
);
1551 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1552 for (auto &c
: it
->first
.chunks())
1554 reg_wires
.insert(c
.wire
->name
);
1558 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1561 case_body_find_regs(&proc
->root_case
);
1562 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1563 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1564 for (auto &c
: it2
->first
.chunks())
1566 reg_wires
.insert(c
.wire
->name
);
1571 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1572 dump_case_body(f
, indent
, &proc
->root_case
, true);
1574 std::string backup_indent
= indent
;
1576 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1578 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1579 indent
= backup_indent
;
1581 if (sync
->type
== RTLIL::STa
) {
1582 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1583 } else if (sync
->type
== RTLIL::STi
) {
1584 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1586 f
<< stringf("%s" "always @(", indent
.c_str());
1587 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1588 f
<< stringf("posedge ");
1589 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1590 f
<< stringf("negedge ");
1591 dump_sigspec(f
, sync
->signal
);
1592 f
<< stringf(") begin\n");
1594 std::string ends
= indent
+ "end\n";
1597 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1598 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1599 dump_sigspec(f
, sync
->signal
);
1600 f
<< stringf(") begin\n");
1601 ends
= indent
+ "end\n" + ends
;
1605 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1606 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1607 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1608 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1609 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1610 dump_sigspec(f
, sync2
->signal
);
1611 f
<< stringf(") begin\n");
1612 ends
= indent
+ "end\n" + ends
;
1618 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1619 if (it
->first
.size() == 0)
1621 f
<< stringf("%s ", indent
.c_str());
1622 dump_sigspec(f
, it
->first
);
1623 f
<< stringf(" <= ");
1624 dump_sigspec(f
, it
->second
);
1625 f
<< stringf(";\n");
1628 f
<< stringf("%s", ends
.c_str());
1632 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1635 reset_auto_counter(module
);
1636 active_module
= module
;
1637 active_sigmap
.set(module
);
1638 active_initdata
.clear();
1640 for (auto wire
: module
->wires())
1641 if (wire
->attributes
.count("\\init")) {
1642 SigSpec sig
= active_sigmap(wire
);
1643 Const val
= wire
->attributes
.at("\\init");
1644 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1645 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1646 active_initdata
[sig
[i
]] = val
[i
];
1649 if (!module
->processes
.empty())
1650 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1651 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1652 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1653 "processes to logic networks and registers.\n", log_id(module
));
1656 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1657 dump_process(f
, indent
+ " ", it
->second
, true);
1661 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1662 for (auto &it
: module
->cells_
)
1664 RTLIL::Cell
*cell
= it
.second
;
1665 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1668 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1670 if (sig
.is_chunk()) {
1671 RTLIL::SigChunk chunk
= sig
.as_chunk();
1672 if (chunk
.wire
!= NULL
)
1673 for (int i
= 0; i
< chunk
.width
; i
++)
1674 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1677 for (auto &it
: module
->wires_
)
1679 RTLIL::Wire
*wire
= it
.second
;
1680 for (int i
= 0; i
< wire
->width
; i
++)
1681 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1682 goto this_wire_aint_reg
;
1684 reg_wires
.insert(wire
->name
);
1685 this_wire_aint_reg
:;
1689 dump_attributes(f
, indent
, module
->attributes
, '\n', /*attr2comment=*/true);
1690 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1691 bool keep_running
= true;
1692 for (int port_id
= 1; keep_running
; port_id
++) {
1693 keep_running
= false;
1694 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1695 RTLIL::Wire
*wire
= it
->second
;
1696 if (wire
->port_id
== port_id
) {
1699 f
<< stringf("%s", id(wire
->name
).c_str());
1700 keep_running
= true;
1705 f
<< stringf(");\n");
1707 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1708 dump_wire(f
, indent
+ " ", it
->second
);
1710 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1711 dump_memory(f
, indent
+ " ", it
->second
);
1713 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1714 dump_cell(f
, indent
+ " ", it
->second
);
1716 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1717 dump_process(f
, indent
+ " ", it
->second
);
1719 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1720 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1722 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1723 active_module
= NULL
;
1724 active_sigmap
.clear();
1725 active_initdata
.clear();
1728 struct VerilogBackend
: public Backend
{
1729 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1730 void help() YS_OVERRIDE
1732 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1734 log(" write_verilog [options] [filename]\n");
1736 log("Write the current design to a Verilog file.\n");
1738 log(" -norename\n");
1739 log(" without this option all internal object names (the ones with a dollar\n");
1740 log(" instead of a backslash prefix) are changed to short names in the\n");
1741 log(" format '_<number>_'.\n");
1743 log(" -renameprefix <prefix>\n");
1744 log(" insert this prefix in front of auto-generated instance names\n");
1747 log(" with this option no attributes are included in the output\n");
1749 log(" -attr2comment\n");
1750 log(" with this option attributes are included as comments in the output\n");
1753 log(" without this option all internal cells are converted to Verilog\n");
1754 log(" expressions.\n");
1757 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1758 log(" in -noexpr mode.\n");
1761 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1762 log(" not bit pattern. This option deactivates this feature and instead\n");
1763 log(" will write out all constants in binary.\n");
1766 log(" dump 32-bit constants in decimal and without size and radix\n");
1769 log(" constant values that are compatible with hex output are usually\n");
1770 log(" dumped as hex values. This option deactivates this feature and\n");
1771 log(" instead will write out all constants in binary.\n");
1774 log(" Parameters and attributes that are specified as strings in the\n");
1775 log(" original input will be output as strings by this back-end. This\n");
1776 log(" deactivates this feature and instead will write string constants\n");
1777 log(" as binary numbers.\n");
1779 log(" -defparam\n");
1780 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1781 log(" cell parameters.\n");
1783 log(" -blackboxes\n");
1784 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1785 log(" this option set only the modules with the 'blackbox' attribute\n");
1786 log(" are written to the output file.\n");
1788 log(" -selected\n");
1789 log(" only write selected modules. modules must be selected entirely or\n");
1790 log(" not at all.\n");
1793 log(" verbose output (print new names of all renamed wires and cells)\n");
1795 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1796 log("always blocks. This frontend should only be used to export an RTLIL\n");
1797 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1798 log("processes to logic networks and registers. A warning is generated when\n");
1799 log("this command is called on a design with RTLIL processes.\n");
1802 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1804 log_header(design
, "Executing Verilog backend.\n");
1809 attr2comment
= false;
1819 bool blackboxes
= false;
1820 bool selected
= false;
1822 auto_name_map
.clear();
1826 reg_ct
.insert("$dff");
1827 reg_ct
.insert("$adff");
1828 reg_ct
.insert("$dffe");
1829 reg_ct
.insert("$dlatch");
1831 reg_ct
.insert("$_DFF_N_");
1832 reg_ct
.insert("$_DFF_P_");
1834 reg_ct
.insert("$_DFF_NN0_");
1835 reg_ct
.insert("$_DFF_NN1_");
1836 reg_ct
.insert("$_DFF_NP0_");
1837 reg_ct
.insert("$_DFF_NP1_");
1838 reg_ct
.insert("$_DFF_PN0_");
1839 reg_ct
.insert("$_DFF_PN1_");
1840 reg_ct
.insert("$_DFF_PP0_");
1841 reg_ct
.insert("$_DFF_PP1_");
1843 reg_ct
.insert("$_DFFSR_NNN_");
1844 reg_ct
.insert("$_DFFSR_NNP_");
1845 reg_ct
.insert("$_DFFSR_NPN_");
1846 reg_ct
.insert("$_DFFSR_NPP_");
1847 reg_ct
.insert("$_DFFSR_PNN_");
1848 reg_ct
.insert("$_DFFSR_PNP_");
1849 reg_ct
.insert("$_DFFSR_PPN_");
1850 reg_ct
.insert("$_DFFSR_PPP_");
1853 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1854 std::string arg
= args
[argidx
];
1855 if (arg
== "-norename") {
1859 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1860 auto_prefix
= args
[++argidx
];
1863 if (arg
== "-noattr") {
1867 if (arg
== "-attr2comment") {
1868 attr2comment
= true;
1871 if (arg
== "-noexpr") {
1875 if (arg
== "-nodec") {
1879 if (arg
== "-nohex") {
1883 if (arg
== "-nostr") {
1887 if (arg
== "-defparam") {
1891 if (arg
== "-decimal") {
1895 if (arg
== "-siminit") {
1899 if (arg
== "-blackboxes") {
1903 if (arg
== "-selected") {
1913 extra_args(f
, filename
, args
, argidx
);
1917 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1918 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1919 if (it
->second
->get_blackbox_attribute() != blackboxes
)
1921 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1922 if (design
->selected_module(it
->first
))
1923 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1926 log("Dumping module `%s'.\n", it
->first
.c_str());
1927 dump_module(*f
, "", it
->second
);
1930 auto_name_map
.clear();
1936 PRIVATE_NAMESPACE_END