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"
28 #include "kernel/ff.h"
35 PRIVATE_NAMESPACE_BEGIN
37 bool verbose
, norename
, noattr
, attr2comment
, noexpr
, nodec
, nohex
, nostr
, extmem
, defparam
, decimal
, siminit
, systemverilog
;
38 int auto_name_counter
, auto_name_offset
, auto_name_digits
, extmem_counter
;
39 std::map
<RTLIL::IdString
, int> auto_name_map
;
40 std::set
<RTLIL::IdString
> reg_wires
;
41 std::string auto_prefix
, extmem_prefix
;
43 RTLIL::Module
*active_module
;
44 dict
<RTLIL::SigBit
, RTLIL::State
> active_initdata
;
47 void reset_auto_counter_id(RTLIL::IdString id
, bool may_rename
)
49 const char *str
= id
.c_str();
51 if (*str
== '$' && may_rename
&& !norename
)
52 auto_name_map
[id
] = auto_name_counter
++;
54 if (str
[0] != '\\' || str
[1] != '_' || str
[2] == 0)
57 for (int i
= 2; str
[i
] != 0; i
++) {
58 if (str
[i
] == '_' && str
[i
+1] == 0)
60 if (str
[i
] < '0' || str
[i
] > '9')
64 int num
= atoi(str
+2);
65 if (num
>= auto_name_offset
)
66 auto_name_offset
= num
+ 1;
69 void reset_auto_counter(RTLIL::Module
*module
)
71 auto_name_map
.clear();
72 auto_name_counter
= 0;
75 reset_auto_counter_id(module
->name
, false);
77 for (auto w
: module
->wires())
78 reset_auto_counter_id(w
->name
, true);
80 for (auto cell
: module
->cells()) {
81 reset_auto_counter_id(cell
->name
, true);
82 reset_auto_counter_id(cell
->type
, false);
85 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
86 reset_auto_counter_id(it
->second
->name
, false);
89 for (size_t i
= 10; i
< auto_name_offset
+ auto_name_map
.size(); i
= i
*10)
93 for (auto it
= auto_name_map
.begin(); it
!= auto_name_map
.end(); ++it
)
94 log(" renaming `%s' to `%s_%0*d_'.\n", it
->first
.c_str(), auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ it
->second
);
97 std::string
next_auto_id()
99 return stringf("%s_%0*d_", auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ auto_name_counter
++);
102 std::string
id(RTLIL::IdString internal_id
, bool may_rename
= true)
104 const char *str
= internal_id
.c_str();
105 bool do_escape
= false;
107 if (may_rename
&& auto_name_map
.count(internal_id
) != 0)
108 return stringf("%s_%0*d_", auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ auto_name_map
[internal_id
]);
113 if ('0' <= *str
&& *str
<= '9')
116 for (int i
= 0; str
[i
]; i
++)
118 if ('0' <= str
[i
] && str
[i
] <= '9')
120 if ('a' <= str
[i
] && str
[i
] <= 'z')
122 if ('A' <= str
[i
] && str
[i
] <= 'Z')
130 const pool
<string
> keywords
= {
131 // IEEE 1800-2017 Annex B
132 "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
133 "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
134 "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
135 "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
136 "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
137 "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
138 "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
139 "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
140 "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
141 "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
142 "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
143 "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
144 "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
145 "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
146 "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
147 "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
148 "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
149 "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
150 "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
151 "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
152 "wildcard", "wire", "with", "within", "wor", "xnor", "xor",
154 if (keywords
.count(str
))
158 return "\\" + std::string(str
) + " ";
159 return std::string(str
);
162 bool is_reg_wire(RTLIL::SigSpec sig
, std::string
®_name
)
164 if (!sig
.is_chunk() || sig
.as_chunk().wire
== NULL
)
167 RTLIL::SigChunk chunk
= sig
.as_chunk();
169 if (reg_wires
.count(chunk
.wire
->name
) == 0)
172 reg_name
= id(chunk
.wire
->name
);
173 if (sig
.size() != chunk
.wire
->width
) {
175 reg_name
+= stringf("[%d]", chunk
.wire
->start_offset
+ chunk
.offset
);
176 else if (chunk
.wire
->upto
)
177 reg_name
+= stringf("[%d:%d]", (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
178 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
180 reg_name
+= stringf("[%d:%d]", chunk
.wire
->start_offset
+ chunk
.offset
+ chunk
.width
- 1,
181 chunk
.wire
->start_offset
+ chunk
.offset
);
187 void dump_const(std::ostream
&f
, const RTLIL::Const
&data
, int width
= -1, int offset
= 0, bool no_decimal
= false, bool escape_comment
= false)
189 bool set_signed
= (data
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
191 width
= data
.bits
.size() - offset
;
193 // See IEEE 1364-2005 Clause 5.1.14.
199 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
200 if (width
== 32 && !no_decimal
&& !nodec
) {
202 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
203 log_assert(i
< (int)data
.bits
.size());
204 if (data
.bits
[i
] != State::S0
&& data
.bits
[i
] != State::S1
)
206 if (data
.bits
[i
] == State::S1
)
207 val
|= 1 << (i
- offset
);
210 f
<< stringf("%d", val
);
211 else if (set_signed
&& val
< 0)
212 f
<< stringf("-32'sd%u", -val
);
214 f
<< stringf("32'%sd%u", set_signed
? "s" : "", val
);
219 vector
<char> bin_digits
, hex_digits
;
220 for (int i
= offset
; i
< offset
+width
; i
++) {
221 log_assert(i
< (int)data
.bits
.size());
222 switch (data
.bits
[i
]) {
223 case State::S0
: bin_digits
.push_back('0'); break;
224 case State::S1
: bin_digits
.push_back('1'); break;
225 case RTLIL::Sx
: bin_digits
.push_back('x'); break;
226 case RTLIL::Sz
: bin_digits
.push_back('z'); break;
227 case RTLIL::Sa
: bin_digits
.push_back('?'); break;
228 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
231 if (GetSize(bin_digits
) == 0)
233 while (GetSize(bin_digits
) % 4 != 0)
234 if (bin_digits
.back() == '1')
235 bin_digits
.push_back('0');
237 bin_digits
.push_back(bin_digits
.back());
238 for (int i
= 0; i
< GetSize(bin_digits
); i
+= 4)
240 char bit_3
= bin_digits
[i
+3];
241 char bit_2
= bin_digits
[i
+2];
242 char bit_1
= bin_digits
[i
+1];
243 char bit_0
= bin_digits
[i
+0];
244 if (bit_3
== 'x' || bit_2
== 'x' || bit_1
== 'x' || bit_0
== 'x') {
245 if (bit_3
!= 'x' || bit_2
!= 'x' || bit_1
!= 'x' || bit_0
!= 'x')
247 hex_digits
.push_back('x');
250 if (bit_3
== 'z' || bit_2
== 'z' || bit_1
== 'z' || bit_0
== 'z') {
251 if (bit_3
!= 'z' || bit_2
!= 'z' || bit_1
!= 'z' || bit_0
!= 'z')
253 hex_digits
.push_back('z');
256 if (bit_3
== '?' || bit_2
== '?' || bit_1
== '?' || bit_0
== '?') {
257 if (bit_3
!= '?' || bit_2
!= '?' || bit_1
!= '?' || bit_0
!= '?')
259 hex_digits
.push_back('?');
262 int val
= 8*(bit_3
- '0') + 4*(bit_2
- '0') + 2*(bit_1
- '0') + (bit_0
- '0');
263 hex_digits
.push_back(val
< 10 ? '0' + val
: 'a' + val
- 10);
265 f
<< stringf("%d'%sh", width
, set_signed
? "s" : "");
266 for (int i
= GetSize(hex_digits
)-1; i
>= 0; i
--)
271 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
274 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
275 log_assert(i
< (int)data
.bits
.size());
276 switch (data
.bits
[i
]) {
277 case State::S0
: f
<< stringf("0"); break;
278 case State::S1
: f
<< stringf("1"); break;
279 case RTLIL::Sx
: f
<< stringf("x"); break;
280 case RTLIL::Sz
: f
<< stringf("z"); break;
281 case RTLIL::Sa
: f
<< stringf("?"); break;
282 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
287 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
289 std::string str
= data
.decode_string();
290 for (size_t i
= 0; i
< str
.size(); i
++) {
293 else if (str
[i
] == '\t')
295 else if (str
[i
] < 32)
296 f
<< stringf("\\%03o", str
[i
]);
297 else if (str
[i
] == '"')
298 f
<< stringf("\\\"");
299 else if (str
[i
] == '\\')
300 f
<< stringf("\\\\");
301 else if (str
[i
] == '/' && escape_comment
&& i
> 0 && str
[i
-1] == '*')
306 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
311 void dump_reg_init(std::ostream
&f
, SigSpec sig
)
314 bool gotinit
= false;
316 for (auto bit
: active_sigmap(sig
)) {
317 if (active_initdata
.count(bit
)) {
318 initval
.bits
.push_back(active_initdata
.at(bit
));
321 initval
.bits
.push_back(State::Sx
);
327 dump_const(f
, initval
);
331 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
333 if (chunk
.wire
== NULL
) {
334 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
336 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0) {
337 f
<< stringf("%s", id(chunk
.wire
->name
).c_str());
338 } else if (chunk
.width
== 1) {
339 if (chunk
.wire
->upto
)
340 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
342 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
344 if (chunk
.wire
->upto
)
345 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
346 (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
347 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
349 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
350 (chunk
.offset
+ chunk
.width
- 1) + chunk
.wire
->start_offset
,
351 chunk
.offset
+ chunk
.wire
->start_offset
);
356 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
358 if (GetSize(sig
) == 0) {
362 if (sig
.is_chunk()) {
363 dump_sigchunk(f
, sig
.as_chunk());
366 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
367 if (it
!= sig
.chunks().rbegin())
369 dump_sigchunk(f
, *it
, true);
375 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)
381 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
382 if (it
->first
== ID::init
&& regattr
) continue;
383 f
<< stringf("%s" "%s %s", indent
.c_str(), as_comment
? "/*" : "(*", id(it
->first
).c_str());
385 if (modattr
&& (it
->second
== State::S0
|| it
->second
== Const(0)))
387 else if (modattr
&& (it
->second
== State::S1
|| it
->second
== Const(1)))
390 dump_const(f
, it
->second
, -1, 0, false, as_comment
);
391 f
<< stringf(" %s%c", as_comment
? "*/" : "*)", term
);
395 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
397 dump_attributes(f
, indent
, wire
->attributes
, '\n', /*modattr=*/false, /*regattr=*/reg_wires
.count(wire
->name
));
399 if (wire
->port_input
&& !wire
->port_output
)
400 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
401 else if (!wire
->port_input
&& wire
->port_output
)
402 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
403 else if (wire
->port_input
&& wire
->port_output
)
404 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
406 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
407 if (wire
->width
!= 1)
408 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
409 f
<< stringf("%s;\n", id(wire
->name
).c_str());
411 // do not use Verilog-2k "output reg" syntax in Verilog export
412 std::string range
= "";
413 if (wire
->width
!= 1) {
415 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
417 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
419 if (wire
->port_input
&& !wire
->port_output
)
420 f
<< stringf("%s" "input%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
421 if (!wire
->port_input
&& wire
->port_output
)
422 f
<< stringf("%s" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
423 if (wire
->port_input
&& wire
->port_output
)
424 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
425 if (reg_wires
.count(wire
->name
)) {
426 f
<< stringf("%s" "reg%s %s", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
427 if (wire
->attributes
.count(ID::init
)) {
429 dump_const(f
, wire
->attributes
.at(ID::init
));
432 } else if (!wire
->port_input
&& !wire
->port_output
)
433 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
437 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
439 dump_attributes(f
, indent
, memory
->attributes
);
440 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
);
443 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
445 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
446 f
<< stringf("$signed(");
447 dump_sigspec(f
, cell
->getPort("\\" + port
));
450 dump_sigspec(f
, cell
->getPort("\\" + port
));
453 std::string
cellname(RTLIL::Cell
*cell
)
455 if (!norename
&& cell
->name
[0] == '$' && RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
)))
457 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
458 if (GetSize(sig
) != 1 || sig
.is_fully_const())
459 goto no_special_reg_name
;
461 RTLIL::Wire
*wire
= sig
[0].wire
;
463 if (wire
->name
[0] != '\\')
464 goto no_special_reg_name
;
466 std::string cell_name
= wire
->name
.str();
468 size_t pos
= cell_name
.find('[');
469 if (pos
!= std::string::npos
)
470 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
472 cell_name
= cell_name
+ "_reg";
474 if (wire
->width
!= 1)
475 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
477 if (active_module
&& active_module
->count_id(cell_name
) > 0)
478 goto no_special_reg_name
;
480 return id(cell_name
);
485 return id(cell
->name
).c_str();
489 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
491 f
<< stringf("%s" "assign ", indent
.c_str());
492 dump_sigspec(f
, cell
->getPort(ID::Y
));
493 f
<< stringf(" = %s ", op
.c_str());
494 dump_attributes(f
, "", cell
->attributes
, ' ');
495 dump_cell_expr_port(f
, cell
, "A", true);
499 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
501 f
<< stringf("%s" "assign ", indent
.c_str());
502 dump_sigspec(f
, cell
->getPort(ID::Y
));
504 dump_cell_expr_port(f
, cell
, "A", true);
505 f
<< stringf(" %s ", op
.c_str());
506 dump_attributes(f
, "", cell
->attributes
, ' ');
507 dump_cell_expr_port(f
, cell
, "B", true);
511 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
513 if (cell
->type
== ID($_NOT_
)) {
514 f
<< stringf("%s" "assign ", indent
.c_str());
515 dump_sigspec(f
, cell
->getPort(ID::Y
));
518 dump_attributes(f
, "", cell
->attributes
, ' ');
519 dump_cell_expr_port(f
, cell
, "A", false);
524 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_OR_
), ID($_NOR_
), ID($_XOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
))) {
525 f
<< stringf("%s" "assign ", indent
.c_str());
526 dump_sigspec(f
, cell
->getPort(ID::Y
));
528 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
)))
530 dump_cell_expr_port(f
, cell
, "A", false);
532 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_ANDNOT_
)))
534 if (cell
->type
.in(ID($_OR_
), ID($_NOR_
), ID($_ORNOT_
)))
536 if (cell
->type
.in(ID($_XOR_
), ID($_XNOR_
)))
538 dump_attributes(f
, "", cell
->attributes
, ' ');
540 if (cell
->type
.in(ID($_ANDNOT_
), ID($_ORNOT_
)))
542 dump_cell_expr_port(f
, cell
, "B", false);
543 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
)))
549 if (cell
->type
== ID($_MUX_
)) {
550 f
<< stringf("%s" "assign ", indent
.c_str());
551 dump_sigspec(f
, cell
->getPort(ID::Y
));
553 dump_cell_expr_port(f
, cell
, "S", false);
555 dump_attributes(f
, "", cell
->attributes
, ' ');
556 dump_cell_expr_port(f
, cell
, "B", false);
558 dump_cell_expr_port(f
, cell
, "A", false);
563 if (cell
->type
== ID($_NMUX_
)) {
564 f
<< stringf("%s" "assign ", indent
.c_str());
565 dump_sigspec(f
, cell
->getPort(ID::Y
));
566 f
<< stringf(" = !(");
567 dump_cell_expr_port(f
, cell
, "S", false);
569 dump_attributes(f
, "", cell
->attributes
, ' ');
570 dump_cell_expr_port(f
, cell
, "B", false);
572 dump_cell_expr_port(f
, cell
, "A", false);
573 f
<< stringf(");\n");
577 if (cell
->type
.in(ID($_AOI3_
), ID($_OAI3_
))) {
578 f
<< stringf("%s" "assign ", indent
.c_str());
579 dump_sigspec(f
, cell
->getPort(ID::Y
));
580 f
<< stringf(" = ~((");
581 dump_cell_expr_port(f
, cell
, "A", false);
582 f
<< stringf(cell
->type
== ID($_AOI3_
) ? " & " : " | ");
583 dump_cell_expr_port(f
, cell
, "B", false);
584 f
<< stringf(cell
->type
== ID($_AOI3_
) ? ") |" : ") &");
585 dump_attributes(f
, "", cell
->attributes
, ' ');
587 dump_cell_expr_port(f
, cell
, "C", false);
588 f
<< stringf(");\n");
592 if (cell
->type
.in(ID($_AOI4_
), ID($_OAI4_
))) {
593 f
<< stringf("%s" "assign ", indent
.c_str());
594 dump_sigspec(f
, cell
->getPort(ID::Y
));
595 f
<< stringf(" = ~((");
596 dump_cell_expr_port(f
, cell
, "A", false);
597 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
598 dump_cell_expr_port(f
, cell
, "B", false);
599 f
<< stringf(cell
->type
== ID($_AOI4_
) ? ") |" : ") &");
600 dump_attributes(f
, "", cell
->attributes
, ' ');
602 dump_cell_expr_port(f
, cell
, "C", false);
603 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
604 dump_cell_expr_port(f
, cell
, "D", false);
605 f
<< stringf("));\n");
609 #define HANDLE_UNIOP(_type, _operator) \
610 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
611 #define HANDLE_BINOP(_type, _operator) \
612 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
614 HANDLE_UNIOP(ID($
not), "~")
615 HANDLE_UNIOP(ID($pos
), "+")
616 HANDLE_UNIOP(ID($neg
), "-")
618 HANDLE_BINOP(ID($
and), "&")
619 HANDLE_BINOP(ID($
or), "|")
620 HANDLE_BINOP(ID($
xor), "^")
621 HANDLE_BINOP(ID($xnor
), "~^")
623 HANDLE_UNIOP(ID($reduce_and
), "&")
624 HANDLE_UNIOP(ID($reduce_or
), "|")
625 HANDLE_UNIOP(ID($reduce_xor
), "^")
626 HANDLE_UNIOP(ID($reduce_xnor
), "~^")
627 HANDLE_UNIOP(ID($reduce_bool
), "|")
629 HANDLE_BINOP(ID($shl
), "<<")
630 HANDLE_BINOP(ID($shr
), ">>")
631 HANDLE_BINOP(ID($sshl
), "<<<")
632 HANDLE_BINOP(ID($sshr
), ">>>")
634 HANDLE_BINOP(ID($lt
), "<")
635 HANDLE_BINOP(ID($le
), "<=")
636 HANDLE_BINOP(ID($eq
), "==")
637 HANDLE_BINOP(ID($ne
), "!=")
638 HANDLE_BINOP(ID($eqx
), "===")
639 HANDLE_BINOP(ID($nex
), "!==")
640 HANDLE_BINOP(ID($ge
), ">=")
641 HANDLE_BINOP(ID($gt
), ">")
643 HANDLE_BINOP(ID($add
), "+")
644 HANDLE_BINOP(ID($sub
), "-")
645 HANDLE_BINOP(ID($mul
), "*")
646 HANDLE_BINOP(ID($div
), "/")
647 HANDLE_BINOP(ID($mod
), "%")
648 HANDLE_BINOP(ID($pow
), "**")
650 HANDLE_UNIOP(ID($logic_not
), "!")
651 HANDLE_BINOP(ID($logic_and
), "&&")
652 HANDLE_BINOP(ID($logic_or
), "||")
657 if (cell
->type
== ID($divfloor
))
659 // wire [MAXLEN+1:0] _0_, _1_, _2_;
660 // assign _0_ = $signed(A);
661 // assign _1_ = $signed(B);
662 // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
663 // assign Y = $signed(_2_) / $signed(_1_);
665 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
666 SigSpec sig_a
= cell
->getPort(ID::A
);
667 SigSpec sig_b
= cell
->getPort(ID::B
);
669 std::string buf_a
= next_auto_id();
670 std::string buf_b
= next_auto_id();
671 std::string buf_num
= next_auto_id();
672 int size_a
= GetSize(sig_a
);
673 int size_b
= GetSize(sig_b
);
674 int size_y
= GetSize(cell
->getPort(ID::Y
));
675 int size_max
= std::max(size_a
, std::max(size_b
, size_y
));
677 // intentionally one wider than maximum width
678 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());
679 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_a
.c_str());
680 dump_cell_expr_port(f
, cell
, "A", true);
682 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_b
.c_str());
683 dump_cell_expr_port(f
, cell
, "B", true);
686 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_num
.c_str());
688 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
689 f
<< stringf(" == ");
690 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
691 f
<< stringf(") || ");
692 dump_sigspec(f
, sig_a
);
693 f
<< stringf(" == 0 ? %s : ", buf_a
.c_str());
694 f
<< stringf("$signed(%s - (", buf_a
.c_str());
695 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
696 f
<< stringf(" ? %s + 1 : %s - 1));\n", buf_b
.c_str(), buf_b
.c_str());
699 f
<< stringf("%s" "assign ", indent
.c_str());
700 dump_sigspec(f
, cell
->getPort(ID::Y
));
701 f
<< stringf(" = $signed(%s) / ", buf_num
.c_str());
702 dump_attributes(f
, "", cell
->attributes
, ' ');
703 f
<< stringf("$signed(%s);\n", buf_b
.c_str());
706 // same as truncating division
707 dump_cell_expr_binop(f
, indent
, cell
, "/");
712 if (cell
->type
== ID($modfloor
))
714 // wire truncated = $signed(A) % $signed(B);
715 // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated);
717 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
718 SigSpec sig_a
= cell
->getPort(ID::A
);
719 SigSpec sig_b
= cell
->getPort(ID::B
);
721 std::string temp_id
= next_auto_id();
722 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
723 dump_cell_expr_port(f
, cell
, "A", true);
724 f
<< stringf(" %% ");
725 dump_attributes(f
, "", cell
->attributes
, ' ');
726 dump_cell_expr_port(f
, cell
, "B", true);
729 f
<< stringf("%s" "assign ", indent
.c_str());
730 dump_sigspec(f
, cell
->getPort(ID::Y
));
731 f
<< stringf(" = (");
732 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
733 f
<< stringf(" == ");
734 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
735 f
<< stringf(") || %s == 0 ? %s : ", temp_id
.c_str(), temp_id
.c_str());
736 dump_cell_expr_port(f
, cell
, "B", true);
737 f
<< stringf(" + $signed(%s);\n", temp_id
.c_str());
740 // same as truncating modulo
741 dump_cell_expr_binop(f
, indent
, cell
, "%");
746 if (cell
->type
== ID($shift
))
748 f
<< stringf("%s" "assign ", indent
.c_str());
749 dump_sigspec(f
, cell
->getPort(ID::Y
));
751 if (cell
->getParam(ID::B_SIGNED
).as_bool())
753 dump_cell_expr_port(f
, cell
, "B", true);
754 f
<< stringf(" < 0 ? ");
755 dump_cell_expr_port(f
, cell
, "A", true);
756 f
<< stringf(" << - ");
757 dump_sigspec(f
, cell
->getPort(ID::B
));
759 dump_cell_expr_port(f
, cell
, "A", true);
760 f
<< stringf(" >> ");
761 dump_sigspec(f
, cell
->getPort(ID::B
));
765 dump_cell_expr_port(f
, cell
, "A", true);
766 f
<< stringf(" >> ");
767 dump_sigspec(f
, cell
->getPort(ID::B
));
773 if (cell
->type
== ID($shiftx
))
775 std::string temp_id
= next_auto_id();
776 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
777 dump_sigspec(f
, cell
->getPort(ID::A
));
780 f
<< stringf("%s" "assign ", indent
.c_str());
781 dump_sigspec(f
, cell
->getPort(ID::Y
));
782 f
<< stringf(" = %s[", temp_id
.c_str());
783 if (cell
->getParam(ID::B_SIGNED
).as_bool())
784 f
<< stringf("$signed(");
785 dump_sigspec(f
, cell
->getPort(ID::B
));
786 if (cell
->getParam(ID::B_SIGNED
).as_bool())
788 f
<< stringf(" +: %d", cell
->getParam(ID::Y_WIDTH
).as_int());
789 f
<< stringf("];\n");
793 if (cell
->type
== ID($mux
))
795 f
<< stringf("%s" "assign ", indent
.c_str());
796 dump_sigspec(f
, cell
->getPort(ID::Y
));
798 dump_sigspec(f
, cell
->getPort(ID::S
));
800 dump_attributes(f
, "", cell
->attributes
, ' ');
801 dump_sigspec(f
, cell
->getPort(ID::B
));
803 dump_sigspec(f
, cell
->getPort(ID::A
));
808 if (cell
->type
== ID($pmux
))
810 int width
= cell
->parameters
[ID::WIDTH
].as_int();
811 int s_width
= cell
->getPort(ID::S
).size();
812 std::string func_name
= cellname(cell
);
814 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
815 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
816 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
817 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
819 dump_attributes(f
, indent
+ " ", cell
->attributes
);
821 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
822 f
<< stringf("%s" " casez (s)", indent
.c_str());
823 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
825 for (int i
= 0; i
< s_width
; i
++)
827 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
829 for (int j
= s_width
-1; j
>= 0; j
--)
830 f
<< stringf("%c", j
== i
? '1' : '?');
833 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
836 f
<< stringf("%s" " default:\n", indent
.c_str());
837 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
839 f
<< stringf("%s" " endcase\n", indent
.c_str());
840 f
<< stringf("%s" "endfunction\n", indent
.c_str());
842 f
<< stringf("%s" "assign ", indent
.c_str());
843 dump_sigspec(f
, cell
->getPort(ID::Y
));
844 f
<< stringf(" = %s(", func_name
.c_str());
845 dump_sigspec(f
, cell
->getPort(ID::A
));
847 dump_sigspec(f
, cell
->getPort(ID::B
));
849 dump_sigspec(f
, cell
->getPort(ID::S
));
850 f
<< stringf(");\n");
854 if (cell
->type
== ID($tribuf
))
856 f
<< stringf("%s" "assign ", indent
.c_str());
857 dump_sigspec(f
, cell
->getPort(ID::Y
));
859 dump_sigspec(f
, cell
->getPort(ID::EN
));
861 dump_sigspec(f
, cell
->getPort(ID::A
));
862 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at(ID::WIDTH
).as_int());
866 if (cell
->type
== ID($slice
))
868 f
<< stringf("%s" "assign ", indent
.c_str());
869 dump_sigspec(f
, cell
->getPort(ID::Y
));
871 dump_sigspec(f
, cell
->getPort(ID::A
));
872 f
<< stringf(" >> %d;\n", cell
->parameters
.at(ID::OFFSET
).as_int());
876 if (cell
->type
== ID($concat
))
878 f
<< stringf("%s" "assign ", indent
.c_str());
879 dump_sigspec(f
, cell
->getPort(ID::Y
));
880 f
<< stringf(" = { ");
881 dump_sigspec(f
, cell
->getPort(ID::B
));
883 dump_sigspec(f
, cell
->getPort(ID::A
));
884 f
<< stringf(" };\n");
888 if (cell
->type
== ID($lut
))
890 f
<< stringf("%s" "assign ", indent
.c_str());
891 dump_sigspec(f
, cell
->getPort(ID::Y
));
893 dump_const(f
, cell
->parameters
.at(ID::LUT
));
894 f
<< stringf(" >> ");
895 dump_attributes(f
, "", cell
->attributes
, ' ');
896 dump_sigspec(f
, cell
->getPort(ID::A
));
901 if (RTLIL::builtin_ff_cell_types().count(cell
->type
))
903 FfData
ff(nullptr, cell
);
905 // $ff / $_FF_ cell: not supported.
906 if (ff
.has_d
&& !ff
.has_clk
&& !ff
.has_en
)
909 std::string reg_name
= cellname(cell
);
910 bool out_is_reg_wire
= is_reg_wire(ff
.sig_q
, reg_name
);
912 if (!out_is_reg_wire
) {
914 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
916 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), ff
.width
-1, reg_name
.c_str());
917 dump_reg_init(f
, ff
.sig_q
);
921 // If the FF has CLR/SET inputs, emit every bit slice separately.
922 int chunks
= ff
.has_sr
? ff
.width
: 1;
923 bool chunky
= ff
.has_sr
&& ff
.width
!= 1;
925 for (int i
= 0; i
< chunks
; i
++)
928 Const val_arst
, val_srst
;
929 std::string reg_bit_name
, sig_set_name
, sig_clr_name
, sig_arst_name
;
931 reg_bit_name
= stringf("%s[%d]", reg_name
.c_str(), i
);
935 reg_bit_name
= reg_name
;
940 val_arst
= chunky
? ff
.val_arst
[i
] : ff
.val_arst
;
942 val_srst
= chunky
? ff
.val_srst
[i
] : ff
.val_srst
;
944 // If there are constants in the sensitivity list, replace them with an intermediate wire
946 if (ff
.sig_set
[i
].wire
== NULL
)
948 sig_set_name
= next_auto_id();
949 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_set_name
.c_str());
950 dump_const(f
, ff
.sig_set
[i
].data
);
953 if (ff
.sig_clr
[i
].wire
== NULL
)
955 sig_clr_name
= next_auto_id();
956 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_clr_name
.c_str());
957 dump_const(f
, ff
.sig_clr
[i
].data
);
960 } else if (ff
.has_arst
) {
961 if (ff
.sig_arst
[i
].wire
== NULL
)
963 sig_arst_name
= next_auto_id();
964 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_arst_name
.c_str());
965 dump_const(f
, ff
.sig_arst
[i
].data
);
970 dump_attributes(f
, indent
, cell
->attributes
);
974 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", ff
.pol_clk
? "pos" : "neg");
975 dump_sigspec(f
, ff
.sig_clk
);
977 f
<< stringf(", %sedge ", ff
.pol_set
? "pos" : "neg");
978 if (ff
.sig_set
[i
].wire
== NULL
)
979 f
<< stringf("%s", sig_set_name
.c_str());
981 dump_sigspec(f
, ff
.sig_set
[i
]);
983 f
<< stringf(", %sedge ", ff
.pol_clr
? "pos" : "neg");
984 if (ff
.sig_clr
[i
].wire
== NULL
)
985 f
<< stringf("%s", sig_clr_name
.c_str());
987 dump_sigspec(f
, ff
.sig_clr
[i
]);
989 } else if (ff
.has_arst
) {
990 f
<< stringf(", %sedge ", ff
.pol_arst
? "pos" : "neg");
991 if (ff
.sig_arst
[i
].wire
== NULL
)
992 f
<< stringf("%s", sig_arst_name
.c_str());
994 dump_sigspec(f
, ff
.sig_arst
);
998 f
<< stringf("%s" " ", indent
.c_str());
1000 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1001 if (ff
.sig_clr
[i
].wire
== NULL
)
1002 f
<< stringf("%s", sig_clr_name
.c_str());
1004 dump_sigspec(f
, ff
.sig_clr
[i
]);
1005 f
<< stringf(") %s <= 1'b0;\n", reg_bit_name
.c_str());
1006 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1007 if (ff
.sig_set
[i
].wire
== NULL
)
1008 f
<< stringf("%s", sig_set_name
.c_str());
1010 dump_sigspec(f
, ff
.sig_set
[i
]);
1011 f
<< stringf(") %s <= 1'b1;\n", reg_bit_name
.c_str());
1012 f
<< stringf("%s" " else ", indent
.c_str());
1013 } else if (ff
.has_arst
) {
1014 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1015 if (ff
.sig_arst
[i
].wire
== NULL
)
1016 f
<< stringf("%s", sig_arst_name
.c_str());
1018 dump_sigspec(f
, ff
.sig_arst
);
1019 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1020 dump_sigspec(f
, val_arst
);
1021 f
<< stringf(";\n");
1022 f
<< stringf("%s" " else ", indent
.c_str());
1025 if (ff
.has_srst
&& ff
.has_en
&& ff
.ce_over_srst
) {
1026 f
<< stringf("if (%s", ff
.pol_en
? "" : "!");
1027 dump_sigspec(f
, ff
.sig_en
);
1028 f
<< stringf(")\n");
1029 f
<< stringf("%s" " if (%s", indent
.c_str(), ff
.pol_srst
? "" : "!");
1030 dump_sigspec(f
, ff
.sig_srst
);
1031 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1032 dump_sigspec(f
, val_srst
);
1033 f
<< stringf(";\n");
1034 f
<< stringf("%s" " else ", indent
.c_str());
1037 f
<< stringf("if (%s", ff
.pol_srst
? "" : "!");
1038 dump_sigspec(f
, ff
.sig_srst
);
1039 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1040 dump_sigspec(f
, val_srst
);
1041 f
<< stringf(";\n");
1042 f
<< stringf("%s" " else ", indent
.c_str());
1045 f
<< stringf("if (%s", ff
.pol_en
? "" : "!");
1046 dump_sigspec(f
, ff
.sig_en
);
1051 f
<< stringf("%s <= ", reg_bit_name
.c_str());
1052 dump_sigspec(f
, sig_d
);
1053 f
<< stringf(";\n");
1058 f
<< stringf("%s" "always%s\n", indent
.c_str(), systemverilog
? "_latch" : " @*");
1060 f
<< stringf("%s" " ", indent
.c_str());
1062 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1063 dump_sigspec(f
, ff
.sig_clr
[i
]);
1064 f
<< stringf(") %s = 1'b0;\n", reg_bit_name
.c_str());
1065 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1066 dump_sigspec(f
, ff
.sig_set
[i
]);
1067 f
<< stringf(") %s = 1'b1;\n", reg_bit_name
.c_str());
1069 f
<< stringf("%s" " else ", indent
.c_str());
1070 } else if (ff
.has_arst
) {
1071 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1072 dump_sigspec(f
, ff
.sig_arst
);
1073 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1074 dump_sigspec(f
, val_arst
);
1075 f
<< stringf(";\n");
1077 f
<< stringf("%s" " else ", indent
.c_str());
1080 f
<< stringf("if (%s", ff
.pol_en
? "" : "!");
1081 dump_sigspec(f
, ff
.sig_en
);
1082 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1083 dump_sigspec(f
, sig_d
);
1084 f
<< stringf(";\n");
1089 if (!out_is_reg_wire
) {
1090 f
<< stringf("%s" "assign ", indent
.c_str());
1091 dump_sigspec(f
, ff
.sig_q
);
1092 f
<< stringf(" = %s;\n", reg_name
.c_str());
1098 if (cell
->type
== ID($mem
))
1100 RTLIL::IdString memid
= cell
->parameters
[ID::MEMID
].decode_string();
1101 std::string mem_id
= id(cell
->parameters
[ID::MEMID
].decode_string());
1102 int abits
= cell
->parameters
[ID::ABITS
].as_int();
1103 int size
= cell
->parameters
[ID::SIZE
].as_int();
1104 int offset
= cell
->parameters
[ID::OFFSET
].as_int();
1105 int width
= cell
->parameters
[ID::WIDTH
].as_int();
1106 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
[ID::INIT
]).is_fully_undef());
1108 // for memory block make something like:
1109 // reg [7:0] memid [3:0];
1113 dump_attributes(f
, indent
.c_str(), cell
->attributes
);
1114 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1119 std::string extmem_filename
= stringf("%s-%d.mem", extmem_prefix
.c_str(), extmem_counter
++);
1121 std::string extmem_filename_esc
;
1122 for (auto c
: extmem_filename
)
1125 extmem_filename_esc
+= "\\n";
1127 extmem_filename_esc
+= "\\t";
1129 extmem_filename_esc
+= stringf("\\%03o", c
);
1131 extmem_filename_esc
+= "\\\"";
1133 extmem_filename_esc
+= "\\\\";
1135 extmem_filename_esc
+= c
;
1137 f
<< stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent
.c_str(), extmem_filename_esc
.c_str(), mem_id
.c_str());
1139 std::ofstream
extmem_f(extmem_filename
, std::ofstream::trunc
);
1140 if (extmem_f
.fail())
1141 log_error("Can't open file `%s' for writing: %s\n", extmem_filename
.c_str(), strerror(errno
));
1144 for (int i
=0; i
<size
; i
++)
1146 RTLIL::Const element
= cell
->parameters
[ID::INIT
].extract(i
*width
, width
);
1147 for (int j
=0; j
<element
.size(); j
++)
1149 switch (element
[element
.size()-j
-1])
1151 case State::S0
: extmem_f
<< '0'; break;
1152 case State::S1
: extmem_f
<< '1'; break;
1153 case State::Sx
: extmem_f
<< 'x'; break;
1154 case State::Sz
: extmem_f
<< 'z'; break;
1155 case State::Sa
: extmem_f
<< '_'; break;
1156 case State::Sm
: log_error("Found marker state in final netlist.");
1166 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1167 for (int i
=0; i
<size
; i
++)
1169 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1170 dump_const(f
, cell
->parameters
[ID::INIT
].extract(i
*width
, width
));
1171 f
<< stringf(";\n");
1173 f
<< stringf("%s" "end\n", indent
.c_str());
1177 // create a map : "edge clk" -> expressions within that clock domain
1178 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1179 clk_to_lof_body
[""] = std::vector
<std::string
>();
1180 std::string clk_domain_str
;
1181 // create a list of reg declarations
1182 std::vector
<std::string
> lof_reg_declarations
;
1184 int nread_ports
= cell
->parameters
[ID::RD_PORTS
].as_int();
1185 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1186 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1188 for (int i
=0; i
< nread_ports
; i
++)
1190 sig_rd_clk
= cell
->getPort(ID::RD_CLK
).extract(i
);
1191 sig_rd_en
= cell
->getPort(ID::RD_EN
).extract(i
);
1192 sig_rd_data
= cell
->getPort(ID::RD_DATA
).extract(i
*width
, width
);
1193 sig_rd_addr
= cell
->getPort(ID::RD_ADDR
).extract(i
*abits
, abits
);
1194 use_rd_clk
= cell
->parameters
[ID::RD_CLK_ENABLE
].extract(i
).as_bool();
1195 rd_clk_posedge
= cell
->parameters
[ID::RD_CLK_POLARITY
].extract(i
).as_bool();
1196 rd_transparent
= cell
->parameters
[ID::RD_TRANSPARENT
].extract(i
).as_bool();
1200 std::ostringstream os
;
1201 dump_sigspec(os
, sig_rd_clk
);
1202 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1203 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1204 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1206 if (!rd_transparent
)
1208 // for clocked read ports make something like:
1209 // reg [..] temp_id;
1210 // always @(posedge clk)
1211 // if (rd_en) temp_id <= array_reg[r_addr];
1212 // assign r_data = temp_id;
1213 std::string temp_id
= next_auto_id();
1214 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1216 std::ostringstream os
;
1217 if (sig_rd_en
!= RTLIL::SigBit(true))
1219 os
<< stringf("if (");
1220 dump_sigspec(os
, sig_rd_en
);
1221 os
<< stringf(") ");
1223 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1224 dump_sigspec(os
, sig_rd_addr
);
1225 os
<< stringf("];\n");
1226 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1229 std::ostringstream os
;
1230 dump_sigspec(os
, sig_rd_data
);
1231 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1232 clk_to_lof_body
[""].push_back(line
);
1237 // for rd-transparent read-ports make something like:
1238 // reg [..] temp_id;
1239 // always @(posedge clk)
1240 // temp_id <= r_addr;
1241 // assign r_data = array_reg[temp_id];
1242 std::string temp_id
= next_auto_id();
1243 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1245 std::ostringstream os
;
1246 dump_sigspec(os
, sig_rd_addr
);
1247 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1248 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1251 std::ostringstream os
;
1252 dump_sigspec(os
, sig_rd_data
);
1253 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1254 clk_to_lof_body
[""].push_back(line
);
1258 // for non-clocked read-ports make something like:
1259 // assign r_data = array_reg[r_addr];
1260 std::ostringstream os
, os2
;
1261 dump_sigspec(os
, sig_rd_data
);
1262 dump_sigspec(os2
, sig_rd_addr
);
1263 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1264 clk_to_lof_body
[""].push_back(line
);
1268 int nwrite_ports
= cell
->parameters
[ID::WR_PORTS
].as_int();
1269 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1270 bool wr_clk_posedge
;
1273 for (int i
=0; i
< nwrite_ports
; i
++)
1275 sig_wr_clk
= cell
->getPort(ID::WR_CLK
).extract(i
);
1276 sig_wr_data
= cell
->getPort(ID::WR_DATA
).extract(i
*width
, width
);
1277 sig_wr_addr
= cell
->getPort(ID::WR_ADDR
).extract(i
*abits
, abits
);
1278 sig_wr_en
= cell
->getPort(ID::WR_EN
).extract(i
*width
, width
);
1279 wr_clk_posedge
= cell
->parameters
[ID::WR_CLK_POLARITY
].extract(i
).as_bool();
1281 std::ostringstream os
;
1282 dump_sigspec(os
, sig_wr_clk
);
1283 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1284 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1285 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1287 // make something like:
1288 // always @(posedge clk)
1289 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1291 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1293 int start_i
= i
, width
= 1;
1294 SigBit wen_bit
= sig_wr_en
[i
];
1296 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1299 if (wen_bit
== State::S0
)
1302 std::ostringstream os
;
1303 if (wen_bit
!= State::S1
)
1305 os
<< stringf("if (");
1306 dump_sigspec(os
, wen_bit
);
1307 os
<< stringf(") ");
1309 os
<< stringf("%s[", mem_id
.c_str());
1310 dump_sigspec(os
, sig_wr_addr
);
1311 if (width
== GetSize(sig_wr_en
))
1312 os
<< stringf("] <= ");
1314 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1315 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1316 os
<< stringf(";\n");
1317 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1320 // Output Verilog that looks something like this:
1322 // always @(posedge CLK2) begin
1323 // _3_ <= memory[D1ADDR];
1325 // memory[A1ADDR] <= A1DATA;
1327 // memory[A2ADDR] <= A2DATA;
1330 // always @(negedge CLK1) begin
1332 // memory[C1ADDR] <= C1DATA;
1335 // assign D1DATA = _3_;
1336 // assign D2DATA <= memory[D2ADDR];
1338 // the reg ... definitions
1339 for(auto ®
: lof_reg_declarations
)
1341 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1343 // the block of expressions by clock domain
1344 for(auto &pair
: clk_to_lof_body
)
1346 std::string clk_domain
= pair
.first
;
1347 std::vector
<std::string
> lof_lines
= pair
.second
;
1348 if( clk_domain
!= "")
1350 f
<< stringf("%s" "always%s @(%s) begin\n", indent
.c_str(), systemverilog
? "_ff" : "", clk_domain
.c_str());
1351 for(auto &line
: lof_lines
)
1352 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1353 f
<< stringf("%s" "end\n", indent
.c_str());
1357 // the non-clocked assignments
1358 for(auto &line
: lof_lines
)
1359 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1366 if (cell
->type
.in(ID($
assert), ID($assume
), ID($cover
)))
1368 f
<< stringf("%s" "always%s if (", indent
.c_str(), systemverilog
? "_comb" : " @*");
1369 dump_sigspec(f
, cell
->getPort(ID::EN
));
1370 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1371 dump_sigspec(f
, cell
->getPort(ID::A
));
1372 f
<< stringf(");\n");
1376 if (cell
->type
.in(ID($specify2
), ID($specify3
)))
1378 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1380 SigSpec en
= cell
->getPort(ID::EN
);
1381 if (en
!= State::S1
) {
1382 f
<< stringf("if (");
1383 dump_sigspec(f
, cell
->getPort(ID::EN
));
1388 if (cell
->type
== ID($specify3
) && cell
->getParam(ID::EDGE_EN
).as_bool())
1389 f
<< (cell
->getParam(ID::EDGE_POL
).as_bool() ? "posedge ": "negedge ");
1391 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1394 if (cell
->getParam(ID::SRC_DST_PEN
).as_bool())
1395 f
<< (cell
->getParam(ID::SRC_DST_POL
).as_bool() ? "+": "-");
1396 f
<< (cell
->getParam(ID::FULL
).as_bool() ? "*> ": "=> ");
1398 if (cell
->type
== ID($specify3
)) {
1400 dump_sigspec(f
, cell
->getPort(ID::DST
));
1402 if (cell
->getParam(ID::DAT_DST_PEN
).as_bool())
1403 f
<< (cell
->getParam(ID::DAT_DST_POL
).as_bool() ? "+": "-");
1405 dump_sigspec(f
, cell
->getPort(ID::DAT
));
1408 dump_sigspec(f
, cell
->getPort(ID::DST
));
1411 bool bak_decimal
= decimal
;
1415 dump_const(f
, cell
->getParam(ID::T_RISE_MIN
));
1417 dump_const(f
, cell
->getParam(ID::T_RISE_TYP
));
1419 dump_const(f
, cell
->getParam(ID::T_RISE_MAX
));
1421 dump_const(f
, cell
->getParam(ID::T_FALL_MIN
));
1423 dump_const(f
, cell
->getParam(ID::T_FALL_TYP
));
1425 dump_const(f
, cell
->getParam(ID::T_FALL_MAX
));
1428 decimal
= bak_decimal
;
1430 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1434 if (cell
->type
== ID($specrule
))
1436 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1438 IdString spec_type
= cell
->getParam(ID::TYPE
).decode_string();
1439 f
<< stringf("%s(", spec_type
.c_str());
1441 if (cell
->getParam(ID::SRC_PEN
).as_bool())
1442 f
<< (cell
->getParam(ID::SRC_POL
).as_bool() ? "posedge ": "negedge ");
1443 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1445 if (cell
->getPort(ID::SRC_EN
) != State::S1
) {
1447 dump_sigspec(f
, cell
->getPort(ID::SRC_EN
));
1451 if (cell
->getParam(ID::DST_PEN
).as_bool())
1452 f
<< (cell
->getParam(ID::DST_POL
).as_bool() ? "posedge ": "negedge ");
1453 dump_sigspec(f
, cell
->getPort(ID::DST
));
1455 if (cell
->getPort(ID::DST_EN
) != State::S1
) {
1457 dump_sigspec(f
, cell
->getPort(ID::DST_EN
));
1460 bool bak_decimal
= decimal
;
1464 dump_const(f
, cell
->getParam(ID::T_LIMIT_MIN
));
1466 dump_const(f
, cell
->getParam(ID::T_LIMIT_TYP
));
1468 dump_const(f
, cell
->getParam(ID::T_LIMIT_MAX
));
1470 if (spec_type
.in(ID($setuphold
), ID($recrem
), ID($fullskew
))) {
1472 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MIN
));
1474 dump_const(f
, cell
->getParam(ID::T_LIMIT2_TYP
));
1476 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MAX
));
1480 decimal
= bak_decimal
;
1482 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1486 // FIXME: $memrd, $memwr, $fsm
1491 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1493 if (cell
->type
[0] == '$' && !noexpr
) {
1494 if (dump_cell_expr(f
, indent
, cell
))
1498 dump_attributes(f
, indent
, cell
->attributes
);
1499 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1501 if (!defparam
&& cell
->parameters
.size() > 0) {
1502 f
<< stringf(" #(");
1503 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1504 if (it
!= cell
->parameters
.begin())
1506 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1507 dump_const(f
, it
->second
);
1510 f
<< stringf("\n%s" ")", indent
.c_str());
1513 std::string cell_name
= cellname(cell
);
1514 if (cell_name
!= id(cell
->name
))
1515 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1517 f
<< stringf(" %s (", cell_name
.c_str());
1519 bool first_arg
= true;
1520 std::set
<RTLIL::IdString
> numbered_ports
;
1521 for (int i
= 1; true; i
++) {
1523 snprintf(str
, 16, "$%d", i
);
1524 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1525 if (it
->first
!= str
)
1530 f
<< stringf("\n%s ", indent
.c_str());
1531 dump_sigspec(f
, it
->second
);
1532 numbered_ports
.insert(it
->first
);
1533 goto found_numbered_port
;
1536 found_numbered_port
:;
1538 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1539 if (numbered_ports
.count(it
->first
))
1544 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1545 if (it
->second
.size() > 0)
1546 dump_sigspec(f
, it
->second
);
1549 f
<< stringf("\n%s" ");\n", indent
.c_str());
1551 if (defparam
&& cell
->parameters
.size() > 0) {
1552 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1553 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1554 dump_const(f
, it
->second
);
1555 f
<< stringf(";\n");
1559 if (siminit
&& RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
))) {
1560 std::stringstream ss
;
1561 dump_reg_init(ss
, cell
->getPort(ID::Q
));
1562 if (!ss
.str().empty()) {
1563 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1570 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1572 f
<< stringf("%s" "assign ", indent
.c_str());
1573 dump_sigspec(f
, left
);
1574 f
<< stringf(" = ");
1575 dump_sigspec(f
, right
);
1576 f
<< stringf(";\n");
1579 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1581 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1583 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1585 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1586 f
<< stringf("%s" "begin\n", indent
.c_str());
1588 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1589 if (it
->first
.size() == 0)
1591 f
<< stringf("%s ", indent
.c_str());
1592 dump_sigspec(f
, it
->first
);
1593 f
<< stringf(" = ");
1594 dump_sigspec(f
, it
->second
);
1595 f
<< stringf(";\n");
1598 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1599 dump_proc_switch(f
, indent
+ " ", *it
);
1601 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1602 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1604 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1605 f
<< stringf("%s" "end\n", indent
.c_str());
1608 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1610 if (sw
->signal
.size() == 0) {
1611 f
<< stringf("%s" "begin\n", indent
.c_str());
1612 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1613 if ((*it
)->compare
.size() == 0)
1614 dump_case_body(f
, indent
+ " ", *it
);
1616 f
<< stringf("%s" "end\n", indent
.c_str());
1620 dump_attributes(f
, indent
, sw
->attributes
);
1621 f
<< stringf("%s" "casez (", indent
.c_str());
1622 dump_sigspec(f
, sw
->signal
);
1623 f
<< stringf(")\n");
1625 bool got_default
= false;
1626 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1627 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1628 if ((*it
)->compare
.size() == 0) {
1631 f
<< stringf("%s default", indent
.c_str());
1634 f
<< stringf("%s ", indent
.c_str());
1635 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1638 dump_sigspec(f
, (*it
)->compare
[i
]);
1641 f
<< stringf(":\n");
1642 dump_case_body(f
, indent
+ " ", *it
);
1645 f
<< stringf("%s" "endcase\n", indent
.c_str());
1648 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1650 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1651 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1652 case_body_find_regs(*it2
);
1654 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1655 for (auto &c
: it
->first
.chunks())
1657 reg_wires
.insert(c
.wire
->name
);
1661 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1664 case_body_find_regs(&proc
->root_case
);
1665 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1666 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1667 for (auto &c
: it2
->first
.chunks())
1669 reg_wires
.insert(c
.wire
->name
);
1674 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1676 f
<< indent
+ " " << "if (" << id("\\initial") << ") begin end\n";
1677 dump_case_body(f
, indent
, &proc
->root_case
, true);
1679 std::string backup_indent
= indent
;
1681 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1683 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1684 indent
= backup_indent
;
1686 if (sync
->type
== RTLIL::STa
) {
1687 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1688 } else if (sync
->type
== RTLIL::STi
) {
1689 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1691 f
<< stringf("%s" "always%s @(", indent
.c_str(), systemverilog
? "_ff" : "");
1692 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1693 f
<< stringf("posedge ");
1694 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1695 f
<< stringf("negedge ");
1696 dump_sigspec(f
, sync
->signal
);
1697 f
<< stringf(") begin\n");
1699 std::string ends
= indent
+ "end\n";
1702 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1703 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1704 dump_sigspec(f
, sync
->signal
);
1705 f
<< stringf(") begin\n");
1706 ends
= indent
+ "end\n" + ends
;
1710 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1711 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1712 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1713 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1714 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1715 dump_sigspec(f
, sync2
->signal
);
1716 f
<< stringf(") begin\n");
1717 ends
= indent
+ "end\n" + ends
;
1723 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1724 if (it
->first
.size() == 0)
1726 f
<< stringf("%s ", indent
.c_str());
1727 dump_sigspec(f
, it
->first
);
1728 f
<< stringf(" <= ");
1729 dump_sigspec(f
, it
->second
);
1730 f
<< stringf(";\n");
1733 f
<< stringf("%s", ends
.c_str());
1737 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1740 reset_auto_counter(module
);
1741 active_module
= module
;
1742 active_sigmap
.set(module
);
1743 active_initdata
.clear();
1745 for (auto wire
: module
->wires())
1746 if (wire
->attributes
.count(ID::init
)) {
1747 SigSpec sig
= active_sigmap(wire
);
1748 Const val
= wire
->attributes
.at(ID::init
);
1749 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1750 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1751 active_initdata
[sig
[i
]] = val
[i
];
1754 if (!module
->processes
.empty())
1755 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1756 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1757 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1758 "processes to logic networks and registers.\n", log_id(module
));
1761 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1762 dump_process(f
, indent
+ " ", it
->second
, true);
1766 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1767 for (auto cell
: module
->cells())
1769 if (!RTLIL::builtin_ff_cell_types().count(cell
->type
) || !cell
->hasPort(ID::Q
) || cell
->type
.in(ID($ff
), ID($_FF_
)))
1772 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
1774 if (sig
.is_chunk()) {
1775 RTLIL::SigChunk chunk
= sig
.as_chunk();
1776 if (chunk
.wire
!= NULL
)
1777 for (int i
= 0; i
< chunk
.width
; i
++)
1778 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1781 for (auto wire
: module
->wires())
1783 for (int i
= 0; i
< wire
->width
; i
++)
1784 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1785 goto this_wire_aint_reg
;
1787 reg_wires
.insert(wire
->name
);
1788 this_wire_aint_reg
:;
1792 dump_attributes(f
, indent
, module
->attributes
, '\n', /*modattr=*/true);
1793 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1794 bool keep_running
= true;
1795 for (int port_id
= 1; keep_running
; port_id
++) {
1796 keep_running
= false;
1797 for (auto wire
: module
->wires()) {
1798 if (wire
->port_id
== port_id
) {
1801 f
<< stringf("%s", id(wire
->name
).c_str());
1802 keep_running
= true;
1807 f
<< stringf(");\n");
1809 if (!systemverilog
&& !module
->processes
.empty())
1810 f
<< indent
+ " " << "reg " << id("\\initial") << " = 0;\n";
1812 for (auto w
: module
->wires())
1813 dump_wire(f
, indent
+ " ", w
);
1815 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1816 dump_memory(f
, indent
+ " ", it
->second
);
1818 for (auto cell
: module
->cells())
1819 dump_cell(f
, indent
+ " ", cell
);
1821 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1822 dump_process(f
, indent
+ " ", it
->second
);
1824 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1825 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1827 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1828 active_module
= NULL
;
1829 active_sigmap
.clear();
1830 active_initdata
.clear();
1833 struct VerilogBackend
: public Backend
{
1834 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1835 void help() override
1837 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1839 log(" write_verilog [options] [filename]\n");
1841 log("Write the current design to a Verilog file.\n");
1844 log(" with this option, SystemVerilog constructs like always_comb are used\n");
1846 log(" -norename\n");
1847 log(" without this option all internal object names (the ones with a dollar\n");
1848 log(" instead of a backslash prefix) are changed to short names in the\n");
1849 log(" format '_<number>_'.\n");
1851 log(" -renameprefix <prefix>\n");
1852 log(" insert this prefix in front of auto-generated instance names\n");
1855 log(" with this option no attributes are included in the output\n");
1857 log(" -attr2comment\n");
1858 log(" with this option attributes are included as comments in the output\n");
1861 log(" without this option all internal cells are converted to Verilog\n");
1862 log(" expressions.\n");
1865 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1866 log(" in -noexpr mode.\n");
1869 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1870 log(" not bit pattern. This option deactivates this feature and instead\n");
1871 log(" will write out all constants in binary.\n");
1874 log(" dump 32-bit constants in decimal and without size and radix\n");
1877 log(" constant values that are compatible with hex output are usually\n");
1878 log(" dumped as hex values. This option deactivates this feature and\n");
1879 log(" instead will write out all constants in binary.\n");
1882 log(" Parameters and attributes that are specified as strings in the\n");
1883 log(" original input will be output as strings by this back-end. This\n");
1884 log(" deactivates this feature and instead will write string constants\n");
1885 log(" as binary numbers.\n");
1888 log(" instead of initializing memories using assignments to individual\n");
1889 log(" elements, use the '$readmemh' function to read initialization data\n");
1890 log(" from a file. This data is written to a file named by appending\n");
1891 log(" a sequential index to the Verilog filename and replacing the extension\n");
1892 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
1893 log(" 'foo-2.mem' and so on.\n");
1895 log(" -defparam\n");
1896 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1897 log(" cell parameters.\n");
1899 log(" -blackboxes\n");
1900 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1901 log(" this option set only the modules with the 'blackbox' attribute\n");
1902 log(" are written to the output file.\n");
1904 log(" -selected\n");
1905 log(" only write selected modules. modules must be selected entirely or\n");
1906 log(" not at all.\n");
1909 log(" verbose output (print new names of all renamed wires and cells)\n");
1911 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1912 log("always blocks. This frontend should only be used to export an RTLIL\n");
1913 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1914 log("processes to logic networks and registers. A warning is generated when\n");
1915 log("this command is called on a design with RTLIL processes.\n");
1918 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1920 log_header(design
, "Executing Verilog backend.\n");
1925 attr2comment
= false;
1936 bool blackboxes
= false;
1937 bool selected
= false;
1939 auto_name_map
.clear();
1943 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1944 std::string arg
= args
[argidx
];
1946 systemverilog
= true;
1949 if (arg
== "-norename") {
1953 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1954 auto_prefix
= args
[++argidx
];
1957 if (arg
== "-noattr") {
1961 if (arg
== "-attr2comment") {
1962 attr2comment
= true;
1965 if (arg
== "-noexpr") {
1969 if (arg
== "-nodec") {
1973 if (arg
== "-nohex") {
1977 if (arg
== "-nostr") {
1981 if (arg
== "-extmem") {
1986 if (arg
== "-defparam") {
1990 if (arg
== "-decimal") {
1994 if (arg
== "-siminit") {
1998 if (arg
== "-blackboxes") {
2002 if (arg
== "-selected") {
2012 extra_args(f
, filename
, args
, argidx
);
2015 if (filename
== "<stdout>")
2016 log_cmd_error("Option -extmem must be used with a filename.\n");
2017 extmem_prefix
= filename
.substr(0, filename
.rfind('.'));
2022 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
2023 for (auto module
: design
->modules()) {
2024 if (module
->get_blackbox_attribute() != blackboxes
)
2026 if (selected
&& !design
->selected_whole_module(module
->name
)) {
2027 if (design
->selected_module(module
->name
))
2028 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module
->name
));
2031 log("Dumping module `%s'.\n", module
->name
.c_str());
2032 dump_module(*f
, "", module
);
2035 auto_name_map
.clear();
2040 PRIVATE_NAMESPACE_END