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();
557 // Decide how to represent the transparency; same idea as Mem::extract_rdff.
558 bool trans_use_addr
= true;
559 for (auto bit
: port
.transparency_mask
)
561 trans_use_addr
= false;
563 if (GetSize(mem
.wr_ports
) == 0)
564 trans_use_addr
= false;
566 if (port
.en
!= State::S1
|| port
.srst
!= State::S0
|| port
.arst
!= State::S0
|| !port
.init_value
.is_fully_undef())
567 trans_use_addr
= false;
571 // for clocked read ports make something like:
573 // always @(posedge clk)
574 // if (rd_en) temp_id <= array_reg[r_addr];
575 // assign r_data = temp_id;
576 std::string temp_id
= next_auto_id();
577 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", port
.data
.size() - 1, temp_id
.c_str()) );
579 bool has_indent
= false;
581 if (port
.arst
!= State::S0
) {
582 std::ostringstream os
;
583 os
<< stringf("%s <= ", temp_id
.c_str());
584 dump_sigspec(os
, port
.arst_value
);
586 clk_to_arst_body
[clk_domain_str
].push_back(os
.str());
589 if (port
.srst
!= State::S0
&& !port
.ce_over_srst
) {
590 std::ostringstream os
;
591 os
<< stringf("if (");
592 dump_sigspec(os
, port
.srst
);
593 os
<< stringf(")\n");
594 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
595 std::ostringstream os2
;
596 os2
<< stringf("%s" "%s <= ", indent
.c_str(), temp_id
.c_str());
597 dump_sigspec(os2
, port
.srst_value
);
599 clk_to_lof_body
[clk_domain_str
].push_back(os2
.str());
600 std::ostringstream os3
;
601 if (port
.en
== State::S1
) {
602 os3
<< "else begin\n";
605 dump_sigspec(os3
, port
.en
);
608 clk_to_lof_body
[clk_domain_str
].push_back(os3
.str());
610 } else if (port
.en
!= State::S1
) {
611 std::ostringstream os
;
612 os
<< stringf("if (");
613 dump_sigspec(os
, port
.en
);
614 os
<< stringf(") begin\n");
615 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
619 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
621 SigSpec addr
= port
.sub_addr(sub
);
622 std::ostringstream os
;
627 os
<< stringf("[%d:%d]", (sub
+ 1) * mem
.width
- 1, sub
* mem
.width
);
628 os
<< stringf(" <= %s[", mem_id
.c_str());
629 dump_sigspec(os
, addr
);
630 os
<< stringf("];\n");
631 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
634 for (int i
= 0; i
< GetSize(mem
.wr_ports
); i
++) {
635 auto &wport
= mem
.wr_ports
[i
];
636 if (!port
.transparency_mask
[i
] && !port
.collision_x_mask
[i
])
638 int min_wide_log2
= std::min(port
.wide_log2
, wport
.wide_log2
);
639 int max_wide_log2
= std::max(port
.wide_log2
, wport
.wide_log2
);
640 bool wide_write
= wport
.wide_log2
> port
.wide_log2
;
641 for (int sub
= 0; sub
< (1 << max_wide_log2
); sub
+= (1 << min_wide_log2
)) {
642 SigSpec raddr
= port
.addr
;
643 SigSpec waddr
= wport
.addr
;
645 waddr
= wport
.sub_addr(sub
);
647 raddr
= port
.sub_addr(sub
);
649 int ewidth
= mem
.width
<< min_wide_log2
;
650 int wsub
= wide_write
? sub
: 0;
651 int rsub
= wide_write
? 0 : sub
;
652 while (pos
< ewidth
) {
654 while (epos
< ewidth
&& wport
.en
[epos
+ wsub
* mem
.width
] == wport
.en
[pos
+ wsub
* mem
.width
])
657 std::ostringstream os
;
661 dump_sigspec(os
, wport
.en
[pos
+ wsub
* mem
.width
]);
662 if (raddr
!= waddr
) {
664 dump_sigspec(os
, raddr
);
666 dump_sigspec(os
, waddr
);
669 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
671 std::ostringstream os2
;
676 if (epos
-pos
!= GetSize(port
.data
))
677 os2
<< stringf("[%d:%d]", rsub
* mem
.width
+ epos
-1, rsub
* mem
.width
+ pos
);
679 if (port
.transparency_mask
[i
])
680 dump_sigspec(os2
, wport
.data
.extract(wsub
* mem
.width
+ pos
, epos
-pos
));
682 dump_sigspec(os2
, Const(State::Sx
, epos
- pos
));
684 clk_to_lof_body
[clk_domain_str
].push_back(os2
.str());
691 if (port
.srst
!= State::S0
&& port
.ce_over_srst
)
693 std::ostringstream os
;
696 os
<< stringf("if (");
697 dump_sigspec(os
, port
.srst
);
698 os
<< stringf(")\n");
699 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
700 std::ostringstream os2
;
703 os2
<< stringf("%s" "%s <= ", indent
.c_str(), temp_id
.c_str());
704 dump_sigspec(os2
, port
.srst_value
);
706 clk_to_lof_body
[clk_domain_str
].push_back(os2
.str());
710 clk_to_lof_body
[clk_domain_str
].push_back("end\n");
712 if (!port
.init_value
.is_fully_undef())
714 std::ostringstream os
;
715 dump_sigspec(os
, port
.init_value
);
716 std::string line
= stringf("initial %s = %s;\n", temp_id
.c_str(), os
.str().c_str());
717 clk_to_lof_body
[""].push_back(line
);
721 std::ostringstream os
;
722 dump_sigspec(os
, port
.data
);
723 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
724 clk_to_lof_body
[""].push_back(line
);
729 // for rd-transparent read-ports make something like:
731 // always @(posedge clk)
732 // temp_id <= r_addr;
733 // assign r_data = array_reg[temp_id];
734 std::string temp_id
= next_auto_id();
735 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", port
.addr
.size() - 1 - port
.wide_log2
, temp_id
.c_str()) );
737 std::ostringstream os
;
738 dump_sigspec(os
, port
.addr
.extract_end(port
.wide_log2
));
739 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
740 clk_to_lof_body
[clk_domain_str
].push_back(line
);
742 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
744 std::ostringstream os
;
746 dump_sigspec(os
, port
.data
.extract(sub
* mem
.width
, mem
.width
));
747 os
<< stringf(" = %s[", mem_id
.c_str());;
748 if (port
.wide_log2
) {
750 for (int i
= 0; i
< port
.wide_log2
; i
++)
751 addr_lo
.bits
.push_back(State(sub
>> i
& 1));
755 dump_const(os
, addr_lo
);
761 clk_to_lof_body
[""].push_back(os
.str());
765 // for non-clocked read-ports make something like:
766 // assign r_data = array_reg[r_addr];
767 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
769 SigSpec addr
= port
.sub_addr(sub
);
771 std::ostringstream os
, os2
;
772 dump_sigspec(os
, port
.data
.extract(sub
* mem
.width
, mem
.width
));
773 dump_sigspec(os2
, addr
);
774 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
775 clk_to_lof_body
[""].push_back(line
);
780 // Write ports. Those are messy because we try to preserve priority, as much as we can:
782 // 1. We split all ports into several disjoint processes.
783 // 2. If a port has priority over another port, the two ports need to share
784 // a process, so that priority can be reconstructed on the other end.
785 // 3. We want each process to be as small as possible, to avoid extra
786 // priorities inferred on the other end.
787 pool
<int> wr_ports_done
;
788 for (int ridx
= 0; ridx
< GetSize(mem
.wr_ports
); ridx
++)
790 if (wr_ports_done
.count(ridx
))
793 auto &root
= mem
.wr_ports
[ridx
];
795 // Start from a root.
796 pool
<int> wr_ports_now
;
797 wr_ports_now
.insert(ridx
);
799 // Transitively fill list of ports in this process by following priority edges.
802 bool changed
= false;
804 for (int i
= 0; i
< GetSize(mem
.wr_ports
); i
++)
805 for (int j
= 0; j
< i
; j
++)
806 if (mem
.wr_ports
[i
].priority_mask
[j
])
808 if (wr_ports_now
.count(i
) && !wr_ports_now
.count(j
)) {
809 wr_ports_now
.insert(j
);
812 if (!wr_ports_now
.count(i
) && wr_ports_now
.count(j
)) {
813 wr_ports_now
.insert(i
);
822 if (root
.clk_enable
) {
823 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", root
.clk_polarity
? "pos" : "neg");
824 dump_sigspec(f
, root
.clk
);
827 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_latch" : " @*");
830 for (int pidx
= 0; pidx
< GetSize(mem
.wr_ports
); pidx
++)
832 if (!wr_ports_now
.count(pidx
))
834 wr_ports_done
.insert(pidx
);
836 auto &port
= mem
.wr_ports
[pidx
];
837 log_assert(port
.clk_enable
== root
.clk_enable
);
838 if (port
.clk_enable
) {
839 log_assert(port
.clk
== root
.clk
);
840 log_assert(port
.clk_polarity
== root
.clk_polarity
);
843 // make something like:
844 // always @(posedge clk)
845 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
847 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
849 SigSpec addr
= port
.sub_addr(sub
);
850 for (int i
= 0; i
< mem
.width
; i
++)
852 int start_i
= i
, width
= 1;
853 SigBit wen_bit
= port
.en
[sub
* mem
.width
+ i
];
855 while (i
+1 < mem
.width
&& active_sigmap(port
.en
[sub
* mem
.width
+ i
+1]) == active_sigmap(wen_bit
))
858 if (wen_bit
== State::S0
)
861 f
<< stringf("%s%s", indent
.c_str(), indent
.c_str());
862 if (wen_bit
!= State::S1
)
864 f
<< stringf("if (");
865 dump_sigspec(f
, wen_bit
);
867 f
<< stringf("%s%s%s", indent
.c_str(), indent
.c_str(), indent
.c_str());
869 f
<< stringf("%s[", mem_id
.c_str());
870 dump_sigspec(f
, addr
);
871 if (width
== GetSize(port
.en
))
872 f
<< stringf("] <= ");
874 f
<< stringf("][%d:%d] <= ", i
, start_i
);
875 dump_sigspec(f
, port
.data
.extract(sub
* mem
.width
+ start_i
, width
));
881 f
<< stringf("%s" "end\n", indent
.c_str());
883 // Output Verilog that looks something like this:
885 // always @(posedge CLK2) begin
886 // _3_ <= memory[D1ADDR];
888 // memory[A1ADDR] <= A1DATA;
890 // memory[A2ADDR] <= A2DATA;
893 // always @(negedge CLK1) begin
895 // memory[C1ADDR] <= C1DATA;
898 // assign D1DATA = _3_;
899 // assign D2DATA <= memory[D2ADDR];
901 // the reg ... definitions
902 for(auto ®
: lof_reg_declarations
)
904 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
906 // the block of expressions by clock domain
907 for(auto &pair
: clk_to_lof_body
)
909 std::string clk_domain
= pair
.first
;
910 std::vector
<std::string
> lof_lines
= pair
.second
;
911 if( clk_domain
!= "")
913 f
<< stringf("%s" "always%s @(%s) begin\n", indent
.c_str(), systemverilog
? "_ff" : "", clk_domain
.c_str());
914 bool has_arst
= clk_to_arst_cond
.count(clk_domain
) != 0;
916 f
<< stringf("%s%s" "if (%s) begin\n", indent
.c_str(), indent
.c_str(), clk_to_arst_cond
[clk_domain
].c_str());
917 for(auto &line
: clk_to_arst_body
[clk_domain
])
918 f
<< stringf("%s%s%s" "%s", indent
.c_str(), indent
.c_str(), indent
.c_str(), line
.c_str());
919 f
<< stringf("%s%s" "end else begin\n", indent
.c_str(), indent
.c_str());
920 for(auto &line
: lof_lines
)
921 f
<< stringf("%s%s%s" "%s", indent
.c_str(), indent
.c_str(), indent
.c_str(), line
.c_str());
922 f
<< stringf("%s%s" "end\n", indent
.c_str(), indent
.c_str());
924 for(auto &line
: lof_lines
)
925 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
927 f
<< stringf("%s" "end\n", indent
.c_str());
931 // the non-clocked assignments
932 for(auto &line
: lof_lines
)
933 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
938 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
940 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
941 f
<< stringf("$signed(");
942 dump_sigspec(f
, cell
->getPort("\\" + port
));
945 dump_sigspec(f
, cell
->getPort("\\" + port
));
948 std::string
cellname(RTLIL::Cell
*cell
)
950 if (!norename
&& cell
->name
[0] == '$' && RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
)))
952 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
953 if (GetSize(sig
) != 1 || sig
.is_fully_const())
954 goto no_special_reg_name
;
956 RTLIL::Wire
*wire
= sig
[0].wire
;
958 if (wire
->name
[0] != '\\')
959 goto no_special_reg_name
;
961 std::string cell_name
= wire
->name
.str();
963 size_t pos
= cell_name
.find('[');
964 if (pos
!= std::string::npos
)
965 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
967 cell_name
= cell_name
+ "_reg";
969 if (wire
->width
!= 1)
970 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
972 if (active_module
&& active_module
->count_id(cell_name
) > 0)
973 goto no_special_reg_name
;
975 return id(cell_name
);
980 return id(cell
->name
).c_str();
984 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
986 f
<< stringf("%s" "assign ", indent
.c_str());
987 dump_sigspec(f
, cell
->getPort(ID::Y
));
988 f
<< stringf(" = %s ", op
.c_str());
989 dump_attributes(f
, "", cell
->attributes
, ' ');
990 dump_cell_expr_port(f
, cell
, "A", true);
994 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
996 f
<< stringf("%s" "assign ", indent
.c_str());
997 dump_sigspec(f
, cell
->getPort(ID::Y
));
999 dump_cell_expr_port(f
, cell
, "A", true);
1000 f
<< stringf(" %s ", op
.c_str());
1001 dump_attributes(f
, "", cell
->attributes
, ' ');
1002 dump_cell_expr_port(f
, cell
, "B", true);
1003 f
<< stringf(";\n");
1006 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1008 if (cell
->type
== ID($_NOT_
)) {
1009 f
<< stringf("%s" "assign ", indent
.c_str());
1010 dump_sigspec(f
, cell
->getPort(ID::Y
));
1011 f
<< stringf(" = ");
1013 dump_attributes(f
, "", cell
->attributes
, ' ');
1014 dump_cell_expr_port(f
, cell
, "A", false);
1015 f
<< stringf(";\n");
1019 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_OR_
), ID($_NOR_
), ID($_XOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
))) {
1020 f
<< stringf("%s" "assign ", indent
.c_str());
1021 dump_sigspec(f
, cell
->getPort(ID::Y
));
1022 f
<< stringf(" = ");
1023 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
)))
1025 dump_cell_expr_port(f
, cell
, "A", false);
1027 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_ANDNOT_
)))
1029 if (cell
->type
.in(ID($_OR_
), ID($_NOR_
), ID($_ORNOT_
)))
1031 if (cell
->type
.in(ID($_XOR_
), ID($_XNOR_
)))
1033 dump_attributes(f
, "", cell
->attributes
, ' ');
1035 if (cell
->type
.in(ID($_ANDNOT_
), ID($_ORNOT_
)))
1037 dump_cell_expr_port(f
, cell
, "B", false);
1038 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
)))
1040 f
<< stringf(";\n");
1044 if (cell
->type
== ID($_MUX_
)) {
1045 f
<< stringf("%s" "assign ", indent
.c_str());
1046 dump_sigspec(f
, cell
->getPort(ID::Y
));
1047 f
<< stringf(" = ");
1048 dump_cell_expr_port(f
, cell
, "S", false);
1049 f
<< stringf(" ? ");
1050 dump_attributes(f
, "", cell
->attributes
, ' ');
1051 dump_cell_expr_port(f
, cell
, "B", false);
1052 f
<< stringf(" : ");
1053 dump_cell_expr_port(f
, cell
, "A", false);
1054 f
<< stringf(";\n");
1058 if (cell
->type
== ID($_NMUX_
)) {
1059 f
<< stringf("%s" "assign ", indent
.c_str());
1060 dump_sigspec(f
, cell
->getPort(ID::Y
));
1061 f
<< stringf(" = !(");
1062 dump_cell_expr_port(f
, cell
, "S", false);
1063 f
<< stringf(" ? ");
1064 dump_attributes(f
, "", cell
->attributes
, ' ');
1065 dump_cell_expr_port(f
, cell
, "B", false);
1066 f
<< stringf(" : ");
1067 dump_cell_expr_port(f
, cell
, "A", false);
1068 f
<< stringf(");\n");
1072 if (cell
->type
.in(ID($_AOI3_
), ID($_OAI3_
))) {
1073 f
<< stringf("%s" "assign ", indent
.c_str());
1074 dump_sigspec(f
, cell
->getPort(ID::Y
));
1075 f
<< stringf(" = ~((");
1076 dump_cell_expr_port(f
, cell
, "A", false);
1077 f
<< stringf(cell
->type
== ID($_AOI3_
) ? " & " : " | ");
1078 dump_cell_expr_port(f
, cell
, "B", false);
1079 f
<< stringf(cell
->type
== ID($_AOI3_
) ? ") |" : ") &");
1080 dump_attributes(f
, "", cell
->attributes
, ' ');
1082 dump_cell_expr_port(f
, cell
, "C", false);
1083 f
<< stringf(");\n");
1087 if (cell
->type
.in(ID($_AOI4_
), ID($_OAI4_
))) {
1088 f
<< stringf("%s" "assign ", indent
.c_str());
1089 dump_sigspec(f
, cell
->getPort(ID::Y
));
1090 f
<< stringf(" = ~((");
1091 dump_cell_expr_port(f
, cell
, "A", false);
1092 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
1093 dump_cell_expr_port(f
, cell
, "B", false);
1094 f
<< stringf(cell
->type
== ID($_AOI4_
) ? ") |" : ") &");
1095 dump_attributes(f
, "", cell
->attributes
, ' ');
1097 dump_cell_expr_port(f
, cell
, "C", false);
1098 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
1099 dump_cell_expr_port(f
, cell
, "D", false);
1100 f
<< stringf("));\n");
1104 #define HANDLE_UNIOP(_type, _operator) \
1105 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
1106 #define HANDLE_BINOP(_type, _operator) \
1107 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
1109 HANDLE_UNIOP(ID($
not), "~")
1110 HANDLE_UNIOP(ID($pos
), "+")
1111 HANDLE_UNIOP(ID($neg
), "-")
1113 HANDLE_BINOP(ID($
and), "&")
1114 HANDLE_BINOP(ID($
or), "|")
1115 HANDLE_BINOP(ID($
xor), "^")
1116 HANDLE_BINOP(ID($xnor
), "~^")
1118 HANDLE_UNIOP(ID($reduce_and
), "&")
1119 HANDLE_UNIOP(ID($reduce_or
), "|")
1120 HANDLE_UNIOP(ID($reduce_xor
), "^")
1121 HANDLE_UNIOP(ID($reduce_xnor
), "~^")
1122 HANDLE_UNIOP(ID($reduce_bool
), "|")
1124 HANDLE_BINOP(ID($shl
), "<<")
1125 HANDLE_BINOP(ID($shr
), ">>")
1126 HANDLE_BINOP(ID($sshl
), "<<<")
1127 HANDLE_BINOP(ID($sshr
), ">>>")
1129 HANDLE_BINOP(ID($lt
), "<")
1130 HANDLE_BINOP(ID($le
), "<=")
1131 HANDLE_BINOP(ID($eq
), "==")
1132 HANDLE_BINOP(ID($ne
), "!=")
1133 HANDLE_BINOP(ID($eqx
), "===")
1134 HANDLE_BINOP(ID($nex
), "!==")
1135 HANDLE_BINOP(ID($ge
), ">=")
1136 HANDLE_BINOP(ID($gt
), ">")
1138 HANDLE_BINOP(ID($add
), "+")
1139 HANDLE_BINOP(ID($sub
), "-")
1140 HANDLE_BINOP(ID($mul
), "*")
1141 HANDLE_BINOP(ID($div
), "/")
1142 HANDLE_BINOP(ID($mod
), "%")
1143 HANDLE_BINOP(ID($pow
), "**")
1145 HANDLE_UNIOP(ID($logic_not
), "!")
1146 HANDLE_BINOP(ID($logic_and
), "&&")
1147 HANDLE_BINOP(ID($logic_or
), "||")
1152 if (cell
->type
== ID($divfloor
))
1154 // wire [MAXLEN+1:0] _0_, _1_, _2_;
1155 // assign _0_ = $signed(A);
1156 // assign _1_ = $signed(B);
1157 // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
1158 // assign Y = $signed(_2_) / $signed(_1_);
1160 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
1161 SigSpec sig_a
= cell
->getPort(ID::A
);
1162 SigSpec sig_b
= cell
->getPort(ID::B
);
1164 std::string buf_a
= next_auto_id();
1165 std::string buf_b
= next_auto_id();
1166 std::string buf_num
= next_auto_id();
1167 int size_a
= GetSize(sig_a
);
1168 int size_b
= GetSize(sig_b
);
1169 int size_y
= GetSize(cell
->getPort(ID::Y
));
1170 int size_max
= std::max(size_a
, std::max(size_b
, size_y
));
1172 // intentionally one wider than maximum width
1173 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());
1174 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_a
.c_str());
1175 dump_cell_expr_port(f
, cell
, "A", true);
1176 f
<< stringf(";\n");
1177 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_b
.c_str());
1178 dump_cell_expr_port(f
, cell
, "B", true);
1179 f
<< stringf(";\n");
1181 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_num
.c_str());
1183 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
1184 f
<< stringf(" == ");
1185 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
1186 f
<< stringf(") || ");
1187 dump_sigspec(f
, sig_a
);
1188 f
<< stringf(" == 0 ? %s : ", buf_a
.c_str());
1189 f
<< stringf("$signed(%s - (", buf_a
.c_str());
1190 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
1191 f
<< stringf(" ? %s + 1 : %s - 1));\n", buf_b
.c_str(), buf_b
.c_str());
1194 f
<< stringf("%s" "assign ", indent
.c_str());
1195 dump_sigspec(f
, cell
->getPort(ID::Y
));
1196 f
<< stringf(" = $signed(%s) / ", buf_num
.c_str());
1197 dump_attributes(f
, "", cell
->attributes
, ' ');
1198 f
<< stringf("$signed(%s);\n", buf_b
.c_str());
1201 // same as truncating division
1202 dump_cell_expr_binop(f
, indent
, cell
, "/");
1207 if (cell
->type
== ID($modfloor
))
1209 // wire truncated = $signed(A) % $signed(B);
1210 // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated);
1212 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
1213 SigSpec sig_a
= cell
->getPort(ID::A
);
1214 SigSpec sig_b
= cell
->getPort(ID::B
);
1216 std::string temp_id
= next_auto_id();
1217 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
1218 dump_cell_expr_port(f
, cell
, "A", true);
1219 f
<< stringf(" %% ");
1220 dump_attributes(f
, "", cell
->attributes
, ' ');
1221 dump_cell_expr_port(f
, cell
, "B", true);
1222 f
<< stringf(";\n");
1224 f
<< stringf("%s" "assign ", indent
.c_str());
1225 dump_sigspec(f
, cell
->getPort(ID::Y
));
1226 f
<< stringf(" = (");
1227 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
1228 f
<< stringf(" == ");
1229 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
1230 f
<< stringf(") || %s == 0 ? %s : ", temp_id
.c_str(), temp_id
.c_str());
1231 dump_cell_expr_port(f
, cell
, "B", true);
1232 f
<< stringf(" + $signed(%s);\n", temp_id
.c_str());
1235 // same as truncating modulo
1236 dump_cell_expr_binop(f
, indent
, cell
, "%");
1241 if (cell
->type
== ID($shift
))
1243 f
<< stringf("%s" "assign ", indent
.c_str());
1244 dump_sigspec(f
, cell
->getPort(ID::Y
));
1245 f
<< stringf(" = ");
1246 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1248 dump_cell_expr_port(f
, cell
, "B", true);
1249 f
<< stringf(" < 0 ? ");
1250 dump_cell_expr_port(f
, cell
, "A", true);
1251 f
<< stringf(" << - ");
1252 dump_sigspec(f
, cell
->getPort(ID::B
));
1253 f
<< stringf(" : ");
1254 dump_cell_expr_port(f
, cell
, "A", true);
1255 f
<< stringf(" >> ");
1256 dump_sigspec(f
, cell
->getPort(ID::B
));
1260 dump_cell_expr_port(f
, cell
, "A", true);
1261 f
<< stringf(" >> ");
1262 dump_sigspec(f
, cell
->getPort(ID::B
));
1264 f
<< stringf(";\n");
1268 if (cell
->type
== ID($shiftx
))
1270 std::string temp_id
= next_auto_id();
1271 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
1272 dump_sigspec(f
, cell
->getPort(ID::A
));
1273 f
<< stringf(";\n");
1275 f
<< stringf("%s" "assign ", indent
.c_str());
1276 dump_sigspec(f
, cell
->getPort(ID::Y
));
1277 f
<< stringf(" = %s[", temp_id
.c_str());
1278 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1279 f
<< stringf("$signed(");
1280 dump_sigspec(f
, cell
->getPort(ID::B
));
1281 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1283 f
<< stringf(" +: %d", cell
->getParam(ID::Y_WIDTH
).as_int());
1284 f
<< stringf("];\n");
1288 if (cell
->type
== ID($mux
))
1290 f
<< stringf("%s" "assign ", indent
.c_str());
1291 dump_sigspec(f
, cell
->getPort(ID::Y
));
1292 f
<< stringf(" = ");
1293 dump_sigspec(f
, cell
->getPort(ID::S
));
1294 f
<< stringf(" ? ");
1295 dump_attributes(f
, "", cell
->attributes
, ' ');
1296 dump_sigspec(f
, cell
->getPort(ID::B
));
1297 f
<< stringf(" : ");
1298 dump_sigspec(f
, cell
->getPort(ID::A
));
1299 f
<< stringf(";\n");
1303 if (cell
->type
== ID($pmux
))
1305 int width
= cell
->parameters
[ID::WIDTH
].as_int();
1306 int s_width
= cell
->getPort(ID::S
).size();
1307 std::string func_name
= cellname(cell
);
1309 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
1310 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
1311 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
1312 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
1314 dump_attributes(f
, indent
+ " ", cell
->attributes
);
1316 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
1317 f
<< stringf("%s" " casez (s)", indent
.c_str());
1318 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
1320 for (int i
= 0; i
< s_width
; i
++)
1322 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
1324 for (int j
= s_width
-1; j
>= 0; j
--)
1325 f
<< stringf("%c", j
== i
? '1' : '?');
1327 f
<< stringf(":\n");
1328 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
1331 f
<< stringf("%s" " default:\n", indent
.c_str());
1332 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
1334 f
<< stringf("%s" " endcase\n", indent
.c_str());
1335 f
<< stringf("%s" "endfunction\n", indent
.c_str());
1337 f
<< stringf("%s" "assign ", indent
.c_str());
1338 dump_sigspec(f
, cell
->getPort(ID::Y
));
1339 f
<< stringf(" = %s(", func_name
.c_str());
1340 dump_sigspec(f
, cell
->getPort(ID::A
));
1342 dump_sigspec(f
, cell
->getPort(ID::B
));
1344 dump_sigspec(f
, cell
->getPort(ID::S
));
1345 f
<< stringf(");\n");
1349 if (cell
->type
== ID($tribuf
))
1351 f
<< stringf("%s" "assign ", indent
.c_str());
1352 dump_sigspec(f
, cell
->getPort(ID::Y
));
1353 f
<< stringf(" = ");
1354 dump_sigspec(f
, cell
->getPort(ID::EN
));
1355 f
<< stringf(" ? ");
1356 dump_sigspec(f
, cell
->getPort(ID::A
));
1357 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at(ID::WIDTH
).as_int());
1361 if (cell
->type
== ID($slice
))
1363 f
<< stringf("%s" "assign ", indent
.c_str());
1364 dump_sigspec(f
, cell
->getPort(ID::Y
));
1365 f
<< stringf(" = ");
1366 dump_sigspec(f
, cell
->getPort(ID::A
));
1367 f
<< stringf(" >> %d;\n", cell
->parameters
.at(ID::OFFSET
).as_int());
1371 if (cell
->type
== ID($concat
))
1373 f
<< stringf("%s" "assign ", indent
.c_str());
1374 dump_sigspec(f
, cell
->getPort(ID::Y
));
1375 f
<< stringf(" = { ");
1376 dump_sigspec(f
, cell
->getPort(ID::B
));
1377 f
<< stringf(" , ");
1378 dump_sigspec(f
, cell
->getPort(ID::A
));
1379 f
<< stringf(" };\n");
1383 if (cell
->type
== ID($lut
))
1385 f
<< stringf("%s" "assign ", indent
.c_str());
1386 dump_sigspec(f
, cell
->getPort(ID::Y
));
1387 f
<< stringf(" = ");
1388 dump_const(f
, cell
->parameters
.at(ID::LUT
));
1389 f
<< stringf(" >> ");
1390 dump_attributes(f
, "", cell
->attributes
, ' ');
1391 dump_sigspec(f
, cell
->getPort(ID::A
));
1392 f
<< stringf(";\n");
1396 if (RTLIL::builtin_ff_cell_types().count(cell
->type
))
1398 FfData
ff(nullptr, cell
);
1400 // $ff / $_FF_ cell: not supported.
1404 std::string reg_name
= cellname(cell
);
1405 bool out_is_reg_wire
= is_reg_wire(ff
.sig_q
, reg_name
);
1407 if (!out_is_reg_wire
) {
1409 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
1411 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), ff
.width
-1, reg_name
.c_str());
1412 dump_reg_init(f
, ff
.sig_q
);
1416 // If the FF has CLR/SET inputs, emit every bit slice separately.
1417 int chunks
= ff
.has_sr
? ff
.width
: 1;
1418 bool chunky
= ff
.has_sr
&& ff
.width
!= 1;
1420 for (int i
= 0; i
< chunks
; i
++)
1422 SigSpec sig_d
, sig_ad
;
1423 Const val_arst
, val_srst
;
1424 std::string reg_bit_name
, sig_set_name
, sig_clr_name
, sig_arst_name
, sig_aload_name
;
1426 reg_bit_name
= stringf("%s[%d]", reg_name
.c_str(), i
);
1427 if (ff
.has_gclk
|| ff
.has_clk
)
1428 sig_d
= ff
.sig_d
[i
];
1430 sig_ad
= ff
.sig_ad
[i
];
1432 reg_bit_name
= reg_name
;
1437 val_arst
= chunky
? ff
.val_arst
[i
] : ff
.val_arst
;
1439 val_srst
= chunky
? ff
.val_srst
[i
] : ff
.val_srst
;
1441 // If there are constants in the sensitivity list, replace them with an intermediate wire
1444 if (ff
.sig_set
[i
].wire
== NULL
)
1446 sig_set_name
= next_auto_id();
1447 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_set_name
.c_str());
1448 dump_const(f
, ff
.sig_set
[i
].data
);
1449 f
<< stringf(";\n");
1451 if (ff
.sig_clr
[i
].wire
== NULL
)
1453 sig_clr_name
= next_auto_id();
1454 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_clr_name
.c_str());
1455 dump_const(f
, ff
.sig_clr
[i
].data
);
1456 f
<< stringf(";\n");
1458 } else if (ff
.has_arst
) {
1459 if (ff
.sig_arst
[0].wire
== NULL
)
1461 sig_arst_name
= next_auto_id();
1462 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_arst_name
.c_str());
1463 dump_const(f
, ff
.sig_arst
[0].data
);
1464 f
<< stringf(";\n");
1466 } else if (ff
.has_aload
) {
1467 if (ff
.sig_aload
[0].wire
== NULL
)
1469 sig_aload_name
= next_auto_id();
1470 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_aload_name
.c_str());
1471 dump_const(f
, ff
.sig_aload
[0].data
);
1472 f
<< stringf(";\n");
1477 dump_attributes(f
, indent
, cell
->attributes
);
1481 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", ff
.pol_clk
? "pos" : "neg");
1482 dump_sigspec(f
, ff
.sig_clk
);
1484 f
<< stringf(", %sedge ", ff
.pol_set
? "pos" : "neg");
1485 if (ff
.sig_set
[i
].wire
== NULL
)
1486 f
<< stringf("%s", sig_set_name
.c_str());
1488 dump_sigspec(f
, ff
.sig_set
[i
]);
1490 f
<< stringf(", %sedge ", ff
.pol_clr
? "pos" : "neg");
1491 if (ff
.sig_clr
[i
].wire
== NULL
)
1492 f
<< stringf("%s", sig_clr_name
.c_str());
1494 dump_sigspec(f
, ff
.sig_clr
[i
]);
1495 } else if (ff
.has_arst
) {
1496 f
<< stringf(", %sedge ", ff
.pol_arst
? "pos" : "neg");
1497 if (ff
.sig_arst
[0].wire
== NULL
)
1498 f
<< stringf("%s", sig_arst_name
.c_str());
1500 dump_sigspec(f
, ff
.sig_arst
);
1501 } else if (ff
.has_aload
) {
1502 f
<< stringf(", %sedge ", ff
.pol_aload
? "pos" : "neg");
1503 if (ff
.sig_aload
[0].wire
== NULL
)
1504 f
<< stringf("%s", sig_aload_name
.c_str());
1506 dump_sigspec(f
, ff
.sig_aload
);
1508 f
<< stringf(")\n");
1510 f
<< stringf("%s" " ", indent
.c_str());
1512 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1513 if (ff
.sig_clr
[i
].wire
== NULL
)
1514 f
<< stringf("%s", sig_clr_name
.c_str());
1516 dump_sigspec(f
, ff
.sig_clr
[i
]);
1517 f
<< stringf(") %s <= 1'b0;\n", reg_bit_name
.c_str());
1518 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1519 if (ff
.sig_set
[i
].wire
== NULL
)
1520 f
<< stringf("%s", sig_set_name
.c_str());
1522 dump_sigspec(f
, ff
.sig_set
[i
]);
1523 f
<< stringf(") %s <= 1'b1;\n", reg_bit_name
.c_str());
1524 f
<< stringf("%s" " else ", indent
.c_str());
1525 } else if (ff
.has_arst
) {
1526 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1527 if (ff
.sig_arst
[0].wire
== NULL
)
1528 f
<< stringf("%s", sig_arst_name
.c_str());
1530 dump_sigspec(f
, ff
.sig_arst
);
1531 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1532 dump_sigspec(f
, val_arst
);
1533 f
<< stringf(";\n");
1534 f
<< stringf("%s" " else ", indent
.c_str());
1535 } else if (ff
.has_aload
) {
1536 f
<< stringf("if (%s", ff
.pol_aload
? "" : "!");
1537 if (ff
.sig_aload
[0].wire
== NULL
)
1538 f
<< stringf("%s", sig_aload_name
.c_str());
1540 dump_sigspec(f
, ff
.sig_aload
);
1541 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1542 dump_sigspec(f
, sig_ad
);
1543 f
<< stringf(";\n");
1544 f
<< stringf("%s" " else ", indent
.c_str());
1547 if (ff
.has_srst
&& ff
.has_ce
&& ff
.ce_over_srst
) {
1548 f
<< stringf("if (%s", ff
.pol_ce
? "" : "!");
1549 dump_sigspec(f
, ff
.sig_ce
);
1550 f
<< stringf(")\n");
1551 f
<< stringf("%s" " if (%s", indent
.c_str(), ff
.pol_srst
? "" : "!");
1552 dump_sigspec(f
, ff
.sig_srst
);
1553 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1554 dump_sigspec(f
, val_srst
);
1555 f
<< stringf(";\n");
1556 f
<< stringf("%s" " else ", indent
.c_str());
1559 f
<< stringf("if (%s", ff
.pol_srst
? "" : "!");
1560 dump_sigspec(f
, ff
.sig_srst
);
1561 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1562 dump_sigspec(f
, val_srst
);
1563 f
<< stringf(";\n");
1564 f
<< stringf("%s" " else ", indent
.c_str());
1567 f
<< stringf("if (%s", ff
.pol_ce
? "" : "!");
1568 dump_sigspec(f
, ff
.sig_ce
);
1573 f
<< stringf("%s <= ", reg_bit_name
.c_str());
1574 dump_sigspec(f
, sig_d
);
1575 f
<< stringf(";\n");
1580 f
<< stringf("%s" "always%s\n", indent
.c_str(), systemverilog
? "_latch" : " @*");
1582 f
<< stringf("%s" " ", indent
.c_str());
1584 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1585 dump_sigspec(f
, ff
.sig_clr
[i
]);
1586 f
<< stringf(") %s = 1'b0;\n", reg_bit_name
.c_str());
1587 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1588 dump_sigspec(f
, ff
.sig_set
[i
]);
1589 f
<< stringf(") %s = 1'b1;\n", reg_bit_name
.c_str());
1591 f
<< stringf("%s" " else ", indent
.c_str());
1592 } else if (ff
.has_arst
) {
1593 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1594 dump_sigspec(f
, ff
.sig_arst
);
1595 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1596 dump_sigspec(f
, val_arst
);
1597 f
<< stringf(";\n");
1599 f
<< stringf("%s" " else ", indent
.c_str());
1602 f
<< stringf("if (%s", ff
.pol_aload
? "" : "!");
1603 dump_sigspec(f
, ff
.sig_aload
);
1604 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1605 dump_sigspec(f
, sig_ad
);
1606 f
<< stringf(";\n");
1611 if (!out_is_reg_wire
) {
1612 f
<< stringf("%s" "assign ", indent
.c_str());
1613 dump_sigspec(f
, ff
.sig_q
);
1614 f
<< stringf(" = %s;\n", reg_name
.c_str());
1620 if (cell
->type
.in(ID($
assert), ID($assume
), ID($cover
)))
1622 f
<< stringf("%s" "always%s if (", indent
.c_str(), systemverilog
? "_comb" : " @*");
1623 dump_sigspec(f
, cell
->getPort(ID::EN
));
1624 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1625 dump_sigspec(f
, cell
->getPort(ID::A
));
1626 f
<< stringf(");\n");
1630 if (cell
->type
.in(ID($specify2
), ID($specify3
)))
1632 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1634 SigSpec en
= cell
->getPort(ID::EN
);
1635 if (en
!= State::S1
) {
1636 f
<< stringf("if (");
1637 dump_sigspec(f
, cell
->getPort(ID::EN
));
1642 if (cell
->type
== ID($specify3
) && cell
->getParam(ID::EDGE_EN
).as_bool())
1643 f
<< (cell
->getParam(ID::EDGE_POL
).as_bool() ? "posedge ": "negedge ");
1645 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1648 if (cell
->getParam(ID::SRC_DST_PEN
).as_bool())
1649 f
<< (cell
->getParam(ID::SRC_DST_POL
).as_bool() ? "+": "-");
1650 f
<< (cell
->getParam(ID::FULL
).as_bool() ? "*> ": "=> ");
1652 if (cell
->type
== ID($specify3
)) {
1654 dump_sigspec(f
, cell
->getPort(ID::DST
));
1656 if (cell
->getParam(ID::DAT_DST_PEN
).as_bool())
1657 f
<< (cell
->getParam(ID::DAT_DST_POL
).as_bool() ? "+": "-");
1659 dump_sigspec(f
, cell
->getPort(ID::DAT
));
1662 dump_sigspec(f
, cell
->getPort(ID::DST
));
1665 bool bak_decimal
= decimal
;
1669 dump_const(f
, cell
->getParam(ID::T_RISE_MIN
));
1671 dump_const(f
, cell
->getParam(ID::T_RISE_TYP
));
1673 dump_const(f
, cell
->getParam(ID::T_RISE_MAX
));
1675 dump_const(f
, cell
->getParam(ID::T_FALL_MIN
));
1677 dump_const(f
, cell
->getParam(ID::T_FALL_TYP
));
1679 dump_const(f
, cell
->getParam(ID::T_FALL_MAX
));
1682 decimal
= bak_decimal
;
1684 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1688 if (cell
->type
== ID($specrule
))
1690 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1692 IdString spec_type
= cell
->getParam(ID::TYPE
).decode_string();
1693 f
<< stringf("%s(", spec_type
.c_str());
1695 if (cell
->getParam(ID::SRC_PEN
).as_bool())
1696 f
<< (cell
->getParam(ID::SRC_POL
).as_bool() ? "posedge ": "negedge ");
1697 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1699 if (cell
->getPort(ID::SRC_EN
) != State::S1
) {
1701 dump_sigspec(f
, cell
->getPort(ID::SRC_EN
));
1705 if (cell
->getParam(ID::DST_PEN
).as_bool())
1706 f
<< (cell
->getParam(ID::DST_POL
).as_bool() ? "posedge ": "negedge ");
1707 dump_sigspec(f
, cell
->getPort(ID::DST
));
1709 if (cell
->getPort(ID::DST_EN
) != State::S1
) {
1711 dump_sigspec(f
, cell
->getPort(ID::DST_EN
));
1714 bool bak_decimal
= decimal
;
1718 dump_const(f
, cell
->getParam(ID::T_LIMIT_MIN
));
1720 dump_const(f
, cell
->getParam(ID::T_LIMIT_TYP
));
1722 dump_const(f
, cell
->getParam(ID::T_LIMIT_MAX
));
1724 if (spec_type
.in(ID($setuphold
), ID($recrem
), ID($fullskew
))) {
1726 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MIN
));
1728 dump_const(f
, cell
->getParam(ID::T_LIMIT2_TYP
));
1730 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MAX
));
1734 decimal
= bak_decimal
;
1736 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1745 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1747 // Handled by dump_memory
1748 if (cell
->is_mem_cell())
1751 if (cell
->type
[0] == '$' && !noexpr
) {
1752 if (dump_cell_expr(f
, indent
, cell
))
1756 dump_attributes(f
, indent
, cell
->attributes
);
1757 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1759 if (!defparam
&& cell
->parameters
.size() > 0) {
1760 f
<< stringf(" #(");
1761 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1762 if (it
!= cell
->parameters
.begin())
1764 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1765 dump_const(f
, it
->second
);
1768 f
<< stringf("\n%s" ")", indent
.c_str());
1771 std::string cell_name
= cellname(cell
);
1772 if (cell_name
!= id(cell
->name
))
1773 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1775 f
<< stringf(" %s (", cell_name
.c_str());
1777 bool first_arg
= true;
1778 std::set
<RTLIL::IdString
> numbered_ports
;
1779 for (int i
= 1; true; i
++) {
1781 snprintf(str
, 16, "$%d", i
);
1782 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1783 if (it
->first
!= str
)
1788 f
<< stringf("\n%s ", indent
.c_str());
1789 dump_sigspec(f
, it
->second
);
1790 numbered_ports
.insert(it
->first
);
1791 goto found_numbered_port
;
1794 found_numbered_port
:;
1796 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1797 if (numbered_ports
.count(it
->first
))
1802 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1803 if (it
->second
.size() > 0)
1804 dump_sigspec(f
, it
->second
);
1807 f
<< stringf("\n%s" ");\n", indent
.c_str());
1809 if (defparam
&& cell
->parameters
.size() > 0) {
1810 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1811 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1812 dump_const(f
, it
->second
);
1813 f
<< stringf(";\n");
1817 if (siminit
&& RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
))) {
1818 std::stringstream ss
;
1819 dump_reg_init(ss
, cell
->getPort(ID::Q
));
1820 if (!ss
.str().empty()) {
1821 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1828 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1832 for (auto &chunk
: left
.chunks()) {
1833 f
<< stringf("%s" "assign ", indent
.c_str());
1834 dump_sigspec(f
, chunk
);
1835 f
<< stringf(" = ");
1836 dump_sigspec(f
, right
.extract(offset
, GetSize(chunk
)));
1837 f
<< stringf(";\n");
1838 offset
+= GetSize(chunk
);
1841 f
<< stringf("%s" "assign ", indent
.c_str());
1842 dump_sigspec(f
, left
);
1843 f
<< stringf(" = ");
1844 dump_sigspec(f
, right
);
1845 f
<< stringf(";\n");
1849 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1851 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1853 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1855 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1856 f
<< stringf("%s" "begin\n", indent
.c_str());
1858 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1859 if (it
->first
.size() == 0)
1861 f
<< stringf("%s ", indent
.c_str());
1862 dump_sigspec(f
, it
->first
);
1863 f
<< stringf(" = ");
1864 dump_sigspec(f
, it
->second
);
1865 f
<< stringf(";\n");
1868 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1869 dump_proc_switch(f
, indent
+ " ", *it
);
1871 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1872 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1874 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1875 f
<< stringf("%s" "end\n", indent
.c_str());
1878 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1880 if (sw
->signal
.size() == 0) {
1881 f
<< stringf("%s" "begin\n", indent
.c_str());
1882 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1883 if ((*it
)->compare
.size() == 0)
1884 dump_case_body(f
, indent
+ " ", *it
);
1886 f
<< stringf("%s" "end\n", indent
.c_str());
1890 dump_attributes(f
, indent
, sw
->attributes
);
1891 f
<< stringf("%s" "casez (", indent
.c_str());
1892 dump_sigspec(f
, sw
->signal
);
1893 f
<< stringf(")\n");
1895 bool got_default
= false;
1896 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1897 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1898 if ((*it
)->compare
.size() == 0) {
1901 f
<< stringf("%s default", indent
.c_str());
1904 f
<< stringf("%s ", indent
.c_str());
1905 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1908 dump_sigspec(f
, (*it
)->compare
[i
]);
1911 f
<< stringf(":\n");
1912 dump_case_body(f
, indent
+ " ", *it
);
1915 f
<< stringf("%s" "endcase\n", indent
.c_str());
1918 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1920 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1921 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1922 case_body_find_regs(*it2
);
1924 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1925 for (auto &c
: it
->first
.chunks())
1927 reg_wires
.insert(c
.wire
->name
);
1931 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1934 case_body_find_regs(&proc
->root_case
);
1935 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1936 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1937 for (auto &c
: it2
->first
.chunks())
1939 reg_wires
.insert(c
.wire
->name
);
1944 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1946 f
<< indent
+ " " << "if (" << id("\\initial") << ") begin end\n";
1947 dump_case_body(f
, indent
, &proc
->root_case
, true);
1949 std::string backup_indent
= indent
;
1951 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1953 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1954 indent
= backup_indent
;
1956 if (sync
->type
== RTLIL::STa
) {
1957 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1958 } else if (sync
->type
== RTLIL::STi
) {
1959 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1961 f
<< stringf("%s" "always%s @(", indent
.c_str(), systemverilog
? "_ff" : "");
1962 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1963 f
<< stringf("posedge ");
1964 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1965 f
<< stringf("negedge ");
1966 dump_sigspec(f
, sync
->signal
);
1967 f
<< stringf(") begin\n");
1969 std::string ends
= indent
+ "end\n";
1972 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1973 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1974 dump_sigspec(f
, sync
->signal
);
1975 f
<< stringf(") begin\n");
1976 ends
= indent
+ "end\n" + ends
;
1980 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1981 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1982 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1983 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1984 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1985 dump_sigspec(f
, sync2
->signal
);
1986 f
<< stringf(") begin\n");
1987 ends
= indent
+ "end\n" + ends
;
1993 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1994 if (it
->first
.size() == 0)
1996 f
<< stringf("%s ", indent
.c_str());
1997 dump_sigspec(f
, it
->first
);
1998 f
<< stringf(" <= ");
1999 dump_sigspec(f
, it
->second
);
2000 f
<< stringf(";\n");
2003 f
<< stringf("%s", ends
.c_str());
2007 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
2010 reset_auto_counter(module
);
2011 active_module
= module
;
2012 active_sigmap
.set(module
);
2013 active_initdata
.clear();
2015 for (auto wire
: module
->wires())
2016 if (wire
->attributes
.count(ID::init
)) {
2017 SigSpec sig
= active_sigmap(wire
);
2018 Const val
= wire
->attributes
.at(ID::init
);
2019 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
2020 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
2021 active_initdata
[sig
[i
]] = val
[i
];
2024 if (!module
->processes
.empty())
2025 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
2026 "can't always be mapped directly to Verilog always blocks. Unintended\n"
2027 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
2028 "processes to logic networks and registers.\n", log_id(module
));
2031 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
2032 dump_process(f
, indent
+ " ", it
->second
, true);
2036 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
2037 for (auto cell
: module
->cells())
2039 if (!RTLIL::builtin_ff_cell_types().count(cell
->type
) || !cell
->hasPort(ID::Q
) || cell
->type
.in(ID($ff
), ID($_FF_
)))
2042 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
2044 if (sig
.is_chunk()) {
2045 RTLIL::SigChunk chunk
= sig
.as_chunk();
2046 if (chunk
.wire
!= NULL
)
2047 for (int i
= 0; i
< chunk
.width
; i
++)
2048 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
2051 for (auto wire
: module
->wires())
2053 for (int i
= 0; i
< wire
->width
; i
++)
2054 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
2055 goto this_wire_aint_reg
;
2057 reg_wires
.insert(wire
->name
);
2058 this_wire_aint_reg
:;
2062 dump_attributes(f
, indent
, module
->attributes
, '\n', /*modattr=*/true);
2063 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
2064 bool keep_running
= true;
2065 for (int port_id
= 1; keep_running
; port_id
++) {
2066 keep_running
= false;
2067 for (auto wire
: module
->wires()) {
2068 if (wire
->port_id
== port_id
) {
2071 f
<< stringf("%s", id(wire
->name
).c_str());
2072 keep_running
= true;
2077 f
<< stringf(");\n");
2079 if (!systemverilog
&& !module
->processes
.empty())
2080 f
<< indent
+ " " << "reg " << id("\\initial") << " = 0;\n";
2082 for (auto w
: module
->wires())
2083 dump_wire(f
, indent
+ " ", w
);
2085 for (auto &mem
: Mem::get_all_memories(module
))
2086 dump_memory(f
, indent
+ " ", mem
);
2088 for (auto cell
: module
->cells())
2089 dump_cell(f
, indent
+ " ", cell
);
2091 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
2092 dump_process(f
, indent
+ " ", it
->second
);
2094 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
2095 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
2097 f
<< stringf("%s" "endmodule\n", indent
.c_str());
2098 active_module
= NULL
;
2099 active_sigmap
.clear();
2100 active_initdata
.clear();
2103 struct VerilogBackend
: public Backend
{
2104 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
2105 void help() override
2107 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2109 log(" write_verilog [options] [filename]\n");
2111 log("Write the current design to a Verilog file.\n");
2114 log(" with this option, SystemVerilog constructs like always_comb are used\n");
2116 log(" -norename\n");
2117 log(" without this option all internal object names (the ones with a dollar\n");
2118 log(" instead of a backslash prefix) are changed to short names in the\n");
2119 log(" format '_<number>_'.\n");
2121 log(" -renameprefix <prefix>\n");
2122 log(" insert this prefix in front of auto-generated instance names\n");
2125 log(" with this option no attributes are included in the output\n");
2127 log(" -attr2comment\n");
2128 log(" with this option attributes are included as comments in the output\n");
2131 log(" without this option all internal cells are converted to Verilog\n");
2132 log(" expressions.\n");
2135 log(" add initial statements with hierarchical refs to initialize FFs when\n");
2136 log(" in -noexpr mode.\n");
2139 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
2140 log(" not bit pattern. This option deactivates this feature and instead\n");
2141 log(" will write out all constants in binary.\n");
2144 log(" dump 32-bit constants in decimal and without size and radix\n");
2147 log(" constant values that are compatible with hex output are usually\n");
2148 log(" dumped as hex values. This option deactivates this feature and\n");
2149 log(" instead will write out all constants in binary.\n");
2152 log(" Parameters and attributes that are specified as strings in the\n");
2153 log(" original input will be output as strings by this back-end. This\n");
2154 log(" deactivates this feature and instead will write string constants\n");
2155 log(" as binary numbers.\n");
2157 log(" -simple-lhs\n");
2158 log(" Connection assignments with simple left hand side without concatenations.\n");
2161 log(" instead of initializing memories using assignments to individual\n");
2162 log(" elements, use the '$readmemh' function to read initialization data\n");
2163 log(" from a file. This data is written to a file named by appending\n");
2164 log(" a sequential index to the Verilog filename and replacing the extension\n");
2165 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
2166 log(" 'foo-2.mem' and so on.\n");
2168 log(" -defparam\n");
2169 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
2170 log(" cell parameters.\n");
2172 log(" -blackboxes\n");
2173 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
2174 log(" this option set only the modules with the 'blackbox' attribute\n");
2175 log(" are written to the output file.\n");
2177 log(" -selected\n");
2178 log(" only write selected modules. modules must be selected entirely or\n");
2179 log(" not at all.\n");
2182 log(" verbose output (print new names of all renamed wires and cells)\n");
2184 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
2185 log("always blocks. This frontend should only be used to export an RTLIL\n");
2186 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
2187 log("processes to logic networks and registers. A warning is generated when\n");
2188 log("this command is called on a design with RTLIL processes.\n");
2191 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2193 log_header(design
, "Executing Verilog backend.\n");
2198 attr2comment
= false;
2210 bool blackboxes
= false;
2211 bool selected
= false;
2213 auto_name_map
.clear();
2217 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2218 std::string arg
= args
[argidx
];
2220 systemverilog
= true;
2223 if (arg
== "-norename") {
2227 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
2228 auto_prefix
= args
[++argidx
];
2231 if (arg
== "-noattr") {
2235 if (arg
== "-attr2comment") {
2236 attr2comment
= true;
2239 if (arg
== "-noexpr") {
2243 if (arg
== "-nodec") {
2247 if (arg
== "-nohex") {
2251 if (arg
== "-nostr") {
2255 if (arg
== "-extmem") {
2260 if (arg
== "-defparam") {
2264 if (arg
== "-decimal") {
2268 if (arg
== "-siminit") {
2272 if (arg
== "-blackboxes") {
2276 if (arg
== "-selected") {
2280 if (arg
== "-simple-lhs") {
2290 extra_args(f
, filename
, args
, argidx
);
2293 if (filename
== "<stdout>")
2294 log_cmd_error("Option -extmem must be used with a filename.\n");
2295 extmem_prefix
= filename
.substr(0, filename
.rfind('.'));
2300 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
2301 for (auto module
: design
->modules()) {
2302 if (module
->get_blackbox_attribute() != blackboxes
)
2304 if (selected
&& !design
->selected_whole_module(module
->name
)) {
2305 if (design
->selected_module(module
->name
))
2306 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module
->name
));
2309 log("Dumping module `%s'.\n", module
->name
.c_str());
2310 dump_module(*f
, "", module
);
2313 auto_name_map
.clear();
2318 PRIVATE_NAMESPACE_END