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
, systemverilog
;
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 w
: module
->wires())
77 reset_auto_counter_id(w
->name
, true);
79 for (auto cell
: module
->cells()) {
80 reset_auto_counter_id(cell
->name
, true);
81 reset_auto_counter_id(cell
->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
== ID::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(ID::init
)) {
428 dump_const(f
, wire
->attributes
.at(ID::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(ID::Q
))
456 RTLIL::SigSpec sig
= cell
->getPort(ID::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(ID::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(ID::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
== ID($_NOT_
)) {
513 f
<< stringf("%s" "assign ", indent
.c_str());
514 dump_sigspec(f
, cell
->getPort(ID::Y
));
517 dump_attributes(f
, "", cell
->attributes
, ' ');
518 dump_cell_expr_port(f
, cell
, "A", false);
523 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_OR_
), ID($_NOR_
), ID($_XOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
))) {
524 f
<< stringf("%s" "assign ", indent
.c_str());
525 dump_sigspec(f
, cell
->getPort(ID::Y
));
527 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
)))
529 dump_cell_expr_port(f
, cell
, "A", false);
531 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_ANDNOT_
)))
533 if (cell
->type
.in(ID($_OR_
), ID($_NOR_
), ID($_ORNOT_
)))
535 if (cell
->type
.in(ID($_XOR_
), ID($_XNOR_
)))
537 dump_attributes(f
, "", cell
->attributes
, ' ');
539 if (cell
->type
.in(ID($_ANDNOT_
), ID($_ORNOT_
)))
541 dump_cell_expr_port(f
, cell
, "B", false);
542 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
)))
548 if (cell
->type
== ID($_MUX_
)) {
549 f
<< stringf("%s" "assign ", indent
.c_str());
550 dump_sigspec(f
, cell
->getPort(ID::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
== ID($_NMUX_
)) {
563 f
<< stringf("%s" "assign ", indent
.c_str());
564 dump_sigspec(f
, cell
->getPort(ID::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(ID($_AOI3_
), ID($_OAI3_
))) {
577 f
<< stringf("%s" "assign ", indent
.c_str());
578 dump_sigspec(f
, cell
->getPort(ID::Y
));
579 f
<< stringf(" = ~((");
580 dump_cell_expr_port(f
, cell
, "A", false);
581 f
<< stringf(cell
->type
== ID($_AOI3_
) ? " & " : " | ");
582 dump_cell_expr_port(f
, cell
, "B", false);
583 f
<< stringf(cell
->type
== ID($_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(ID($_AOI4_
), ID($_OAI4_
))) {
592 f
<< stringf("%s" "assign ", indent
.c_str());
593 dump_sigspec(f
, cell
->getPort(ID::Y
));
594 f
<< stringf(" = ~((");
595 dump_cell_expr_port(f
, cell
, "A", false);
596 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
597 dump_cell_expr_port(f
, cell
, "B", false);
598 f
<< stringf(cell
->type
== ID($_AOI4_
) ? ") |" : ") &");
599 dump_attributes(f
, "", cell
->attributes
, ' ');
601 dump_cell_expr_port(f
, cell
, "C", false);
602 f
<< stringf(cell
->type
== ID($_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(ID::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(ID::Q
));
619 dump_attributes(f
, indent
, cell
->attributes
);
620 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", cell
->type
[6] == 'P' ? "pos" : "neg");
621 dump_sigspec(f
, cell
->getPort(ID::C
));
622 if (cell
->type
[7] != '_') {
623 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
624 dump_sigspec(f
, cell
->getPort(ID::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(ID::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(ID::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(ID::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(ID::Q
));
662 dump_attributes(f
, indent
, cell
->attributes
);
663 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", pol_c
== 'P' ? "pos" : "neg");
664 dump_sigspec(f
, cell
->getPort(ID::C
));
665 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
666 dump_sigspec(f
, cell
->getPort(ID::S
));
667 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
668 dump_sigspec(f
, cell
->getPort(ID::R
));
671 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
672 dump_sigspec(f
, cell
->getPort(ID::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(ID::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(ID::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(ID($
not), "~")
701 HANDLE_UNIOP(ID($pos
), "+")
702 HANDLE_UNIOP(ID($neg
), "-")
704 HANDLE_BINOP(ID($
and), "&")
705 HANDLE_BINOP(ID($
or), "|")
706 HANDLE_BINOP(ID($
xor), "^")
707 HANDLE_BINOP(ID($xnor
), "~^")
709 HANDLE_UNIOP(ID($reduce_and
), "&")
710 HANDLE_UNIOP(ID($reduce_or
), "|")
711 HANDLE_UNIOP(ID($reduce_xor
), "^")
712 HANDLE_UNIOP(ID($reduce_xnor
), "~^")
713 HANDLE_UNIOP(ID($reduce_bool
), "|")
715 HANDLE_BINOP(ID($shl
), "<<")
716 HANDLE_BINOP(ID($shr
), ">>")
717 HANDLE_BINOP(ID($sshl
), "<<<")
718 HANDLE_BINOP(ID($sshr
), ">>>")
720 HANDLE_BINOP(ID($lt
), "<")
721 HANDLE_BINOP(ID($le
), "<=")
722 HANDLE_BINOP(ID($eq
), "==")
723 HANDLE_BINOP(ID($ne
), "!=")
724 HANDLE_BINOP(ID($eqx
), "===")
725 HANDLE_BINOP(ID($nex
), "!==")
726 HANDLE_BINOP(ID($ge
), ">=")
727 HANDLE_BINOP(ID($gt
), ">")
729 HANDLE_BINOP(ID($add
), "+")
730 HANDLE_BINOP(ID($sub
), "-")
731 HANDLE_BINOP(ID($mul
), "*")
732 HANDLE_BINOP(ID($div
), "/")
733 HANDLE_BINOP(ID($mod
), "%")
734 HANDLE_BINOP(ID($pow
), "**")
736 HANDLE_UNIOP(ID($logic_not
), "!")
737 HANDLE_BINOP(ID($logic_and
), "&&")
738 HANDLE_BINOP(ID($logic_or
), "||")
743 if (cell
->type
== ID($divfloor
))
745 // wire [MAXLEN+1:0] _0_, _1_, _2_;
746 // assign _0_ = $signed(A);
747 // assign _1_ = $signed(B);
748 // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
749 // assign Y = $signed(_2_) / $signed(_1_);
751 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
752 SigSpec sig_a
= cell
->getPort(ID::A
);
753 SigSpec sig_b
= cell
->getPort(ID::B
);
755 std::string buf_a
= next_auto_id();
756 std::string buf_b
= next_auto_id();
757 std::string buf_num
= next_auto_id();
758 int size_a
= GetSize(sig_a
);
759 int size_b
= GetSize(sig_b
);
760 int size_y
= GetSize(cell
->getPort(ID::Y
));
761 int size_max
= std::max(size_a
, std::max(size_b
, size_y
));
763 // intentionally one wider than maximum width
764 f
<< stringf("%s" "wire [%d:0] %s, %s, %s;\n", indent
.c_str(), size_max
, buf_a
.c_str(), buf_b
.c_str(), buf_num
.c_str());
765 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_a
.c_str());
766 dump_cell_expr_port(f
, cell
, "A", true);
768 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_b
.c_str());
769 dump_cell_expr_port(f
, cell
, "B", true);
772 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_num
.c_str());
774 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
775 f
<< stringf(" == ");
776 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
777 f
<< stringf(") || ");
778 dump_sigspec(f
, sig_a
);
779 f
<< stringf(" == 0 ? %s : ", buf_a
.c_str());
780 f
<< stringf("$signed(%s - (", buf_a
.c_str());
781 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
782 f
<< stringf(" ? %s + 1 : %s - 1));\n", buf_b
.c_str(), buf_b
.c_str());
785 f
<< stringf("%s" "assign ", indent
.c_str());
786 dump_sigspec(f
, cell
->getPort(ID::Y
));
787 f
<< stringf(" = $signed(%s) / ", buf_num
.c_str());
788 dump_attributes(f
, "", cell
->attributes
, ' ');
789 f
<< stringf("$signed(%s);\n", buf_b
.c_str());
792 // same as truncating division
793 dump_cell_expr_binop(f
, indent
, cell
, "/");
798 if (cell
->type
== ID($modfloor
))
800 // wire truncated = $signed(A) % $signed(B);
801 // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated);
803 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
804 SigSpec sig_a
= cell
->getPort(ID::A
);
805 SigSpec sig_b
= cell
->getPort(ID::B
);
807 std::string temp_id
= next_auto_id();
808 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
809 dump_cell_expr_port(f
, cell
, "A", true);
810 f
<< stringf(" %% ");
811 dump_attributes(f
, "", cell
->attributes
, ' ');
812 dump_cell_expr_port(f
, cell
, "B", true);
815 f
<< stringf("%s" "assign ", indent
.c_str());
816 dump_sigspec(f
, cell
->getPort(ID::Y
));
817 f
<< stringf(" = (");
818 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
819 f
<< stringf(" == ");
820 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
821 f
<< stringf(") || %s == 0 ? %s : ", temp_id
.c_str(), temp_id
.c_str());
822 dump_cell_expr_port(f
, cell
, "B", true);
823 f
<< stringf(" + $signed(%s);\n", temp_id
.c_str());
826 // same as truncating modulo
827 dump_cell_expr_binop(f
, indent
, cell
, "%");
832 if (cell
->type
== ID($shift
))
834 f
<< stringf("%s" "assign ", indent
.c_str());
835 dump_sigspec(f
, cell
->getPort(ID::Y
));
837 if (cell
->getParam(ID::B_SIGNED
).as_bool())
839 f
<< stringf("$signed(");
840 dump_sigspec(f
, cell
->getPort(ID::B
));
842 f
<< stringf(" < 0 ? ");
843 dump_sigspec(f
, cell
->getPort(ID::A
));
844 f
<< stringf(" << - ");
845 dump_sigspec(f
, cell
->getPort(ID::B
));
847 dump_sigspec(f
, cell
->getPort(ID::A
));
848 f
<< stringf(" >> ");
849 dump_sigspec(f
, cell
->getPort(ID::B
));
853 dump_sigspec(f
, cell
->getPort(ID::A
));
854 f
<< stringf(" >> ");
855 dump_sigspec(f
, cell
->getPort(ID::B
));
861 if (cell
->type
== ID($shiftx
))
863 std::string temp_id
= next_auto_id();
864 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
865 dump_sigspec(f
, cell
->getPort(ID::A
));
868 f
<< stringf("%s" "assign ", indent
.c_str());
869 dump_sigspec(f
, cell
->getPort(ID::Y
));
870 f
<< stringf(" = %s[", temp_id
.c_str());
871 if (cell
->getParam(ID::B_SIGNED
).as_bool())
872 f
<< stringf("$signed(");
873 dump_sigspec(f
, cell
->getPort(ID::B
));
874 if (cell
->getParam(ID::B_SIGNED
).as_bool())
876 f
<< stringf(" +: %d", cell
->getParam(ID::Y_WIDTH
).as_int());
877 f
<< stringf("];\n");
881 if (cell
->type
== ID($mux
))
883 f
<< stringf("%s" "assign ", indent
.c_str());
884 dump_sigspec(f
, cell
->getPort(ID::Y
));
886 dump_sigspec(f
, cell
->getPort(ID::S
));
888 dump_attributes(f
, "", cell
->attributes
, ' ');
889 dump_sigspec(f
, cell
->getPort(ID::B
));
891 dump_sigspec(f
, cell
->getPort(ID::A
));
896 if (cell
->type
== ID($pmux
))
898 int width
= cell
->parameters
[ID::WIDTH
].as_int();
899 int s_width
= cell
->getPort(ID::S
).size();
900 std::string func_name
= cellname(cell
);
902 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
903 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
904 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
905 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
907 dump_attributes(f
, indent
+ " ", cell
->attributes
);
909 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
910 f
<< stringf("%s" " casez (s)", indent
.c_str());
911 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
913 for (int i
= 0; i
< s_width
; i
++)
915 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
917 for (int j
= s_width
-1; j
>= 0; j
--)
918 f
<< stringf("%c", j
== i
? '1' : '?');
921 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
924 f
<< stringf("%s" " default:\n", indent
.c_str());
925 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
927 f
<< stringf("%s" " endcase\n", indent
.c_str());
928 f
<< stringf("%s" "endfunction\n", indent
.c_str());
930 f
<< stringf("%s" "assign ", indent
.c_str());
931 dump_sigspec(f
, cell
->getPort(ID::Y
));
932 f
<< stringf(" = %s(", func_name
.c_str());
933 dump_sigspec(f
, cell
->getPort(ID::A
));
935 dump_sigspec(f
, cell
->getPort(ID::B
));
937 dump_sigspec(f
, cell
->getPort(ID::S
));
938 f
<< stringf(");\n");
942 if (cell
->type
== ID($tribuf
))
944 f
<< stringf("%s" "assign ", indent
.c_str());
945 dump_sigspec(f
, cell
->getPort(ID::Y
));
947 dump_sigspec(f
, cell
->getPort(ID::EN
));
949 dump_sigspec(f
, cell
->getPort(ID::A
));
950 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at(ID::WIDTH
).as_int());
954 if (cell
->type
== ID($slice
))
956 f
<< stringf("%s" "assign ", indent
.c_str());
957 dump_sigspec(f
, cell
->getPort(ID::Y
));
959 dump_sigspec(f
, cell
->getPort(ID::A
));
960 f
<< stringf(" >> %d;\n", cell
->parameters
.at(ID::OFFSET
).as_int());
964 if (cell
->type
== ID($concat
))
966 f
<< stringf("%s" "assign ", indent
.c_str());
967 dump_sigspec(f
, cell
->getPort(ID::Y
));
968 f
<< stringf(" = { ");
969 dump_sigspec(f
, cell
->getPort(ID::B
));
971 dump_sigspec(f
, cell
->getPort(ID::A
));
972 f
<< stringf(" };\n");
976 if (cell
->type
== ID($lut
))
978 f
<< stringf("%s" "assign ", indent
.c_str());
979 dump_sigspec(f
, cell
->getPort(ID::Y
));
981 dump_const(f
, cell
->parameters
.at(ID::LUT
));
982 f
<< stringf(" >> ");
983 dump_attributes(f
, "", cell
->attributes
, ' ');
984 dump_sigspec(f
, cell
->getPort(ID::A
));
989 if (cell
->type
== ID($dffsr
))
991 SigSpec sig_clk
= cell
->getPort(ID::CLK
);
992 SigSpec sig_set
= cell
->getPort(ID::SET
);
993 SigSpec sig_clr
= cell
->getPort(ID::CLR
);
994 SigSpec sig_d
= cell
->getPort(ID::D
);
995 SigSpec sig_q
= cell
->getPort(ID::Q
);
997 int width
= cell
->parameters
[ID::WIDTH
].as_int();
998 bool pol_clk
= cell
->parameters
[ID::CLK_POLARITY
].as_bool();
999 bool pol_set
= cell
->parameters
[ID::SET_POLARITY
].as_bool();
1000 bool pol_clr
= cell
->parameters
[ID::CLR_POLARITY
].as_bool();
1002 std::string reg_name
= cellname(cell
);
1003 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
1005 if (!out_is_reg_wire
) {
1006 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
1007 dump_reg_init(f
, sig_q
);
1011 for (int i
= 0; i
< width
; i
++) {
1012 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", pol_clk
? "pos" : "neg");
1013 dump_sigspec(f
, sig_clk
);
1014 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
1015 dump_sigspec(f
, sig_set
);
1016 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
1017 dump_sigspec(f
, sig_clr
);
1018 f
<< stringf(")\n");
1020 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
1021 dump_sigspec(f
, sig_clr
);
1022 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
1024 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
1025 dump_sigspec(f
, sig_set
);
1026 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
1028 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
1029 dump_sigspec(f
, sig_d
[i
]);
1030 f
<< stringf(";\n");
1033 if (!out_is_reg_wire
) {
1034 f
<< stringf("%s" "assign ", indent
.c_str());
1035 dump_sigspec(f
, sig_q
);
1036 f
<< stringf(" = %s;\n", reg_name
.c_str());
1042 if (cell
->type
.in(ID($dff
), ID($adff
), ID($dffe
)))
1044 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
1045 bool pol_clk
, pol_arst
= false, pol_en
= false;
1047 sig_clk
= cell
->getPort(ID::CLK
);
1048 pol_clk
= cell
->parameters
[ID::CLK_POLARITY
].as_bool();
1050 if (cell
->type
== ID($adff
)) {
1051 sig_arst
= cell
->getPort(ID::ARST
);
1052 pol_arst
= cell
->parameters
[ID::ARST_POLARITY
].as_bool();
1053 val_arst
= RTLIL::SigSpec(cell
->parameters
[ID::ARST_VALUE
]);
1056 if (cell
->type
== ID($dffe
)) {
1057 sig_en
= cell
->getPort(ID::EN
);
1058 pol_en
= cell
->parameters
[ID::EN_POLARITY
].as_bool();
1061 std::string reg_name
= cellname(cell
);
1062 bool out_is_reg_wire
= is_reg_wire(cell
->getPort(ID::Q
), reg_name
);
1064 if (!out_is_reg_wire
) {
1065 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
[ID::WIDTH
].as_int()-1, reg_name
.c_str());
1066 dump_reg_init(f
, cell
->getPort(ID::Q
));
1070 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", pol_clk
? "pos" : "neg");
1071 dump_sigspec(f
, sig_clk
);
1072 if (cell
->type
== ID($adff
)) {
1073 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
1074 dump_sigspec(f
, sig_arst
);
1076 f
<< stringf(")\n");
1078 if (cell
->type
== ID($adff
)) {
1079 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
1080 dump_sigspec(f
, sig_arst
);
1081 f
<< stringf(")\n");
1082 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
1083 dump_sigspec(f
, val_arst
);
1084 f
<< stringf(";\n");
1085 f
<< stringf("%s" " else\n", indent
.c_str());
1088 if (cell
->type
== ID($dffe
)) {
1089 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1090 dump_sigspec(f
, sig_en
);
1091 f
<< stringf(")\n");
1094 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
1095 dump_cell_expr_port(f
, cell
, "D", false);
1096 f
<< stringf(";\n");
1098 if (!out_is_reg_wire
) {
1099 f
<< stringf("%s" "assign ", indent
.c_str());
1100 dump_sigspec(f
, cell
->getPort(ID::Q
));
1101 f
<< stringf(" = %s;\n", reg_name
.c_str());
1107 if (cell
->type
== ID($dlatch
))
1109 RTLIL::SigSpec sig_en
;
1110 bool pol_en
= false;
1112 sig_en
= cell
->getPort(ID::EN
);
1113 pol_en
= cell
->parameters
[ID::EN_POLARITY
].as_bool();
1115 std::string reg_name
= cellname(cell
);
1116 bool out_is_reg_wire
= is_reg_wire(cell
->getPort(ID::Q
), reg_name
);
1118 if (!out_is_reg_wire
) {
1119 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
[ID::WIDTH
].as_int()-1, reg_name
.c_str());
1120 dump_reg_init(f
, cell
->getPort(ID::Q
));
1124 f
<< stringf("%s" "always%s\n", indent
.c_str(), systemverilog
? "_latch" : " @*");
1126 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1127 dump_sigspec(f
, sig_en
);
1128 f
<< stringf(")\n");
1130 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
1131 dump_cell_expr_port(f
, cell
, "D", false);
1132 f
<< stringf(";\n");
1134 if (!out_is_reg_wire
) {
1135 f
<< stringf("%s" "assign ", indent
.c_str());
1136 dump_sigspec(f
, cell
->getPort(ID::Q
));
1137 f
<< stringf(" = %s;\n", reg_name
.c_str());
1143 if (cell
->type
== ID($mem
))
1145 RTLIL::IdString memid
= cell
->parameters
[ID::MEMID
].decode_string();
1146 std::string mem_id
= id(cell
->parameters
[ID::MEMID
].decode_string());
1147 int abits
= cell
->parameters
[ID::ABITS
].as_int();
1148 int size
= cell
->parameters
[ID::SIZE
].as_int();
1149 int offset
= cell
->parameters
[ID::OFFSET
].as_int();
1150 int width
= cell
->parameters
[ID::WIDTH
].as_int();
1151 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
[ID::INIT
]).is_fully_undef());
1153 // for memory block make something like:
1154 // reg [7:0] memid [3:0];
1158 dump_attributes(f
, indent
.c_str(), cell
->attributes
);
1159 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1164 std::string extmem_filename
= stringf("%s-%d.mem", extmem_prefix
.c_str(), extmem_counter
++);
1166 std::string extmem_filename_esc
;
1167 for (auto c
: extmem_filename
)
1170 extmem_filename_esc
+= "\\n";
1172 extmem_filename_esc
+= "\\t";
1174 extmem_filename_esc
+= stringf("\\%03o", c
);
1176 extmem_filename_esc
+= "\\\"";
1178 extmem_filename_esc
+= "\\\\";
1180 extmem_filename_esc
+= c
;
1182 f
<< stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent
.c_str(), extmem_filename_esc
.c_str(), mem_id
.c_str());
1184 std::ofstream
extmem_f(extmem_filename
, std::ofstream::trunc
);
1185 if (extmem_f
.fail())
1186 log_error("Can't open file `%s' for writing: %s\n", extmem_filename
.c_str(), strerror(errno
));
1189 for (int i
=0; i
<size
; i
++)
1191 RTLIL::Const element
= cell
->parameters
[ID::INIT
].extract(i
*width
, width
);
1192 for (int j
=0; j
<element
.size(); j
++)
1194 switch (element
[element
.size()-j
-1])
1196 case State::S0
: extmem_f
<< '0'; break;
1197 case State::S1
: extmem_f
<< '1'; break;
1198 case State::Sx
: extmem_f
<< 'x'; break;
1199 case State::Sz
: extmem_f
<< 'z'; break;
1200 case State::Sa
: extmem_f
<< '_'; break;
1201 case State::Sm
: log_error("Found marker state in final netlist.");
1211 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1212 for (int i
=0; i
<size
; i
++)
1214 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1215 dump_const(f
, cell
->parameters
[ID::INIT
].extract(i
*width
, width
));
1216 f
<< stringf(";\n");
1218 f
<< stringf("%s" "end\n", indent
.c_str());
1222 // create a map : "edge clk" -> expressions within that clock domain
1223 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1224 clk_to_lof_body
[""] = std::vector
<std::string
>();
1225 std::string clk_domain_str
;
1226 // create a list of reg declarations
1227 std::vector
<std::string
> lof_reg_declarations
;
1229 int nread_ports
= cell
->parameters
[ID::RD_PORTS
].as_int();
1230 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1231 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1233 for (int i
=0; i
< nread_ports
; i
++)
1235 sig_rd_clk
= cell
->getPort(ID::RD_CLK
).extract(i
);
1236 sig_rd_en
= cell
->getPort(ID::RD_EN
).extract(i
);
1237 sig_rd_data
= cell
->getPort(ID::RD_DATA
).extract(i
*width
, width
);
1238 sig_rd_addr
= cell
->getPort(ID::RD_ADDR
).extract(i
*abits
, abits
);
1239 use_rd_clk
= cell
->parameters
[ID::RD_CLK_ENABLE
].extract(i
).as_bool();
1240 rd_clk_posedge
= cell
->parameters
[ID::RD_CLK_POLARITY
].extract(i
).as_bool();
1241 rd_transparent
= cell
->parameters
[ID::RD_TRANSPARENT
].extract(i
).as_bool();
1245 std::ostringstream os
;
1246 dump_sigspec(os
, sig_rd_clk
);
1247 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1248 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1249 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1251 if (!rd_transparent
)
1253 // for clocked read ports make something like:
1254 // reg [..] temp_id;
1255 // always @(posedge clk)
1256 // if (rd_en) temp_id <= array_reg[r_addr];
1257 // assign r_data = temp_id;
1258 std::string temp_id
= next_auto_id();
1259 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1261 std::ostringstream os
;
1262 if (sig_rd_en
!= RTLIL::SigBit(true))
1264 os
<< stringf("if (");
1265 dump_sigspec(os
, sig_rd_en
);
1266 os
<< stringf(") ");
1268 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1269 dump_sigspec(os
, sig_rd_addr
);
1270 os
<< stringf("];\n");
1271 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1274 std::ostringstream os
;
1275 dump_sigspec(os
, sig_rd_data
);
1276 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1277 clk_to_lof_body
[""].push_back(line
);
1282 // for rd-transparent read-ports make something like:
1283 // reg [..] temp_id;
1284 // always @(posedge clk)
1285 // temp_id <= r_addr;
1286 // assign r_data = array_reg[temp_id];
1287 std::string temp_id
= next_auto_id();
1288 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1290 std::ostringstream os
;
1291 dump_sigspec(os
, sig_rd_addr
);
1292 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1293 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1296 std::ostringstream os
;
1297 dump_sigspec(os
, sig_rd_data
);
1298 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1299 clk_to_lof_body
[""].push_back(line
);
1303 // for non-clocked read-ports make something like:
1304 // assign r_data = array_reg[r_addr];
1305 std::ostringstream os
, os2
;
1306 dump_sigspec(os
, sig_rd_data
);
1307 dump_sigspec(os2
, sig_rd_addr
);
1308 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1309 clk_to_lof_body
[""].push_back(line
);
1313 int nwrite_ports
= cell
->parameters
[ID::WR_PORTS
].as_int();
1314 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1315 bool wr_clk_posedge
;
1318 for (int i
=0; i
< nwrite_ports
; i
++)
1320 sig_wr_clk
= cell
->getPort(ID::WR_CLK
).extract(i
);
1321 sig_wr_data
= cell
->getPort(ID::WR_DATA
).extract(i
*width
, width
);
1322 sig_wr_addr
= cell
->getPort(ID::WR_ADDR
).extract(i
*abits
, abits
);
1323 sig_wr_en
= cell
->getPort(ID::WR_EN
).extract(i
*width
, width
);
1324 wr_clk_posedge
= cell
->parameters
[ID::WR_CLK_POLARITY
].extract(i
).as_bool();
1326 std::ostringstream os
;
1327 dump_sigspec(os
, sig_wr_clk
);
1328 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1329 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1330 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1332 // make something like:
1333 // always @(posedge clk)
1334 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1336 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1338 int start_i
= i
, width
= 1;
1339 SigBit wen_bit
= sig_wr_en
[i
];
1341 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1344 if (wen_bit
== State::S0
)
1347 std::ostringstream os
;
1348 if (wen_bit
!= State::S1
)
1350 os
<< stringf("if (");
1351 dump_sigspec(os
, wen_bit
);
1352 os
<< stringf(") ");
1354 os
<< stringf("%s[", mem_id
.c_str());
1355 dump_sigspec(os
, sig_wr_addr
);
1356 if (width
== GetSize(sig_wr_en
))
1357 os
<< stringf("] <= ");
1359 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1360 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1361 os
<< stringf(";\n");
1362 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1365 // Output Verilog that looks something like this:
1367 // always @(posedge CLK2) begin
1368 // _3_ <= memory[D1ADDR];
1370 // memory[A1ADDR] <= A1DATA;
1372 // memory[A2ADDR] <= A2DATA;
1375 // always @(negedge CLK1) begin
1377 // memory[C1ADDR] <= C1DATA;
1380 // assign D1DATA = _3_;
1381 // assign D2DATA <= memory[D2ADDR];
1383 // the reg ... definitions
1384 for(auto ®
: lof_reg_declarations
)
1386 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1388 // the block of expressions by clock domain
1389 for(auto &pair
: clk_to_lof_body
)
1391 std::string clk_domain
= pair
.first
;
1392 std::vector
<std::string
> lof_lines
= pair
.second
;
1393 if( clk_domain
!= "")
1395 f
<< stringf("%s" "always%s @(%s) begin\n", indent
.c_str(), systemverilog
? "_ff" : "", clk_domain
.c_str());
1396 for(auto &line
: lof_lines
)
1397 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1398 f
<< stringf("%s" "end\n", indent
.c_str());
1402 // the non-clocked assignments
1403 for(auto &line
: lof_lines
)
1404 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1411 if (cell
->type
.in(ID($
assert), ID($assume
), ID($cover
)))
1413 f
<< stringf("%s" "always%s if (", indent
.c_str(), systemverilog
? "_comb" : " @*");
1414 dump_sigspec(f
, cell
->getPort(ID::EN
));
1415 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1416 dump_sigspec(f
, cell
->getPort(ID::A
));
1417 f
<< stringf(");\n");
1421 if (cell
->type
.in(ID($specify2
), ID($specify3
)))
1423 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1425 SigSpec en
= cell
->getPort(ID::EN
);
1426 if (en
!= State::S1
) {
1427 f
<< stringf("if (");
1428 dump_sigspec(f
, cell
->getPort(ID::EN
));
1433 if (cell
->type
== ID($specify3
) && cell
->getParam(ID::EDGE_EN
).as_bool())
1434 f
<< (cell
->getParam(ID::EDGE_POL
).as_bool() ? "posedge ": "negedge ");
1436 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1439 if (cell
->getParam(ID::SRC_DST_PEN
).as_bool())
1440 f
<< (cell
->getParam(ID::SRC_DST_POL
).as_bool() ? "+": "-");
1441 f
<< (cell
->getParam(ID::FULL
).as_bool() ? "*> ": "=> ");
1443 if (cell
->type
== ID($specify3
)) {
1445 dump_sigspec(f
, cell
->getPort(ID::DST
));
1447 if (cell
->getParam(ID::DAT_DST_PEN
).as_bool())
1448 f
<< (cell
->getParam(ID::DAT_DST_POL
).as_bool() ? "+": "-");
1450 dump_sigspec(f
, cell
->getPort(ID::DAT
));
1453 dump_sigspec(f
, cell
->getPort(ID::DST
));
1456 bool bak_decimal
= decimal
;
1460 dump_const(f
, cell
->getParam(ID::T_RISE_MIN
));
1462 dump_const(f
, cell
->getParam(ID::T_RISE_TYP
));
1464 dump_const(f
, cell
->getParam(ID::T_RISE_MAX
));
1466 dump_const(f
, cell
->getParam(ID::T_FALL_MIN
));
1468 dump_const(f
, cell
->getParam(ID::T_FALL_TYP
));
1470 dump_const(f
, cell
->getParam(ID::T_FALL_MAX
));
1473 decimal
= bak_decimal
;
1475 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1479 if (cell
->type
== ID($specrule
))
1481 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1483 IdString spec_type
= cell
->getParam(ID::TYPE
).decode_string();
1484 f
<< stringf("%s(", spec_type
.c_str());
1486 if (cell
->getParam(ID::SRC_PEN
).as_bool())
1487 f
<< (cell
->getParam(ID::SRC_POL
).as_bool() ? "posedge ": "negedge ");
1488 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1490 if (cell
->getPort(ID::SRC_EN
) != State::S1
) {
1492 dump_sigspec(f
, cell
->getPort(ID::SRC_EN
));
1496 if (cell
->getParam(ID::DST_PEN
).as_bool())
1497 f
<< (cell
->getParam(ID::DST_POL
).as_bool() ? "posedge ": "negedge ");
1498 dump_sigspec(f
, cell
->getPort(ID::DST
));
1500 if (cell
->getPort(ID::DST_EN
) != State::S1
) {
1502 dump_sigspec(f
, cell
->getPort(ID::DST_EN
));
1505 bool bak_decimal
= decimal
;
1509 dump_const(f
, cell
->getParam(ID::T_LIMIT_MIN
));
1511 dump_const(f
, cell
->getParam(ID::T_LIMIT_TYP
));
1513 dump_const(f
, cell
->getParam(ID::T_LIMIT_MAX
));
1515 if (spec_type
.in(ID($setuphold
), ID($recrem
), ID($fullskew
))) {
1517 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MIN
));
1519 dump_const(f
, cell
->getParam(ID::T_LIMIT2_TYP
));
1521 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MAX
));
1525 decimal
= bak_decimal
;
1527 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1531 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1532 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1537 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1539 if (cell
->type
[0] == '$' && !noexpr
) {
1540 if (dump_cell_expr(f
, indent
, cell
))
1544 dump_attributes(f
, indent
, cell
->attributes
);
1545 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1547 if (!defparam
&& cell
->parameters
.size() > 0) {
1548 f
<< stringf(" #(");
1549 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1550 if (it
!= cell
->parameters
.begin())
1552 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1553 dump_const(f
, it
->second
);
1556 f
<< stringf("\n%s" ")", indent
.c_str());
1559 std::string cell_name
= cellname(cell
);
1560 if (cell_name
!= id(cell
->name
))
1561 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1563 f
<< stringf(" %s (", cell_name
.c_str());
1565 bool first_arg
= true;
1566 std::set
<RTLIL::IdString
> numbered_ports
;
1567 for (int i
= 1; true; i
++) {
1569 snprintf(str
, 16, "$%d", i
);
1570 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1571 if (it
->first
!= str
)
1576 f
<< stringf("\n%s ", indent
.c_str());
1577 dump_sigspec(f
, it
->second
);
1578 numbered_ports
.insert(it
->first
);
1579 goto found_numbered_port
;
1582 found_numbered_port
:;
1584 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1585 if (numbered_ports
.count(it
->first
))
1590 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1591 if (it
->second
.size() > 0)
1592 dump_sigspec(f
, it
->second
);
1595 f
<< stringf("\n%s" ");\n", indent
.c_str());
1597 if (defparam
&& cell
->parameters
.size() > 0) {
1598 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1599 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1600 dump_const(f
, it
->second
);
1601 f
<< stringf(";\n");
1605 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort(ID::Q
)) {
1606 std::stringstream ss
;
1607 dump_reg_init(ss
, cell
->getPort(ID::Q
));
1608 if (!ss
.str().empty()) {
1609 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1616 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1618 f
<< stringf("%s" "assign ", indent
.c_str());
1619 dump_sigspec(f
, left
);
1620 f
<< stringf(" = ");
1621 dump_sigspec(f
, right
);
1622 f
<< stringf(";\n");
1625 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1627 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1629 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1631 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1632 f
<< stringf("%s" "begin\n", indent
.c_str());
1634 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1635 if (it
->first
.size() == 0)
1637 f
<< stringf("%s ", indent
.c_str());
1638 dump_sigspec(f
, it
->first
);
1639 f
<< stringf(" = ");
1640 dump_sigspec(f
, it
->second
);
1641 f
<< stringf(";\n");
1644 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1645 dump_proc_switch(f
, indent
+ " ", *it
);
1647 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1648 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1650 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1651 f
<< stringf("%s" "end\n", indent
.c_str());
1654 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1656 if (sw
->signal
.size() == 0) {
1657 f
<< stringf("%s" "begin\n", indent
.c_str());
1658 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1659 if ((*it
)->compare
.size() == 0)
1660 dump_case_body(f
, indent
+ " ", *it
);
1662 f
<< stringf("%s" "end\n", indent
.c_str());
1666 dump_attributes(f
, indent
, sw
->attributes
);
1667 f
<< stringf("%s" "casez (", indent
.c_str());
1668 dump_sigspec(f
, sw
->signal
);
1669 f
<< stringf(")\n");
1671 bool got_default
= false;
1672 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1673 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1674 if ((*it
)->compare
.size() == 0) {
1677 f
<< stringf("%s default", indent
.c_str());
1680 f
<< stringf("%s ", indent
.c_str());
1681 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1684 dump_sigspec(f
, (*it
)->compare
[i
]);
1687 f
<< stringf(":\n");
1688 dump_case_body(f
, indent
+ " ", *it
);
1691 f
<< stringf("%s" "endcase\n", indent
.c_str());
1694 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1696 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1697 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1698 case_body_find_regs(*it2
);
1700 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1701 for (auto &c
: it
->first
.chunks())
1703 reg_wires
.insert(c
.wire
->name
);
1707 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1710 case_body_find_regs(&proc
->root_case
);
1711 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1712 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1713 for (auto &c
: it2
->first
.chunks())
1715 reg_wires
.insert(c
.wire
->name
);
1720 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1721 dump_case_body(f
, indent
, &proc
->root_case
, true);
1723 std::string backup_indent
= indent
;
1725 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1727 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1728 indent
= backup_indent
;
1730 if (sync
->type
== RTLIL::STa
) {
1731 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1732 } else if (sync
->type
== RTLIL::STi
) {
1733 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1735 f
<< stringf("%s" "always%s @(", indent
.c_str(), systemverilog
? "_ff" : "");
1736 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1737 f
<< stringf("posedge ");
1738 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1739 f
<< stringf("negedge ");
1740 dump_sigspec(f
, sync
->signal
);
1741 f
<< stringf(") begin\n");
1743 std::string ends
= indent
+ "end\n";
1746 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1747 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1748 dump_sigspec(f
, sync
->signal
);
1749 f
<< stringf(") begin\n");
1750 ends
= indent
+ "end\n" + ends
;
1754 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1755 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1756 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1757 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1758 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1759 dump_sigspec(f
, sync2
->signal
);
1760 f
<< stringf(") begin\n");
1761 ends
= indent
+ "end\n" + ends
;
1767 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1768 if (it
->first
.size() == 0)
1770 f
<< stringf("%s ", indent
.c_str());
1771 dump_sigspec(f
, it
->first
);
1772 f
<< stringf(" <= ");
1773 dump_sigspec(f
, it
->second
);
1774 f
<< stringf(";\n");
1777 f
<< stringf("%s", ends
.c_str());
1781 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1784 reset_auto_counter(module
);
1785 active_module
= module
;
1786 active_sigmap
.set(module
);
1787 active_initdata
.clear();
1789 for (auto wire
: module
->wires())
1790 if (wire
->attributes
.count(ID::init
)) {
1791 SigSpec sig
= active_sigmap(wire
);
1792 Const val
= wire
->attributes
.at(ID::init
);
1793 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1794 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1795 active_initdata
[sig
[i
]] = val
[i
];
1798 if (!module
->processes
.empty())
1799 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1800 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1801 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1802 "processes to logic networks and registers.\n", log_id(module
));
1805 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1806 dump_process(f
, indent
+ " ", it
->second
, true);
1810 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1811 for (auto cell
: module
->cells())
1813 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort(ID::Q
))
1816 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
1818 if (sig
.is_chunk()) {
1819 RTLIL::SigChunk chunk
= sig
.as_chunk();
1820 if (chunk
.wire
!= NULL
)
1821 for (int i
= 0; i
< chunk
.width
; i
++)
1822 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1825 for (auto wire
: module
->wires())
1827 for (int i
= 0; i
< wire
->width
; i
++)
1828 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1829 goto this_wire_aint_reg
;
1831 reg_wires
.insert(wire
->name
);
1832 this_wire_aint_reg
:;
1836 dump_attributes(f
, indent
, module
->attributes
, '\n', /*modattr=*/true);
1837 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1838 bool keep_running
= true;
1839 for (int port_id
= 1; keep_running
; port_id
++) {
1840 keep_running
= false;
1841 for (auto wire
: module
->wires()) {
1842 if (wire
->port_id
== port_id
) {
1845 f
<< stringf("%s", id(wire
->name
).c_str());
1846 keep_running
= true;
1851 f
<< stringf(");\n");
1853 for (auto w
: module
->wires())
1854 dump_wire(f
, indent
+ " ", w
);
1856 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1857 dump_memory(f
, indent
+ " ", it
->second
);
1859 for (auto cell
: module
->cells())
1860 dump_cell(f
, indent
+ " ", cell
);
1862 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1863 dump_process(f
, indent
+ " ", it
->second
);
1865 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1866 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1868 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1869 active_module
= NULL
;
1870 active_sigmap
.clear();
1871 active_initdata
.clear();
1874 struct VerilogBackend
: public Backend
{
1875 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1876 void help() override
1878 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1880 log(" write_verilog [options] [filename]\n");
1882 log("Write the current design to a Verilog file.\n");
1885 log(" with this option, SystemVerilog constructs like always_comb are used\n");
1887 log(" -norename\n");
1888 log(" without this option all internal object names (the ones with a dollar\n");
1889 log(" instead of a backslash prefix) are changed to short names in the\n");
1890 log(" format '_<number>_'.\n");
1892 log(" -renameprefix <prefix>\n");
1893 log(" insert this prefix in front of auto-generated instance names\n");
1896 log(" with this option no attributes are included in the output\n");
1898 log(" -attr2comment\n");
1899 log(" with this option attributes are included as comments in the output\n");
1902 log(" without this option all internal cells are converted to Verilog\n");
1903 log(" expressions.\n");
1906 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1907 log(" in -noexpr mode.\n");
1910 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1911 log(" not bit pattern. This option deactivates this feature and instead\n");
1912 log(" will write out all constants in binary.\n");
1915 log(" dump 32-bit constants in decimal and without size and radix\n");
1918 log(" constant values that are compatible with hex output are usually\n");
1919 log(" dumped as hex values. This option deactivates this feature and\n");
1920 log(" instead will write out all constants in binary.\n");
1923 log(" Parameters and attributes that are specified as strings in the\n");
1924 log(" original input will be output as strings by this back-end. This\n");
1925 log(" deactivates this feature and instead will write string constants\n");
1926 log(" as binary numbers.\n");
1929 log(" instead of initializing memories using assignments to individual\n");
1930 log(" elements, use the '$readmemh' function to read initialization data\n");
1931 log(" from a file. This data is written to a file named by appending\n");
1932 log(" a sequential index to the Verilog filename and replacing the extension\n");
1933 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
1934 log(" 'foo-2.mem' and so on.\n");
1936 log(" -defparam\n");
1937 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1938 log(" cell parameters.\n");
1940 log(" -blackboxes\n");
1941 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1942 log(" this option set only the modules with the 'blackbox' attribute\n");
1943 log(" are written to the output file.\n");
1945 log(" -selected\n");
1946 log(" only write selected modules. modules must be selected entirely or\n");
1947 log(" not at all.\n");
1950 log(" verbose output (print new names of all renamed wires and cells)\n");
1952 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1953 log("always blocks. This frontend should only be used to export an RTLIL\n");
1954 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1955 log("processes to logic networks and registers. A warning is generated when\n");
1956 log("this command is called on a design with RTLIL processes.\n");
1959 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1961 log_header(design
, "Executing Verilog backend.\n");
1966 attr2comment
= false;
1977 bool blackboxes
= false;
1978 bool selected
= false;
1980 auto_name_map
.clear();
1984 reg_ct
.insert(ID($dff
));
1985 reg_ct
.insert(ID($adff
));
1986 reg_ct
.insert(ID($dffe
));
1987 reg_ct
.insert(ID($dlatch
));
1989 reg_ct
.insert(ID($_DFF_N_
));
1990 reg_ct
.insert(ID($_DFF_P_
));
1992 reg_ct
.insert(ID($_DFF_NN0_
));
1993 reg_ct
.insert(ID($_DFF_NN1_
));
1994 reg_ct
.insert(ID($_DFF_NP0_
));
1995 reg_ct
.insert(ID($_DFF_NP1_
));
1996 reg_ct
.insert(ID($_DFF_PN0_
));
1997 reg_ct
.insert(ID($_DFF_PN1_
));
1998 reg_ct
.insert(ID($_DFF_PP0_
));
1999 reg_ct
.insert(ID($_DFF_PP1_
));
2001 reg_ct
.insert(ID($_DFFSR_NNN_
));
2002 reg_ct
.insert(ID($_DFFSR_NNP_
));
2003 reg_ct
.insert(ID($_DFFSR_NPN_
));
2004 reg_ct
.insert(ID($_DFFSR_NPP_
));
2005 reg_ct
.insert(ID($_DFFSR_PNN_
));
2006 reg_ct
.insert(ID($_DFFSR_PNP_
));
2007 reg_ct
.insert(ID($_DFFSR_PPN_
));
2008 reg_ct
.insert(ID($_DFFSR_PPP_
));
2011 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2012 std::string arg
= args
[argidx
];
2014 systemverilog
= true;
2017 if (arg
== "-norename") {
2021 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
2022 auto_prefix
= args
[++argidx
];
2025 if (arg
== "-noattr") {
2029 if (arg
== "-attr2comment") {
2030 attr2comment
= true;
2033 if (arg
== "-noexpr") {
2037 if (arg
== "-nodec") {
2041 if (arg
== "-nohex") {
2045 if (arg
== "-nostr") {
2049 if (arg
== "-extmem") {
2054 if (arg
== "-defparam") {
2058 if (arg
== "-decimal") {
2062 if (arg
== "-siminit") {
2066 if (arg
== "-blackboxes") {
2070 if (arg
== "-selected") {
2080 extra_args(f
, filename
, args
, argidx
);
2083 if (filename
== "<stdout>")
2084 log_cmd_error("Option -extmem must be used with a filename.\n");
2085 extmem_prefix
= filename
.substr(0, filename
.rfind('.'));
2090 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
2091 for (auto module
: design
->modules()) {
2092 if (module
->get_blackbox_attribute() != blackboxes
)
2094 if (selected
&& !design
->selected_whole_module(module
->name
)) {
2095 if (design
->selected_module(module
->name
))
2096 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module
->name
));
2099 log("Dumping module `%s'.\n", module
->name
.c_str());
2100 dump_module(*f
, "", module
);
2103 auto_name_map
.clear();
2109 PRIVATE_NAMESPACE_END