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
, simple_lhs
;
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
)
1551 for (auto &chunk
: left
.chunks()) {
1552 f
<< stringf("%s" "assign ", indent
.c_str());
1553 dump_sigspec(f
, chunk
);
1554 f
<< stringf(" = ");
1555 dump_sigspec(f
, right
.extract(offset
, GetSize(chunk
)));
1556 f
<< stringf(";\n");
1557 offset
+= GetSize(chunk
);
1560 f
<< stringf("%s" "assign ", indent
.c_str());
1561 dump_sigspec(f
, left
);
1562 f
<< stringf(" = ");
1563 dump_sigspec(f
, right
);
1564 f
<< stringf(";\n");
1568 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1570 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1572 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1574 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1575 f
<< stringf("%s" "begin\n", indent
.c_str());
1577 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1578 if (it
->first
.size() == 0)
1580 f
<< stringf("%s ", indent
.c_str());
1581 dump_sigspec(f
, it
->first
);
1582 f
<< stringf(" = ");
1583 dump_sigspec(f
, it
->second
);
1584 f
<< stringf(";\n");
1587 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1588 dump_proc_switch(f
, indent
+ " ", *it
);
1590 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1591 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1593 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1594 f
<< stringf("%s" "end\n", indent
.c_str());
1597 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1599 if (sw
->signal
.size() == 0) {
1600 f
<< stringf("%s" "begin\n", indent
.c_str());
1601 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1602 if ((*it
)->compare
.size() == 0)
1603 dump_case_body(f
, indent
+ " ", *it
);
1605 f
<< stringf("%s" "end\n", indent
.c_str());
1609 dump_attributes(f
, indent
, sw
->attributes
);
1610 f
<< stringf("%s" "casez (", indent
.c_str());
1611 dump_sigspec(f
, sw
->signal
);
1612 f
<< stringf(")\n");
1614 bool got_default
= false;
1615 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1616 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1617 if ((*it
)->compare
.size() == 0) {
1620 f
<< stringf("%s default", indent
.c_str());
1623 f
<< stringf("%s ", indent
.c_str());
1624 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1627 dump_sigspec(f
, (*it
)->compare
[i
]);
1630 f
<< stringf(":\n");
1631 dump_case_body(f
, indent
+ " ", *it
);
1634 f
<< stringf("%s" "endcase\n", indent
.c_str());
1637 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1639 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1640 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1641 case_body_find_regs(*it2
);
1643 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1644 for (auto &c
: it
->first
.chunks())
1646 reg_wires
.insert(c
.wire
->name
);
1650 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1653 case_body_find_regs(&proc
->root_case
);
1654 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1655 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1656 for (auto &c
: it2
->first
.chunks())
1658 reg_wires
.insert(c
.wire
->name
);
1663 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1665 f
<< indent
+ " " << "if (" << id("\\initial") << ") begin end\n";
1666 dump_case_body(f
, indent
, &proc
->root_case
, true);
1668 std::string backup_indent
= indent
;
1670 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1672 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1673 indent
= backup_indent
;
1675 if (sync
->type
== RTLIL::STa
) {
1676 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1677 } else if (sync
->type
== RTLIL::STi
) {
1678 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1680 f
<< stringf("%s" "always%s @(", indent
.c_str(), systemverilog
? "_ff" : "");
1681 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1682 f
<< stringf("posedge ");
1683 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1684 f
<< stringf("negedge ");
1685 dump_sigspec(f
, sync
->signal
);
1686 f
<< stringf(") begin\n");
1688 std::string ends
= indent
+ "end\n";
1691 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1692 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1693 dump_sigspec(f
, sync
->signal
);
1694 f
<< stringf(") begin\n");
1695 ends
= indent
+ "end\n" + ends
;
1699 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1700 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1701 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1702 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1703 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1704 dump_sigspec(f
, sync2
->signal
);
1705 f
<< stringf(") begin\n");
1706 ends
= indent
+ "end\n" + ends
;
1712 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1713 if (it
->first
.size() == 0)
1715 f
<< stringf("%s ", indent
.c_str());
1716 dump_sigspec(f
, it
->first
);
1717 f
<< stringf(" <= ");
1718 dump_sigspec(f
, it
->second
);
1719 f
<< stringf(";\n");
1722 f
<< stringf("%s", ends
.c_str());
1726 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1729 reset_auto_counter(module
);
1730 active_module
= module
;
1731 active_sigmap
.set(module
);
1732 active_initdata
.clear();
1734 for (auto wire
: module
->wires())
1735 if (wire
->attributes
.count(ID::init
)) {
1736 SigSpec sig
= active_sigmap(wire
);
1737 Const val
= wire
->attributes
.at(ID::init
);
1738 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1739 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1740 active_initdata
[sig
[i
]] = val
[i
];
1743 if (!module
->processes
.empty())
1744 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1745 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1746 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1747 "processes to logic networks and registers.\n", log_id(module
));
1750 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1751 dump_process(f
, indent
+ " ", it
->second
, true);
1755 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1756 for (auto cell
: module
->cells())
1758 if (!RTLIL::builtin_ff_cell_types().count(cell
->type
) || !cell
->hasPort(ID::Q
) || cell
->type
.in(ID($ff
), ID($_FF_
)))
1761 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
1763 if (sig
.is_chunk()) {
1764 RTLIL::SigChunk chunk
= sig
.as_chunk();
1765 if (chunk
.wire
!= NULL
)
1766 for (int i
= 0; i
< chunk
.width
; i
++)
1767 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1770 for (auto wire
: module
->wires())
1772 for (int i
= 0; i
< wire
->width
; i
++)
1773 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1774 goto this_wire_aint_reg
;
1776 reg_wires
.insert(wire
->name
);
1777 this_wire_aint_reg
:;
1781 dump_attributes(f
, indent
, module
->attributes
, '\n', /*modattr=*/true);
1782 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1783 bool keep_running
= true;
1784 for (int port_id
= 1; keep_running
; port_id
++) {
1785 keep_running
= false;
1786 for (auto wire
: module
->wires()) {
1787 if (wire
->port_id
== port_id
) {
1790 f
<< stringf("%s", id(wire
->name
).c_str());
1791 keep_running
= true;
1796 f
<< stringf(");\n");
1798 if (!systemverilog
&& !module
->processes
.empty())
1799 f
<< indent
+ " " << "reg " << id("\\initial") << " = 0;\n";
1801 for (auto w
: module
->wires())
1802 dump_wire(f
, indent
+ " ", w
);
1804 for (auto &mem
: Mem::get_all_memories(module
))
1805 dump_memory(f
, indent
+ " ", mem
);
1807 for (auto cell
: module
->cells())
1808 dump_cell(f
, indent
+ " ", cell
);
1810 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1811 dump_process(f
, indent
+ " ", it
->second
);
1813 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1814 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1816 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1817 active_module
= NULL
;
1818 active_sigmap
.clear();
1819 active_initdata
.clear();
1822 struct VerilogBackend
: public Backend
{
1823 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1824 void help() override
1826 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1828 log(" write_verilog [options] [filename]\n");
1830 log("Write the current design to a Verilog file.\n");
1833 log(" with this option, SystemVerilog constructs like always_comb are used\n");
1835 log(" -norename\n");
1836 log(" without this option all internal object names (the ones with a dollar\n");
1837 log(" instead of a backslash prefix) are changed to short names in the\n");
1838 log(" format '_<number>_'.\n");
1840 log(" -renameprefix <prefix>\n");
1841 log(" insert this prefix in front of auto-generated instance names\n");
1844 log(" with this option no attributes are included in the output\n");
1846 log(" -attr2comment\n");
1847 log(" with this option attributes are included as comments in the output\n");
1850 log(" without this option all internal cells are converted to Verilog\n");
1851 log(" expressions.\n");
1854 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1855 log(" in -noexpr mode.\n");
1858 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1859 log(" not bit pattern. This option deactivates this feature and instead\n");
1860 log(" will write out all constants in binary.\n");
1863 log(" dump 32-bit constants in decimal and without size and radix\n");
1866 log(" constant values that are compatible with hex output are usually\n");
1867 log(" dumped as hex values. This option deactivates this feature and\n");
1868 log(" instead will write out all constants in binary.\n");
1871 log(" Parameters and attributes that are specified as strings in the\n");
1872 log(" original input will be output as strings by this back-end. This\n");
1873 log(" deactivates this feature and instead will write string constants\n");
1874 log(" as binary numbers.\n");
1876 log(" -simple-lhs\n");
1877 log(" Connection assignments with simple left hand side without concatenations.\n");
1880 log(" instead of initializing memories using assignments to individual\n");
1881 log(" elements, use the '$readmemh' function to read initialization data\n");
1882 log(" from a file. This data is written to a file named by appending\n");
1883 log(" a sequential index to the Verilog filename and replacing the extension\n");
1884 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
1885 log(" 'foo-2.mem' and so on.\n");
1887 log(" -defparam\n");
1888 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1889 log(" cell parameters.\n");
1891 log(" -blackboxes\n");
1892 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1893 log(" this option set only the modules with the 'blackbox' attribute\n");
1894 log(" are written to the output file.\n");
1896 log(" -selected\n");
1897 log(" only write selected modules. modules must be selected entirely or\n");
1898 log(" not at all.\n");
1901 log(" verbose output (print new names of all renamed wires and cells)\n");
1903 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1904 log("always blocks. This frontend should only be used to export an RTLIL\n");
1905 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1906 log("processes to logic networks and registers. A warning is generated when\n");
1907 log("this command is called on a design with RTLIL processes.\n");
1910 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1912 log_header(design
, "Executing Verilog backend.\n");
1917 attr2comment
= false;
1929 bool blackboxes
= false;
1930 bool selected
= false;
1932 auto_name_map
.clear();
1936 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1937 std::string arg
= args
[argidx
];
1939 systemverilog
= true;
1942 if (arg
== "-norename") {
1946 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1947 auto_prefix
= args
[++argidx
];
1950 if (arg
== "-noattr") {
1954 if (arg
== "-attr2comment") {
1955 attr2comment
= true;
1958 if (arg
== "-noexpr") {
1962 if (arg
== "-nodec") {
1966 if (arg
== "-nohex") {
1970 if (arg
== "-nostr") {
1974 if (arg
== "-extmem") {
1979 if (arg
== "-defparam") {
1983 if (arg
== "-decimal") {
1987 if (arg
== "-siminit") {
1991 if (arg
== "-blackboxes") {
1995 if (arg
== "-selected") {
1999 if (arg
== "-simple-lhs") {
2009 extra_args(f
, filename
, args
, argidx
);
2012 if (filename
== "<stdout>")
2013 log_cmd_error("Option -extmem must be used with a filename.\n");
2014 extmem_prefix
= filename
.substr(0, filename
.rfind('.'));
2019 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
2020 for (auto module
: design
->modules()) {
2021 if (module
->get_blackbox_attribute() != blackboxes
)
2023 if (selected
&& !design
->selected_whole_module(module
->name
)) {
2024 if (design
->selected_module(module
->name
))
2025 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module
->name
));
2028 log("Dumping module `%s'.\n", module
->name
.c_str());
2029 dump_module(*f
, "", module
);
2032 auto_name_map
.clear();
2037 PRIVATE_NAMESPACE_END