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
, extmem
, defparam
, decimal
, siminit
;
37 int auto_name_counter
, auto_name_offset
, auto_name_digits
, extmem_counter
;
38 std::map
<RTLIL::IdString
, int> auto_name_map
;
39 std::set
<RTLIL::IdString
> reg_wires
, reg_ct
;
40 std::string auto_prefix
, extmem_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
] != State::S0
&& data
.bits
[i
] != State::S1
)
205 if (data
.bits
[i
] == State::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 State::S0
: bin_digits
.push_back('0'); break;
223 case State::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 State::S0
: f
<< stringf("0"); break;
277 case State::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 regattr
= false, bool as_comment
= false)
380 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
381 if (it
->first
== "\\init" && regattr
) continue;
382 f
<< stringf("%s" "%s %s", indent
.c_str(), as_comment
? "/*" : "(*", id(it
->first
).c_str());
384 if (modattr
&& (it
->second
== State::S0
|| it
->second
== Const(0)))
386 else if (modattr
&& (it
->second
== State::S1
|| it
->second
== Const(1)))
389 dump_const(f
, it
->second
, -1, 0, false, as_comment
);
390 f
<< stringf(" %s%c", as_comment
? "*/" : "*)", term
);
394 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
396 dump_attributes(f
, indent
, wire
->attributes
, '\n', /*modattr=*/false, /*regattr=*/reg_wires
.count(wire
->name
));
398 if (wire
->port_input
&& !wire
->port_output
)
399 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
400 else if (!wire
->port_input
&& wire
->port_output
)
401 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
402 else if (wire
->port_input
&& wire
->port_output
)
403 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
405 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
406 if (wire
->width
!= 1)
407 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
408 f
<< stringf("%s;\n", id(wire
->name
).c_str());
410 // do not use Verilog-2k "output reg" syntax in Verilog export
411 std::string range
= "";
412 if (wire
->width
!= 1) {
414 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
416 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
418 if (wire
->port_input
&& !wire
->port_output
)
419 f
<< stringf("%s" "input%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
420 if (!wire
->port_input
&& wire
->port_output
)
421 f
<< stringf("%s" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
422 if (wire
->port_input
&& wire
->port_output
)
423 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
424 if (reg_wires
.count(wire
->name
)) {
425 f
<< stringf("%s" "reg%s %s", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
426 if (wire
->attributes
.count("\\init")) {
428 dump_const(f
, wire
->attributes
.at("\\init"));
431 } else if (!wire
->port_input
&& !wire
->port_output
)
432 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
436 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
438 dump_attributes(f
, indent
, memory
->attributes
);
439 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
);
442 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
444 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
445 f
<< stringf("$signed(");
446 dump_sigspec(f
, cell
->getPort("\\" + port
));
449 dump_sigspec(f
, cell
->getPort("\\" + port
));
452 std::string
cellname(RTLIL::Cell
*cell
)
454 if (!norename
&& cell
->name
[0] == '$' && reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q"))
456 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
457 if (GetSize(sig
) != 1 || sig
.is_fully_const())
458 goto no_special_reg_name
;
460 RTLIL::Wire
*wire
= sig
[0].wire
;
462 if (wire
->name
[0] != '\\')
463 goto no_special_reg_name
;
465 std::string cell_name
= wire
->name
.str();
467 size_t pos
= cell_name
.find('[');
468 if (pos
!= std::string::npos
)
469 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
471 cell_name
= cell_name
+ "_reg";
473 if (wire
->width
!= 1)
474 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
476 if (active_module
&& active_module
->count_id(cell_name
) > 0)
477 goto no_special_reg_name
;
479 return id(cell_name
);
484 return id(cell
->name
).c_str();
488 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
490 f
<< stringf("%s" "assign ", indent
.c_str());
491 dump_sigspec(f
, cell
->getPort("\\Y"));
492 f
<< stringf(" = %s ", op
.c_str());
493 dump_attributes(f
, "", cell
->attributes
, ' ');
494 dump_cell_expr_port(f
, cell
, "A", true);
498 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
500 f
<< stringf("%s" "assign ", indent
.c_str());
501 dump_sigspec(f
, cell
->getPort("\\Y"));
503 dump_cell_expr_port(f
, cell
, "A", true);
504 f
<< stringf(" %s ", op
.c_str());
505 dump_attributes(f
, "", cell
->attributes
, ' ');
506 dump_cell_expr_port(f
, cell
, "B", true);
510 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
512 if (cell
->type
== "$_NOT_") {
513 f
<< stringf("%s" "assign ", indent
.c_str());
514 dump_sigspec(f
, cell
->getPort("\\Y"));
517 dump_attributes(f
, "", cell
->attributes
, ' ');
518 dump_cell_expr_port(f
, cell
, "A", false);
523 if (cell
->type
.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
524 f
<< stringf("%s" "assign ", indent
.c_str());
525 dump_sigspec(f
, cell
->getPort("\\Y"));
527 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
529 dump_cell_expr_port(f
, cell
, "A", false);
531 if (cell
->type
.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
533 if (cell
->type
.in("$_OR_", "$_NOR_", "$_ORNOT_"))
535 if (cell
->type
.in("$_XOR_", "$_XNOR_"))
537 dump_attributes(f
, "", cell
->attributes
, ' ');
539 if (cell
->type
.in("$_ANDNOT_", "$_ORNOT_"))
541 dump_cell_expr_port(f
, cell
, "B", false);
542 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
548 if (cell
->type
== "$_MUX_") {
549 f
<< stringf("%s" "assign ", indent
.c_str());
550 dump_sigspec(f
, cell
->getPort("\\Y"));
552 dump_cell_expr_port(f
, cell
, "S", false);
554 dump_attributes(f
, "", cell
->attributes
, ' ');
555 dump_cell_expr_port(f
, cell
, "B", false);
557 dump_cell_expr_port(f
, cell
, "A", false);
562 if (cell
->type
== "$_NMUX_") {
563 f
<< stringf("%s" "assign ", indent
.c_str());
564 dump_sigspec(f
, cell
->getPort("\\Y"));
565 f
<< stringf(" = !(");
566 dump_cell_expr_port(f
, cell
, "S", false);
568 dump_attributes(f
, "", cell
->attributes
, ' ');
569 dump_cell_expr_port(f
, cell
, "B", false);
571 dump_cell_expr_port(f
, cell
, "A", false);
572 f
<< stringf(");\n");
576 if (cell
->type
.in("$_AOI3_", "$_OAI3_")) {
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
== "$_AOI3_" ? " & " : " | ");
582 dump_cell_expr_port(f
, cell
, "B", false);
583 f
<< stringf(cell
->type
== "$_AOI3_" ? ") |" : ") &");
584 dump_attributes(f
, "", cell
->attributes
, ' ');
586 dump_cell_expr_port(f
, cell
, "C", false);
587 f
<< stringf(");\n");
591 if (cell
->type
.in("$_AOI4_", "$_OAI4_")) {
592 f
<< stringf("%s" "assign ", indent
.c_str());
593 dump_sigspec(f
, cell
->getPort("\\Y"));
594 f
<< stringf(" = ~((");
595 dump_cell_expr_port(f
, cell
, "A", false);
596 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
597 dump_cell_expr_port(f
, cell
, "B", false);
598 f
<< stringf(cell
->type
== "$_AOI4_" ? ") |" : ") &");
599 dump_attributes(f
, "", cell
->attributes
, ' ');
601 dump_cell_expr_port(f
, cell
, "C", false);
602 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
603 dump_cell_expr_port(f
, cell
, "D", false);
604 f
<< stringf("));\n");
608 if (cell
->type
.begins_with("$_DFF_"))
610 std::string reg_name
= cellname(cell
);
611 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
613 if (!out_is_reg_wire
) {
614 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
615 dump_reg_init(f
, cell
->getPort("\\Q"));
619 dump_attributes(f
, indent
, cell
->attributes
);
620 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), cell
->type
[6] == 'P' ? "pos" : "neg");
621 dump_sigspec(f
, cell
->getPort("\\C"));
622 if (cell
->type
[7] != '_') {
623 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
624 dump_sigspec(f
, cell
->getPort("\\R"));
628 if (cell
->type
[7] != '_') {
629 f
<< stringf("%s" " if (%s", indent
.c_str(), cell
->type
[7] == 'P' ? "" : "!");
630 dump_sigspec(f
, cell
->getPort("\\R"));
632 f
<< stringf("%s" " %s <= %c;\n", indent
.c_str(), reg_name
.c_str(), cell
->type
[8]);
633 f
<< stringf("%s" " else\n", indent
.c_str());
636 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
637 dump_cell_expr_port(f
, cell
, "D", false);
640 if (!out_is_reg_wire
) {
641 f
<< stringf("%s" "assign ", indent
.c_str());
642 dump_sigspec(f
, cell
->getPort("\\Q"));
643 f
<< stringf(" = %s;\n", reg_name
.c_str());
649 if (cell
->type
.begins_with("$_DFFSR_"))
651 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
653 std::string reg_name
= cellname(cell
);
654 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
656 if (!out_is_reg_wire
) {
657 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
658 dump_reg_init(f
, cell
->getPort("\\Q"));
662 dump_attributes(f
, indent
, cell
->attributes
);
663 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_c
== 'P' ? "pos" : "neg");
664 dump_sigspec(f
, cell
->getPort("\\C"));
665 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
666 dump_sigspec(f
, cell
->getPort("\\S"));
667 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
668 dump_sigspec(f
, cell
->getPort("\\R"));
671 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
672 dump_sigspec(f
, cell
->getPort("\\R"));
674 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
676 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
677 dump_sigspec(f
, cell
->getPort("\\S"));
679 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
681 f
<< stringf("%s" " else\n", indent
.c_str());
682 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
683 dump_cell_expr_port(f
, cell
, "D", false);
686 if (!out_is_reg_wire
) {
687 f
<< stringf("%s" "assign ", indent
.c_str());
688 dump_sigspec(f
, cell
->getPort("\\Q"));
689 f
<< stringf(" = %s;\n", reg_name
.c_str());
695 #define HANDLE_UNIOP(_type, _operator) \
696 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
697 #define HANDLE_BINOP(_type, _operator) \
698 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
700 HANDLE_UNIOP("$not", "~")
701 HANDLE_UNIOP("$pos", "+")
702 HANDLE_UNIOP("$neg", "-")
704 HANDLE_BINOP("$and", "&")
705 HANDLE_BINOP("$or", "|")
706 HANDLE_BINOP("$xor", "^")
707 HANDLE_BINOP("$xnor", "~^")
709 HANDLE_UNIOP("$reduce_and", "&")
710 HANDLE_UNIOP("$reduce_or", "|")
711 HANDLE_UNIOP("$reduce_xor", "^")
712 HANDLE_UNIOP("$reduce_xnor", "~^")
713 HANDLE_UNIOP("$reduce_bool", "|")
715 HANDLE_BINOP("$shl", "<<")
716 HANDLE_BINOP("$shr", ">>")
717 HANDLE_BINOP("$sshl", "<<<")
718 HANDLE_BINOP("$sshr", ">>>")
720 HANDLE_BINOP("$lt", "<")
721 HANDLE_BINOP("$le", "<=")
722 HANDLE_BINOP("$eq", "==")
723 HANDLE_BINOP("$ne", "!=")
724 HANDLE_BINOP("$eqx", "===")
725 HANDLE_BINOP("$nex", "!==")
726 HANDLE_BINOP("$ge", ">=")
727 HANDLE_BINOP("$gt", ">")
729 HANDLE_BINOP("$add", "+")
730 HANDLE_BINOP("$sub", "-")
731 HANDLE_BINOP("$mul", "*")
732 HANDLE_BINOP("$div", "/")
733 HANDLE_BINOP("$mod", "%")
734 HANDLE_BINOP("$pow", "**")
736 HANDLE_UNIOP("$logic_not", "!")
737 HANDLE_BINOP("$logic_and", "&&")
738 HANDLE_BINOP("$logic_or", "||")
743 if (cell
->type
== "$shift")
745 f
<< stringf("%s" "assign ", indent
.c_str());
746 dump_sigspec(f
, cell
->getPort("\\Y"));
748 if (cell
->getParam("\\B_SIGNED").as_bool())
750 f
<< stringf("$signed(");
751 dump_sigspec(f
, cell
->getPort("\\B"));
753 f
<< stringf(" < 0 ? ");
754 dump_sigspec(f
, cell
->getPort("\\A"));
755 f
<< stringf(" << - ");
756 dump_sigspec(f
, cell
->getPort("\\B"));
758 dump_sigspec(f
, cell
->getPort("\\A"));
759 f
<< stringf(" >> ");
760 dump_sigspec(f
, cell
->getPort("\\B"));
764 dump_sigspec(f
, cell
->getPort("\\A"));
765 f
<< stringf(" >> ");
766 dump_sigspec(f
, cell
->getPort("\\B"));
772 if (cell
->type
== "$shiftx")
774 std::string temp_id
= next_auto_id();
775 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort("\\A"))-1, temp_id
.c_str());
776 dump_sigspec(f
, cell
->getPort("\\A"));
779 f
<< stringf("%s" "assign ", indent
.c_str());
780 dump_sigspec(f
, cell
->getPort("\\Y"));
781 f
<< stringf(" = %s[", temp_id
.c_str());
782 if (cell
->getParam("\\B_SIGNED").as_bool())
783 f
<< stringf("$signed(");
784 dump_sigspec(f
, cell
->getPort("\\B"));
785 if (cell
->getParam("\\B_SIGNED").as_bool())
787 f
<< stringf(" +: %d", cell
->getParam("\\Y_WIDTH").as_int());
788 f
<< stringf("];\n");
792 if (cell
->type
== "$mux")
794 f
<< stringf("%s" "assign ", indent
.c_str());
795 dump_sigspec(f
, cell
->getPort("\\Y"));
797 dump_sigspec(f
, cell
->getPort("\\S"));
799 dump_attributes(f
, "", cell
->attributes
, ' ');
800 dump_sigspec(f
, cell
->getPort("\\B"));
802 dump_sigspec(f
, cell
->getPort("\\A"));
807 if (cell
->type
== "$pmux")
809 int width
= cell
->parameters
["\\WIDTH"].as_int();
810 int s_width
= cell
->getPort("\\S").size();
811 std::string func_name
= cellname(cell
);
813 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
814 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
815 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
816 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
818 dump_attributes(f
, indent
+ " ", cell
->attributes
);
820 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
821 f
<< stringf("%s" " casez (s)", indent
.c_str());
822 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
824 for (int i
= 0; i
< s_width
; i
++)
826 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
828 for (int j
= s_width
-1; j
>= 0; j
--)
829 f
<< stringf("%c", j
== i
? '1' : '?');
832 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
835 f
<< stringf("%s" " default:\n", indent
.c_str());
836 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
838 f
<< stringf("%s" " endcase\n", indent
.c_str());
839 f
<< stringf("%s" "endfunction\n", indent
.c_str());
841 f
<< stringf("%s" "assign ", indent
.c_str());
842 dump_sigspec(f
, cell
->getPort("\\Y"));
843 f
<< stringf(" = %s(", func_name
.c_str());
844 dump_sigspec(f
, cell
->getPort("\\A"));
846 dump_sigspec(f
, cell
->getPort("\\B"));
848 dump_sigspec(f
, cell
->getPort("\\S"));
849 f
<< stringf(");\n");
853 if (cell
->type
== "$tribuf")
855 f
<< stringf("%s" "assign ", indent
.c_str());
856 dump_sigspec(f
, cell
->getPort("\\Y"));
858 dump_sigspec(f
, cell
->getPort("\\EN"));
860 dump_sigspec(f
, cell
->getPort("\\A"));
861 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at("\\WIDTH").as_int());
865 if (cell
->type
== "$slice")
867 f
<< stringf("%s" "assign ", indent
.c_str());
868 dump_sigspec(f
, cell
->getPort("\\Y"));
870 dump_sigspec(f
, cell
->getPort("\\A"));
871 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
875 if (cell
->type
== "$concat")
877 f
<< stringf("%s" "assign ", indent
.c_str());
878 dump_sigspec(f
, cell
->getPort("\\Y"));
879 f
<< stringf(" = { ");
880 dump_sigspec(f
, cell
->getPort("\\B"));
882 dump_sigspec(f
, cell
->getPort("\\A"));
883 f
<< stringf(" };\n");
887 if (cell
->type
== "$lut")
889 f
<< stringf("%s" "assign ", indent
.c_str());
890 dump_sigspec(f
, cell
->getPort("\\Y"));
892 dump_const(f
, cell
->parameters
.at("\\LUT"));
893 f
<< stringf(" >> ");
894 dump_attributes(f
, "", cell
->attributes
, ' ');
895 dump_sigspec(f
, cell
->getPort("\\A"));
900 if (cell
->type
== "$dffsr")
902 SigSpec sig_clk
= cell
->getPort("\\CLK");
903 SigSpec sig_set
= cell
->getPort("\\SET");
904 SigSpec sig_clr
= cell
->getPort("\\CLR");
905 SigSpec sig_d
= cell
->getPort("\\D");
906 SigSpec sig_q
= cell
->getPort("\\Q");
908 int width
= cell
->parameters
["\\WIDTH"].as_int();
909 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
910 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
911 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
913 std::string reg_name
= cellname(cell
);
914 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
916 if (!out_is_reg_wire
) {
917 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
918 dump_reg_init(f
, sig_q
);
922 for (int i
= 0; i
< width
; i
++) {
923 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
924 dump_sigspec(f
, sig_clk
);
925 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
926 dump_sigspec(f
, sig_set
);
927 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
928 dump_sigspec(f
, sig_clr
);
931 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
932 dump_sigspec(f
, sig_clr
);
933 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
935 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
936 dump_sigspec(f
, sig_set
);
937 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
939 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
940 dump_sigspec(f
, sig_d
[i
]);
944 if (!out_is_reg_wire
) {
945 f
<< stringf("%s" "assign ", indent
.c_str());
946 dump_sigspec(f
, sig_q
);
947 f
<< stringf(" = %s;\n", reg_name
.c_str());
953 if (cell
->type
.in("$dff", "$adff", "$dffe"))
955 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
956 bool pol_clk
, pol_arst
= false, pol_en
= false;
958 sig_clk
= cell
->getPort("\\CLK");
959 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
961 if (cell
->type
== "$adff") {
962 sig_arst
= cell
->getPort("\\ARST");
963 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
964 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
967 if (cell
->type
== "$dffe") {
968 sig_en
= cell
->getPort("\\EN");
969 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
972 std::string reg_name
= cellname(cell
);
973 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
975 if (!out_is_reg_wire
) {
976 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
977 dump_reg_init(f
, cell
->getPort("\\Q"));
981 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
982 dump_sigspec(f
, sig_clk
);
983 if (cell
->type
== "$adff") {
984 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
985 dump_sigspec(f
, sig_arst
);
989 if (cell
->type
== "$adff") {
990 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
991 dump_sigspec(f
, sig_arst
);
993 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
994 dump_sigspec(f
, val_arst
);
996 f
<< stringf("%s" " else\n", indent
.c_str());
999 if (cell
->type
== "$dffe") {
1000 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1001 dump_sigspec(f
, sig_en
);
1002 f
<< stringf(")\n");
1005 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
1006 dump_cell_expr_port(f
, cell
, "D", false);
1007 f
<< stringf(";\n");
1009 if (!out_is_reg_wire
) {
1010 f
<< stringf("%s" "assign ", indent
.c_str());
1011 dump_sigspec(f
, cell
->getPort("\\Q"));
1012 f
<< stringf(" = %s;\n", reg_name
.c_str());
1018 if (cell
->type
== "$dlatch")
1020 RTLIL::SigSpec sig_en
;
1021 bool pol_en
= false;
1023 sig_en
= cell
->getPort("\\EN");
1024 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
1026 std::string reg_name
= cellname(cell
);
1027 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
1029 if (!out_is_reg_wire
) {
1030 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
1031 dump_reg_init(f
, cell
->getPort("\\Q"));
1035 f
<< stringf("%s" "always @*\n", indent
.c_str());
1037 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1038 dump_sigspec(f
, sig_en
);
1039 f
<< stringf(")\n");
1041 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
1042 dump_cell_expr_port(f
, cell
, "D", false);
1043 f
<< stringf(";\n");
1045 if (!out_is_reg_wire
) {
1046 f
<< stringf("%s" "assign ", indent
.c_str());
1047 dump_sigspec(f
, cell
->getPort("\\Q"));
1048 f
<< stringf(" = %s;\n", reg_name
.c_str());
1054 if (cell
->type
== "$mem")
1056 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
1057 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
1058 int abits
= cell
->parameters
["\\ABITS"].as_int();
1059 int size
= cell
->parameters
["\\SIZE"].as_int();
1060 int offset
= cell
->parameters
["\\OFFSET"].as_int();
1061 int width
= cell
->parameters
["\\WIDTH"].as_int();
1062 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
1064 // for memory block make something like:
1065 // reg [7:0] memid [3:0];
1069 dump_attributes(f
, indent
.c_str(), cell
->attributes
);
1070 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1075 std::string extmem_filename
= stringf("%s-%d.mem", extmem_prefix
.c_str(), extmem_counter
++);
1077 std::string extmem_filename_esc
;
1078 for (auto c
: extmem_filename
)
1081 extmem_filename_esc
+= "\\n";
1083 extmem_filename_esc
+= "\\t";
1085 extmem_filename_esc
+= stringf("\\%03o", c
);
1087 extmem_filename_esc
+= "\\\"";
1089 extmem_filename_esc
+= "\\\\";
1091 extmem_filename_esc
+= c
;
1093 f
<< stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent
.c_str(), extmem_filename_esc
.c_str(), mem_id
.c_str());
1095 std::ofstream
extmem_f(extmem_filename
, std::ofstream::trunc
);
1096 if (extmem_f
.fail())
1097 log_error("Can't open file `%s' for writing: %s\n", extmem_filename
.c_str(), strerror(errno
));
1100 for (int i
=0; i
<size
; i
++)
1102 RTLIL::Const element
= cell
->parameters
["\\INIT"].extract(i
*width
, width
);
1103 for (int j
=0; j
<element
.size(); j
++)
1105 switch (element
[element
.size()-j
-1])
1107 case State::S0
: extmem_f
<< '0'; break;
1108 case State::S1
: extmem_f
<< '1'; break;
1109 case State::Sx
: extmem_f
<< 'x'; break;
1110 case State::Sz
: extmem_f
<< 'z'; break;
1111 case State::Sa
: extmem_f
<< '_'; break;
1112 case State::Sm
: log_error("Found marker state in final netlist.");
1122 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1123 for (int i
=0; i
<size
; i
++)
1125 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1126 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1127 f
<< stringf(";\n");
1129 f
<< stringf("%s" "end\n", indent
.c_str());
1133 // create a map : "edge clk" -> expressions within that clock domain
1134 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1135 clk_to_lof_body
[""] = std::vector
<std::string
>();
1136 std::string clk_domain_str
;
1137 // create a list of reg declarations
1138 std::vector
<std::string
> lof_reg_declarations
;
1140 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1141 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1142 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1144 for (int i
=0; i
< nread_ports
; i
++)
1146 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1147 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1148 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1149 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1150 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1151 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1152 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1156 std::ostringstream os
;
1157 dump_sigspec(os
, sig_rd_clk
);
1158 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1159 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1160 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1162 if (!rd_transparent
)
1164 // for clocked read ports make something like:
1165 // reg [..] temp_id;
1166 // always @(posedge clk)
1167 // if (rd_en) temp_id <= array_reg[r_addr];
1168 // assign r_data = temp_id;
1169 std::string temp_id
= next_auto_id();
1170 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1172 std::ostringstream os
;
1173 if (sig_rd_en
!= RTLIL::SigBit(true))
1175 os
<< stringf("if (");
1176 dump_sigspec(os
, sig_rd_en
);
1177 os
<< stringf(") ");
1179 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1180 dump_sigspec(os
, sig_rd_addr
);
1181 os
<< stringf("];\n");
1182 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1185 std::ostringstream os
;
1186 dump_sigspec(os
, sig_rd_data
);
1187 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1188 clk_to_lof_body
[""].push_back(line
);
1193 // for rd-transparent read-ports make something like:
1194 // reg [..] temp_id;
1195 // always @(posedge clk)
1196 // temp_id <= r_addr;
1197 // assign r_data = array_reg[temp_id];
1198 std::string temp_id
= next_auto_id();
1199 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1201 std::ostringstream os
;
1202 dump_sigspec(os
, sig_rd_addr
);
1203 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1204 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1207 std::ostringstream os
;
1208 dump_sigspec(os
, sig_rd_data
);
1209 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1210 clk_to_lof_body
[""].push_back(line
);
1214 // for non-clocked read-ports make something like:
1215 // assign r_data = array_reg[r_addr];
1216 std::ostringstream os
, os2
;
1217 dump_sigspec(os
, sig_rd_data
);
1218 dump_sigspec(os2
, sig_rd_addr
);
1219 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1220 clk_to_lof_body
[""].push_back(line
);
1224 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1225 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1226 bool wr_clk_posedge
;
1229 for (int i
=0; i
< nwrite_ports
; i
++)
1231 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1232 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1233 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1234 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1235 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1237 std::ostringstream os
;
1238 dump_sigspec(os
, sig_wr_clk
);
1239 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1240 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1241 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1243 // make something like:
1244 // always @(posedge clk)
1245 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1247 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1249 int start_i
= i
, width
= 1;
1250 SigBit wen_bit
= sig_wr_en
[i
];
1252 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1255 if (wen_bit
== State::S0
)
1258 std::ostringstream os
;
1259 if (wen_bit
!= State::S1
)
1261 os
<< stringf("if (");
1262 dump_sigspec(os
, wen_bit
);
1263 os
<< stringf(") ");
1265 os
<< stringf("%s[", mem_id
.c_str());
1266 dump_sigspec(os
, sig_wr_addr
);
1267 if (width
== GetSize(sig_wr_en
))
1268 os
<< stringf("] <= ");
1270 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1271 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1272 os
<< stringf(";\n");
1273 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1276 // Output Verilog that looks something like this:
1278 // always @(posedge CLK2) begin
1279 // _3_ <= memory[D1ADDR];
1281 // memory[A1ADDR] <= A1DATA;
1283 // memory[A2ADDR] <= A2DATA;
1286 // always @(negedge CLK1) begin
1288 // memory[C1ADDR] <= C1DATA;
1291 // assign D1DATA = _3_;
1292 // assign D2DATA <= memory[D2ADDR];
1294 // the reg ... definitions
1295 for(auto ®
: lof_reg_declarations
)
1297 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1299 // the block of expressions by clock domain
1300 for(auto &pair
: clk_to_lof_body
)
1302 std::string clk_domain
= pair
.first
;
1303 std::vector
<std::string
> lof_lines
= pair
.second
;
1304 if( clk_domain
!= "")
1306 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1307 for(auto &line
: lof_lines
)
1308 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1309 f
<< stringf("%s" "end\n", indent
.c_str());
1313 // the non-clocked assignments
1314 for(auto &line
: lof_lines
)
1315 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1322 if (cell
->type
.in("$assert", "$assume", "$cover"))
1324 f
<< stringf("%s" "always @* if (", indent
.c_str());
1325 dump_sigspec(f
, cell
->getPort("\\EN"));
1326 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1327 dump_sigspec(f
, cell
->getPort("\\A"));
1328 f
<< stringf(");\n");
1332 if (cell
->type
.in("$specify2", "$specify3"))
1334 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1336 SigSpec en
= cell
->getPort("\\EN");
1337 if (en
!= State::S1
) {
1338 f
<< stringf("if (");
1339 dump_sigspec(f
, cell
->getPort("\\EN"));
1344 if (cell
->type
== "$specify3" && cell
->getParam("\\EDGE_EN").as_bool())
1345 f
<< (cell
->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1347 dump_sigspec(f
, cell
->getPort("\\SRC"));
1350 if (cell
->getParam("\\SRC_DST_PEN").as_bool())
1351 f
<< (cell
->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1352 f
<< (cell
->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1354 if (cell
->type
== "$specify3") {
1356 dump_sigspec(f
, cell
->getPort("\\DST"));
1358 if (cell
->getParam("\\DAT_DST_PEN").as_bool())
1359 f
<< (cell
->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1361 dump_sigspec(f
, cell
->getPort("\\DAT"));
1364 dump_sigspec(f
, cell
->getPort("\\DST"));
1367 bool bak_decimal
= decimal
;
1371 dump_const(f
, cell
->getParam("\\T_RISE_MIN"));
1373 dump_const(f
, cell
->getParam("\\T_RISE_TYP"));
1375 dump_const(f
, cell
->getParam("\\T_RISE_MAX"));
1377 dump_const(f
, cell
->getParam("\\T_FALL_MIN"));
1379 dump_const(f
, cell
->getParam("\\T_FALL_TYP"));
1381 dump_const(f
, cell
->getParam("\\T_FALL_MAX"));
1384 decimal
= bak_decimal
;
1386 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1390 if (cell
->type
== "$specrule")
1392 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1394 string spec_type
= cell
->getParam("\\TYPE").decode_string();
1395 f
<< stringf("%s(", spec_type
.c_str());
1397 if (cell
->getParam("\\SRC_PEN").as_bool())
1398 f
<< (cell
->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1399 dump_sigspec(f
, cell
->getPort("\\SRC"));
1401 if (cell
->getPort("\\SRC_EN") != State::S1
) {
1403 dump_sigspec(f
, cell
->getPort("\\SRC_EN"));
1407 if (cell
->getParam("\\DST_PEN").as_bool())
1408 f
<< (cell
->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1409 dump_sigspec(f
, cell
->getPort("\\DST"));
1411 if (cell
->getPort("\\DST_EN") != State::S1
) {
1413 dump_sigspec(f
, cell
->getPort("\\DST_EN"));
1416 bool bak_decimal
= decimal
;
1420 dump_const(f
, cell
->getParam("\\T_LIMIT"));
1422 if (spec_type
== "$setuphold" || spec_type
== "$recrem" || spec_type
== "$fullskew") {
1424 dump_const(f
, cell
->getParam("\\T_LIMIT2"));
1428 decimal
= bak_decimal
;
1430 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1434 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1435 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1440 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1442 if (cell
->type
[0] == '$' && !noexpr
) {
1443 if (dump_cell_expr(f
, indent
, cell
))
1447 dump_attributes(f
, indent
, cell
->attributes
);
1448 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1450 if (!defparam
&& cell
->parameters
.size() > 0) {
1451 f
<< stringf(" #(");
1452 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1453 if (it
!= cell
->parameters
.begin())
1455 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1456 dump_const(f
, it
->second
);
1459 f
<< stringf("\n%s" ")", indent
.c_str());
1462 std::string cell_name
= cellname(cell
);
1463 if (cell_name
!= id(cell
->name
))
1464 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1466 f
<< stringf(" %s (", cell_name
.c_str());
1468 bool first_arg
= true;
1469 std::set
<RTLIL::IdString
> numbered_ports
;
1470 for (int i
= 1; true; i
++) {
1472 snprintf(str
, 16, "$%d", i
);
1473 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1474 if (it
->first
!= str
)
1479 f
<< stringf("\n%s ", indent
.c_str());
1480 dump_sigspec(f
, it
->second
);
1481 numbered_ports
.insert(it
->first
);
1482 goto found_numbered_port
;
1485 found_numbered_port
:;
1487 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1488 if (numbered_ports
.count(it
->first
))
1493 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1494 if (it
->second
.size() > 0)
1495 dump_sigspec(f
, it
->second
);
1498 f
<< stringf("\n%s" ");\n", indent
.c_str());
1500 if (defparam
&& cell
->parameters
.size() > 0) {
1501 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1502 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1503 dump_const(f
, it
->second
);
1504 f
<< stringf(";\n");
1508 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q")) {
1509 std::stringstream ss
;
1510 dump_reg_init(ss
, cell
->getPort("\\Q"));
1511 if (!ss
.str().empty()) {
1512 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1519 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1521 f
<< stringf("%s" "assign ", indent
.c_str());
1522 dump_sigspec(f
, left
);
1523 f
<< stringf(" = ");
1524 dump_sigspec(f
, right
);
1525 f
<< stringf(";\n");
1528 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1530 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1532 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1534 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1535 f
<< stringf("%s" "begin\n", indent
.c_str());
1537 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1538 if (it
->first
.size() == 0)
1540 f
<< stringf("%s ", indent
.c_str());
1541 dump_sigspec(f
, it
->first
);
1542 f
<< stringf(" = ");
1543 dump_sigspec(f
, it
->second
);
1544 f
<< stringf(";\n");
1547 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1548 dump_proc_switch(f
, indent
+ " ", *it
);
1550 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1551 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1553 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1554 f
<< stringf("%s" "end\n", indent
.c_str());
1557 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1559 if (sw
->signal
.size() == 0) {
1560 f
<< stringf("%s" "begin\n", indent
.c_str());
1561 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1562 if ((*it
)->compare
.size() == 0)
1563 dump_case_body(f
, indent
+ " ", *it
);
1565 f
<< stringf("%s" "end\n", indent
.c_str());
1569 dump_attributes(f
, indent
, sw
->attributes
);
1570 f
<< stringf("%s" "casez (", indent
.c_str());
1571 dump_sigspec(f
, sw
->signal
);
1572 f
<< stringf(")\n");
1574 bool got_default
= false;
1575 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1576 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1577 if ((*it
)->compare
.size() == 0) {
1580 f
<< stringf("%s default", indent
.c_str());
1583 f
<< stringf("%s ", indent
.c_str());
1584 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1587 dump_sigspec(f
, (*it
)->compare
[i
]);
1590 f
<< stringf(":\n");
1591 dump_case_body(f
, indent
+ " ", *it
);
1594 f
<< stringf("%s" "endcase\n", indent
.c_str());
1597 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1599 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1600 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1601 case_body_find_regs(*it2
);
1603 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1604 for (auto &c
: it
->first
.chunks())
1606 reg_wires
.insert(c
.wire
->name
);
1610 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1613 case_body_find_regs(&proc
->root_case
);
1614 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1615 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1616 for (auto &c
: it2
->first
.chunks())
1618 reg_wires
.insert(c
.wire
->name
);
1623 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1624 dump_case_body(f
, indent
, &proc
->root_case
, true);
1626 std::string backup_indent
= indent
;
1628 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1630 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1631 indent
= backup_indent
;
1633 if (sync
->type
== RTLIL::STa
) {
1634 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1635 } else if (sync
->type
== RTLIL::STi
) {
1636 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1638 f
<< stringf("%s" "always @(", indent
.c_str());
1639 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1640 f
<< stringf("posedge ");
1641 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1642 f
<< stringf("negedge ");
1643 dump_sigspec(f
, sync
->signal
);
1644 f
<< stringf(") begin\n");
1646 std::string ends
= indent
+ "end\n";
1649 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1650 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1651 dump_sigspec(f
, sync
->signal
);
1652 f
<< stringf(") begin\n");
1653 ends
= indent
+ "end\n" + ends
;
1657 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1658 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1659 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1660 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1661 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1662 dump_sigspec(f
, sync2
->signal
);
1663 f
<< stringf(") begin\n");
1664 ends
= indent
+ "end\n" + ends
;
1670 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1671 if (it
->first
.size() == 0)
1673 f
<< stringf("%s ", indent
.c_str());
1674 dump_sigspec(f
, it
->first
);
1675 f
<< stringf(" <= ");
1676 dump_sigspec(f
, it
->second
);
1677 f
<< stringf(";\n");
1680 f
<< stringf("%s", ends
.c_str());
1684 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1687 reset_auto_counter(module
);
1688 active_module
= module
;
1689 active_sigmap
.set(module
);
1690 active_initdata
.clear();
1692 for (auto wire
: module
->wires())
1693 if (wire
->attributes
.count("\\init")) {
1694 SigSpec sig
= active_sigmap(wire
);
1695 Const val
= wire
->attributes
.at("\\init");
1696 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1697 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1698 active_initdata
[sig
[i
]] = val
[i
];
1701 if (!module
->processes
.empty())
1702 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1703 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1704 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1705 "processes to logic networks and registers.\n", log_id(module
));
1708 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1709 dump_process(f
, indent
+ " ", it
->second
, true);
1713 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1714 for (auto &it
: module
->cells_
)
1716 RTLIL::Cell
*cell
= it
.second
;
1717 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1720 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1722 if (sig
.is_chunk()) {
1723 RTLIL::SigChunk chunk
= sig
.as_chunk();
1724 if (chunk
.wire
!= NULL
)
1725 for (int i
= 0; i
< chunk
.width
; i
++)
1726 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1729 for (auto &it
: module
->wires_
)
1731 RTLIL::Wire
*wire
= it
.second
;
1732 for (int i
= 0; i
< wire
->width
; i
++)
1733 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1734 goto this_wire_aint_reg
;
1736 reg_wires
.insert(wire
->name
);
1737 this_wire_aint_reg
:;
1741 dump_attributes(f
, indent
, module
->attributes
, '\n', /*modattr=*/true);
1742 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1743 bool keep_running
= true;
1744 for (int port_id
= 1; keep_running
; port_id
++) {
1745 keep_running
= false;
1746 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1747 RTLIL::Wire
*wire
= it
->second
;
1748 if (wire
->port_id
== port_id
) {
1751 f
<< stringf("%s", id(wire
->name
).c_str());
1752 keep_running
= true;
1757 f
<< stringf(");\n");
1759 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1760 dump_wire(f
, indent
+ " ", it
->second
);
1762 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1763 dump_memory(f
, indent
+ " ", it
->second
);
1765 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1766 dump_cell(f
, indent
+ " ", it
->second
);
1768 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1769 dump_process(f
, indent
+ " ", it
->second
);
1771 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1772 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1774 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1775 active_module
= NULL
;
1776 active_sigmap
.clear();
1777 active_initdata
.clear();
1780 struct VerilogBackend
: public Backend
{
1781 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1782 void help() YS_OVERRIDE
1784 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1786 log(" write_verilog [options] [filename]\n");
1788 log("Write the current design to a Verilog file.\n");
1790 log(" -norename\n");
1791 log(" without this option all internal object names (the ones with a dollar\n");
1792 log(" instead of a backslash prefix) are changed to short names in the\n");
1793 log(" format '_<number>_'.\n");
1795 log(" -renameprefix <prefix>\n");
1796 log(" insert this prefix in front of auto-generated instance names\n");
1799 log(" with this option no attributes are included in the output\n");
1801 log(" -attr2comment\n");
1802 log(" with this option attributes are included as comments in the output\n");
1805 log(" without this option all internal cells are converted to Verilog\n");
1806 log(" expressions.\n");
1809 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1810 log(" in -noexpr mode.\n");
1813 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1814 log(" not bit pattern. This option deactivates this feature and instead\n");
1815 log(" will write out all constants in binary.\n");
1818 log(" dump 32-bit constants in decimal and without size and radix\n");
1821 log(" constant values that are compatible with hex output are usually\n");
1822 log(" dumped as hex values. This option deactivates this feature and\n");
1823 log(" instead will write out all constants in binary.\n");
1826 log(" Parameters and attributes that are specified as strings in the\n");
1827 log(" original input will be output as strings by this back-end. This\n");
1828 log(" deactivates this feature and instead will write string constants\n");
1829 log(" as binary numbers.\n");
1832 log(" instead of initializing memories using assignments to individual\n");
1833 log(" elements, use the '$readmemh' function to read initialization data\n");
1834 log(" from a file. This data is written to a file named by appending\n");
1835 log(" a sequential index to the Verilog filename and replacing the extension\n");
1836 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
1837 log(" 'foo-2.mem' and so on.\n");
1839 log(" -defparam\n");
1840 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1841 log(" cell parameters.\n");
1843 log(" -blackboxes\n");
1844 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1845 log(" this option set only the modules with the 'blackbox' attribute\n");
1846 log(" are written to the output file.\n");
1848 log(" -selected\n");
1849 log(" only write selected modules. modules must be selected entirely or\n");
1850 log(" not at all.\n");
1853 log(" verbose output (print new names of all renamed wires and cells)\n");
1855 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1856 log("always blocks. This frontend should only be used to export an RTLIL\n");
1857 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1858 log("processes to logic networks and registers. A warning is generated when\n");
1859 log("this command is called on a design with RTLIL processes.\n");
1862 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1864 log_header(design
, "Executing Verilog backend.\n");
1869 attr2comment
= false;
1880 bool blackboxes
= false;
1881 bool selected
= false;
1883 auto_name_map
.clear();
1887 reg_ct
.insert("$dff");
1888 reg_ct
.insert("$adff");
1889 reg_ct
.insert("$dffe");
1890 reg_ct
.insert("$dlatch");
1892 reg_ct
.insert("$_DFF_N_");
1893 reg_ct
.insert("$_DFF_P_");
1895 reg_ct
.insert("$_DFF_NN0_");
1896 reg_ct
.insert("$_DFF_NN1_");
1897 reg_ct
.insert("$_DFF_NP0_");
1898 reg_ct
.insert("$_DFF_NP1_");
1899 reg_ct
.insert("$_DFF_PN0_");
1900 reg_ct
.insert("$_DFF_PN1_");
1901 reg_ct
.insert("$_DFF_PP0_");
1902 reg_ct
.insert("$_DFF_PP1_");
1904 reg_ct
.insert("$_DFFSR_NNN_");
1905 reg_ct
.insert("$_DFFSR_NNP_");
1906 reg_ct
.insert("$_DFFSR_NPN_");
1907 reg_ct
.insert("$_DFFSR_NPP_");
1908 reg_ct
.insert("$_DFFSR_PNN_");
1909 reg_ct
.insert("$_DFFSR_PNP_");
1910 reg_ct
.insert("$_DFFSR_PPN_");
1911 reg_ct
.insert("$_DFFSR_PPP_");
1914 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1915 std::string arg
= args
[argidx
];
1916 if (arg
== "-norename") {
1920 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1921 auto_prefix
= args
[++argidx
];
1924 if (arg
== "-noattr") {
1928 if (arg
== "-attr2comment") {
1929 attr2comment
= true;
1932 if (arg
== "-noexpr") {
1936 if (arg
== "-nodec") {
1940 if (arg
== "-nohex") {
1944 if (arg
== "-nostr") {
1948 if (arg
== "-extmem") {
1953 if (arg
== "-defparam") {
1957 if (arg
== "-decimal") {
1961 if (arg
== "-siminit") {
1965 if (arg
== "-blackboxes") {
1969 if (arg
== "-selected") {
1979 extra_args(f
, filename
, args
, argidx
);
1982 if (filename
.empty())
1983 log_cmd_error("Option -extmem must be used with a filename.\n");
1984 extmem_prefix
= filename
.substr(0, filename
.rfind('.'));
1989 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1990 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1991 if (it
->second
->get_blackbox_attribute() != blackboxes
)
1993 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1994 if (design
->selected_module(it
->first
))
1995 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1998 log("Dumping module `%s'.\n", it
->first
.c_str());
1999 dump_module(*f
, "", it
->second
);
2002 auto_name_map
.clear();
2008 PRIVATE_NAMESPACE_END