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 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1074 std::string extmem_filename
= stringf("%s-%d.mem", extmem_prefix
.c_str(), extmem_counter
++);
1076 std::string extmem_filename_esc
;
1077 for (auto c
: extmem_filename
)
1080 extmem_filename_esc
+= "\\n";
1082 extmem_filename_esc
+= "\\t";
1084 extmem_filename_esc
+= stringf("\\%03o", c
);
1086 extmem_filename_esc
+= "\\\"";
1088 extmem_filename_esc
+= "\\\\";
1090 extmem_filename_esc
+= c
;
1092 f
<< stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent
.c_str(), extmem_filename_esc
.c_str(), mem_id
.c_str());
1094 std::ofstream
extmem_f(extmem_filename
, std::ofstream::trunc
);
1095 if (extmem_f
.fail())
1096 log_error("Can't open file `%s' for writing: %s\n", extmem_filename
.c_str(), strerror(errno
));
1099 for (int i
=0; i
<size
; i
++)
1101 RTLIL::Const element
= cell
->parameters
["\\INIT"].extract(i
*width
, width
);
1102 for (int j
=0; j
<element
.size(); j
++)
1104 switch (element
[element
.size()-j
-1])
1106 case State::S0
: extmem_f
<< '0'; break;
1107 case State::S1
: extmem_f
<< '1'; break;
1108 case State::Sx
: extmem_f
<< 'x'; break;
1109 case State::Sz
: extmem_f
<< 'z'; break;
1110 case State::Sa
: extmem_f
<< '_'; break;
1111 case State::Sm
: log_error("Found marker state in final netlist.");
1121 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1122 for (int i
=0; i
<size
; i
++)
1124 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1125 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1126 f
<< stringf(";\n");
1128 f
<< stringf("%s" "end\n", indent
.c_str());
1132 // create a map : "edge clk" -> expressions within that clock domain
1133 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1134 clk_to_lof_body
[""] = std::vector
<std::string
>();
1135 std::string clk_domain_str
;
1136 // create a list of reg declarations
1137 std::vector
<std::string
> lof_reg_declarations
;
1139 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1140 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1141 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1143 for (int i
=0; i
< nread_ports
; i
++)
1145 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1146 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1147 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1148 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1149 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1150 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1151 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1155 std::ostringstream os
;
1156 dump_sigspec(os
, sig_rd_clk
);
1157 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1158 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1159 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1161 if (!rd_transparent
)
1163 // for clocked read ports make something like:
1164 // reg [..] temp_id;
1165 // always @(posedge clk)
1166 // if (rd_en) temp_id <= array_reg[r_addr];
1167 // assign r_data = temp_id;
1168 std::string temp_id
= next_auto_id();
1169 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1171 std::ostringstream os
;
1172 if (sig_rd_en
!= RTLIL::SigBit(true))
1174 os
<< stringf("if (");
1175 dump_sigspec(os
, sig_rd_en
);
1176 os
<< stringf(") ");
1178 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1179 dump_sigspec(os
, sig_rd_addr
);
1180 os
<< stringf("];\n");
1181 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1184 std::ostringstream os
;
1185 dump_sigspec(os
, sig_rd_data
);
1186 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1187 clk_to_lof_body
[""].push_back(line
);
1192 // for rd-transparent read-ports make something like:
1193 // reg [..] temp_id;
1194 // always @(posedge clk)
1195 // temp_id <= r_addr;
1196 // assign r_data = array_reg[temp_id];
1197 std::string temp_id
= next_auto_id();
1198 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1200 std::ostringstream os
;
1201 dump_sigspec(os
, sig_rd_addr
);
1202 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1203 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1206 std::ostringstream os
;
1207 dump_sigspec(os
, sig_rd_data
);
1208 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1209 clk_to_lof_body
[""].push_back(line
);
1213 // for non-clocked read-ports make something like:
1214 // assign r_data = array_reg[r_addr];
1215 std::ostringstream os
, os2
;
1216 dump_sigspec(os
, sig_rd_data
);
1217 dump_sigspec(os2
, sig_rd_addr
);
1218 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1219 clk_to_lof_body
[""].push_back(line
);
1223 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1224 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1225 bool wr_clk_posedge
;
1228 for (int i
=0; i
< nwrite_ports
; i
++)
1230 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1231 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1232 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1233 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1234 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1236 std::ostringstream os
;
1237 dump_sigspec(os
, sig_wr_clk
);
1238 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1239 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1240 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1242 // make something like:
1243 // always @(posedge clk)
1244 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1246 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1248 int start_i
= i
, width
= 1;
1249 SigBit wen_bit
= sig_wr_en
[i
];
1251 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1254 if (wen_bit
== State::S0
)
1257 std::ostringstream os
;
1258 if (wen_bit
!= State::S1
)
1260 os
<< stringf("if (");
1261 dump_sigspec(os
, wen_bit
);
1262 os
<< stringf(") ");
1264 os
<< stringf("%s[", mem_id
.c_str());
1265 dump_sigspec(os
, sig_wr_addr
);
1266 if (width
== GetSize(sig_wr_en
))
1267 os
<< stringf("] <= ");
1269 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1270 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1271 os
<< stringf(";\n");
1272 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1275 // Output Verilog that looks something like this:
1277 // always @(posedge CLK2) begin
1278 // _3_ <= memory[D1ADDR];
1280 // memory[A1ADDR] <= A1DATA;
1282 // memory[A2ADDR] <= A2DATA;
1285 // always @(negedge CLK1) begin
1287 // memory[C1ADDR] <= C1DATA;
1290 // assign D1DATA = _3_;
1291 // assign D2DATA <= memory[D2ADDR];
1293 // the reg ... definitions
1294 for(auto ®
: lof_reg_declarations
)
1296 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1298 // the block of expressions by clock domain
1299 for(auto &pair
: clk_to_lof_body
)
1301 std::string clk_domain
= pair
.first
;
1302 std::vector
<std::string
> lof_lines
= pair
.second
;
1303 if( clk_domain
!= "")
1305 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1306 for(auto &line
: lof_lines
)
1307 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1308 f
<< stringf("%s" "end\n", indent
.c_str());
1312 // the non-clocked assignments
1313 for(auto &line
: lof_lines
)
1314 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1321 if (cell
->type
.in("$assert", "$assume", "$cover"))
1323 f
<< stringf("%s" "always @* if (", indent
.c_str());
1324 dump_sigspec(f
, cell
->getPort("\\EN"));
1325 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1326 dump_sigspec(f
, cell
->getPort("\\A"));
1327 f
<< stringf(");\n");
1331 if (cell
->type
.in("$specify2", "$specify3"))
1333 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1335 SigSpec en
= cell
->getPort("\\EN");
1336 if (en
!= State::S1
) {
1337 f
<< stringf("if (");
1338 dump_sigspec(f
, cell
->getPort("\\EN"));
1343 if (cell
->type
== "$specify3" && cell
->getParam("\\EDGE_EN").as_bool())
1344 f
<< (cell
->getParam("\\EDGE_POL").as_bool() ? "posedge ": "negedge ");
1346 dump_sigspec(f
, cell
->getPort("\\SRC"));
1349 if (cell
->getParam("\\SRC_DST_PEN").as_bool())
1350 f
<< (cell
->getParam("\\SRC_DST_POL").as_bool() ? "+": "-");
1351 f
<< (cell
->getParam("\\FULL").as_bool() ? "*> ": "=> ");
1353 if (cell
->type
== "$specify3") {
1355 dump_sigspec(f
, cell
->getPort("\\DST"));
1357 if (cell
->getParam("\\DAT_DST_PEN").as_bool())
1358 f
<< (cell
->getParam("\\DAT_DST_POL").as_bool() ? "+": "-");
1360 dump_sigspec(f
, cell
->getPort("\\DAT"));
1363 dump_sigspec(f
, cell
->getPort("\\DST"));
1366 bool bak_decimal
= decimal
;
1370 dump_const(f
, cell
->getParam("\\T_RISE_MIN"));
1372 dump_const(f
, cell
->getParam("\\T_RISE_TYP"));
1374 dump_const(f
, cell
->getParam("\\T_RISE_MAX"));
1376 dump_const(f
, cell
->getParam("\\T_FALL_MIN"));
1378 dump_const(f
, cell
->getParam("\\T_FALL_TYP"));
1380 dump_const(f
, cell
->getParam("\\T_FALL_MAX"));
1383 decimal
= bak_decimal
;
1385 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1389 if (cell
->type
== "$specrule")
1391 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1393 string spec_type
= cell
->getParam("\\TYPE").decode_string();
1394 f
<< stringf("%s(", spec_type
.c_str());
1396 if (cell
->getParam("\\SRC_PEN").as_bool())
1397 f
<< (cell
->getParam("\\SRC_POL").as_bool() ? "posedge ": "negedge ");
1398 dump_sigspec(f
, cell
->getPort("\\SRC"));
1400 if (cell
->getPort("\\SRC_EN") != State::S1
) {
1402 dump_sigspec(f
, cell
->getPort("\\SRC_EN"));
1406 if (cell
->getParam("\\DST_PEN").as_bool())
1407 f
<< (cell
->getParam("\\DST_POL").as_bool() ? "posedge ": "negedge ");
1408 dump_sigspec(f
, cell
->getPort("\\DST"));
1410 if (cell
->getPort("\\DST_EN") != State::S1
) {
1412 dump_sigspec(f
, cell
->getPort("\\DST_EN"));
1415 bool bak_decimal
= decimal
;
1419 dump_const(f
, cell
->getParam("\\T_LIMIT"));
1421 if (spec_type
== "$setuphold" || spec_type
== "$recrem" || spec_type
== "$fullskew") {
1423 dump_const(f
, cell
->getParam("\\T_LIMIT2"));
1427 decimal
= bak_decimal
;
1429 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1433 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1434 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1439 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1441 if (cell
->type
[0] == '$' && !noexpr
) {
1442 if (dump_cell_expr(f
, indent
, cell
))
1446 dump_attributes(f
, indent
, cell
->attributes
);
1447 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1449 if (!defparam
&& cell
->parameters
.size() > 0) {
1450 f
<< stringf(" #(");
1451 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1452 if (it
!= cell
->parameters
.begin())
1454 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1455 dump_const(f
, it
->second
);
1458 f
<< stringf("\n%s" ")", indent
.c_str());
1461 std::string cell_name
= cellname(cell
);
1462 if (cell_name
!= id(cell
->name
))
1463 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1465 f
<< stringf(" %s (", cell_name
.c_str());
1467 bool first_arg
= true;
1468 std::set
<RTLIL::IdString
> numbered_ports
;
1469 for (int i
= 1; true; i
++) {
1471 snprintf(str
, 16, "$%d", i
);
1472 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1473 if (it
->first
!= str
)
1478 f
<< stringf("\n%s ", indent
.c_str());
1479 dump_sigspec(f
, it
->second
);
1480 numbered_ports
.insert(it
->first
);
1481 goto found_numbered_port
;
1484 found_numbered_port
:;
1486 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1487 if (numbered_ports
.count(it
->first
))
1492 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1493 if (it
->second
.size() > 0)
1494 dump_sigspec(f
, it
->second
);
1497 f
<< stringf("\n%s" ");\n", indent
.c_str());
1499 if (defparam
&& cell
->parameters
.size() > 0) {
1500 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1501 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1502 dump_const(f
, it
->second
);
1503 f
<< stringf(";\n");
1507 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q")) {
1508 std::stringstream ss
;
1509 dump_reg_init(ss
, cell
->getPort("\\Q"));
1510 if (!ss
.str().empty()) {
1511 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1518 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1520 f
<< stringf("%s" "assign ", indent
.c_str());
1521 dump_sigspec(f
, left
);
1522 f
<< stringf(" = ");
1523 dump_sigspec(f
, right
);
1524 f
<< stringf(";\n");
1527 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1529 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1531 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1533 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1534 f
<< stringf("%s" "begin\n", indent
.c_str());
1536 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1537 if (it
->first
.size() == 0)
1539 f
<< stringf("%s ", indent
.c_str());
1540 dump_sigspec(f
, it
->first
);
1541 f
<< stringf(" = ");
1542 dump_sigspec(f
, it
->second
);
1543 f
<< stringf(";\n");
1546 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1547 dump_proc_switch(f
, indent
+ " ", *it
);
1549 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1550 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1552 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1553 f
<< stringf("%s" "end\n", indent
.c_str());
1556 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1558 if (sw
->signal
.size() == 0) {
1559 f
<< stringf("%s" "begin\n", indent
.c_str());
1560 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1561 if ((*it
)->compare
.size() == 0)
1562 dump_case_body(f
, indent
+ " ", *it
);
1564 f
<< stringf("%s" "end\n", indent
.c_str());
1568 dump_attributes(f
, indent
, sw
->attributes
);
1569 f
<< stringf("%s" "casez (", indent
.c_str());
1570 dump_sigspec(f
, sw
->signal
);
1571 f
<< stringf(")\n");
1573 bool got_default
= false;
1574 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1575 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1576 if ((*it
)->compare
.size() == 0) {
1579 f
<< stringf("%s default", indent
.c_str());
1582 f
<< stringf("%s ", indent
.c_str());
1583 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1586 dump_sigspec(f
, (*it
)->compare
[i
]);
1589 f
<< stringf(":\n");
1590 dump_case_body(f
, indent
+ " ", *it
);
1593 f
<< stringf("%s" "endcase\n", indent
.c_str());
1596 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1598 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1599 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1600 case_body_find_regs(*it2
);
1602 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1603 for (auto &c
: it
->first
.chunks())
1605 reg_wires
.insert(c
.wire
->name
);
1609 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1612 case_body_find_regs(&proc
->root_case
);
1613 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1614 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1615 for (auto &c
: it2
->first
.chunks())
1617 reg_wires
.insert(c
.wire
->name
);
1622 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1623 dump_case_body(f
, indent
, &proc
->root_case
, true);
1625 std::string backup_indent
= indent
;
1627 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1629 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1630 indent
= backup_indent
;
1632 if (sync
->type
== RTLIL::STa
) {
1633 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1634 } else if (sync
->type
== RTLIL::STi
) {
1635 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1637 f
<< stringf("%s" "always @(", indent
.c_str());
1638 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1639 f
<< stringf("posedge ");
1640 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1641 f
<< stringf("negedge ");
1642 dump_sigspec(f
, sync
->signal
);
1643 f
<< stringf(") begin\n");
1645 std::string ends
= indent
+ "end\n";
1648 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1649 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1650 dump_sigspec(f
, sync
->signal
);
1651 f
<< stringf(") begin\n");
1652 ends
= indent
+ "end\n" + ends
;
1656 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1657 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1658 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1659 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1660 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1661 dump_sigspec(f
, sync2
->signal
);
1662 f
<< stringf(") begin\n");
1663 ends
= indent
+ "end\n" + ends
;
1669 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1670 if (it
->first
.size() == 0)
1672 f
<< stringf("%s ", indent
.c_str());
1673 dump_sigspec(f
, it
->first
);
1674 f
<< stringf(" <= ");
1675 dump_sigspec(f
, it
->second
);
1676 f
<< stringf(";\n");
1679 f
<< stringf("%s", ends
.c_str());
1683 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1686 reset_auto_counter(module
);
1687 active_module
= module
;
1688 active_sigmap
.set(module
);
1689 active_initdata
.clear();
1691 for (auto wire
: module
->wires())
1692 if (wire
->attributes
.count("\\init")) {
1693 SigSpec sig
= active_sigmap(wire
);
1694 Const val
= wire
->attributes
.at("\\init");
1695 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1696 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1697 active_initdata
[sig
[i
]] = val
[i
];
1700 if (!module
->processes
.empty())
1701 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1702 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1703 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1704 "processes to logic networks and registers.\n", log_id(module
));
1707 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1708 dump_process(f
, indent
+ " ", it
->second
, true);
1712 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1713 for (auto &it
: module
->cells_
)
1715 RTLIL::Cell
*cell
= it
.second
;
1716 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1719 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1721 if (sig
.is_chunk()) {
1722 RTLIL::SigChunk chunk
= sig
.as_chunk();
1723 if (chunk
.wire
!= NULL
)
1724 for (int i
= 0; i
< chunk
.width
; i
++)
1725 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1728 for (auto &it
: module
->wires_
)
1730 RTLIL::Wire
*wire
= it
.second
;
1731 for (int i
= 0; i
< wire
->width
; i
++)
1732 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1733 goto this_wire_aint_reg
;
1735 reg_wires
.insert(wire
->name
);
1736 this_wire_aint_reg
:;
1740 dump_attributes(f
, indent
, module
->attributes
, '\n', /*modattr=*/true);
1741 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1742 bool keep_running
= true;
1743 for (int port_id
= 1; keep_running
; port_id
++) {
1744 keep_running
= false;
1745 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1746 RTLIL::Wire
*wire
= it
->second
;
1747 if (wire
->port_id
== port_id
) {
1750 f
<< stringf("%s", id(wire
->name
).c_str());
1751 keep_running
= true;
1756 f
<< stringf(");\n");
1758 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1759 dump_wire(f
, indent
+ " ", it
->second
);
1761 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1762 dump_memory(f
, indent
+ " ", it
->second
);
1764 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1765 dump_cell(f
, indent
+ " ", it
->second
);
1767 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1768 dump_process(f
, indent
+ " ", it
->second
);
1770 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1771 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1773 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1774 active_module
= NULL
;
1775 active_sigmap
.clear();
1776 active_initdata
.clear();
1779 struct VerilogBackend
: public Backend
{
1780 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1781 void help() YS_OVERRIDE
1783 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1785 log(" write_verilog [options] [filename]\n");
1787 log("Write the current design to a Verilog file.\n");
1789 log(" -norename\n");
1790 log(" without this option all internal object names (the ones with a dollar\n");
1791 log(" instead of a backslash prefix) are changed to short names in the\n");
1792 log(" format '_<number>_'.\n");
1794 log(" -renameprefix <prefix>\n");
1795 log(" insert this prefix in front of auto-generated instance names\n");
1798 log(" with this option no attributes are included in the output\n");
1800 log(" -attr2comment\n");
1801 log(" with this option attributes are included as comments in the output\n");
1804 log(" without this option all internal cells are converted to Verilog\n");
1805 log(" expressions.\n");
1808 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1809 log(" in -noexpr mode.\n");
1812 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1813 log(" not bit pattern. This option deactivates this feature and instead\n");
1814 log(" will write out all constants in binary.\n");
1817 log(" dump 32-bit constants in decimal and without size and radix\n");
1820 log(" constant values that are compatible with hex output are usually\n");
1821 log(" dumped as hex values. This option deactivates this feature and\n");
1822 log(" instead will write out all constants in binary.\n");
1825 log(" Parameters and attributes that are specified as strings in the\n");
1826 log(" original input will be output as strings by this back-end. This\n");
1827 log(" deactivates this feature and instead will write string constants\n");
1828 log(" as binary numbers.\n");
1831 log(" instead of initializing memories using assignments to individual\n");
1832 log(" elements, use the '$readmemh' function to read initialization data\n");
1833 log(" from a file. This data is written to a file named by appending\n");
1834 log(" a sequential index to the Verilog filename and replacing the extension\n");
1835 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
1836 log(" 'foo-2.mem' and so on.\n");
1838 log(" -defparam\n");
1839 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1840 log(" cell parameters.\n");
1842 log(" -blackboxes\n");
1843 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1844 log(" this option set only the modules with the 'blackbox' attribute\n");
1845 log(" are written to the output file.\n");
1847 log(" -selected\n");
1848 log(" only write selected modules. modules must be selected entirely or\n");
1849 log(" not at all.\n");
1852 log(" verbose output (print new names of all renamed wires and cells)\n");
1854 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1855 log("always blocks. This frontend should only be used to export an RTLIL\n");
1856 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1857 log("processes to logic networks and registers. A warning is generated when\n");
1858 log("this command is called on a design with RTLIL processes.\n");
1861 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1863 log_header(design
, "Executing Verilog backend.\n");
1868 attr2comment
= false;
1879 bool blackboxes
= false;
1880 bool selected
= false;
1882 auto_name_map
.clear();
1886 reg_ct
.insert("$dff");
1887 reg_ct
.insert("$adff");
1888 reg_ct
.insert("$dffe");
1889 reg_ct
.insert("$dlatch");
1891 reg_ct
.insert("$_DFF_N_");
1892 reg_ct
.insert("$_DFF_P_");
1894 reg_ct
.insert("$_DFF_NN0_");
1895 reg_ct
.insert("$_DFF_NN1_");
1896 reg_ct
.insert("$_DFF_NP0_");
1897 reg_ct
.insert("$_DFF_NP1_");
1898 reg_ct
.insert("$_DFF_PN0_");
1899 reg_ct
.insert("$_DFF_PN1_");
1900 reg_ct
.insert("$_DFF_PP0_");
1901 reg_ct
.insert("$_DFF_PP1_");
1903 reg_ct
.insert("$_DFFSR_NNN_");
1904 reg_ct
.insert("$_DFFSR_NNP_");
1905 reg_ct
.insert("$_DFFSR_NPN_");
1906 reg_ct
.insert("$_DFFSR_NPP_");
1907 reg_ct
.insert("$_DFFSR_PNN_");
1908 reg_ct
.insert("$_DFFSR_PNP_");
1909 reg_ct
.insert("$_DFFSR_PPN_");
1910 reg_ct
.insert("$_DFFSR_PPP_");
1913 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1914 std::string arg
= args
[argidx
];
1915 if (arg
== "-norename") {
1919 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1920 auto_prefix
= args
[++argidx
];
1923 if (arg
== "-noattr") {
1927 if (arg
== "-attr2comment") {
1928 attr2comment
= true;
1931 if (arg
== "-noexpr") {
1935 if (arg
== "-nodec") {
1939 if (arg
== "-nohex") {
1943 if (arg
== "-nostr") {
1947 if (arg
== "-extmem") {
1952 if (arg
== "-defparam") {
1956 if (arg
== "-decimal") {
1960 if (arg
== "-siminit") {
1964 if (arg
== "-blackboxes") {
1968 if (arg
== "-selected") {
1978 extra_args(f
, filename
, args
, argidx
);
1981 if (filename
.empty())
1982 log_cmd_error("Option -extmem must be used with a filename.\n");
1983 extmem_prefix
= filename
.substr(0, filename
.rfind('.'));
1988 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1989 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1990 if (it
->second
->get_blackbox_attribute() != blackboxes
)
1992 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1993 if (design
->selected_module(it
->first
))
1994 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1997 log("Dumping module `%s'.\n", it
->first
.c_str());
1998 dump_module(*f
, "", it
->second
);
2001 auto_name_map
.clear();
2007 PRIVATE_NAMESPACE_END