2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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 for (int j
= 0; j
< mem
.width
; j
++)
509 if (init
.en
[j
] != State::S1
)
512 int start_j
= j
, width
= 1;
514 while (j
+1 < mem
.width
&& init
.en
[j
+1] == State::S1
)
517 if (width
== mem
.width
) {
518 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
+ start
);
520 f
<< stringf("%s" " %s[%d][%d:%d] = ", indent
.c_str(), mem_id
.c_str(), i
+ start
, j
, start_j
);
522 dump_const(f
, init
.data
.extract(i
*mem
.width
+start_j
, width
));
527 f
<< stringf("%s" "end\n", indent
.c_str());
531 // create a map : "edge clk" -> expressions within that clock domain
532 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
533 dict
<std::string
, std::string
> clk_to_arst_cond
;
534 dict
<std::string
, std::vector
<std::string
>> clk_to_arst_body
;
535 clk_to_lof_body
[""] = std::vector
<std::string
>();
536 std::string clk_domain_str
;
537 // create a list of reg declarations
538 std::vector
<std::string
> lof_reg_declarations
;
541 for (auto &port
: mem
.rd_ports
)
546 std::ostringstream os
;
547 dump_sigspec(os
, port
.clk
);
548 clk_domain_str
= stringf("%sedge %s", port
.clk_polarity
? "pos" : "neg", os
.str().c_str());
549 if (port
.arst
!= State::S0
) {
550 std::ostringstream os2
;
551 dump_sigspec(os2
, port
.arst
);
552 clk_domain_str
+= stringf(", posedge %s", os2
.str().c_str());
553 clk_to_arst_cond
[clk_domain_str
] = os2
.str();
556 if (!port
.transparent
)
558 // for clocked read ports make something like:
560 // always @(posedge clk)
561 // if (rd_en) temp_id <= array_reg[r_addr];
562 // assign r_data = temp_id;
563 std::string temp_id
= next_auto_id();
564 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", port
.data
.size() - 1, temp_id
.c_str()) );
566 bool has_indent
= false;
568 if (port
.arst
!= State::S0
) {
569 std::ostringstream os
;
570 os
<< stringf("%s <= ", temp_id
.c_str());
571 dump_sigspec(os
, port
.arst_value
);
573 clk_to_arst_body
[clk_domain_str
].push_back(os
.str());
576 if (port
.srst
!= State::S0
&& !port
.ce_over_srst
) {
577 std::ostringstream os
;
578 os
<< stringf("if (");
579 dump_sigspec(os
, port
.srst
);
580 os
<< stringf(")\n");
581 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
582 std::ostringstream os2
;
583 os2
<< stringf("%s" "%s <= ", indent
.c_str(), temp_id
.c_str());
584 dump_sigspec(os2
, port
.srst_value
);
586 clk_to_lof_body
[clk_domain_str
].push_back(os2
.str());
587 std::ostringstream os3
;
588 if (port
.en
== State::S1
) {
589 os3
<< "else begin\n";
592 dump_sigspec(os3
, port
.en
);
595 clk_to_lof_body
[clk_domain_str
].push_back(os3
.str());
597 } else if (port
.en
!= State::S1
) {
598 std::ostringstream os
;
599 os
<< stringf("if (");
600 dump_sigspec(os
, port
.en
);
601 os
<< stringf(") begin\n");
602 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
606 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
608 SigSpec addr
= port
.sub_addr(sub
);
609 std::ostringstream os
;
614 os
<< stringf("[%d:%d]", (sub
+ 1) * mem
.width
- 1, sub
* mem
.width
);
615 os
<< stringf(" <= %s[", mem_id
.c_str());
616 dump_sigspec(os
, addr
);
617 os
<< stringf("];\n");
618 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
621 if (port
.srst
!= State::S0
&& port
.ce_over_srst
)
623 std::ostringstream os
;
626 os
<< stringf("if (");
627 dump_sigspec(os
, port
.srst
);
628 os
<< stringf(")\n");
629 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
630 std::ostringstream os2
;
633 os2
<< stringf("%s" "%s <= ", indent
.c_str(), temp_id
.c_str());
634 dump_sigspec(os2
, port
.srst_value
);
636 clk_to_lof_body
[clk_domain_str
].push_back(os2
.str());
640 clk_to_lof_body
[clk_domain_str
].push_back("end\n");
642 if (!port
.init_value
.is_fully_undef())
644 std::ostringstream os
;
645 dump_sigspec(os
, port
.init_value
);
646 std::string line
= stringf("initial %s = %s;\n", temp_id
.c_str(), os
.str().c_str());
647 clk_to_lof_body
[""].push_back(line
);
651 std::ostringstream os
;
652 dump_sigspec(os
, port
.data
);
653 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
654 clk_to_lof_body
[""].push_back(line
);
659 // for rd-transparent read-ports make something like:
661 // always @(posedge clk)
662 // temp_id <= r_addr;
663 // assign r_data = array_reg[temp_id];
664 std::string temp_id
= next_auto_id();
665 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", port
.addr
.size() - 1 - port
.wide_log2
, temp_id
.c_str()) );
667 std::ostringstream os
;
668 dump_sigspec(os
, port
.addr
.extract_end(port
.wide_log2
));
669 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
670 clk_to_lof_body
[clk_domain_str
].push_back(line
);
672 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
674 std::ostringstream os
;
676 dump_sigspec(os
, port
.data
.extract(sub
* mem
.width
, mem
.width
));
677 os
<< stringf(" = %s[", mem_id
.c_str());;
678 if (port
.wide_log2
) {
680 for (int i
= 0; i
< port
.wide_log2
; i
++)
681 addr_lo
.bits
.push_back(State(sub
>> i
& 1));
685 dump_const(os
, addr_lo
);
691 clk_to_lof_body
[""].push_back(os
.str());
695 // for non-clocked read-ports make something like:
696 // assign r_data = array_reg[r_addr];
697 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
699 SigSpec addr
= port
.sub_addr(sub
);
701 std::ostringstream os
, os2
;
702 dump_sigspec(os
, port
.data
.extract(sub
* mem
.width
, mem
.width
));
703 dump_sigspec(os2
, addr
);
704 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
705 clk_to_lof_body
[""].push_back(line
);
710 // Write ports. Those are messy because we try to preserve priority, as much as we can:
712 // 1. We split all ports into several disjoint processes.
713 // 2. If a port has priority over another port, the two ports need to share
714 // a process, so that priority can be reconstructed on the other end.
715 // 3. We want each process to be as small as possible, to avoid extra
716 // priorities inferred on the other end.
717 pool
<int> wr_ports_done
;
718 for (int ridx
= 0; ridx
< GetSize(mem
.wr_ports
); ridx
++)
720 if (wr_ports_done
.count(ridx
))
723 auto &root
= mem
.wr_ports
[ridx
];
725 // Start from a root.
726 pool
<int> wr_ports_now
;
727 wr_ports_now
.insert(ridx
);
729 // Transitively fill list of ports in this process by following priority edges.
732 bool changed
= false;
734 for (int i
= 0; i
< GetSize(mem
.wr_ports
); i
++)
735 for (int j
= 0; j
< i
; j
++)
736 if (mem
.wr_ports
[i
].priority_mask
[j
])
738 if (wr_ports_now
.count(i
) && !wr_ports_now
.count(j
)) {
739 wr_ports_now
.insert(j
);
742 if (!wr_ports_now
.count(i
) && wr_ports_now
.count(j
)) {
743 wr_ports_now
.insert(i
);
752 if (root
.clk_enable
) {
753 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", root
.clk_polarity
? "pos" : "neg");
754 dump_sigspec(f
, root
.clk
);
757 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_latch" : " @*");
760 for (int pidx
= 0; pidx
< GetSize(mem
.wr_ports
); pidx
++)
762 if (!wr_ports_now
.count(pidx
))
764 wr_ports_done
.insert(pidx
);
766 auto &port
= mem
.wr_ports
[pidx
];
767 log_assert(port
.clk_enable
== root
.clk_enable
);
768 if (port
.clk_enable
) {
769 log_assert(port
.clk
== root
.clk
);
770 log_assert(port
.clk_polarity
== root
.clk_polarity
);
773 // make something like:
774 // always @(posedge clk)
775 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
777 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
779 SigSpec addr
= port
.sub_addr(sub
);
780 for (int i
= 0; i
< mem
.width
; i
++)
782 int start_i
= i
, width
= 1;
783 SigBit wen_bit
= port
.en
[sub
* mem
.width
+ i
];
785 while (i
+1 < mem
.width
&& active_sigmap(port
.en
[sub
* mem
.width
+ i
+1]) == active_sigmap(wen_bit
))
788 if (wen_bit
== State::S0
)
791 f
<< stringf("%s%s", indent
.c_str(), indent
.c_str());
792 if (wen_bit
!= State::S1
)
794 f
<< stringf("if (");
795 dump_sigspec(f
, wen_bit
);
797 f
<< stringf("%s%s%s", indent
.c_str(), indent
.c_str(), indent
.c_str());
799 f
<< stringf("%s[", mem_id
.c_str());
800 dump_sigspec(f
, addr
);
801 if (width
== GetSize(port
.en
))
802 f
<< stringf("] <= ");
804 f
<< stringf("][%d:%d] <= ", i
, start_i
);
805 dump_sigspec(f
, port
.data
.extract(sub
* mem
.width
+ start_i
, width
));
811 f
<< stringf("%s" "end\n", indent
.c_str());
813 // Output Verilog that looks something like this:
815 // always @(posedge CLK2) begin
816 // _3_ <= memory[D1ADDR];
818 // memory[A1ADDR] <= A1DATA;
820 // memory[A2ADDR] <= A2DATA;
823 // always @(negedge CLK1) begin
825 // memory[C1ADDR] <= C1DATA;
828 // assign D1DATA = _3_;
829 // assign D2DATA <= memory[D2ADDR];
831 // the reg ... definitions
832 for(auto ®
: lof_reg_declarations
)
834 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
836 // the block of expressions by clock domain
837 for(auto &pair
: clk_to_lof_body
)
839 std::string clk_domain
= pair
.first
;
840 std::vector
<std::string
> lof_lines
= pair
.second
;
841 if( clk_domain
!= "")
843 f
<< stringf("%s" "always%s @(%s) begin\n", indent
.c_str(), systemverilog
? "_ff" : "", clk_domain
.c_str());
844 bool has_arst
= clk_to_arst_cond
.count(clk_domain
) != 0;
846 f
<< stringf("%s%s" "if (%s) begin\n", indent
.c_str(), indent
.c_str(), clk_to_arst_cond
[clk_domain
].c_str());
847 for(auto &line
: clk_to_arst_body
[clk_domain
])
848 f
<< stringf("%s%s%s" "%s", indent
.c_str(), indent
.c_str(), indent
.c_str(), line
.c_str());
849 f
<< stringf("%s%s" "end else begin\n", indent
.c_str(), indent
.c_str());
850 for(auto &line
: lof_lines
)
851 f
<< stringf("%s%s%s" "%s", indent
.c_str(), indent
.c_str(), indent
.c_str(), line
.c_str());
852 f
<< stringf("%s%s" "end\n", indent
.c_str(), indent
.c_str());
854 for(auto &line
: lof_lines
)
855 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
857 f
<< stringf("%s" "end\n", indent
.c_str());
861 // the non-clocked assignments
862 for(auto &line
: lof_lines
)
863 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
868 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
870 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
871 f
<< stringf("$signed(");
872 dump_sigspec(f
, cell
->getPort("\\" + port
));
875 dump_sigspec(f
, cell
->getPort("\\" + port
));
878 std::string
cellname(RTLIL::Cell
*cell
)
880 if (!norename
&& cell
->name
[0] == '$' && RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
)))
882 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
883 if (GetSize(sig
) != 1 || sig
.is_fully_const())
884 goto no_special_reg_name
;
886 RTLIL::Wire
*wire
= sig
[0].wire
;
888 if (wire
->name
[0] != '\\')
889 goto no_special_reg_name
;
891 std::string cell_name
= wire
->name
.str();
893 size_t pos
= cell_name
.find('[');
894 if (pos
!= std::string::npos
)
895 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
897 cell_name
= cell_name
+ "_reg";
899 if (wire
->width
!= 1)
900 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
902 if (active_module
&& active_module
->count_id(cell_name
) > 0)
903 goto no_special_reg_name
;
905 return id(cell_name
);
910 return id(cell
->name
).c_str();
914 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
916 f
<< stringf("%s" "assign ", indent
.c_str());
917 dump_sigspec(f
, cell
->getPort(ID::Y
));
918 f
<< stringf(" = %s ", op
.c_str());
919 dump_attributes(f
, "", cell
->attributes
, ' ');
920 dump_cell_expr_port(f
, cell
, "A", true);
924 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
926 f
<< stringf("%s" "assign ", indent
.c_str());
927 dump_sigspec(f
, cell
->getPort(ID::Y
));
929 dump_cell_expr_port(f
, cell
, "A", true);
930 f
<< stringf(" %s ", op
.c_str());
931 dump_attributes(f
, "", cell
->attributes
, ' ');
932 dump_cell_expr_port(f
, cell
, "B", true);
936 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
938 if (cell
->type
== ID($_NOT_
)) {
939 f
<< stringf("%s" "assign ", indent
.c_str());
940 dump_sigspec(f
, cell
->getPort(ID::Y
));
943 dump_attributes(f
, "", cell
->attributes
, ' ');
944 dump_cell_expr_port(f
, cell
, "A", false);
949 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_OR_
), ID($_NOR_
), ID($_XOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
))) {
950 f
<< stringf("%s" "assign ", indent
.c_str());
951 dump_sigspec(f
, cell
->getPort(ID::Y
));
953 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
)))
955 dump_cell_expr_port(f
, cell
, "A", false);
957 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_ANDNOT_
)))
959 if (cell
->type
.in(ID($_OR_
), ID($_NOR_
), ID($_ORNOT_
)))
961 if (cell
->type
.in(ID($_XOR_
), ID($_XNOR_
)))
963 dump_attributes(f
, "", cell
->attributes
, ' ');
965 if (cell
->type
.in(ID($_ANDNOT_
), ID($_ORNOT_
)))
967 dump_cell_expr_port(f
, cell
, "B", false);
968 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
)))
974 if (cell
->type
== ID($_MUX_
)) {
975 f
<< stringf("%s" "assign ", indent
.c_str());
976 dump_sigspec(f
, cell
->getPort(ID::Y
));
978 dump_cell_expr_port(f
, cell
, "S", false);
980 dump_attributes(f
, "", cell
->attributes
, ' ');
981 dump_cell_expr_port(f
, cell
, "B", false);
983 dump_cell_expr_port(f
, cell
, "A", false);
988 if (cell
->type
== ID($_NMUX_
)) {
989 f
<< stringf("%s" "assign ", indent
.c_str());
990 dump_sigspec(f
, cell
->getPort(ID::Y
));
991 f
<< stringf(" = !(");
992 dump_cell_expr_port(f
, cell
, "S", false);
994 dump_attributes(f
, "", cell
->attributes
, ' ');
995 dump_cell_expr_port(f
, cell
, "B", false);
997 dump_cell_expr_port(f
, cell
, "A", false);
998 f
<< stringf(");\n");
1002 if (cell
->type
.in(ID($_AOI3_
), ID($_OAI3_
))) {
1003 f
<< stringf("%s" "assign ", indent
.c_str());
1004 dump_sigspec(f
, cell
->getPort(ID::Y
));
1005 f
<< stringf(" = ~((");
1006 dump_cell_expr_port(f
, cell
, "A", false);
1007 f
<< stringf(cell
->type
== ID($_AOI3_
) ? " & " : " | ");
1008 dump_cell_expr_port(f
, cell
, "B", false);
1009 f
<< stringf(cell
->type
== ID($_AOI3_
) ? ") |" : ") &");
1010 dump_attributes(f
, "", cell
->attributes
, ' ');
1012 dump_cell_expr_port(f
, cell
, "C", false);
1013 f
<< stringf(");\n");
1017 if (cell
->type
.in(ID($_AOI4_
), ID($_OAI4_
))) {
1018 f
<< stringf("%s" "assign ", indent
.c_str());
1019 dump_sigspec(f
, cell
->getPort(ID::Y
));
1020 f
<< stringf(" = ~((");
1021 dump_cell_expr_port(f
, cell
, "A", false);
1022 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
1023 dump_cell_expr_port(f
, cell
, "B", false);
1024 f
<< stringf(cell
->type
== ID($_AOI4_
) ? ") |" : ") &");
1025 dump_attributes(f
, "", cell
->attributes
, ' ');
1027 dump_cell_expr_port(f
, cell
, "C", false);
1028 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
1029 dump_cell_expr_port(f
, cell
, "D", false);
1030 f
<< stringf("));\n");
1034 #define HANDLE_UNIOP(_type, _operator) \
1035 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
1036 #define HANDLE_BINOP(_type, _operator) \
1037 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
1039 HANDLE_UNIOP(ID($
not), "~")
1040 HANDLE_UNIOP(ID($pos
), "+")
1041 HANDLE_UNIOP(ID($neg
), "-")
1043 HANDLE_BINOP(ID($
and), "&")
1044 HANDLE_BINOP(ID($
or), "|")
1045 HANDLE_BINOP(ID($
xor), "^")
1046 HANDLE_BINOP(ID($xnor
), "~^")
1048 HANDLE_UNIOP(ID($reduce_and
), "&")
1049 HANDLE_UNIOP(ID($reduce_or
), "|")
1050 HANDLE_UNIOP(ID($reduce_xor
), "^")
1051 HANDLE_UNIOP(ID($reduce_xnor
), "~^")
1052 HANDLE_UNIOP(ID($reduce_bool
), "|")
1054 HANDLE_BINOP(ID($shl
), "<<")
1055 HANDLE_BINOP(ID($shr
), ">>")
1056 HANDLE_BINOP(ID($sshl
), "<<<")
1057 HANDLE_BINOP(ID($sshr
), ">>>")
1059 HANDLE_BINOP(ID($lt
), "<")
1060 HANDLE_BINOP(ID($le
), "<=")
1061 HANDLE_BINOP(ID($eq
), "==")
1062 HANDLE_BINOP(ID($ne
), "!=")
1063 HANDLE_BINOP(ID($eqx
), "===")
1064 HANDLE_BINOP(ID($nex
), "!==")
1065 HANDLE_BINOP(ID($ge
), ">=")
1066 HANDLE_BINOP(ID($gt
), ">")
1068 HANDLE_BINOP(ID($add
), "+")
1069 HANDLE_BINOP(ID($sub
), "-")
1070 HANDLE_BINOP(ID($mul
), "*")
1071 HANDLE_BINOP(ID($div
), "/")
1072 HANDLE_BINOP(ID($mod
), "%")
1073 HANDLE_BINOP(ID($pow
), "**")
1075 HANDLE_UNIOP(ID($logic_not
), "!")
1076 HANDLE_BINOP(ID($logic_and
), "&&")
1077 HANDLE_BINOP(ID($logic_or
), "||")
1082 if (cell
->type
== ID($divfloor
))
1084 // wire [MAXLEN+1:0] _0_, _1_, _2_;
1085 // assign _0_ = $signed(A);
1086 // assign _1_ = $signed(B);
1087 // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
1088 // assign Y = $signed(_2_) / $signed(_1_);
1090 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
1091 SigSpec sig_a
= cell
->getPort(ID::A
);
1092 SigSpec sig_b
= cell
->getPort(ID::B
);
1094 std::string buf_a
= next_auto_id();
1095 std::string buf_b
= next_auto_id();
1096 std::string buf_num
= next_auto_id();
1097 int size_a
= GetSize(sig_a
);
1098 int size_b
= GetSize(sig_b
);
1099 int size_y
= GetSize(cell
->getPort(ID::Y
));
1100 int size_max
= std::max(size_a
, std::max(size_b
, size_y
));
1102 // intentionally one wider than maximum width
1103 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());
1104 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_a
.c_str());
1105 dump_cell_expr_port(f
, cell
, "A", true);
1106 f
<< stringf(";\n");
1107 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_b
.c_str());
1108 dump_cell_expr_port(f
, cell
, "B", true);
1109 f
<< stringf(";\n");
1111 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_num
.c_str());
1113 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
1114 f
<< stringf(" == ");
1115 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
1116 f
<< stringf(") || ");
1117 dump_sigspec(f
, sig_a
);
1118 f
<< stringf(" == 0 ? %s : ", buf_a
.c_str());
1119 f
<< stringf("$signed(%s - (", buf_a
.c_str());
1120 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
1121 f
<< stringf(" ? %s + 1 : %s - 1));\n", buf_b
.c_str(), buf_b
.c_str());
1124 f
<< stringf("%s" "assign ", indent
.c_str());
1125 dump_sigspec(f
, cell
->getPort(ID::Y
));
1126 f
<< stringf(" = $signed(%s) / ", buf_num
.c_str());
1127 dump_attributes(f
, "", cell
->attributes
, ' ');
1128 f
<< stringf("$signed(%s);\n", buf_b
.c_str());
1131 // same as truncating division
1132 dump_cell_expr_binop(f
, indent
, cell
, "/");
1137 if (cell
->type
== ID($modfloor
))
1139 // wire truncated = $signed(A) % $signed(B);
1140 // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated);
1142 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
1143 SigSpec sig_a
= cell
->getPort(ID::A
);
1144 SigSpec sig_b
= cell
->getPort(ID::B
);
1146 std::string temp_id
= next_auto_id();
1147 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
1148 dump_cell_expr_port(f
, cell
, "A", true);
1149 f
<< stringf(" %% ");
1150 dump_attributes(f
, "", cell
->attributes
, ' ');
1151 dump_cell_expr_port(f
, cell
, "B", true);
1152 f
<< stringf(";\n");
1154 f
<< stringf("%s" "assign ", indent
.c_str());
1155 dump_sigspec(f
, cell
->getPort(ID::Y
));
1156 f
<< stringf(" = (");
1157 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
1158 f
<< stringf(" == ");
1159 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
1160 f
<< stringf(") || %s == 0 ? %s : ", temp_id
.c_str(), temp_id
.c_str());
1161 dump_cell_expr_port(f
, cell
, "B", true);
1162 f
<< stringf(" + $signed(%s);\n", temp_id
.c_str());
1165 // same as truncating modulo
1166 dump_cell_expr_binop(f
, indent
, cell
, "%");
1171 if (cell
->type
== ID($shift
))
1173 f
<< stringf("%s" "assign ", indent
.c_str());
1174 dump_sigspec(f
, cell
->getPort(ID::Y
));
1175 f
<< stringf(" = ");
1176 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1178 dump_cell_expr_port(f
, cell
, "B", true);
1179 f
<< stringf(" < 0 ? ");
1180 dump_cell_expr_port(f
, cell
, "A", true);
1181 f
<< stringf(" << - ");
1182 dump_sigspec(f
, cell
->getPort(ID::B
));
1183 f
<< stringf(" : ");
1184 dump_cell_expr_port(f
, cell
, "A", true);
1185 f
<< stringf(" >> ");
1186 dump_sigspec(f
, cell
->getPort(ID::B
));
1190 dump_cell_expr_port(f
, cell
, "A", true);
1191 f
<< stringf(" >> ");
1192 dump_sigspec(f
, cell
->getPort(ID::B
));
1194 f
<< stringf(";\n");
1198 if (cell
->type
== ID($shiftx
))
1200 std::string temp_id
= next_auto_id();
1201 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
1202 dump_sigspec(f
, cell
->getPort(ID::A
));
1203 f
<< stringf(";\n");
1205 f
<< stringf("%s" "assign ", indent
.c_str());
1206 dump_sigspec(f
, cell
->getPort(ID::Y
));
1207 f
<< stringf(" = %s[", temp_id
.c_str());
1208 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1209 f
<< stringf("$signed(");
1210 dump_sigspec(f
, cell
->getPort(ID::B
));
1211 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1213 f
<< stringf(" +: %d", cell
->getParam(ID::Y_WIDTH
).as_int());
1214 f
<< stringf("];\n");
1218 if (cell
->type
== ID($mux
))
1220 f
<< stringf("%s" "assign ", indent
.c_str());
1221 dump_sigspec(f
, cell
->getPort(ID::Y
));
1222 f
<< stringf(" = ");
1223 dump_sigspec(f
, cell
->getPort(ID::S
));
1224 f
<< stringf(" ? ");
1225 dump_attributes(f
, "", cell
->attributes
, ' ');
1226 dump_sigspec(f
, cell
->getPort(ID::B
));
1227 f
<< stringf(" : ");
1228 dump_sigspec(f
, cell
->getPort(ID::A
));
1229 f
<< stringf(";\n");
1233 if (cell
->type
== ID($pmux
))
1235 int width
= cell
->parameters
[ID::WIDTH
].as_int();
1236 int s_width
= cell
->getPort(ID::S
).size();
1237 std::string func_name
= cellname(cell
);
1239 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
1240 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
1241 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
1242 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
1244 dump_attributes(f
, indent
+ " ", cell
->attributes
);
1246 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
1247 f
<< stringf("%s" " casez (s)", indent
.c_str());
1248 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
1250 for (int i
= 0; i
< s_width
; i
++)
1252 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
1254 for (int j
= s_width
-1; j
>= 0; j
--)
1255 f
<< stringf("%c", j
== i
? '1' : '?');
1257 f
<< stringf(":\n");
1258 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
1261 f
<< stringf("%s" " default:\n", indent
.c_str());
1262 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
1264 f
<< stringf("%s" " endcase\n", indent
.c_str());
1265 f
<< stringf("%s" "endfunction\n", indent
.c_str());
1267 f
<< stringf("%s" "assign ", indent
.c_str());
1268 dump_sigspec(f
, cell
->getPort(ID::Y
));
1269 f
<< stringf(" = %s(", func_name
.c_str());
1270 dump_sigspec(f
, cell
->getPort(ID::A
));
1272 dump_sigspec(f
, cell
->getPort(ID::B
));
1274 dump_sigspec(f
, cell
->getPort(ID::S
));
1275 f
<< stringf(");\n");
1279 if (cell
->type
== ID($tribuf
))
1281 f
<< stringf("%s" "assign ", indent
.c_str());
1282 dump_sigspec(f
, cell
->getPort(ID::Y
));
1283 f
<< stringf(" = ");
1284 dump_sigspec(f
, cell
->getPort(ID::EN
));
1285 f
<< stringf(" ? ");
1286 dump_sigspec(f
, cell
->getPort(ID::A
));
1287 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at(ID::WIDTH
).as_int());
1291 if (cell
->type
== ID($slice
))
1293 f
<< stringf("%s" "assign ", indent
.c_str());
1294 dump_sigspec(f
, cell
->getPort(ID::Y
));
1295 f
<< stringf(" = ");
1296 dump_sigspec(f
, cell
->getPort(ID::A
));
1297 f
<< stringf(" >> %d;\n", cell
->parameters
.at(ID::OFFSET
).as_int());
1301 if (cell
->type
== ID($concat
))
1303 f
<< stringf("%s" "assign ", indent
.c_str());
1304 dump_sigspec(f
, cell
->getPort(ID::Y
));
1305 f
<< stringf(" = { ");
1306 dump_sigspec(f
, cell
->getPort(ID::B
));
1307 f
<< stringf(" , ");
1308 dump_sigspec(f
, cell
->getPort(ID::A
));
1309 f
<< stringf(" };\n");
1313 if (cell
->type
== ID($lut
))
1315 f
<< stringf("%s" "assign ", indent
.c_str());
1316 dump_sigspec(f
, cell
->getPort(ID::Y
));
1317 f
<< stringf(" = ");
1318 dump_const(f
, cell
->parameters
.at(ID::LUT
));
1319 f
<< stringf(" >> ");
1320 dump_attributes(f
, "", cell
->attributes
, ' ');
1321 dump_sigspec(f
, cell
->getPort(ID::A
));
1322 f
<< stringf(";\n");
1326 if (RTLIL::builtin_ff_cell_types().count(cell
->type
))
1328 FfData
ff(nullptr, cell
);
1330 // $ff / $_FF_ cell: not supported.
1331 if (ff
.has_d
&& !ff
.has_clk
&& !ff
.has_en
)
1334 std::string reg_name
= cellname(cell
);
1335 bool out_is_reg_wire
= is_reg_wire(ff
.sig_q
, reg_name
);
1337 if (!out_is_reg_wire
) {
1339 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
1341 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), ff
.width
-1, reg_name
.c_str());
1342 dump_reg_init(f
, ff
.sig_q
);
1346 // If the FF has CLR/SET inputs, emit every bit slice separately.
1347 int chunks
= ff
.has_sr
? ff
.width
: 1;
1348 bool chunky
= ff
.has_sr
&& ff
.width
!= 1;
1350 for (int i
= 0; i
< chunks
; i
++)
1353 Const val_arst
, val_srst
;
1354 std::string reg_bit_name
, sig_set_name
, sig_clr_name
, sig_arst_name
;
1356 reg_bit_name
= stringf("%s[%d]", reg_name
.c_str(), i
);
1358 sig_d
= ff
.sig_d
[i
];
1360 reg_bit_name
= reg_name
;
1365 val_arst
= chunky
? ff
.val_arst
[i
] : ff
.val_arst
;
1367 val_srst
= chunky
? ff
.val_srst
[i
] : ff
.val_srst
;
1369 // If there are constants in the sensitivity list, replace them with an intermediate wire
1371 if (ff
.sig_set
[i
].wire
== NULL
)
1373 sig_set_name
= next_auto_id();
1374 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_set_name
.c_str());
1375 dump_const(f
, ff
.sig_set
[i
].data
);
1376 f
<< stringf(";\n");
1378 if (ff
.sig_clr
[i
].wire
== NULL
)
1380 sig_clr_name
= next_auto_id();
1381 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_clr_name
.c_str());
1382 dump_const(f
, ff
.sig_clr
[i
].data
);
1383 f
<< stringf(";\n");
1385 } else if (ff
.has_arst
) {
1386 if (ff
.sig_arst
[i
].wire
== NULL
)
1388 sig_arst_name
= next_auto_id();
1389 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_arst_name
.c_str());
1390 dump_const(f
, ff
.sig_arst
[i
].data
);
1391 f
<< stringf(";\n");
1395 dump_attributes(f
, indent
, cell
->attributes
);
1399 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", ff
.pol_clk
? "pos" : "neg");
1400 dump_sigspec(f
, ff
.sig_clk
);
1402 f
<< stringf(", %sedge ", ff
.pol_set
? "pos" : "neg");
1403 if (ff
.sig_set
[i
].wire
== NULL
)
1404 f
<< stringf("%s", sig_set_name
.c_str());
1406 dump_sigspec(f
, ff
.sig_set
[i
]);
1408 f
<< stringf(", %sedge ", ff
.pol_clr
? "pos" : "neg");
1409 if (ff
.sig_clr
[i
].wire
== NULL
)
1410 f
<< stringf("%s", sig_clr_name
.c_str());
1412 dump_sigspec(f
, ff
.sig_clr
[i
]);
1414 } else if (ff
.has_arst
) {
1415 f
<< stringf(", %sedge ", ff
.pol_arst
? "pos" : "neg");
1416 if (ff
.sig_arst
[i
].wire
== NULL
)
1417 f
<< stringf("%s", sig_arst_name
.c_str());
1419 dump_sigspec(f
, ff
.sig_arst
);
1421 f
<< stringf(")\n");
1423 f
<< stringf("%s" " ", indent
.c_str());
1425 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1426 if (ff
.sig_clr
[i
].wire
== NULL
)
1427 f
<< stringf("%s", sig_clr_name
.c_str());
1429 dump_sigspec(f
, ff
.sig_clr
[i
]);
1430 f
<< stringf(") %s <= 1'b0;\n", reg_bit_name
.c_str());
1431 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1432 if (ff
.sig_set
[i
].wire
== NULL
)
1433 f
<< stringf("%s", sig_set_name
.c_str());
1435 dump_sigspec(f
, ff
.sig_set
[i
]);
1436 f
<< stringf(") %s <= 1'b1;\n", reg_bit_name
.c_str());
1437 f
<< stringf("%s" " else ", indent
.c_str());
1438 } else if (ff
.has_arst
) {
1439 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1440 if (ff
.sig_arst
[i
].wire
== NULL
)
1441 f
<< stringf("%s", sig_arst_name
.c_str());
1443 dump_sigspec(f
, ff
.sig_arst
);
1444 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1445 dump_sigspec(f
, val_arst
);
1446 f
<< stringf(";\n");
1447 f
<< stringf("%s" " else ", indent
.c_str());
1450 if (ff
.has_srst
&& ff
.has_en
&& ff
.ce_over_srst
) {
1451 f
<< stringf("if (%s", ff
.pol_en
? "" : "!");
1452 dump_sigspec(f
, ff
.sig_en
);
1453 f
<< stringf(")\n");
1454 f
<< stringf("%s" " if (%s", indent
.c_str(), ff
.pol_srst
? "" : "!");
1455 dump_sigspec(f
, ff
.sig_srst
);
1456 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1457 dump_sigspec(f
, val_srst
);
1458 f
<< stringf(";\n");
1459 f
<< stringf("%s" " else ", indent
.c_str());
1462 f
<< stringf("if (%s", ff
.pol_srst
? "" : "!");
1463 dump_sigspec(f
, ff
.sig_srst
);
1464 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1465 dump_sigspec(f
, val_srst
);
1466 f
<< stringf(";\n");
1467 f
<< stringf("%s" " else ", indent
.c_str());
1470 f
<< stringf("if (%s", ff
.pol_en
? "" : "!");
1471 dump_sigspec(f
, ff
.sig_en
);
1476 f
<< stringf("%s <= ", reg_bit_name
.c_str());
1477 dump_sigspec(f
, sig_d
);
1478 f
<< stringf(";\n");
1483 f
<< stringf("%s" "always%s\n", indent
.c_str(), systemverilog
? "_latch" : " @*");
1485 f
<< stringf("%s" " ", indent
.c_str());
1487 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1488 dump_sigspec(f
, ff
.sig_clr
[i
]);
1489 f
<< stringf(") %s = 1'b0;\n", reg_bit_name
.c_str());
1490 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1491 dump_sigspec(f
, ff
.sig_set
[i
]);
1492 f
<< stringf(") %s = 1'b1;\n", reg_bit_name
.c_str());
1494 f
<< stringf("%s" " else ", indent
.c_str());
1495 } else if (ff
.has_arst
) {
1496 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1497 dump_sigspec(f
, ff
.sig_arst
);
1498 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1499 dump_sigspec(f
, val_arst
);
1500 f
<< stringf(";\n");
1502 f
<< stringf("%s" " else ", indent
.c_str());
1505 f
<< stringf("if (%s", ff
.pol_en
? "" : "!");
1506 dump_sigspec(f
, ff
.sig_en
);
1507 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1508 dump_sigspec(f
, sig_d
);
1509 f
<< stringf(";\n");
1514 if (!out_is_reg_wire
) {
1515 f
<< stringf("%s" "assign ", indent
.c_str());
1516 dump_sigspec(f
, ff
.sig_q
);
1517 f
<< stringf(" = %s;\n", reg_name
.c_str());
1523 if (cell
->type
.in(ID($
assert), ID($assume
), ID($cover
)))
1525 f
<< stringf("%s" "always%s if (", indent
.c_str(), systemverilog
? "_comb" : " @*");
1526 dump_sigspec(f
, cell
->getPort(ID::EN
));
1527 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1528 dump_sigspec(f
, cell
->getPort(ID::A
));
1529 f
<< stringf(");\n");
1533 if (cell
->type
.in(ID($specify2
), ID($specify3
)))
1535 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1537 SigSpec en
= cell
->getPort(ID::EN
);
1538 if (en
!= State::S1
) {
1539 f
<< stringf("if (");
1540 dump_sigspec(f
, cell
->getPort(ID::EN
));
1545 if (cell
->type
== ID($specify3
) && cell
->getParam(ID::EDGE_EN
).as_bool())
1546 f
<< (cell
->getParam(ID::EDGE_POL
).as_bool() ? "posedge ": "negedge ");
1548 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1551 if (cell
->getParam(ID::SRC_DST_PEN
).as_bool())
1552 f
<< (cell
->getParam(ID::SRC_DST_POL
).as_bool() ? "+": "-");
1553 f
<< (cell
->getParam(ID::FULL
).as_bool() ? "*> ": "=> ");
1555 if (cell
->type
== ID($specify3
)) {
1557 dump_sigspec(f
, cell
->getPort(ID::DST
));
1559 if (cell
->getParam(ID::DAT_DST_PEN
).as_bool())
1560 f
<< (cell
->getParam(ID::DAT_DST_POL
).as_bool() ? "+": "-");
1562 dump_sigspec(f
, cell
->getPort(ID::DAT
));
1565 dump_sigspec(f
, cell
->getPort(ID::DST
));
1568 bool bak_decimal
= decimal
;
1572 dump_const(f
, cell
->getParam(ID::T_RISE_MIN
));
1574 dump_const(f
, cell
->getParam(ID::T_RISE_TYP
));
1576 dump_const(f
, cell
->getParam(ID::T_RISE_MAX
));
1578 dump_const(f
, cell
->getParam(ID::T_FALL_MIN
));
1580 dump_const(f
, cell
->getParam(ID::T_FALL_TYP
));
1582 dump_const(f
, cell
->getParam(ID::T_FALL_MAX
));
1585 decimal
= bak_decimal
;
1587 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1591 if (cell
->type
== ID($specrule
))
1593 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1595 IdString spec_type
= cell
->getParam(ID::TYPE
).decode_string();
1596 f
<< stringf("%s(", spec_type
.c_str());
1598 if (cell
->getParam(ID::SRC_PEN
).as_bool())
1599 f
<< (cell
->getParam(ID::SRC_POL
).as_bool() ? "posedge ": "negedge ");
1600 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1602 if (cell
->getPort(ID::SRC_EN
) != State::S1
) {
1604 dump_sigspec(f
, cell
->getPort(ID::SRC_EN
));
1608 if (cell
->getParam(ID::DST_PEN
).as_bool())
1609 f
<< (cell
->getParam(ID::DST_POL
).as_bool() ? "posedge ": "negedge ");
1610 dump_sigspec(f
, cell
->getPort(ID::DST
));
1612 if (cell
->getPort(ID::DST_EN
) != State::S1
) {
1614 dump_sigspec(f
, cell
->getPort(ID::DST_EN
));
1617 bool bak_decimal
= decimal
;
1621 dump_const(f
, cell
->getParam(ID::T_LIMIT_MIN
));
1623 dump_const(f
, cell
->getParam(ID::T_LIMIT_TYP
));
1625 dump_const(f
, cell
->getParam(ID::T_LIMIT_MAX
));
1627 if (spec_type
.in(ID($setuphold
), ID($recrem
), ID($fullskew
))) {
1629 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MIN
));
1631 dump_const(f
, cell
->getParam(ID::T_LIMIT2_TYP
));
1633 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MAX
));
1637 decimal
= bak_decimal
;
1639 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1648 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1650 // Handled by dump_memory
1651 if (cell
->is_mem_cell())
1654 if (cell
->type
[0] == '$' && !noexpr
) {
1655 if (dump_cell_expr(f
, indent
, cell
))
1659 dump_attributes(f
, indent
, cell
->attributes
);
1660 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1662 if (!defparam
&& cell
->parameters
.size() > 0) {
1663 f
<< stringf(" #(");
1664 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1665 if (it
!= cell
->parameters
.begin())
1667 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1668 dump_const(f
, it
->second
);
1671 f
<< stringf("\n%s" ")", indent
.c_str());
1674 std::string cell_name
= cellname(cell
);
1675 if (cell_name
!= id(cell
->name
))
1676 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1678 f
<< stringf(" %s (", cell_name
.c_str());
1680 bool first_arg
= true;
1681 std::set
<RTLIL::IdString
> numbered_ports
;
1682 for (int i
= 1; true; i
++) {
1684 snprintf(str
, 16, "$%d", i
);
1685 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1686 if (it
->first
!= str
)
1691 f
<< stringf("\n%s ", indent
.c_str());
1692 dump_sigspec(f
, it
->second
);
1693 numbered_ports
.insert(it
->first
);
1694 goto found_numbered_port
;
1697 found_numbered_port
:;
1699 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1700 if (numbered_ports
.count(it
->first
))
1705 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1706 if (it
->second
.size() > 0)
1707 dump_sigspec(f
, it
->second
);
1710 f
<< stringf("\n%s" ");\n", indent
.c_str());
1712 if (defparam
&& cell
->parameters
.size() > 0) {
1713 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1714 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1715 dump_const(f
, it
->second
);
1716 f
<< stringf(";\n");
1720 if (siminit
&& RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
))) {
1721 std::stringstream ss
;
1722 dump_reg_init(ss
, cell
->getPort(ID::Q
));
1723 if (!ss
.str().empty()) {
1724 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1731 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1735 for (auto &chunk
: left
.chunks()) {
1736 f
<< stringf("%s" "assign ", indent
.c_str());
1737 dump_sigspec(f
, chunk
);
1738 f
<< stringf(" = ");
1739 dump_sigspec(f
, right
.extract(offset
, GetSize(chunk
)));
1740 f
<< stringf(";\n");
1741 offset
+= GetSize(chunk
);
1744 f
<< stringf("%s" "assign ", indent
.c_str());
1745 dump_sigspec(f
, left
);
1746 f
<< stringf(" = ");
1747 dump_sigspec(f
, right
);
1748 f
<< stringf(";\n");
1752 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1754 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1756 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1758 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1759 f
<< stringf("%s" "begin\n", indent
.c_str());
1761 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1762 if (it
->first
.size() == 0)
1764 f
<< stringf("%s ", indent
.c_str());
1765 dump_sigspec(f
, it
->first
);
1766 f
<< stringf(" = ");
1767 dump_sigspec(f
, it
->second
);
1768 f
<< stringf(";\n");
1771 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1772 dump_proc_switch(f
, indent
+ " ", *it
);
1774 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1775 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1777 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1778 f
<< stringf("%s" "end\n", indent
.c_str());
1781 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1783 if (sw
->signal
.size() == 0) {
1784 f
<< stringf("%s" "begin\n", indent
.c_str());
1785 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1786 if ((*it
)->compare
.size() == 0)
1787 dump_case_body(f
, indent
+ " ", *it
);
1789 f
<< stringf("%s" "end\n", indent
.c_str());
1793 dump_attributes(f
, indent
, sw
->attributes
);
1794 f
<< stringf("%s" "casez (", indent
.c_str());
1795 dump_sigspec(f
, sw
->signal
);
1796 f
<< stringf(")\n");
1798 bool got_default
= false;
1799 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1800 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1801 if ((*it
)->compare
.size() == 0) {
1804 f
<< stringf("%s default", indent
.c_str());
1807 f
<< stringf("%s ", indent
.c_str());
1808 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1811 dump_sigspec(f
, (*it
)->compare
[i
]);
1814 f
<< stringf(":\n");
1815 dump_case_body(f
, indent
+ " ", *it
);
1818 f
<< stringf("%s" "endcase\n", indent
.c_str());
1821 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1823 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1824 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1825 case_body_find_regs(*it2
);
1827 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1828 for (auto &c
: it
->first
.chunks())
1830 reg_wires
.insert(c
.wire
->name
);
1834 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1837 case_body_find_regs(&proc
->root_case
);
1838 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1839 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1840 for (auto &c
: it2
->first
.chunks())
1842 reg_wires
.insert(c
.wire
->name
);
1847 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1849 f
<< indent
+ " " << "if (" << id("\\initial") << ") begin end\n";
1850 dump_case_body(f
, indent
, &proc
->root_case
, true);
1852 std::string backup_indent
= indent
;
1854 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1856 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1857 indent
= backup_indent
;
1859 if (sync
->type
== RTLIL::STa
) {
1860 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1861 } else if (sync
->type
== RTLIL::STi
) {
1862 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1864 f
<< stringf("%s" "always%s @(", indent
.c_str(), systemverilog
? "_ff" : "");
1865 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1866 f
<< stringf("posedge ");
1867 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1868 f
<< stringf("negedge ");
1869 dump_sigspec(f
, sync
->signal
);
1870 f
<< stringf(") begin\n");
1872 std::string ends
= indent
+ "end\n";
1875 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1876 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1877 dump_sigspec(f
, sync
->signal
);
1878 f
<< stringf(") begin\n");
1879 ends
= indent
+ "end\n" + ends
;
1883 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1884 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1885 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1886 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1887 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1888 dump_sigspec(f
, sync2
->signal
);
1889 f
<< stringf(") begin\n");
1890 ends
= indent
+ "end\n" + ends
;
1896 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1897 if (it
->first
.size() == 0)
1899 f
<< stringf("%s ", indent
.c_str());
1900 dump_sigspec(f
, it
->first
);
1901 f
<< stringf(" <= ");
1902 dump_sigspec(f
, it
->second
);
1903 f
<< stringf(";\n");
1906 f
<< stringf("%s", ends
.c_str());
1910 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1913 reset_auto_counter(module
);
1914 active_module
= module
;
1915 active_sigmap
.set(module
);
1916 active_initdata
.clear();
1918 for (auto wire
: module
->wires())
1919 if (wire
->attributes
.count(ID::init
)) {
1920 SigSpec sig
= active_sigmap(wire
);
1921 Const val
= wire
->attributes
.at(ID::init
);
1922 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1923 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
1924 active_initdata
[sig
[i
]] = val
[i
];
1927 if (!module
->processes
.empty())
1928 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1929 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1930 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1931 "processes to logic networks and registers.\n", log_id(module
));
1934 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1935 dump_process(f
, indent
+ " ", it
->second
, true);
1939 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1940 for (auto cell
: module
->cells())
1942 if (!RTLIL::builtin_ff_cell_types().count(cell
->type
) || !cell
->hasPort(ID::Q
) || cell
->type
.in(ID($ff
), ID($_FF_
)))
1945 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
1947 if (sig
.is_chunk()) {
1948 RTLIL::SigChunk chunk
= sig
.as_chunk();
1949 if (chunk
.wire
!= NULL
)
1950 for (int i
= 0; i
< chunk
.width
; i
++)
1951 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1954 for (auto wire
: module
->wires())
1956 for (int i
= 0; i
< wire
->width
; i
++)
1957 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1958 goto this_wire_aint_reg
;
1960 reg_wires
.insert(wire
->name
);
1961 this_wire_aint_reg
:;
1965 dump_attributes(f
, indent
, module
->attributes
, '\n', /*modattr=*/true);
1966 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1967 bool keep_running
= true;
1968 for (int port_id
= 1; keep_running
; port_id
++) {
1969 keep_running
= false;
1970 for (auto wire
: module
->wires()) {
1971 if (wire
->port_id
== port_id
) {
1974 f
<< stringf("%s", id(wire
->name
).c_str());
1975 keep_running
= true;
1980 f
<< stringf(");\n");
1982 if (!systemverilog
&& !module
->processes
.empty())
1983 f
<< indent
+ " " << "reg " << id("\\initial") << " = 0;\n";
1985 for (auto w
: module
->wires())
1986 dump_wire(f
, indent
+ " ", w
);
1988 for (auto &mem
: Mem::get_all_memories(module
))
1989 dump_memory(f
, indent
+ " ", mem
);
1991 for (auto cell
: module
->cells())
1992 dump_cell(f
, indent
+ " ", cell
);
1994 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1995 dump_process(f
, indent
+ " ", it
->second
);
1997 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1998 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
2000 f
<< stringf("%s" "endmodule\n", indent
.c_str());
2001 active_module
= NULL
;
2002 active_sigmap
.clear();
2003 active_initdata
.clear();
2006 struct VerilogBackend
: public Backend
{
2007 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
2008 void help() override
2010 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2012 log(" write_verilog [options] [filename]\n");
2014 log("Write the current design to a Verilog file.\n");
2017 log(" with this option, SystemVerilog constructs like always_comb are used\n");
2019 log(" -norename\n");
2020 log(" without this option all internal object names (the ones with a dollar\n");
2021 log(" instead of a backslash prefix) are changed to short names in the\n");
2022 log(" format '_<number>_'.\n");
2024 log(" -renameprefix <prefix>\n");
2025 log(" insert this prefix in front of auto-generated instance names\n");
2028 log(" with this option no attributes are included in the output\n");
2030 log(" -attr2comment\n");
2031 log(" with this option attributes are included as comments in the output\n");
2034 log(" without this option all internal cells are converted to Verilog\n");
2035 log(" expressions.\n");
2038 log(" add initial statements with hierarchical refs to initialize FFs when\n");
2039 log(" in -noexpr mode.\n");
2042 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
2043 log(" not bit pattern. This option deactivates this feature and instead\n");
2044 log(" will write out all constants in binary.\n");
2047 log(" dump 32-bit constants in decimal and without size and radix\n");
2050 log(" constant values that are compatible with hex output are usually\n");
2051 log(" dumped as hex values. This option deactivates this feature and\n");
2052 log(" instead will write out all constants in binary.\n");
2055 log(" Parameters and attributes that are specified as strings in the\n");
2056 log(" original input will be output as strings by this back-end. This\n");
2057 log(" deactivates this feature and instead will write string constants\n");
2058 log(" as binary numbers.\n");
2060 log(" -simple-lhs\n");
2061 log(" Connection assignments with simple left hand side without concatenations.\n");
2064 log(" instead of initializing memories using assignments to individual\n");
2065 log(" elements, use the '$readmemh' function to read initialization data\n");
2066 log(" from a file. This data is written to a file named by appending\n");
2067 log(" a sequential index to the Verilog filename and replacing the extension\n");
2068 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
2069 log(" 'foo-2.mem' and so on.\n");
2071 log(" -defparam\n");
2072 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
2073 log(" cell parameters.\n");
2075 log(" -blackboxes\n");
2076 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
2077 log(" this option set only the modules with the 'blackbox' attribute\n");
2078 log(" are written to the output file.\n");
2080 log(" -selected\n");
2081 log(" only write selected modules. modules must be selected entirely or\n");
2082 log(" not at all.\n");
2085 log(" verbose output (print new names of all renamed wires and cells)\n");
2087 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
2088 log("always blocks. This frontend should only be used to export an RTLIL\n");
2089 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
2090 log("processes to logic networks and registers. A warning is generated when\n");
2091 log("this command is called on a design with RTLIL processes.\n");
2094 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2096 log_header(design
, "Executing Verilog backend.\n");
2101 attr2comment
= false;
2113 bool blackboxes
= false;
2114 bool selected
= false;
2116 auto_name_map
.clear();
2120 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2121 std::string arg
= args
[argidx
];
2123 systemverilog
= true;
2126 if (arg
== "-norename") {
2130 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
2131 auto_prefix
= args
[++argidx
];
2134 if (arg
== "-noattr") {
2138 if (arg
== "-attr2comment") {
2139 attr2comment
= true;
2142 if (arg
== "-noexpr") {
2146 if (arg
== "-nodec") {
2150 if (arg
== "-nohex") {
2154 if (arg
== "-nostr") {
2158 if (arg
== "-extmem") {
2163 if (arg
== "-defparam") {
2167 if (arg
== "-decimal") {
2171 if (arg
== "-siminit") {
2175 if (arg
== "-blackboxes") {
2179 if (arg
== "-selected") {
2183 if (arg
== "-simple-lhs") {
2193 extra_args(f
, filename
, args
, argidx
);
2196 if (filename
== "<stdout>")
2197 log_cmd_error("Option -extmem must be used with a filename.\n");
2198 extmem_prefix
= filename
.substr(0, filename
.rfind('.'));
2203 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
2204 for (auto module
: design
->modules()) {
2205 if (module
->get_blackbox_attribute() != blackboxes
)
2207 if (selected
&& !design
->selected_whole_module(module
->name
)) {
2208 if (design
->selected_module(module
->name
))
2209 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module
->name
));
2212 log("Dumping module `%s'.\n", module
->name
.c_str());
2213 dump_module(*f
, "", module
);
2216 auto_name_map
.clear();
2221 PRIVATE_NAMESPACE_END