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"
29 #include "kernel/mem.h"
36 PRIVATE_NAMESPACE_BEGIN
38 bool verbose
, norename
, noattr
, attr2comment
, noexpr
, nodec
, nohex
, nostr
, extmem
, defparam
, decimal
, siminit
, systemverilog
;
39 int auto_name_counter
, auto_name_offset
, auto_name_digits
, extmem_counter
;
40 std::map
<RTLIL::IdString
, int> auto_name_map
;
41 std::set
<RTLIL::IdString
> reg_wires
;
42 std::string auto_prefix
, extmem_prefix
;
44 RTLIL::Module
*active_module
;
45 dict
<RTLIL::SigBit
, RTLIL::State
> active_initdata
;
48 void reset_auto_counter_id(RTLIL::IdString id
, bool may_rename
)
50 const char *str
= id
.c_str();
52 if (*str
== '$' && may_rename
&& !norename
)
53 auto_name_map
[id
] = auto_name_counter
++;
55 if (str
[0] != '\\' || str
[1] != '_' || str
[2] == 0)
58 for (int i
= 2; str
[i
] != 0; i
++) {
59 if (str
[i
] == '_' && str
[i
+1] == 0)
61 if (str
[i
] < '0' || str
[i
] > '9')
65 int num
= atoi(str
+2);
66 if (num
>= auto_name_offset
)
67 auto_name_offset
= num
+ 1;
70 void reset_auto_counter(RTLIL::Module
*module
)
72 auto_name_map
.clear();
73 auto_name_counter
= 0;
76 reset_auto_counter_id(module
->name
, false);
78 for (auto w
: module
->wires())
79 reset_auto_counter_id(w
->name
, true);
81 for (auto cell
: module
->cells()) {
82 reset_auto_counter_id(cell
->name
, true);
83 reset_auto_counter_id(cell
->type
, false);
86 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
87 reset_auto_counter_id(it
->second
->name
, false);
90 for (size_t i
= 10; i
< auto_name_offset
+ auto_name_map
.size(); i
= i
*10)
94 for (auto it
= auto_name_map
.begin(); it
!= auto_name_map
.end(); ++it
)
95 log(" renaming `%s' to `%s_%0*d_'.\n", it
->first
.c_str(), auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ it
->second
);
98 std::string
next_auto_id()
100 return stringf("%s_%0*d_", auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ auto_name_counter
++);
103 std::string
id(RTLIL::IdString internal_id
, bool may_rename
= true)
105 const char *str
= internal_id
.c_str();
106 bool do_escape
= false;
108 if (may_rename
&& auto_name_map
.count(internal_id
) != 0)
109 return stringf("%s_%0*d_", auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ auto_name_map
[internal_id
]);
114 if ('0' <= *str
&& *str
<= '9')
117 for (int i
= 0; str
[i
]; i
++)
119 if ('0' <= str
[i
] && str
[i
] <= '9')
121 if ('a' <= str
[i
] && str
[i
] <= 'z')
123 if ('A' <= str
[i
] && str
[i
] <= 'Z')
131 const pool
<string
> keywords
= {
132 // IEEE 1800-2017 Annex B
133 "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
134 "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
135 "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
136 "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
137 "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
138 "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
139 "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
140 "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
141 "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
142 "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
143 "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
144 "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
145 "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
146 "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
147 "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
148 "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
149 "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
150 "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
151 "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
152 "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
153 "wildcard", "wire", "with", "within", "wor", "xnor", "xor",
155 if (keywords
.count(str
))
159 return "\\" + std::string(str
) + " ";
160 return std::string(str
);
163 bool is_reg_wire(RTLIL::SigSpec sig
, std::string
®_name
)
165 if (!sig
.is_chunk() || sig
.as_chunk().wire
== NULL
)
168 RTLIL::SigChunk chunk
= sig
.as_chunk();
170 if (reg_wires
.count(chunk
.wire
->name
) == 0)
173 reg_name
= id(chunk
.wire
->name
);
174 if (sig
.size() != chunk
.wire
->width
) {
176 reg_name
+= stringf("[%d]", chunk
.wire
->start_offset
+ chunk
.offset
);
177 else if (chunk
.wire
->upto
)
178 reg_name
+= stringf("[%d:%d]", (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
179 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
181 reg_name
+= stringf("[%d:%d]", chunk
.wire
->start_offset
+ chunk
.offset
+ chunk
.width
- 1,
182 chunk
.wire
->start_offset
+ chunk
.offset
);
188 void dump_const(std::ostream
&f
, const RTLIL::Const
&data
, int width
= -1, int offset
= 0, bool no_decimal
= false, bool escape_comment
= false)
190 bool set_signed
= (data
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
192 width
= data
.bits
.size() - offset
;
194 // See IEEE 1364-2005 Clause 5.1.14.
200 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
201 if (width
== 32 && !no_decimal
&& !nodec
) {
203 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
204 log_assert(i
< (int)data
.bits
.size());
205 if (data
.bits
[i
] != State::S0
&& data
.bits
[i
] != State::S1
)
207 if (data
.bits
[i
] == State::S1
)
208 val
|= 1 << (i
- offset
);
211 f
<< stringf("%d", val
);
212 else if (set_signed
&& val
< 0)
213 f
<< stringf("-32'sd%u", -val
);
215 f
<< stringf("32'%sd%u", set_signed
? "s" : "", val
);
220 vector
<char> bin_digits
, hex_digits
;
221 for (int i
= offset
; i
< offset
+width
; i
++) {
222 log_assert(i
< (int)data
.bits
.size());
223 switch (data
.bits
[i
]) {
224 case State::S0
: bin_digits
.push_back('0'); break;
225 case State::S1
: bin_digits
.push_back('1'); break;
226 case RTLIL::Sx
: bin_digits
.push_back('x'); break;
227 case RTLIL::Sz
: bin_digits
.push_back('z'); break;
228 case RTLIL::Sa
: bin_digits
.push_back('?'); break;
229 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
232 if (GetSize(bin_digits
) == 0)
234 while (GetSize(bin_digits
) % 4 != 0)
235 if (bin_digits
.back() == '1')
236 bin_digits
.push_back('0');
238 bin_digits
.push_back(bin_digits
.back());
239 for (int i
= 0; i
< GetSize(bin_digits
); i
+= 4)
241 char bit_3
= bin_digits
[i
+3];
242 char bit_2
= bin_digits
[i
+2];
243 char bit_1
= bin_digits
[i
+1];
244 char bit_0
= bin_digits
[i
+0];
245 if (bit_3
== 'x' || bit_2
== 'x' || bit_1
== 'x' || bit_0
== 'x') {
246 if (bit_3
!= 'x' || bit_2
!= 'x' || bit_1
!= 'x' || bit_0
!= 'x')
248 hex_digits
.push_back('x');
251 if (bit_3
== 'z' || bit_2
== 'z' || bit_1
== 'z' || bit_0
== 'z') {
252 if (bit_3
!= 'z' || bit_2
!= 'z' || bit_1
!= 'z' || bit_0
!= 'z')
254 hex_digits
.push_back('z');
257 if (bit_3
== '?' || bit_2
== '?' || bit_1
== '?' || bit_0
== '?') {
258 if (bit_3
!= '?' || bit_2
!= '?' || bit_1
!= '?' || bit_0
!= '?')
260 hex_digits
.push_back('?');
263 int val
= 8*(bit_3
- '0') + 4*(bit_2
- '0') + 2*(bit_1
- '0') + (bit_0
- '0');
264 hex_digits
.push_back(val
< 10 ? '0' + val
: 'a' + val
- 10);
266 f
<< stringf("%d'%sh", width
, set_signed
? "s" : "");
267 for (int i
= GetSize(hex_digits
)-1; i
>= 0; i
--)
272 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
275 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
276 log_assert(i
< (int)data
.bits
.size());
277 switch (data
.bits
[i
]) {
278 case State::S0
: f
<< stringf("0"); break;
279 case State::S1
: f
<< stringf("1"); break;
280 case RTLIL::Sx
: f
<< stringf("x"); break;
281 case RTLIL::Sz
: f
<< stringf("z"); break;
282 case RTLIL::Sa
: f
<< stringf("?"); break;
283 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
288 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
290 std::string str
= data
.decode_string();
291 for (size_t i
= 0; i
< str
.size(); i
++) {
294 else if (str
[i
] == '\t')
296 else if (str
[i
] < 32)
297 f
<< stringf("\\%03o", str
[i
]);
298 else if (str
[i
] == '"')
299 f
<< stringf("\\\"");
300 else if (str
[i
] == '\\')
301 f
<< stringf("\\\\");
302 else if (str
[i
] == '/' && escape_comment
&& i
> 0 && str
[i
-1] == '*')
307 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
312 void dump_reg_init(std::ostream
&f
, SigSpec sig
)
315 bool gotinit
= false;
317 for (auto bit
: active_sigmap(sig
)) {
318 if (active_initdata
.count(bit
)) {
319 initval
.bits
.push_back(active_initdata
.at(bit
));
322 initval
.bits
.push_back(State::Sx
);
328 dump_const(f
, initval
);
332 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
334 if (chunk
.wire
== NULL
) {
335 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
337 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0) {
338 f
<< stringf("%s", id(chunk
.wire
->name
).c_str());
339 } else if (chunk
.width
== 1) {
340 if (chunk
.wire
->upto
)
341 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
343 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
345 if (chunk
.wire
->upto
)
346 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
347 (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
348 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
350 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
351 (chunk
.offset
+ chunk
.width
- 1) + chunk
.wire
->start_offset
,
352 chunk
.offset
+ chunk
.wire
->start_offset
);
357 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
359 if (GetSize(sig
) == 0) {
363 if (sig
.is_chunk()) {
364 dump_sigchunk(f
, sig
.as_chunk());
367 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
368 if (it
!= sig
.chunks().rbegin())
370 dump_sigchunk(f
, *it
, true);
376 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)
382 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
383 if (it
->first
== ID::init
&& regattr
) continue;
384 f
<< stringf("%s" "%s %s", indent
.c_str(), as_comment
? "/*" : "(*", id(it
->first
).c_str());
386 if (modattr
&& (it
->second
== State::S0
|| it
->second
== Const(0)))
388 else if (modattr
&& (it
->second
== State::S1
|| it
->second
== Const(1)))
391 dump_const(f
, it
->second
, -1, 0, false, as_comment
);
392 f
<< stringf(" %s%c", as_comment
? "*/" : "*)", term
);
396 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
398 dump_attributes(f
, indent
, wire
->attributes
, '\n', /*modattr=*/false, /*regattr=*/reg_wires
.count(wire
->name
));
400 if (wire
->port_input
&& !wire
->port_output
)
401 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
402 else if (!wire
->port_input
&& wire
->port_output
)
403 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
404 else if (wire
->port_input
&& wire
->port_output
)
405 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
407 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
408 if (wire
->width
!= 1)
409 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
410 f
<< stringf("%s;\n", id(wire
->name
).c_str());
412 // do not use Verilog-2k "output reg" syntax in Verilog export
413 std::string range
= "";
414 if (wire
->width
!= 1) {
416 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
418 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
420 if (wire
->port_input
&& !wire
->port_output
)
421 f
<< stringf("%s" "input%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" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
424 if (wire
->port_input
&& wire
->port_output
)
425 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
426 if (reg_wires
.count(wire
->name
)) {
427 f
<< stringf("%s" "reg%s %s", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
428 if (wire
->attributes
.count(ID::init
)) {
430 dump_const(f
, wire
->attributes
.at(ID::init
));
433 } else if (!wire
->port_input
&& !wire
->port_output
)
434 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
438 void dump_memory(std::ostream
&f
, std::string indent
, Mem
&mem
)
440 std::string mem_id
= id(mem
.memid
);
442 dump_attributes(f
, indent
, mem
.attributes
);
443 f
<< stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent
.c_str(), mem
.width
-1, mem_id
.c_str(), mem
.size
+mem
.start_offset
-1, mem
.start_offset
);
445 // for memory block make something like:
446 // reg [7:0] memid [3:0];
450 if (!mem
.inits
.empty())
454 std::string extmem_filename
= stringf("%s-%d.mem", extmem_prefix
.c_str(), extmem_counter
++);
456 std::string extmem_filename_esc
;
457 for (auto c
: extmem_filename
)
460 extmem_filename_esc
+= "\\n";
462 extmem_filename_esc
+= "\\t";
464 extmem_filename_esc
+= stringf("\\%03o", c
);
466 extmem_filename_esc
+= "\\\"";
468 extmem_filename_esc
+= "\\\\";
470 extmem_filename_esc
+= c
;
472 f
<< stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent
.c_str(), extmem_filename_esc
.c_str(), mem_id
.c_str());
474 std::ofstream
extmem_f(extmem_filename
, std::ofstream::trunc
);
476 log_error("Can't open file `%s' for writing: %s\n", extmem_filename
.c_str(), strerror(errno
));
479 Const data
= mem
.get_init_data();
480 for (int i
=0; i
<mem
.size
; i
++)
482 RTLIL::Const element
= data
.extract(i
*mem
.width
, mem
.width
);
483 for (int j
=0; j
<element
.size(); j
++)
485 switch (element
[element
.size()-j
-1])
487 case State::S0
: extmem_f
<< '0'; break;
488 case State::S1
: extmem_f
<< '1'; break;
489 case State::Sx
: extmem_f
<< 'x'; break;
490 case State::Sz
: extmem_f
<< 'z'; break;
491 case State::Sa
: extmem_f
<< '_'; break;
492 case State::Sm
: log_error("Found marker state in final netlist.");
501 f
<< stringf("%s" "initial begin\n", indent
.c_str());
502 for (auto &init
: mem
.inits
) {
503 int words
= GetSize(init
.data
) / mem
.width
;
504 int start
= init
.addr
.as_int();
505 for (int i
=0; i
<words
; i
++)
507 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
+ start
);
508 dump_const(f
, init
.data
.extract(i
*mem
.width
, mem
.width
));
512 f
<< stringf("%s" "end\n", indent
.c_str());
516 // create a map : "edge clk" -> expressions within that clock domain
517 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
518 clk_to_lof_body
[""] = std::vector
<std::string
>();
519 std::string clk_domain_str
;
520 // create a list of reg declarations
521 std::vector
<std::string
> lof_reg_declarations
;
524 for (auto &port
: mem
.rd_ports
)
529 std::ostringstream os
;
530 dump_sigspec(os
, port
.clk
);
531 clk_domain_str
= stringf("%sedge %s", port
.clk_polarity
? "pos" : "neg", os
.str().c_str());
532 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
533 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
535 if (!port
.transparent
)
537 // for clocked read ports make something like:
539 // always @(posedge clk)
540 // if (rd_en) temp_id <= array_reg[r_addr];
541 // assign r_data = temp_id;
542 std::string temp_id
= next_auto_id();
543 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", port
.data
.size() - 1, temp_id
.c_str()) );
545 std::ostringstream os
;
546 if (port
.en
!= RTLIL::SigBit(true))
548 os
<< stringf("if (");
549 dump_sigspec(os
, port
.en
);
552 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
553 dump_sigspec(os
, port
.addr
);
554 os
<< stringf("];\n");
555 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
558 std::ostringstream os
;
559 dump_sigspec(os
, port
.data
);
560 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
561 clk_to_lof_body
[""].push_back(line
);
566 // for rd-transparent read-ports make something like:
568 // always @(posedge clk)
569 // temp_id <= r_addr;
570 // assign r_data = array_reg[temp_id];
571 std::string temp_id
= next_auto_id();
572 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", port
.addr
.size() - 1, temp_id
.c_str()) );
574 std::ostringstream os
;
575 dump_sigspec(os
, port
.addr
);
576 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
577 clk_to_lof_body
[clk_domain_str
].push_back(line
);
580 std::ostringstream os
;
581 dump_sigspec(os
, port
.data
);
582 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
583 clk_to_lof_body
[""].push_back(line
);
587 // for non-clocked read-ports make something like:
588 // assign r_data = array_reg[r_addr];
589 std::ostringstream os
, os2
;
590 dump_sigspec(os
, port
.data
);
591 dump_sigspec(os2
, port
.addr
);
592 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
593 clk_to_lof_body
[""].push_back(line
);
598 for (auto &port
: mem
.wr_ports
)
601 std::ostringstream os
;
602 dump_sigspec(os
, port
.clk
);
603 clk_domain_str
= stringf("%sedge %s", port
.clk_polarity
? "pos" : "neg", os
.str().c_str());
604 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
605 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
607 // make something like:
608 // always @(posedge clk)
609 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
611 for (int i
= 0; i
< GetSize(port
.en
); i
++)
613 int start_i
= i
, width
= 1;
614 SigBit wen_bit
= port
.en
[i
];
616 while (i
+1 < GetSize(port
.en
) && active_sigmap(port
.en
[i
+1]) == active_sigmap(wen_bit
))
619 if (wen_bit
== State::S0
)
622 std::ostringstream os
;
623 if (wen_bit
!= State::S1
)
625 os
<< stringf("if (");
626 dump_sigspec(os
, wen_bit
);
629 os
<< stringf("%s[", mem_id
.c_str());
630 dump_sigspec(os
, port
.addr
);
631 if (width
== GetSize(port
.en
))
632 os
<< stringf("] <= ");
634 os
<< stringf("][%d:%d] <= ", i
, start_i
);
635 dump_sigspec(os
, port
.data
.extract(start_i
, width
));
636 os
<< stringf(";\n");
637 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
640 // Output Verilog that looks something like this:
642 // always @(posedge CLK2) begin
643 // _3_ <= memory[D1ADDR];
645 // memory[A1ADDR] <= A1DATA;
647 // memory[A2ADDR] <= A2DATA;
650 // always @(negedge CLK1) begin
652 // memory[C1ADDR] <= C1DATA;
655 // assign D1DATA = _3_;
656 // assign D2DATA <= memory[D2ADDR];
658 // the reg ... definitions
659 for(auto ®
: lof_reg_declarations
)
661 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
663 // the block of expressions by clock domain
664 for(auto &pair
: clk_to_lof_body
)
666 std::string clk_domain
= pair
.first
;
667 std::vector
<std::string
> lof_lines
= pair
.second
;
668 if( clk_domain
!= "")
670 f
<< stringf("%s" "always%s @(%s) begin\n", indent
.c_str(), systemverilog
? "_ff" : "", clk_domain
.c_str());
671 for(auto &line
: lof_lines
)
672 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
673 f
<< stringf("%s" "end\n", indent
.c_str());
677 // the non-clocked assignments
678 for(auto &line
: lof_lines
)
679 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
684 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
686 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
687 f
<< stringf("$signed(");
688 dump_sigspec(f
, cell
->getPort("\\" + port
));
691 dump_sigspec(f
, cell
->getPort("\\" + port
));
694 std::string
cellname(RTLIL::Cell
*cell
)
696 if (!norename
&& cell
->name
[0] == '$' && RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
)))
698 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
699 if (GetSize(sig
) != 1 || sig
.is_fully_const())
700 goto no_special_reg_name
;
702 RTLIL::Wire
*wire
= sig
[0].wire
;
704 if (wire
->name
[0] != '\\')
705 goto no_special_reg_name
;
707 std::string cell_name
= wire
->name
.str();
709 size_t pos
= cell_name
.find('[');
710 if (pos
!= std::string::npos
)
711 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
713 cell_name
= cell_name
+ "_reg";
715 if (wire
->width
!= 1)
716 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
718 if (active_module
&& active_module
->count_id(cell_name
) > 0)
719 goto no_special_reg_name
;
721 return id(cell_name
);
726 return id(cell
->name
).c_str();
730 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
732 f
<< stringf("%s" "assign ", indent
.c_str());
733 dump_sigspec(f
, cell
->getPort(ID::Y
));
734 f
<< stringf(" = %s ", op
.c_str());
735 dump_attributes(f
, "", cell
->attributes
, ' ');
736 dump_cell_expr_port(f
, cell
, "A", true);
740 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
742 f
<< stringf("%s" "assign ", indent
.c_str());
743 dump_sigspec(f
, cell
->getPort(ID::Y
));
745 dump_cell_expr_port(f
, cell
, "A", true);
746 f
<< stringf(" %s ", op
.c_str());
747 dump_attributes(f
, "", cell
->attributes
, ' ');
748 dump_cell_expr_port(f
, cell
, "B", true);
752 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
754 if (cell
->type
== ID($_NOT_
)) {
755 f
<< stringf("%s" "assign ", indent
.c_str());
756 dump_sigspec(f
, cell
->getPort(ID::Y
));
759 dump_attributes(f
, "", cell
->attributes
, ' ');
760 dump_cell_expr_port(f
, cell
, "A", false);
765 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_OR_
), ID($_NOR_
), ID($_XOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
))) {
766 f
<< stringf("%s" "assign ", indent
.c_str());
767 dump_sigspec(f
, cell
->getPort(ID::Y
));
769 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
)))
771 dump_cell_expr_port(f
, cell
, "A", false);
773 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_ANDNOT_
)))
775 if (cell
->type
.in(ID($_OR_
), ID($_NOR_
), ID($_ORNOT_
)))
777 if (cell
->type
.in(ID($_XOR_
), ID($_XNOR_
)))
779 dump_attributes(f
, "", cell
->attributes
, ' ');
781 if (cell
->type
.in(ID($_ANDNOT_
), ID($_ORNOT_
)))
783 dump_cell_expr_port(f
, cell
, "B", false);
784 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
)))
790 if (cell
->type
== ID($_MUX_
)) {
791 f
<< stringf("%s" "assign ", indent
.c_str());
792 dump_sigspec(f
, cell
->getPort(ID::Y
));
794 dump_cell_expr_port(f
, cell
, "S", false);
796 dump_attributes(f
, "", cell
->attributes
, ' ');
797 dump_cell_expr_port(f
, cell
, "B", false);
799 dump_cell_expr_port(f
, cell
, "A", false);
804 if (cell
->type
== ID($_NMUX_
)) {
805 f
<< stringf("%s" "assign ", indent
.c_str());
806 dump_sigspec(f
, cell
->getPort(ID::Y
));
807 f
<< stringf(" = !(");
808 dump_cell_expr_port(f
, cell
, "S", false);
810 dump_attributes(f
, "", cell
->attributes
, ' ');
811 dump_cell_expr_port(f
, cell
, "B", false);
813 dump_cell_expr_port(f
, cell
, "A", false);
814 f
<< stringf(");\n");
818 if (cell
->type
.in(ID($_AOI3_
), ID($_OAI3_
))) {
819 f
<< stringf("%s" "assign ", indent
.c_str());
820 dump_sigspec(f
, cell
->getPort(ID::Y
));
821 f
<< stringf(" = ~((");
822 dump_cell_expr_port(f
, cell
, "A", false);
823 f
<< stringf(cell
->type
== ID($_AOI3_
) ? " & " : " | ");
824 dump_cell_expr_port(f
, cell
, "B", false);
825 f
<< stringf(cell
->type
== ID($_AOI3_
) ? ") |" : ") &");
826 dump_attributes(f
, "", cell
->attributes
, ' ');
828 dump_cell_expr_port(f
, cell
, "C", false);
829 f
<< stringf(");\n");
833 if (cell
->type
.in(ID($_AOI4_
), ID($_OAI4_
))) {
834 f
<< stringf("%s" "assign ", indent
.c_str());
835 dump_sigspec(f
, cell
->getPort(ID::Y
));
836 f
<< stringf(" = ~((");
837 dump_cell_expr_port(f
, cell
, "A", false);
838 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
839 dump_cell_expr_port(f
, cell
, "B", false);
840 f
<< stringf(cell
->type
== ID($_AOI4_
) ? ") |" : ") &");
841 dump_attributes(f
, "", cell
->attributes
, ' ');
843 dump_cell_expr_port(f
, cell
, "C", false);
844 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
845 dump_cell_expr_port(f
, cell
, "D", false);
846 f
<< stringf("));\n");
850 #define HANDLE_UNIOP(_type, _operator) \
851 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
852 #define HANDLE_BINOP(_type, _operator) \
853 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
855 HANDLE_UNIOP(ID($
not), "~")
856 HANDLE_UNIOP(ID($pos
), "+")
857 HANDLE_UNIOP(ID($neg
), "-")
859 HANDLE_BINOP(ID($
and), "&")
860 HANDLE_BINOP(ID($
or), "|")
861 HANDLE_BINOP(ID($
xor), "^")
862 HANDLE_BINOP(ID($xnor
), "~^")
864 HANDLE_UNIOP(ID($reduce_and
), "&")
865 HANDLE_UNIOP(ID($reduce_or
), "|")
866 HANDLE_UNIOP(ID($reduce_xor
), "^")
867 HANDLE_UNIOP(ID($reduce_xnor
), "~^")
868 HANDLE_UNIOP(ID($reduce_bool
), "|")
870 HANDLE_BINOP(ID($shl
), "<<")
871 HANDLE_BINOP(ID($shr
), ">>")
872 HANDLE_BINOP(ID($sshl
), "<<<")
873 HANDLE_BINOP(ID($sshr
), ">>>")
875 HANDLE_BINOP(ID($lt
), "<")
876 HANDLE_BINOP(ID($le
), "<=")
877 HANDLE_BINOP(ID($eq
), "==")
878 HANDLE_BINOP(ID($ne
), "!=")
879 HANDLE_BINOP(ID($eqx
), "===")
880 HANDLE_BINOP(ID($nex
), "!==")
881 HANDLE_BINOP(ID($ge
), ">=")
882 HANDLE_BINOP(ID($gt
), ">")
884 HANDLE_BINOP(ID($add
), "+")
885 HANDLE_BINOP(ID($sub
), "-")
886 HANDLE_BINOP(ID($mul
), "*")
887 HANDLE_BINOP(ID($div
), "/")
888 HANDLE_BINOP(ID($mod
), "%")
889 HANDLE_BINOP(ID($pow
), "**")
891 HANDLE_UNIOP(ID($logic_not
), "!")
892 HANDLE_BINOP(ID($logic_and
), "&&")
893 HANDLE_BINOP(ID($logic_or
), "||")
898 if (cell
->type
== ID($divfloor
))
900 // wire [MAXLEN+1:0] _0_, _1_, _2_;
901 // assign _0_ = $signed(A);
902 // assign _1_ = $signed(B);
903 // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
904 // assign Y = $signed(_2_) / $signed(_1_);
906 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
907 SigSpec sig_a
= cell
->getPort(ID::A
);
908 SigSpec sig_b
= cell
->getPort(ID::B
);
910 std::string buf_a
= next_auto_id();
911 std::string buf_b
= next_auto_id();
912 std::string buf_num
= next_auto_id();
913 int size_a
= GetSize(sig_a
);
914 int size_b
= GetSize(sig_b
);
915 int size_y
= GetSize(cell
->getPort(ID::Y
));
916 int size_max
= std::max(size_a
, std::max(size_b
, size_y
));
918 // intentionally one wider than maximum width
919 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());
920 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_a
.c_str());
921 dump_cell_expr_port(f
, cell
, "A", true);
923 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_b
.c_str());
924 dump_cell_expr_port(f
, cell
, "B", true);
927 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_num
.c_str());
929 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
930 f
<< stringf(" == ");
931 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
932 f
<< stringf(") || ");
933 dump_sigspec(f
, sig_a
);
934 f
<< stringf(" == 0 ? %s : ", buf_a
.c_str());
935 f
<< stringf("$signed(%s - (", buf_a
.c_str());
936 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
937 f
<< stringf(" ? %s + 1 : %s - 1));\n", buf_b
.c_str(), buf_b
.c_str());
940 f
<< stringf("%s" "assign ", indent
.c_str());
941 dump_sigspec(f
, cell
->getPort(ID::Y
));
942 f
<< stringf(" = $signed(%s) / ", buf_num
.c_str());
943 dump_attributes(f
, "", cell
->attributes
, ' ');
944 f
<< stringf("$signed(%s);\n", buf_b
.c_str());
947 // same as truncating division
948 dump_cell_expr_binop(f
, indent
, cell
, "/");
953 if (cell
->type
== ID($modfloor
))
955 // wire truncated = $signed(A) % $signed(B);
956 // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated);
958 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
959 SigSpec sig_a
= cell
->getPort(ID::A
);
960 SigSpec sig_b
= cell
->getPort(ID::B
);
962 std::string temp_id
= next_auto_id();
963 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
964 dump_cell_expr_port(f
, cell
, "A", true);
965 f
<< stringf(" %% ");
966 dump_attributes(f
, "", cell
->attributes
, ' ');
967 dump_cell_expr_port(f
, cell
, "B", true);
970 f
<< stringf("%s" "assign ", indent
.c_str());
971 dump_sigspec(f
, cell
->getPort(ID::Y
));
972 f
<< stringf(" = (");
973 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
974 f
<< stringf(" == ");
975 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
976 f
<< stringf(") || %s == 0 ? %s : ", temp_id
.c_str(), temp_id
.c_str());
977 dump_cell_expr_port(f
, cell
, "B", true);
978 f
<< stringf(" + $signed(%s);\n", temp_id
.c_str());
981 // same as truncating modulo
982 dump_cell_expr_binop(f
, indent
, cell
, "%");
987 if (cell
->type
== ID($shift
))
989 f
<< stringf("%s" "assign ", indent
.c_str());
990 dump_sigspec(f
, cell
->getPort(ID::Y
));
992 if (cell
->getParam(ID::B_SIGNED
).as_bool())
994 dump_cell_expr_port(f
, cell
, "B", true);
995 f
<< stringf(" < 0 ? ");
996 dump_cell_expr_port(f
, cell
, "A", true);
997 f
<< stringf(" << - ");
998 dump_sigspec(f
, cell
->getPort(ID::B
));
1000 dump_cell_expr_port(f
, cell
, "A", true);
1001 f
<< stringf(" >> ");
1002 dump_sigspec(f
, cell
->getPort(ID::B
));
1006 dump_cell_expr_port(f
, cell
, "A", true);
1007 f
<< stringf(" >> ");
1008 dump_sigspec(f
, cell
->getPort(ID::B
));
1010 f
<< stringf(";\n");
1014 if (cell
->type
== ID($shiftx
))
1016 std::string temp_id
= next_auto_id();
1017 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
1018 dump_sigspec(f
, cell
->getPort(ID::A
));
1019 f
<< stringf(";\n");
1021 f
<< stringf("%s" "assign ", indent
.c_str());
1022 dump_sigspec(f
, cell
->getPort(ID::Y
));
1023 f
<< stringf(" = %s[", temp_id
.c_str());
1024 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1025 f
<< stringf("$signed(");
1026 dump_sigspec(f
, cell
->getPort(ID::B
));
1027 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1029 f
<< stringf(" +: %d", cell
->getParam(ID::Y_WIDTH
).as_int());
1030 f
<< stringf("];\n");
1034 if (cell
->type
== ID($mux
))
1036 f
<< stringf("%s" "assign ", indent
.c_str());
1037 dump_sigspec(f
, cell
->getPort(ID::Y
));
1038 f
<< stringf(" = ");
1039 dump_sigspec(f
, cell
->getPort(ID::S
));
1040 f
<< stringf(" ? ");
1041 dump_attributes(f
, "", cell
->attributes
, ' ');
1042 dump_sigspec(f
, cell
->getPort(ID::B
));
1043 f
<< stringf(" : ");
1044 dump_sigspec(f
, cell
->getPort(ID::A
));
1045 f
<< stringf(";\n");
1049 if (cell
->type
== ID($pmux
))
1051 int width
= cell
->parameters
[ID::WIDTH
].as_int();
1052 int s_width
= cell
->getPort(ID::S
).size();
1053 std::string func_name
= cellname(cell
);
1055 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
1056 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
1057 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
1058 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
1060 dump_attributes(f
, indent
+ " ", cell
->attributes
);
1062 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
1063 f
<< stringf("%s" " casez (s)", indent
.c_str());
1064 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
1066 for (int i
= 0; i
< s_width
; i
++)
1068 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
1070 for (int j
= s_width
-1; j
>= 0; j
--)
1071 f
<< stringf("%c", j
== i
? '1' : '?');
1073 f
<< stringf(":\n");
1074 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
1077 f
<< stringf("%s" " default:\n", indent
.c_str());
1078 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
1080 f
<< stringf("%s" " endcase\n", indent
.c_str());
1081 f
<< stringf("%s" "endfunction\n", indent
.c_str());
1083 f
<< stringf("%s" "assign ", indent
.c_str());
1084 dump_sigspec(f
, cell
->getPort(ID::Y
));
1085 f
<< stringf(" = %s(", func_name
.c_str());
1086 dump_sigspec(f
, cell
->getPort(ID::A
));
1088 dump_sigspec(f
, cell
->getPort(ID::B
));
1090 dump_sigspec(f
, cell
->getPort(ID::S
));
1091 f
<< stringf(");\n");
1095 if (cell
->type
== ID($tribuf
))
1097 f
<< stringf("%s" "assign ", indent
.c_str());
1098 dump_sigspec(f
, cell
->getPort(ID::Y
));
1099 f
<< stringf(" = ");
1100 dump_sigspec(f
, cell
->getPort(ID::EN
));
1101 f
<< stringf(" ? ");
1102 dump_sigspec(f
, cell
->getPort(ID::A
));
1103 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at(ID::WIDTH
).as_int());
1107 if (cell
->type
== ID($slice
))
1109 f
<< stringf("%s" "assign ", indent
.c_str());
1110 dump_sigspec(f
, cell
->getPort(ID::Y
));
1111 f
<< stringf(" = ");
1112 dump_sigspec(f
, cell
->getPort(ID::A
));
1113 f
<< stringf(" >> %d;\n", cell
->parameters
.at(ID::OFFSET
).as_int());
1117 if (cell
->type
== ID($concat
))
1119 f
<< stringf("%s" "assign ", indent
.c_str());
1120 dump_sigspec(f
, cell
->getPort(ID::Y
));
1121 f
<< stringf(" = { ");
1122 dump_sigspec(f
, cell
->getPort(ID::B
));
1123 f
<< stringf(" , ");
1124 dump_sigspec(f
, cell
->getPort(ID::A
));
1125 f
<< stringf(" };\n");
1129 if (cell
->type
== ID($lut
))
1131 f
<< stringf("%s" "assign ", indent
.c_str());
1132 dump_sigspec(f
, cell
->getPort(ID::Y
));
1133 f
<< stringf(" = ");
1134 dump_const(f
, cell
->parameters
.at(ID::LUT
));
1135 f
<< stringf(" >> ");
1136 dump_attributes(f
, "", cell
->attributes
, ' ');
1137 dump_sigspec(f
, cell
->getPort(ID::A
));
1138 f
<< stringf(";\n");
1142 if (RTLIL::builtin_ff_cell_types().count(cell
->type
))
1144 FfData
ff(nullptr, cell
);
1146 // $ff / $_FF_ cell: not supported.
1147 if (ff
.has_d
&& !ff
.has_clk
&& !ff
.has_en
)
1150 std::string reg_name
= cellname(cell
);
1151 bool out_is_reg_wire
= is_reg_wire(ff
.sig_q
, reg_name
);
1153 if (!out_is_reg_wire
) {
1155 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
1157 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), ff
.width
-1, reg_name
.c_str());
1158 dump_reg_init(f
, ff
.sig_q
);
1162 // If the FF has CLR/SET inputs, emit every bit slice separately.
1163 int chunks
= ff
.has_sr
? ff
.width
: 1;
1164 bool chunky
= ff
.has_sr
&& ff
.width
!= 1;
1166 for (int i
= 0; i
< chunks
; i
++)
1169 Const val_arst
, val_srst
;
1170 std::string reg_bit_name
, sig_set_name
, sig_clr_name
, sig_arst_name
;
1172 reg_bit_name
= stringf("%s[%d]", reg_name
.c_str(), i
);
1174 sig_d
= ff
.sig_d
[i
];
1176 reg_bit_name
= reg_name
;
1181 val_arst
= chunky
? ff
.val_arst
[i
] : ff
.val_arst
;
1183 val_srst
= chunky
? ff
.val_srst
[i
] : ff
.val_srst
;
1185 // If there are constants in the sensitivity list, replace them with an intermediate wire
1187 if (ff
.sig_set
[i
].wire
== NULL
)
1189 sig_set_name
= next_auto_id();
1190 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_set_name
.c_str());
1191 dump_const(f
, ff
.sig_set
[i
].data
);
1192 f
<< stringf(";\n");
1194 if (ff
.sig_clr
[i
].wire
== NULL
)
1196 sig_clr_name
= next_auto_id();
1197 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_clr_name
.c_str());
1198 dump_const(f
, ff
.sig_clr
[i
].data
);
1199 f
<< stringf(";\n");
1201 } else if (ff
.has_arst
) {
1202 if (ff
.sig_arst
[i
].wire
== NULL
)
1204 sig_arst_name
= next_auto_id();
1205 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_arst_name
.c_str());
1206 dump_const(f
, ff
.sig_arst
[i
].data
);
1207 f
<< stringf(";\n");
1211 dump_attributes(f
, indent
, cell
->attributes
);
1215 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", ff
.pol_clk
? "pos" : "neg");
1216 dump_sigspec(f
, ff
.sig_clk
);
1218 f
<< stringf(", %sedge ", ff
.pol_set
? "pos" : "neg");
1219 if (ff
.sig_set
[i
].wire
== NULL
)
1220 f
<< stringf("%s", sig_set_name
.c_str());
1222 dump_sigspec(f
, ff
.sig_set
[i
]);
1224 f
<< stringf(", %sedge ", ff
.pol_clr
? "pos" : "neg");
1225 if (ff
.sig_clr
[i
].wire
== NULL
)
1226 f
<< stringf("%s", sig_clr_name
.c_str());
1228 dump_sigspec(f
, ff
.sig_clr
[i
]);
1230 } else if (ff
.has_arst
) {
1231 f
<< stringf(", %sedge ", ff
.pol_arst
? "pos" : "neg");
1232 if (ff
.sig_arst
[i
].wire
== NULL
)
1233 f
<< stringf("%s", sig_arst_name
.c_str());
1235 dump_sigspec(f
, ff
.sig_arst
);
1237 f
<< stringf(")\n");
1239 f
<< stringf("%s" " ", indent
.c_str());
1241 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1242 if (ff
.sig_clr
[i
].wire
== NULL
)
1243 f
<< stringf("%s", sig_clr_name
.c_str());
1245 dump_sigspec(f
, ff
.sig_clr
[i
]);
1246 f
<< stringf(") %s <= 1'b0;\n", reg_bit_name
.c_str());
1247 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1248 if (ff
.sig_set
[i
].wire
== NULL
)
1249 f
<< stringf("%s", sig_set_name
.c_str());
1251 dump_sigspec(f
, ff
.sig_set
[i
]);
1252 f
<< stringf(") %s <= 1'b1;\n", reg_bit_name
.c_str());
1253 f
<< stringf("%s" " else ", indent
.c_str());
1254 } else if (ff
.has_arst
) {
1255 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1256 if (ff
.sig_arst
[i
].wire
== NULL
)
1257 f
<< stringf("%s", sig_arst_name
.c_str());
1259 dump_sigspec(f
, ff
.sig_arst
);
1260 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1261 dump_sigspec(f
, val_arst
);
1262 f
<< stringf(";\n");
1263 f
<< stringf("%s" " else ", indent
.c_str());
1266 if (ff
.has_srst
&& ff
.has_en
&& ff
.ce_over_srst
) {
1267 f
<< stringf("if (%s", ff
.pol_en
? "" : "!");
1268 dump_sigspec(f
, ff
.sig_en
);
1269 f
<< stringf(")\n");
1270 f
<< stringf("%s" " if (%s", indent
.c_str(), ff
.pol_srst
? "" : "!");
1271 dump_sigspec(f
, ff
.sig_srst
);
1272 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1273 dump_sigspec(f
, val_srst
);
1274 f
<< stringf(";\n");
1275 f
<< stringf("%s" " else ", indent
.c_str());
1278 f
<< stringf("if (%s", ff
.pol_srst
? "" : "!");
1279 dump_sigspec(f
, ff
.sig_srst
);
1280 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1281 dump_sigspec(f
, val_srst
);
1282 f
<< stringf(";\n");
1283 f
<< stringf("%s" " else ", indent
.c_str());
1286 f
<< stringf("if (%s", ff
.pol_en
? "" : "!");
1287 dump_sigspec(f
, ff
.sig_en
);
1292 f
<< stringf("%s <= ", reg_bit_name
.c_str());
1293 dump_sigspec(f
, sig_d
);
1294 f
<< stringf(";\n");
1299 f
<< stringf("%s" "always%s\n", indent
.c_str(), systemverilog
? "_latch" : " @*");
1301 f
<< stringf("%s" " ", indent
.c_str());
1303 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1304 dump_sigspec(f
, ff
.sig_clr
[i
]);
1305 f
<< stringf(") %s = 1'b0;\n", reg_bit_name
.c_str());
1306 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1307 dump_sigspec(f
, ff
.sig_set
[i
]);
1308 f
<< stringf(") %s = 1'b1;\n", reg_bit_name
.c_str());
1310 f
<< stringf("%s" " else ", indent
.c_str());
1311 } else if (ff
.has_arst
) {
1312 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1313 dump_sigspec(f
, ff
.sig_arst
);
1314 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1315 dump_sigspec(f
, val_arst
);
1316 f
<< stringf(";\n");
1318 f
<< stringf("%s" " else ", indent
.c_str());
1321 f
<< stringf("if (%s", ff
.pol_en
? "" : "!");
1322 dump_sigspec(f
, ff
.sig_en
);
1323 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1324 dump_sigspec(f
, sig_d
);
1325 f
<< stringf(";\n");
1330 if (!out_is_reg_wire
) {
1331 f
<< stringf("%s" "assign ", indent
.c_str());
1332 dump_sigspec(f
, ff
.sig_q
);
1333 f
<< stringf(" = %s;\n", reg_name
.c_str());
1339 if (cell
->type
.in(ID($
assert), ID($assume
), ID($cover
)))
1341 f
<< stringf("%s" "always%s if (", indent
.c_str(), systemverilog
? "_comb" : " @*");
1342 dump_sigspec(f
, cell
->getPort(ID::EN
));
1343 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1344 dump_sigspec(f
, cell
->getPort(ID::A
));
1345 f
<< stringf(");\n");
1349 if (cell
->type
.in(ID($specify2
), ID($specify3
)))
1351 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1353 SigSpec en
= cell
->getPort(ID::EN
);
1354 if (en
!= State::S1
) {
1355 f
<< stringf("if (");
1356 dump_sigspec(f
, cell
->getPort(ID::EN
));
1361 if (cell
->type
== ID($specify3
) && cell
->getParam(ID::EDGE_EN
).as_bool())
1362 f
<< (cell
->getParam(ID::EDGE_POL
).as_bool() ? "posedge ": "negedge ");
1364 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1367 if (cell
->getParam(ID::SRC_DST_PEN
).as_bool())
1368 f
<< (cell
->getParam(ID::SRC_DST_POL
).as_bool() ? "+": "-");
1369 f
<< (cell
->getParam(ID::FULL
).as_bool() ? "*> ": "=> ");
1371 if (cell
->type
== ID($specify3
)) {
1373 dump_sigspec(f
, cell
->getPort(ID::DST
));
1375 if (cell
->getParam(ID::DAT_DST_PEN
).as_bool())
1376 f
<< (cell
->getParam(ID::DAT_DST_POL
).as_bool() ? "+": "-");
1378 dump_sigspec(f
, cell
->getPort(ID::DAT
));
1381 dump_sigspec(f
, cell
->getPort(ID::DST
));
1384 bool bak_decimal
= decimal
;
1388 dump_const(f
, cell
->getParam(ID::T_RISE_MIN
));
1390 dump_const(f
, cell
->getParam(ID::T_RISE_TYP
));
1392 dump_const(f
, cell
->getParam(ID::T_RISE_MAX
));
1394 dump_const(f
, cell
->getParam(ID::T_FALL_MIN
));
1396 dump_const(f
, cell
->getParam(ID::T_FALL_TYP
));
1398 dump_const(f
, cell
->getParam(ID::T_FALL_MAX
));
1401 decimal
= bak_decimal
;
1403 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1407 if (cell
->type
== ID($specrule
))
1409 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1411 IdString spec_type
= cell
->getParam(ID::TYPE
).decode_string();
1412 f
<< stringf("%s(", spec_type
.c_str());
1414 if (cell
->getParam(ID::SRC_PEN
).as_bool())
1415 f
<< (cell
->getParam(ID::SRC_POL
).as_bool() ? "posedge ": "negedge ");
1416 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1418 if (cell
->getPort(ID::SRC_EN
) != State::S1
) {
1420 dump_sigspec(f
, cell
->getPort(ID::SRC_EN
));
1424 if (cell
->getParam(ID::DST_PEN
).as_bool())
1425 f
<< (cell
->getParam(ID::DST_POL
).as_bool() ? "posedge ": "negedge ");
1426 dump_sigspec(f
, cell
->getPort(ID::DST
));
1428 if (cell
->getPort(ID::DST_EN
) != State::S1
) {
1430 dump_sigspec(f
, cell
->getPort(ID::DST_EN
));
1433 bool bak_decimal
= decimal
;
1437 dump_const(f
, cell
->getParam(ID::T_LIMIT_MIN
));
1439 dump_const(f
, cell
->getParam(ID::T_LIMIT_TYP
));
1441 dump_const(f
, cell
->getParam(ID::T_LIMIT_MAX
));
1443 if (spec_type
.in(ID($setuphold
), ID($recrem
), ID($fullskew
))) {
1445 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MIN
));
1447 dump_const(f
, cell
->getParam(ID::T_LIMIT2_TYP
));
1449 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MAX
));
1453 decimal
= bak_decimal
;
1455 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1464 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1466 // Handled by dump_memory
1467 if (cell
->type
.in(ID($mem
), ID($memwr
), ID($memrd
), ID($meminit
)))
1470 if (cell
->type
[0] == '$' && !noexpr
) {
1471 if (dump_cell_expr(f
, indent
, cell
))
1475 dump_attributes(f
, indent
, cell
->attributes
);
1476 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1478 if (!defparam
&& cell
->parameters
.size() > 0) {
1479 f
<< stringf(" #(");
1480 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1481 if (it
!= cell
->parameters
.begin())
1483 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1484 dump_const(f
, it
->second
);
1487 f
<< stringf("\n%s" ")", indent
.c_str());
1490 std::string cell_name
= cellname(cell
);
1491 if (cell_name
!= id(cell
->name
))
1492 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1494 f
<< stringf(" %s (", cell_name
.c_str());
1496 bool first_arg
= true;
1497 std::set
<RTLIL::IdString
> numbered_ports
;
1498 for (int i
= 1; true; i
++) {
1500 snprintf(str
, 16, "$%d", i
);
1501 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1502 if (it
->first
!= str
)
1507 f
<< stringf("\n%s ", indent
.c_str());
1508 dump_sigspec(f
, it
->second
);
1509 numbered_ports
.insert(it
->first
);
1510 goto found_numbered_port
;
1513 found_numbered_port
:;
1515 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1516 if (numbered_ports
.count(it
->first
))
1521 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1522 if (it
->second
.size() > 0)
1523 dump_sigspec(f
, it
->second
);
1526 f
<< stringf("\n%s" ");\n", indent
.c_str());
1528 if (defparam
&& cell
->parameters
.size() > 0) {
1529 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1530 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1531 dump_const(f
, it
->second
);
1532 f
<< stringf(";\n");
1536 if (siminit
&& RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
))) {
1537 std::stringstream ss
;
1538 dump_reg_init(ss
, cell
->getPort(ID::Q
));
1539 if (!ss
.str().empty()) {
1540 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1547 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1550 for (auto &chunk
: left
.chunks()) {
1551 f
<< stringf("%s" "assign ", indent
.c_str());
1552 dump_sigspec(f
, chunk
);
1553 f
<< stringf(" = ");
1554 dump_sigspec(f
, right
.extract(offset
, GetSize(chunk
)));
1555 f
<< stringf(";\n");
1556 offset
+= GetSize(chunk
);
1560 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1562 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1564 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1566 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1567 f
<< stringf("%s" "begin\n", indent
.c_str());
1569 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1570 if (it
->first
.size() == 0)
1572 f
<< stringf("%s ", indent
.c_str());
1573 dump_sigspec(f
, it
->first
);
1574 f
<< stringf(" = ");
1575 dump_sigspec(f
, it
->second
);
1576 f
<< stringf(";\n");
1579 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1580 dump_proc_switch(f
, indent
+ " ", *it
);
1582 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1583 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1585 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1586 f
<< stringf("%s" "end\n", indent
.c_str());
1589 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1591 if (sw
->signal
.size() == 0) {
1592 f
<< stringf("%s" "begin\n", indent
.c_str());
1593 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1594 if ((*it
)->compare
.size() == 0)
1595 dump_case_body(f
, indent
+ " ", *it
);
1597 f
<< stringf("%s" "end\n", indent
.c_str());
1601 dump_attributes(f
, indent
, sw
->attributes
);
1602 f
<< stringf("%s" "casez (", indent
.c_str());
1603 dump_sigspec(f
, sw
->signal
);
1604 f
<< stringf(")\n");
1606 bool got_default
= false;
1607 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1608 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1609 if ((*it
)->compare
.size() == 0) {
1612 f
<< stringf("%s default", indent
.c_str());
1615 f
<< stringf("%s ", indent
.c_str());
1616 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1619 dump_sigspec(f
, (*it
)->compare
[i
]);
1622 f
<< stringf(":\n");
1623 dump_case_body(f
, indent
+ " ", *it
);
1626 f
<< stringf("%s" "endcase\n", indent
.c_str());
1629 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1631 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1632 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1633 case_body_find_regs(*it2
);
1635 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1636 for (auto &c
: it
->first
.chunks())
1638 reg_wires
.insert(c
.wire
->name
);
1642 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1645 case_body_find_regs(&proc
->root_case
);
1646 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1647 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1648 for (auto &c
: it2
->first
.chunks())
1650 reg_wires
.insert(c
.wire
->name
);
1655 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1657 f
<< indent
+ " " << "if (" << id("\\initial") << ") begin end\n";
1658 dump_case_body(f
, indent
, &proc
->root_case
, true);
1660 std::string backup_indent
= indent
;
1662 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1664 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1665 indent
= backup_indent
;
1667 if (sync
->type
== RTLIL::STa
) {
1668 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1669 } else if (sync
->type
== RTLIL::STi
) {
1670 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1672 f
<< stringf("%s" "always%s @(", indent
.c_str(), systemverilog
? "_ff" : "");
1673 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1674 f
<< stringf("posedge ");
1675 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1676 f
<< stringf("negedge ");
1677 dump_sigspec(f
, sync
->signal
);
1678 f
<< stringf(") begin\n");
1680 std::string ends
= indent
+ "end\n";
1683 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1684 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1685 dump_sigspec(f
, sync
->signal
);
1686 f
<< stringf(") begin\n");
1687 ends
= indent
+ "end\n" + ends
;
1691 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1692 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1693 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1694 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1695 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1696 dump_sigspec(f
, sync2
->signal
);
1697 f
<< stringf(") begin\n");
1698 ends
= indent
+ "end\n" + ends
;
1704 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1705 if (it
->first
.size() == 0)
1707 f
<< stringf("%s ", indent
.c_str());
1708 dump_sigspec(f
, it
->first
);
1709 f
<< stringf(" <= ");
1710 dump_sigspec(f
, it
->second
);
1711 f
<< stringf(";\n");
1714 f
<< stringf("%s", ends
.c_str());
1718 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1721 reset_auto_counter(module
);
1722 active_module
= module
;
1723 active_sigmap
.set(module
);
1724 active_initdata
.clear();
1726 for (auto wire
: module
->wires())
1727 if (wire
->attributes
.count(ID::init
)) {
1728 SigSpec sig
= active_sigmap(wire
);
1729 Const val
= wire
->attributes
.at(ID::init
);
1730 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1731 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1732 active_initdata
[sig
[i
]] = val
[i
];
1735 if (!module
->processes
.empty())
1736 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1737 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1738 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1739 "processes to logic networks and registers.\n", log_id(module
));
1742 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1743 dump_process(f
, indent
+ " ", it
->second
, true);
1747 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1748 for (auto cell
: module
->cells())
1750 if (!RTLIL::builtin_ff_cell_types().count(cell
->type
) || !cell
->hasPort(ID::Q
) || cell
->type
.in(ID($ff
), ID($_FF_
)))
1753 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
1755 if (sig
.is_chunk()) {
1756 RTLIL::SigChunk chunk
= sig
.as_chunk();
1757 if (chunk
.wire
!= NULL
)
1758 for (int i
= 0; i
< chunk
.width
; i
++)
1759 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1762 for (auto wire
: module
->wires())
1764 for (int i
= 0; i
< wire
->width
; i
++)
1765 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1766 goto this_wire_aint_reg
;
1768 reg_wires
.insert(wire
->name
);
1769 this_wire_aint_reg
:;
1773 dump_attributes(f
, indent
, module
->attributes
, '\n', /*modattr=*/true);
1774 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1775 bool keep_running
= true;
1776 for (int port_id
= 1; keep_running
; port_id
++) {
1777 keep_running
= false;
1778 for (auto wire
: module
->wires()) {
1779 if (wire
->port_id
== port_id
) {
1782 f
<< stringf("%s", id(wire
->name
).c_str());
1783 keep_running
= true;
1788 f
<< stringf(");\n");
1790 if (!systemverilog
&& !module
->processes
.empty())
1791 f
<< indent
+ " " << "reg " << id("\\initial") << " = 0;\n";
1793 for (auto w
: module
->wires())
1794 dump_wire(f
, indent
+ " ", w
);
1796 for (auto &mem
: Mem::get_all_memories(module
))
1797 dump_memory(f
, indent
+ " ", mem
);
1799 for (auto cell
: module
->cells())
1800 dump_cell(f
, indent
+ " ", cell
);
1802 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1803 dump_process(f
, indent
+ " ", it
->second
);
1805 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1806 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1808 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1809 active_module
= NULL
;
1810 active_sigmap
.clear();
1811 active_initdata
.clear();
1814 struct VerilogBackend
: public Backend
{
1815 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1816 void help() override
1818 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1820 log(" write_verilog [options] [filename]\n");
1822 log("Write the current design to a Verilog file.\n");
1825 log(" with this option, SystemVerilog constructs like always_comb are used\n");
1827 log(" -norename\n");
1828 log(" without this option all internal object names (the ones with a dollar\n");
1829 log(" instead of a backslash prefix) are changed to short names in the\n");
1830 log(" format '_<number>_'.\n");
1832 log(" -renameprefix <prefix>\n");
1833 log(" insert this prefix in front of auto-generated instance names\n");
1836 log(" with this option no attributes are included in the output\n");
1838 log(" -attr2comment\n");
1839 log(" with this option attributes are included as comments in the output\n");
1842 log(" without this option all internal cells are converted to Verilog\n");
1843 log(" expressions.\n");
1846 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1847 log(" in -noexpr mode.\n");
1850 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1851 log(" not bit pattern. This option deactivates this feature and instead\n");
1852 log(" will write out all constants in binary.\n");
1855 log(" dump 32-bit constants in decimal and without size and radix\n");
1858 log(" constant values that are compatible with hex output are usually\n");
1859 log(" dumped as hex values. This option deactivates this feature and\n");
1860 log(" instead will write out all constants in binary.\n");
1863 log(" Parameters and attributes that are specified as strings in the\n");
1864 log(" original input will be output as strings by this back-end. This\n");
1865 log(" deactivates this feature and instead will write string constants\n");
1866 log(" as binary numbers.\n");
1869 log(" instead of initializing memories using assignments to individual\n");
1870 log(" elements, use the '$readmemh' function to read initialization data\n");
1871 log(" from a file. This data is written to a file named by appending\n");
1872 log(" a sequential index to the Verilog filename and replacing the extension\n");
1873 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
1874 log(" 'foo-2.mem' and so on.\n");
1876 log(" -defparam\n");
1877 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1878 log(" cell parameters.\n");
1880 log(" -blackboxes\n");
1881 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1882 log(" this option set only the modules with the 'blackbox' attribute\n");
1883 log(" are written to the output file.\n");
1885 log(" -selected\n");
1886 log(" only write selected modules. modules must be selected entirely or\n");
1887 log(" not at all.\n");
1890 log(" verbose output (print new names of all renamed wires and cells)\n");
1892 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1893 log("always blocks. This frontend should only be used to export an RTLIL\n");
1894 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1895 log("processes to logic networks and registers. A warning is generated when\n");
1896 log("this command is called on a design with RTLIL processes.\n");
1899 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1901 log_header(design
, "Executing Verilog backend.\n");
1906 attr2comment
= false;
1917 bool blackboxes
= false;
1918 bool selected
= false;
1920 auto_name_map
.clear();
1924 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1925 std::string arg
= args
[argidx
];
1927 systemverilog
= true;
1930 if (arg
== "-norename") {
1934 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1935 auto_prefix
= args
[++argidx
];
1938 if (arg
== "-noattr") {
1942 if (arg
== "-attr2comment") {
1943 attr2comment
= true;
1946 if (arg
== "-noexpr") {
1950 if (arg
== "-nodec") {
1954 if (arg
== "-nohex") {
1958 if (arg
== "-nostr") {
1962 if (arg
== "-extmem") {
1967 if (arg
== "-defparam") {
1971 if (arg
== "-decimal") {
1975 if (arg
== "-siminit") {
1979 if (arg
== "-blackboxes") {
1983 if (arg
== "-selected") {
1993 extra_args(f
, filename
, args
, argidx
);
1996 if (filename
== "<stdout>")
1997 log_cmd_error("Option -extmem must be used with a filename.\n");
1998 extmem_prefix
= filename
.substr(0, filename
.rfind('.'));
2003 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
2004 for (auto module
: design
->modules()) {
2005 if (module
->get_blackbox_attribute() != blackboxes
)
2007 if (selected
&& !design
->selected_whole_module(module
->name
)) {
2008 if (design
->selected_module(module
->name
))
2009 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module
->name
));
2012 log("Dumping module `%s'.\n", module
->name
.c_str());
2013 dump_module(*f
, "", module
);
2016 auto_name_map
.clear();
2021 PRIVATE_NAMESPACE_END