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
;
49 void reset_auto_counter_id(RTLIL::IdString id
, bool may_rename
)
51 const char *str
= id
.c_str();
53 if (*str
== '$' && may_rename
&& !norename
)
54 auto_name_map
[id
] = auto_name_counter
++;
56 if (str
[0] != '\\' || str
[1] != '_' || str
[2] == 0)
59 for (int i
= 2; str
[i
] != 0; i
++) {
60 if (str
[i
] == '_' && str
[i
+1] == 0)
62 if (str
[i
] < '0' || str
[i
] > '9')
66 int num
= atoi(str
+2);
67 if (num
>= auto_name_offset
)
68 auto_name_offset
= num
+ 1;
71 void reset_auto_counter(RTLIL::Module
*module
)
73 auto_name_map
.clear();
74 auto_name_counter
= 0;
77 reset_auto_counter_id(module
->name
, false);
79 for (auto w
: module
->wires())
80 reset_auto_counter_id(w
->name
, true);
82 for (auto cell
: module
->cells()) {
83 reset_auto_counter_id(cell
->name
, true);
84 reset_auto_counter_id(cell
->type
, false);
87 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
88 reset_auto_counter_id(it
->second
->name
, false);
91 for (size_t i
= 10; i
< auto_name_offset
+ auto_name_map
.size(); i
= i
*10)
95 for (auto it
= auto_name_map
.begin(); it
!= auto_name_map
.end(); ++it
)
96 log(" renaming `%s' to `%s_%0*d_'.\n", it
->first
.c_str(), auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ it
->second
);
99 std::string
next_auto_id()
101 return stringf("%s_%0*d_", auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ auto_name_counter
++);
104 std::string
id(RTLIL::IdString internal_id
, bool may_rename
= true)
106 const char *str
= internal_id
.c_str();
107 bool do_escape
= false;
109 if (may_rename
&& auto_name_map
.count(internal_id
) != 0)
110 return stringf("%s_%0*d_", auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ auto_name_map
[internal_id
]);
115 if ('0' <= *str
&& *str
<= '9')
118 for (int i
= 0; str
[i
]; i
++)
120 if ('0' <= str
[i
] && str
[i
] <= '9')
122 if ('a' <= str
[i
] && str
[i
] <= 'z')
124 if ('A' <= str
[i
] && str
[i
] <= 'Z')
132 const pool
<string
> keywords
= {
133 // IEEE 1800-2017 Annex B
134 "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
135 "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
136 "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
137 "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
138 "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
139 "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
140 "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
141 "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
142 "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
143 "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
144 "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
145 "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
146 "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
147 "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
148 "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
149 "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
150 "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
151 "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
152 "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
153 "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
154 "wildcard", "wire", "with", "within", "wor", "xnor", "xor",
156 if (keywords
.count(str
))
160 return "\\" + std::string(str
) + " ";
161 return std::string(str
);
164 bool is_reg_wire(RTLIL::SigSpec sig
, std::string
®_name
)
166 if (!sig
.is_chunk() || sig
.as_chunk().wire
== NULL
)
169 RTLIL::SigChunk chunk
= sig
.as_chunk();
171 if (reg_wires
.count(chunk
.wire
->name
) == 0)
174 reg_name
= id(chunk
.wire
->name
);
175 if (sig
.size() != chunk
.wire
->width
) {
177 reg_name
+= stringf("[%d]", chunk
.wire
->start_offset
+ chunk
.offset
);
178 else if (chunk
.wire
->upto
)
179 reg_name
+= stringf("[%d:%d]", (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
180 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
182 reg_name
+= stringf("[%d:%d]", chunk
.wire
->start_offset
+ chunk
.offset
+ chunk
.width
- 1,
183 chunk
.wire
->start_offset
+ chunk
.offset
);
189 void dump_const(std::ostream
&f
, const RTLIL::Const
&data
, int width
= -1, int offset
= 0, bool no_decimal
= false, bool escape_comment
= false)
191 bool set_signed
= (data
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
193 width
= data
.bits
.size() - offset
;
195 // See IEEE 1364-2005 Clause 5.1.14.
201 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
202 if (width
== 32 && !no_decimal
&& !nodec
) {
204 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
205 log_assert(i
< (int)data
.bits
.size());
206 if (data
.bits
[i
] != State::S0
&& data
.bits
[i
] != State::S1
)
208 if (data
.bits
[i
] == State::S1
)
209 val
|= 1 << (i
- offset
);
212 f
<< stringf("%d", val
);
213 else if (set_signed
&& val
< 0)
214 f
<< stringf("-32'sd%u", -val
);
216 f
<< stringf("32'%sd%u", set_signed
? "s" : "", val
);
221 vector
<char> bin_digits
, hex_digits
;
222 for (int i
= offset
; i
< offset
+width
; i
++) {
223 log_assert(i
< (int)data
.bits
.size());
224 switch (data
.bits
[i
]) {
225 case State::S0
: bin_digits
.push_back('0'); break;
226 case State::S1
: bin_digits
.push_back('1'); break;
227 case RTLIL::Sx
: bin_digits
.push_back('x'); break;
228 case RTLIL::Sz
: bin_digits
.push_back('z'); break;
229 case RTLIL::Sa
: bin_digits
.push_back('?'); break;
230 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
233 if (GetSize(bin_digits
) == 0)
235 while (GetSize(bin_digits
) % 4 != 0)
236 if (bin_digits
.back() == '1')
237 bin_digits
.push_back('0');
239 bin_digits
.push_back(bin_digits
.back());
240 for (int i
= 0; i
< GetSize(bin_digits
); i
+= 4)
242 char bit_3
= bin_digits
[i
+3];
243 char bit_2
= bin_digits
[i
+2];
244 char bit_1
= bin_digits
[i
+1];
245 char bit_0
= bin_digits
[i
+0];
246 if (bit_3
== 'x' || bit_2
== 'x' || bit_1
== 'x' || bit_0
== 'x') {
247 if (bit_3
!= 'x' || bit_2
!= 'x' || bit_1
!= 'x' || bit_0
!= 'x')
249 hex_digits
.push_back('x');
252 if (bit_3
== 'z' || bit_2
== 'z' || bit_1
== 'z' || bit_0
== 'z') {
253 if (bit_3
!= 'z' || bit_2
!= 'z' || bit_1
!= 'z' || bit_0
!= 'z')
255 hex_digits
.push_back('z');
258 if (bit_3
== '?' || bit_2
== '?' || bit_1
== '?' || bit_0
== '?') {
259 if (bit_3
!= '?' || bit_2
!= '?' || bit_1
!= '?' || bit_0
!= '?')
261 hex_digits
.push_back('?');
264 int val
= 8*(bit_3
- '0') + 4*(bit_2
- '0') + 2*(bit_1
- '0') + (bit_0
- '0');
265 hex_digits
.push_back(val
< 10 ? '0' + val
: 'a' + val
- 10);
267 f
<< stringf("%d'%sh", width
, set_signed
? "s" : "");
268 for (int i
= GetSize(hex_digits
)-1; i
>= 0; i
--)
273 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
276 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
277 log_assert(i
< (int)data
.bits
.size());
278 switch (data
.bits
[i
]) {
279 case State::S0
: f
<< stringf("0"); break;
280 case State::S1
: f
<< stringf("1"); break;
281 case RTLIL::Sx
: f
<< stringf("x"); break;
282 case RTLIL::Sz
: f
<< stringf("z"); break;
283 case RTLIL::Sa
: f
<< stringf("?"); break;
284 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
289 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
291 std::string str
= data
.decode_string();
292 for (size_t i
= 0; i
< str
.size(); i
++) {
295 else if (str
[i
] == '\t')
297 else if (str
[i
] < 32)
298 f
<< stringf("\\%03o", str
[i
]);
299 else if (str
[i
] == '"')
300 f
<< stringf("\\\"");
301 else if (str
[i
] == '\\')
302 f
<< stringf("\\\\");
303 else if (str
[i
] == '/' && escape_comment
&& i
> 0 && str
[i
-1] == '*')
308 if ((data
.flags
& RTLIL::CONST_FLAG_REAL
) == 0)
313 void dump_reg_init(std::ostream
&f
, SigSpec sig
)
316 bool gotinit
= false;
318 for (auto bit
: active_sigmap(sig
)) {
319 if (active_initdata
.count(bit
)) {
320 initval
.bits
.push_back(active_initdata
.at(bit
));
323 initval
.bits
.push_back(State::Sx
);
329 dump_const(f
, initval
);
333 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
335 if (chunk
.wire
== NULL
) {
336 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
338 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0) {
339 f
<< stringf("%s", id(chunk
.wire
->name
).c_str());
340 } else if (chunk
.width
== 1) {
341 if (chunk
.wire
->upto
)
342 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
344 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
346 if (chunk
.wire
->upto
)
347 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
348 (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
349 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
351 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
352 (chunk
.offset
+ chunk
.width
- 1) + chunk
.wire
->start_offset
,
353 chunk
.offset
+ chunk
.wire
->start_offset
);
358 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
360 if (GetSize(sig
) == 0) {
361 // See IEEE 1364-2005 Clause 5.1.14.
365 if (sig
.is_chunk()) {
366 dump_sigchunk(f
, sig
.as_chunk());
369 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
370 if (it
!= sig
.chunks().rbegin())
372 dump_sigchunk(f
, *it
, true);
378 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)
384 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
385 if (it
->first
== ID::init
&& regattr
) continue;
386 f
<< stringf("%s" "%s %s", indent
.c_str(), as_comment
? "/*" : "(*", id(it
->first
).c_str());
388 if (modattr
&& (it
->second
== State::S0
|| it
->second
== Const(0)))
390 else if (modattr
&& (it
->second
== State::S1
|| it
->second
== Const(1)))
393 dump_const(f
, it
->second
, -1, 0, false, as_comment
);
394 f
<< stringf(" %s%c", as_comment
? "*/" : "*)", term
);
398 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
400 dump_attributes(f
, indent
, wire
->attributes
, '\n', /*modattr=*/false, /*regattr=*/reg_wires
.count(wire
->name
));
402 if (wire
->port_input
&& !wire
->port_output
)
403 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
404 else if (!wire
->port_input
&& wire
->port_output
)
405 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
406 else if (wire
->port_input
&& wire
->port_output
)
407 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
409 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
410 if (wire
->width
!= 1)
411 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
412 f
<< stringf("%s;\n", id(wire
->name
).c_str());
414 // do not use Verilog-2k "output reg" syntax in Verilog export
415 std::string range
= "";
416 if (wire
->width
!= 1) {
418 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
420 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
422 if (wire
->port_input
&& !wire
->port_output
)
423 f
<< stringf("%s" "input%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" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
426 if (wire
->port_input
&& wire
->port_output
)
427 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
428 if (reg_wires
.count(wire
->name
)) {
429 f
<< stringf("%s" "reg%s %s", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
430 if (wire
->attributes
.count(ID::init
)) {
432 dump_const(f
, wire
->attributes
.at(ID::init
));
435 } else if (!wire
->port_input
&& !wire
->port_output
)
436 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
440 void dump_memory(std::ostream
&f
, std::string indent
, Mem
&mem
)
442 std::string mem_id
= id(mem
.memid
);
444 dump_attributes(f
, indent
, mem
.attributes
);
445 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
);
447 // for memory block make something like:
448 // reg [7:0] memid [3:0];
452 if (!mem
.inits
.empty())
456 std::string extmem_filename
= stringf("%s-%d.mem", extmem_prefix
.c_str(), extmem_counter
++);
458 std::string extmem_filename_esc
;
459 for (auto c
: extmem_filename
)
462 extmem_filename_esc
+= "\\n";
464 extmem_filename_esc
+= "\\t";
466 extmem_filename_esc
+= stringf("\\%03o", c
);
468 extmem_filename_esc
+= "\\\"";
470 extmem_filename_esc
+= "\\\\";
472 extmem_filename_esc
+= c
;
474 f
<< stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent
.c_str(), extmem_filename_esc
.c_str(), mem_id
.c_str());
476 std::ofstream
extmem_f(extmem_filename
, std::ofstream::trunc
);
478 log_error("Can't open file `%s' for writing: %s\n", extmem_filename
.c_str(), strerror(errno
));
481 Const data
= mem
.get_init_data();
482 for (int i
=0; i
<mem
.size
; i
++)
484 RTLIL::Const element
= data
.extract(i
*mem
.width
, mem
.width
);
485 for (int j
=0; j
<element
.size(); j
++)
487 switch (element
[element
.size()-j
-1])
489 case State::S0
: extmem_f
<< '0'; break;
490 case State::S1
: extmem_f
<< '1'; break;
491 case State::Sx
: extmem_f
<< 'x'; break;
492 case State::Sz
: extmem_f
<< 'z'; break;
493 case State::Sa
: extmem_f
<< '_'; break;
494 case State::Sm
: log_error("Found marker state in final netlist.");
503 f
<< stringf("%s" "initial begin\n", indent
.c_str());
504 for (auto &init
: mem
.inits
) {
505 int words
= GetSize(init
.data
) / mem
.width
;
506 int start
= init
.addr
.as_int();
507 for (int i
=0; i
<words
; i
++)
509 for (int j
= 0; j
< mem
.width
; j
++)
511 if (init
.en
[j
] != State::S1
)
514 int start_j
= j
, width
= 1;
516 while (j
+1 < mem
.width
&& init
.en
[j
+1] == State::S1
)
519 if (width
== mem
.width
) {
520 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
+ start
);
522 f
<< stringf("%s" " %s[%d][%d:%d] = ", indent
.c_str(), mem_id
.c_str(), i
+ start
, j
, start_j
);
524 dump_const(f
, init
.data
.extract(i
*mem
.width
+start_j
, width
));
529 f
<< stringf("%s" "end\n", indent
.c_str());
533 // create a map : "edge clk" -> expressions within that clock domain
534 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
535 dict
<std::string
, std::string
> clk_to_arst_cond
;
536 dict
<std::string
, std::vector
<std::string
>> clk_to_arst_body
;
537 clk_to_lof_body
[""] = std::vector
<std::string
>();
538 std::string clk_domain_str
;
539 // create a list of reg declarations
540 std::vector
<std::string
> lof_reg_declarations
;
543 for (auto &port
: mem
.rd_ports
)
548 std::ostringstream os
;
549 dump_sigspec(os
, port
.clk
);
550 clk_domain_str
= stringf("%sedge %s", port
.clk_polarity
? "pos" : "neg", os
.str().c_str());
551 if (port
.arst
!= State::S0
) {
552 std::ostringstream os2
;
553 dump_sigspec(os2
, port
.arst
);
554 clk_domain_str
+= stringf(", posedge %s", os2
.str().c_str());
555 clk_to_arst_cond
[clk_domain_str
] = os2
.str();
559 // Decide how to represent the transparency; same idea as Mem::extract_rdff.
560 bool trans_use_addr
= true;
561 for (auto bit
: port
.transparency_mask
)
563 trans_use_addr
= false;
565 if (GetSize(mem
.wr_ports
) == 0)
566 trans_use_addr
= false;
568 if (port
.en
!= State::S1
|| port
.srst
!= State::S0
|| port
.arst
!= State::S0
|| !port
.init_value
.is_fully_undef())
569 trans_use_addr
= false;
573 // for clocked read ports make something like:
575 // always @(posedge clk)
576 // if (rd_en) temp_id <= array_reg[r_addr];
577 // assign r_data = temp_id;
578 std::string temp_id
= next_auto_id();
579 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", port
.data
.size() - 1, temp_id
.c_str()) );
581 bool has_indent
= false;
583 if (port
.arst
!= State::S0
) {
584 std::ostringstream os
;
585 os
<< stringf("%s <= ", temp_id
.c_str());
586 dump_sigspec(os
, port
.arst_value
);
588 clk_to_arst_body
[clk_domain_str
].push_back(os
.str());
591 if (port
.srst
!= State::S0
&& !port
.ce_over_srst
) {
592 std::ostringstream os
;
593 os
<< stringf("if (");
594 dump_sigspec(os
, port
.srst
);
595 os
<< stringf(")\n");
596 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
597 std::ostringstream os2
;
598 os2
<< stringf("%s" "%s <= ", indent
.c_str(), temp_id
.c_str());
599 dump_sigspec(os2
, port
.srst_value
);
601 clk_to_lof_body
[clk_domain_str
].push_back(os2
.str());
602 std::ostringstream os3
;
603 if (port
.en
== State::S1
) {
604 os3
<< "else begin\n";
607 dump_sigspec(os3
, port
.en
);
610 clk_to_lof_body
[clk_domain_str
].push_back(os3
.str());
612 } else if (port
.en
!= State::S1
) {
613 std::ostringstream os
;
614 os
<< stringf("if (");
615 dump_sigspec(os
, port
.en
);
616 os
<< stringf(") begin\n");
617 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
621 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
623 SigSpec addr
= port
.sub_addr(sub
);
624 std::ostringstream os
;
629 os
<< stringf("[%d:%d]", (sub
+ 1) * mem
.width
- 1, sub
* mem
.width
);
630 os
<< stringf(" <= %s[", mem_id
.c_str());
631 dump_sigspec(os
, addr
);
632 os
<< stringf("];\n");
633 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
636 for (int i
= 0; i
< GetSize(mem
.wr_ports
); i
++) {
637 auto &wport
= mem
.wr_ports
[i
];
638 if (!port
.transparency_mask
[i
] && !port
.collision_x_mask
[i
])
640 int min_wide_log2
= std::min(port
.wide_log2
, wport
.wide_log2
);
641 int max_wide_log2
= std::max(port
.wide_log2
, wport
.wide_log2
);
642 bool wide_write
= wport
.wide_log2
> port
.wide_log2
;
643 for (int sub
= 0; sub
< (1 << max_wide_log2
); sub
+= (1 << min_wide_log2
)) {
644 SigSpec raddr
= port
.addr
;
645 SigSpec waddr
= wport
.addr
;
647 waddr
= wport
.sub_addr(sub
);
649 raddr
= port
.sub_addr(sub
);
651 int ewidth
= mem
.width
<< min_wide_log2
;
652 int wsub
= wide_write
? sub
: 0;
653 int rsub
= wide_write
? 0 : sub
;
654 while (pos
< ewidth
) {
656 while (epos
< ewidth
&& wport
.en
[epos
+ wsub
* mem
.width
] == wport
.en
[pos
+ wsub
* mem
.width
])
659 std::ostringstream os
;
663 dump_sigspec(os
, wport
.en
[pos
+ wsub
* mem
.width
]);
664 if (raddr
!= waddr
) {
666 dump_sigspec(os
, raddr
);
668 dump_sigspec(os
, waddr
);
671 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
673 std::ostringstream os2
;
678 if (epos
-pos
!= GetSize(port
.data
))
679 os2
<< stringf("[%d:%d]", rsub
* mem
.width
+ epos
-1, rsub
* mem
.width
+ pos
);
681 if (port
.transparency_mask
[i
])
682 dump_sigspec(os2
, wport
.data
.extract(wsub
* mem
.width
+ pos
, epos
-pos
));
684 dump_sigspec(os2
, Const(State::Sx
, epos
- pos
));
686 clk_to_lof_body
[clk_domain_str
].push_back(os2
.str());
693 if (port
.srst
!= State::S0
&& port
.ce_over_srst
)
695 std::ostringstream os
;
698 os
<< stringf("if (");
699 dump_sigspec(os
, port
.srst
);
700 os
<< stringf(")\n");
701 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
702 std::ostringstream os2
;
705 os2
<< stringf("%s" "%s <= ", indent
.c_str(), temp_id
.c_str());
706 dump_sigspec(os2
, port
.srst_value
);
708 clk_to_lof_body
[clk_domain_str
].push_back(os2
.str());
712 clk_to_lof_body
[clk_domain_str
].push_back("end\n");
714 if (!port
.init_value
.is_fully_undef())
716 std::ostringstream os
;
717 dump_sigspec(os
, port
.init_value
);
718 std::string line
= stringf("initial %s = %s;\n", temp_id
.c_str(), os
.str().c_str());
719 clk_to_lof_body
[""].push_back(line
);
723 std::ostringstream os
;
724 dump_sigspec(os
, port
.data
);
725 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
726 clk_to_lof_body
[""].push_back(line
);
731 // for rd-transparent read-ports make something like:
733 // always @(posedge clk)
734 // temp_id <= r_addr;
735 // assign r_data = array_reg[temp_id];
736 std::string temp_id
= next_auto_id();
737 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", port
.addr
.size() - 1 - port
.wide_log2
, temp_id
.c_str()) );
739 std::ostringstream os
;
740 dump_sigspec(os
, port
.addr
.extract_end(port
.wide_log2
));
741 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
742 clk_to_lof_body
[clk_domain_str
].push_back(line
);
744 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
746 std::ostringstream os
;
748 dump_sigspec(os
, port
.data
.extract(sub
* mem
.width
, mem
.width
));
749 os
<< stringf(" = %s[", mem_id
.c_str());;
750 if (port
.wide_log2
) {
752 for (int i
= 0; i
< port
.wide_log2
; i
++)
753 addr_lo
.bits
.push_back(State(sub
>> i
& 1));
757 dump_const(os
, addr_lo
);
763 clk_to_lof_body
[""].push_back(os
.str());
767 // for non-clocked read-ports make something like:
768 // assign r_data = array_reg[r_addr];
769 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
771 SigSpec addr
= port
.sub_addr(sub
);
773 std::ostringstream os
, os2
;
774 dump_sigspec(os
, port
.data
.extract(sub
* mem
.width
, mem
.width
));
775 dump_sigspec(os2
, addr
);
776 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
777 clk_to_lof_body
[""].push_back(line
);
782 // Write ports. Those are messy because we try to preserve priority, as much as we can:
784 // 1. We split all ports into several disjoint processes.
785 // 2. If a port has priority over another port, the two ports need to share
786 // a process, so that priority can be reconstructed on the other end.
787 // 3. We want each process to be as small as possible, to avoid extra
788 // priorities inferred on the other end.
789 pool
<int> wr_ports_done
;
790 for (int ridx
= 0; ridx
< GetSize(mem
.wr_ports
); ridx
++)
792 if (wr_ports_done
.count(ridx
))
795 auto &root
= mem
.wr_ports
[ridx
];
797 // Start from a root.
798 pool
<int> wr_ports_now
;
799 wr_ports_now
.insert(ridx
);
801 // Transitively fill list of ports in this process by following priority edges.
804 bool changed
= false;
806 for (int i
= 0; i
< GetSize(mem
.wr_ports
); i
++)
807 for (int j
= 0; j
< i
; j
++)
808 if (mem
.wr_ports
[i
].priority_mask
[j
])
810 if (wr_ports_now
.count(i
) && !wr_ports_now
.count(j
)) {
811 wr_ports_now
.insert(j
);
814 if (!wr_ports_now
.count(i
) && wr_ports_now
.count(j
)) {
815 wr_ports_now
.insert(i
);
824 if (root
.clk_enable
) {
825 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", root
.clk_polarity
? "pos" : "neg");
826 dump_sigspec(f
, root
.clk
);
829 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_latch" : " @*");
832 for (int pidx
= 0; pidx
< GetSize(mem
.wr_ports
); pidx
++)
834 if (!wr_ports_now
.count(pidx
))
836 wr_ports_done
.insert(pidx
);
838 auto &port
= mem
.wr_ports
[pidx
];
839 log_assert(port
.clk_enable
== root
.clk_enable
);
840 if (port
.clk_enable
) {
841 log_assert(port
.clk
== root
.clk
);
842 log_assert(port
.clk_polarity
== root
.clk_polarity
);
845 // make something like:
846 // always @(posedge clk)
847 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
849 for (int sub
= 0; sub
< (1 << port
.wide_log2
); sub
++)
851 SigSpec addr
= port
.sub_addr(sub
);
852 for (int i
= 0; i
< mem
.width
; i
++)
854 int start_i
= i
, width
= 1;
855 SigBit wen_bit
= port
.en
[sub
* mem
.width
+ i
];
857 while (i
+1 < mem
.width
&& active_sigmap(port
.en
[sub
* mem
.width
+ i
+1]) == active_sigmap(wen_bit
))
860 if (wen_bit
== State::S0
)
863 f
<< stringf("%s%s", indent
.c_str(), indent
.c_str());
864 if (wen_bit
!= State::S1
)
866 f
<< stringf("if (");
867 dump_sigspec(f
, wen_bit
);
869 f
<< stringf("%s%s%s", indent
.c_str(), indent
.c_str(), indent
.c_str());
871 f
<< stringf("%s[", mem_id
.c_str());
872 dump_sigspec(f
, addr
);
873 if (width
== GetSize(port
.en
))
874 f
<< stringf("] <= ");
876 f
<< stringf("][%d:%d] <= ", i
, start_i
);
877 dump_sigspec(f
, port
.data
.extract(sub
* mem
.width
+ start_i
, width
));
883 f
<< stringf("%s" "end\n", indent
.c_str());
885 // Output Verilog that looks something like this:
887 // always @(posedge CLK2) begin
888 // _3_ <= memory[D1ADDR];
890 // memory[A1ADDR] <= A1DATA;
892 // memory[A2ADDR] <= A2DATA;
895 // always @(negedge CLK1) begin
897 // memory[C1ADDR] <= C1DATA;
900 // assign D1DATA = _3_;
901 // assign D2DATA <= memory[D2ADDR];
903 // the reg ... definitions
904 for(auto ®
: lof_reg_declarations
)
906 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
908 // the block of expressions by clock domain
909 for(auto &pair
: clk_to_lof_body
)
911 std::string clk_domain
= pair
.first
;
912 std::vector
<std::string
> lof_lines
= pair
.second
;
913 if( clk_domain
!= "")
915 f
<< stringf("%s" "always%s @(%s) begin\n", indent
.c_str(), systemverilog
? "_ff" : "", clk_domain
.c_str());
916 bool has_arst
= clk_to_arst_cond
.count(clk_domain
) != 0;
918 f
<< stringf("%s%s" "if (%s) begin\n", indent
.c_str(), indent
.c_str(), clk_to_arst_cond
[clk_domain
].c_str());
919 for(auto &line
: clk_to_arst_body
[clk_domain
])
920 f
<< stringf("%s%s%s" "%s", indent
.c_str(), indent
.c_str(), indent
.c_str(), line
.c_str());
921 f
<< stringf("%s%s" "end else begin\n", indent
.c_str(), indent
.c_str());
922 for(auto &line
: lof_lines
)
923 f
<< stringf("%s%s%s" "%s", indent
.c_str(), indent
.c_str(), indent
.c_str(), line
.c_str());
924 f
<< stringf("%s%s" "end\n", indent
.c_str(), indent
.c_str());
926 for(auto &line
: lof_lines
)
927 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
929 f
<< stringf("%s" "end\n", indent
.c_str());
933 // the non-clocked assignments
934 for(auto &line
: lof_lines
)
935 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
940 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
942 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
943 f
<< stringf("$signed(");
944 dump_sigspec(f
, cell
->getPort("\\" + port
));
947 dump_sigspec(f
, cell
->getPort("\\" + port
));
950 std::string
cellname(RTLIL::Cell
*cell
)
952 if (!norename
&& cell
->name
[0] == '$' && RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
)))
954 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
955 if (GetSize(sig
) != 1 || sig
.is_fully_const())
956 goto no_special_reg_name
;
958 RTLIL::Wire
*wire
= sig
[0].wire
;
960 if (wire
->name
[0] != '\\')
961 goto no_special_reg_name
;
963 std::string cell_name
= wire
->name
.str();
965 size_t pos
= cell_name
.find('[');
966 if (pos
!= std::string::npos
)
967 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
969 cell_name
= cell_name
+ "_reg";
971 if (wire
->width
!= 1)
972 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
974 if (active_module
&& active_module
->count_id(cell_name
) > 0)
975 goto no_special_reg_name
;
977 return id(cell_name
);
982 return id(cell
->name
).c_str();
986 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
988 f
<< stringf("%s" "assign ", indent
.c_str());
989 dump_sigspec(f
, cell
->getPort(ID::Y
));
990 f
<< stringf(" = %s ", op
.c_str());
991 dump_attributes(f
, "", cell
->attributes
, ' ');
992 dump_cell_expr_port(f
, cell
, "A", true);
996 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
998 f
<< stringf("%s" "assign ", indent
.c_str());
999 dump_sigspec(f
, cell
->getPort(ID::Y
));
1000 f
<< stringf(" = ");
1001 dump_cell_expr_port(f
, cell
, "A", true);
1002 f
<< stringf(" %s ", op
.c_str());
1003 dump_attributes(f
, "", cell
->attributes
, ' ');
1004 dump_cell_expr_port(f
, cell
, "B", true);
1005 f
<< stringf(";\n");
1008 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1010 if (cell
->type
== ID($_NOT_
)) {
1011 f
<< stringf("%s" "assign ", indent
.c_str());
1012 dump_sigspec(f
, cell
->getPort(ID::Y
));
1013 f
<< stringf(" = ");
1015 dump_attributes(f
, "", cell
->attributes
, ' ');
1016 dump_cell_expr_port(f
, cell
, "A", false);
1017 f
<< stringf(";\n");
1021 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_OR_
), ID($_NOR_
), ID($_XOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
))) {
1022 f
<< stringf("%s" "assign ", indent
.c_str());
1023 dump_sigspec(f
, cell
->getPort(ID::Y
));
1024 f
<< stringf(" = ");
1025 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
)))
1027 dump_cell_expr_port(f
, cell
, "A", false);
1029 if (cell
->type
.in(ID($_AND_
), ID($_NAND_
), ID($_ANDNOT_
)))
1031 if (cell
->type
.in(ID($_OR_
), ID($_NOR_
), ID($_ORNOT_
)))
1033 if (cell
->type
.in(ID($_XOR_
), ID($_XNOR_
)))
1035 dump_attributes(f
, "", cell
->attributes
, ' ');
1037 if (cell
->type
.in(ID($_ANDNOT_
), ID($_ORNOT_
)))
1039 dump_cell_expr_port(f
, cell
, "B", false);
1040 if (cell
->type
.in(ID($_NAND_
), ID($_NOR_
), ID($_XNOR_
), ID($_ANDNOT_
), ID($_ORNOT_
)))
1042 f
<< stringf(";\n");
1046 if (cell
->type
== ID($_MUX_
)) {
1047 f
<< stringf("%s" "assign ", indent
.c_str());
1048 dump_sigspec(f
, cell
->getPort(ID::Y
));
1049 f
<< stringf(" = ");
1050 dump_cell_expr_port(f
, cell
, "S", false);
1051 f
<< stringf(" ? ");
1052 dump_attributes(f
, "", cell
->attributes
, ' ');
1053 dump_cell_expr_port(f
, cell
, "B", false);
1054 f
<< stringf(" : ");
1055 dump_cell_expr_port(f
, cell
, "A", false);
1056 f
<< stringf(";\n");
1060 if (cell
->type
== ID($_NMUX_
)) {
1061 f
<< stringf("%s" "assign ", indent
.c_str());
1062 dump_sigspec(f
, cell
->getPort(ID::Y
));
1063 f
<< stringf(" = !(");
1064 dump_cell_expr_port(f
, cell
, "S", false);
1065 f
<< stringf(" ? ");
1066 dump_attributes(f
, "", cell
->attributes
, ' ');
1067 dump_cell_expr_port(f
, cell
, "B", false);
1068 f
<< stringf(" : ");
1069 dump_cell_expr_port(f
, cell
, "A", false);
1070 f
<< stringf(");\n");
1074 if (cell
->type
.in(ID($_AOI3_
), ID($_OAI3_
))) {
1075 f
<< stringf("%s" "assign ", indent
.c_str());
1076 dump_sigspec(f
, cell
->getPort(ID::Y
));
1077 f
<< stringf(" = ~((");
1078 dump_cell_expr_port(f
, cell
, "A", false);
1079 f
<< stringf(cell
->type
== ID($_AOI3_
) ? " & " : " | ");
1080 dump_cell_expr_port(f
, cell
, "B", false);
1081 f
<< stringf(cell
->type
== ID($_AOI3_
) ? ") |" : ") &");
1082 dump_attributes(f
, "", cell
->attributes
, ' ');
1084 dump_cell_expr_port(f
, cell
, "C", false);
1085 f
<< stringf(");\n");
1089 if (cell
->type
.in(ID($_AOI4_
), ID($_OAI4_
))) {
1090 f
<< stringf("%s" "assign ", indent
.c_str());
1091 dump_sigspec(f
, cell
->getPort(ID::Y
));
1092 f
<< stringf(" = ~((");
1093 dump_cell_expr_port(f
, cell
, "A", false);
1094 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
1095 dump_cell_expr_port(f
, cell
, "B", false);
1096 f
<< stringf(cell
->type
== ID($_AOI4_
) ? ") |" : ") &");
1097 dump_attributes(f
, "", cell
->attributes
, ' ');
1099 dump_cell_expr_port(f
, cell
, "C", false);
1100 f
<< stringf(cell
->type
== ID($_AOI4_
) ? " & " : " | ");
1101 dump_cell_expr_port(f
, cell
, "D", false);
1102 f
<< stringf("));\n");
1106 #define HANDLE_UNIOP(_type, _operator) \
1107 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
1108 #define HANDLE_BINOP(_type, _operator) \
1109 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
1111 HANDLE_UNIOP(ID($
not), "~")
1112 HANDLE_UNIOP(ID($pos
), "+")
1113 HANDLE_UNIOP(ID($neg
), "-")
1115 HANDLE_BINOP(ID($
and), "&")
1116 HANDLE_BINOP(ID($
or), "|")
1117 HANDLE_BINOP(ID($
xor), "^")
1118 HANDLE_BINOP(ID($xnor
), "~^")
1120 HANDLE_UNIOP(ID($reduce_and
), "&")
1121 HANDLE_UNIOP(ID($reduce_or
), "|")
1122 HANDLE_UNIOP(ID($reduce_xor
), "^")
1123 HANDLE_UNIOP(ID($reduce_xnor
), "~^")
1124 HANDLE_UNIOP(ID($reduce_bool
), "|")
1126 HANDLE_BINOP(ID($shl
), "<<")
1127 HANDLE_BINOP(ID($shr
), ">>")
1128 HANDLE_BINOP(ID($sshl
), "<<<")
1129 HANDLE_BINOP(ID($sshr
), ">>>")
1131 HANDLE_BINOP(ID($lt
), "<")
1132 HANDLE_BINOP(ID($le
), "<=")
1133 HANDLE_BINOP(ID($eq
), "==")
1134 HANDLE_BINOP(ID($ne
), "!=")
1135 HANDLE_BINOP(ID($eqx
), "===")
1136 HANDLE_BINOP(ID($nex
), "!==")
1137 HANDLE_BINOP(ID($ge
), ">=")
1138 HANDLE_BINOP(ID($gt
), ">")
1140 HANDLE_BINOP(ID($add
), "+")
1141 HANDLE_BINOP(ID($sub
), "-")
1142 HANDLE_BINOP(ID($mul
), "*")
1143 HANDLE_BINOP(ID($div
), "/")
1144 HANDLE_BINOP(ID($mod
), "%")
1145 HANDLE_BINOP(ID($pow
), "**")
1147 HANDLE_UNIOP(ID($logic_not
), "!")
1148 HANDLE_BINOP(ID($logic_and
), "&&")
1149 HANDLE_BINOP(ID($logic_or
), "||")
1154 if (cell
->type
== ID($divfloor
))
1156 // wire [MAXLEN+1:0] _0_, _1_, _2_;
1157 // assign _0_ = $signed(A);
1158 // assign _1_ = $signed(B);
1159 // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
1160 // assign Y = $signed(_2_) / $signed(_1_);
1162 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
1163 SigSpec sig_a
= cell
->getPort(ID::A
);
1164 SigSpec sig_b
= cell
->getPort(ID::B
);
1166 std::string buf_a
= next_auto_id();
1167 std::string buf_b
= next_auto_id();
1168 std::string buf_num
= next_auto_id();
1169 int size_a
= GetSize(sig_a
);
1170 int size_b
= GetSize(sig_b
);
1171 int size_y
= GetSize(cell
->getPort(ID::Y
));
1172 int size_max
= std::max(size_a
, std::max(size_b
, size_y
));
1174 // intentionally one wider than maximum width
1175 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());
1176 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_a
.c_str());
1177 dump_cell_expr_port(f
, cell
, "A", true);
1178 f
<< stringf(";\n");
1179 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_b
.c_str());
1180 dump_cell_expr_port(f
, cell
, "B", true);
1181 f
<< stringf(";\n");
1183 f
<< stringf("%s" "assign %s = ", indent
.c_str(), buf_num
.c_str());
1185 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
1186 f
<< stringf(" == ");
1187 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
1188 f
<< stringf(") || ");
1189 dump_sigspec(f
, sig_a
);
1190 f
<< stringf(" == 0 ? %s : ", buf_a
.c_str());
1191 f
<< stringf("$signed(%s - (", buf_a
.c_str());
1192 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
1193 f
<< stringf(" ? %s + 1 : %s - 1));\n", buf_b
.c_str(), buf_b
.c_str());
1196 f
<< stringf("%s" "assign ", indent
.c_str());
1197 dump_sigspec(f
, cell
->getPort(ID::Y
));
1198 f
<< stringf(" = $signed(%s) / ", buf_num
.c_str());
1199 dump_attributes(f
, "", cell
->attributes
, ' ');
1200 f
<< stringf("$signed(%s);\n", buf_b
.c_str());
1203 // same as truncating division
1204 dump_cell_expr_binop(f
, indent
, cell
, "/");
1209 if (cell
->type
== ID($modfloor
))
1211 // wire truncated = $signed(A) % $signed(B);
1212 // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated);
1214 if (cell
->getParam(ID::A_SIGNED
).as_bool() && cell
->getParam(ID::B_SIGNED
).as_bool()) {
1215 SigSpec sig_a
= cell
->getPort(ID::A
);
1216 SigSpec sig_b
= cell
->getPort(ID::B
);
1218 std::string temp_id
= next_auto_id();
1219 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
1220 dump_cell_expr_port(f
, cell
, "A", true);
1221 f
<< stringf(" %% ");
1222 dump_attributes(f
, "", cell
->attributes
, ' ');
1223 dump_cell_expr_port(f
, cell
, "B", true);
1224 f
<< stringf(";\n");
1226 f
<< stringf("%s" "assign ", indent
.c_str());
1227 dump_sigspec(f
, cell
->getPort(ID::Y
));
1228 f
<< stringf(" = (");
1229 dump_sigspec(f
, sig_a
.extract(sig_a
.size()-1));
1230 f
<< stringf(" == ");
1231 dump_sigspec(f
, sig_b
.extract(sig_b
.size()-1));
1232 f
<< stringf(") || %s == 0 ? %s : ", temp_id
.c_str(), temp_id
.c_str());
1233 dump_cell_expr_port(f
, cell
, "B", true);
1234 f
<< stringf(" + $signed(%s);\n", temp_id
.c_str());
1237 // same as truncating modulo
1238 dump_cell_expr_binop(f
, indent
, cell
, "%");
1243 if (cell
->type
== ID($shift
))
1245 f
<< stringf("%s" "assign ", indent
.c_str());
1246 dump_sigspec(f
, cell
->getPort(ID::Y
));
1247 f
<< stringf(" = ");
1248 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1250 dump_cell_expr_port(f
, cell
, "B", true);
1251 f
<< stringf(" < 0 ? ");
1252 dump_cell_expr_port(f
, cell
, "A", true);
1253 f
<< stringf(" << - ");
1254 dump_sigspec(f
, cell
->getPort(ID::B
));
1255 f
<< stringf(" : ");
1256 dump_cell_expr_port(f
, cell
, "A", true);
1257 f
<< stringf(" >> ");
1258 dump_sigspec(f
, cell
->getPort(ID::B
));
1262 dump_cell_expr_port(f
, cell
, "A", true);
1263 f
<< stringf(" >> ");
1264 dump_sigspec(f
, cell
->getPort(ID::B
));
1266 f
<< stringf(";\n");
1270 if (cell
->type
== ID($shiftx
))
1272 std::string temp_id
= next_auto_id();
1273 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort(ID::A
))-1, temp_id
.c_str());
1274 dump_sigspec(f
, cell
->getPort(ID::A
));
1275 f
<< stringf(";\n");
1277 f
<< stringf("%s" "assign ", indent
.c_str());
1278 dump_sigspec(f
, cell
->getPort(ID::Y
));
1279 f
<< stringf(" = %s[", temp_id
.c_str());
1280 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1281 f
<< stringf("$signed(");
1282 dump_sigspec(f
, cell
->getPort(ID::B
));
1283 if (cell
->getParam(ID::B_SIGNED
).as_bool())
1285 f
<< stringf(" +: %d", cell
->getParam(ID::Y_WIDTH
).as_int());
1286 f
<< stringf("];\n");
1290 if (cell
->type
== ID($mux
))
1292 f
<< stringf("%s" "assign ", indent
.c_str());
1293 dump_sigspec(f
, cell
->getPort(ID::Y
));
1294 f
<< stringf(" = ");
1295 dump_sigspec(f
, cell
->getPort(ID::S
));
1296 f
<< stringf(" ? ");
1297 dump_attributes(f
, "", cell
->attributes
, ' ');
1298 dump_sigspec(f
, cell
->getPort(ID::B
));
1299 f
<< stringf(" : ");
1300 dump_sigspec(f
, cell
->getPort(ID::A
));
1301 f
<< stringf(";\n");
1305 if (cell
->type
== ID($pmux
))
1307 int width
= cell
->parameters
[ID::WIDTH
].as_int();
1308 int s_width
= cell
->getPort(ID::S
).size();
1309 std::string func_name
= cellname(cell
);
1311 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
1312 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
1313 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
1314 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
1316 dump_attributes(f
, indent
+ " ", cell
->attributes
);
1318 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
1319 f
<< stringf("%s" " casez (s)", indent
.c_str());
1320 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
1322 for (int i
= 0; i
< s_width
; i
++)
1324 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
1326 for (int j
= s_width
-1; j
>= 0; j
--)
1327 f
<< stringf("%c", j
== i
? '1' : '?');
1329 f
<< stringf(":\n");
1330 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
1333 f
<< stringf("%s" " default:\n", indent
.c_str());
1334 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
1336 f
<< stringf("%s" " endcase\n", indent
.c_str());
1337 f
<< stringf("%s" "endfunction\n", indent
.c_str());
1339 f
<< stringf("%s" "assign ", indent
.c_str());
1340 dump_sigspec(f
, cell
->getPort(ID::Y
));
1341 f
<< stringf(" = %s(", func_name
.c_str());
1342 dump_sigspec(f
, cell
->getPort(ID::A
));
1344 dump_sigspec(f
, cell
->getPort(ID::B
));
1346 dump_sigspec(f
, cell
->getPort(ID::S
));
1347 f
<< stringf(");\n");
1351 if (cell
->type
== ID($tribuf
))
1353 f
<< stringf("%s" "assign ", indent
.c_str());
1354 dump_sigspec(f
, cell
->getPort(ID::Y
));
1355 f
<< stringf(" = ");
1356 dump_sigspec(f
, cell
->getPort(ID::EN
));
1357 f
<< stringf(" ? ");
1358 dump_sigspec(f
, cell
->getPort(ID::A
));
1359 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at(ID::WIDTH
).as_int());
1363 if (cell
->type
== ID($slice
))
1365 f
<< stringf("%s" "assign ", indent
.c_str());
1366 dump_sigspec(f
, cell
->getPort(ID::Y
));
1367 f
<< stringf(" = ");
1368 dump_sigspec(f
, cell
->getPort(ID::A
));
1369 f
<< stringf(" >> %d;\n", cell
->parameters
.at(ID::OFFSET
).as_int());
1373 if (cell
->type
== ID($concat
))
1375 f
<< stringf("%s" "assign ", indent
.c_str());
1376 dump_sigspec(f
, cell
->getPort(ID::Y
));
1377 f
<< stringf(" = { ");
1378 dump_sigspec(f
, cell
->getPort(ID::B
));
1379 f
<< stringf(" , ");
1380 dump_sigspec(f
, cell
->getPort(ID::A
));
1381 f
<< stringf(" };\n");
1385 if (cell
->type
== ID($lut
))
1387 f
<< stringf("%s" "assign ", indent
.c_str());
1388 dump_sigspec(f
, cell
->getPort(ID::Y
));
1389 f
<< stringf(" = ");
1390 dump_const(f
, cell
->parameters
.at(ID::LUT
));
1391 f
<< stringf(" >> ");
1392 dump_attributes(f
, "", cell
->attributes
, ' ');
1393 dump_sigspec(f
, cell
->getPort(ID::A
));
1394 f
<< stringf(";\n");
1398 if (RTLIL::builtin_ff_cell_types().count(cell
->type
))
1400 FfData
ff(nullptr, cell
);
1402 // $ff / $_FF_ cell: not supported.
1406 std::string reg_name
= cellname(cell
);
1407 bool out_is_reg_wire
= is_reg_wire(ff
.sig_q
, reg_name
);
1409 if (!out_is_reg_wire
) {
1411 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
1413 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), ff
.width
-1, reg_name
.c_str());
1414 dump_reg_init(f
, ff
.sig_q
);
1418 // If the FF has CLR/SET inputs, emit every bit slice separately.
1419 int chunks
= ff
.has_sr
? ff
.width
: 1;
1420 bool chunky
= ff
.has_sr
&& ff
.width
!= 1;
1422 for (int i
= 0; i
< chunks
; i
++)
1424 SigSpec sig_d
, sig_ad
;
1425 Const val_arst
, val_srst
;
1426 std::string reg_bit_name
, sig_set_name
, sig_clr_name
, sig_arst_name
, sig_aload_name
;
1428 reg_bit_name
= stringf("%s[%d]", reg_name
.c_str(), i
);
1429 if (ff
.has_gclk
|| ff
.has_clk
)
1430 sig_d
= ff
.sig_d
[i
];
1432 sig_ad
= ff
.sig_ad
[i
];
1434 reg_bit_name
= reg_name
;
1439 val_arst
= chunky
? ff
.val_arst
[i
] : ff
.val_arst
;
1441 val_srst
= chunky
? ff
.val_srst
[i
] : ff
.val_srst
;
1443 // If there are constants in the sensitivity list, replace them with an intermediate wire
1446 if (ff
.sig_set
[i
].wire
== NULL
)
1448 sig_set_name
= next_auto_id();
1449 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_set_name
.c_str());
1450 dump_const(f
, ff
.sig_set
[i
].data
);
1451 f
<< stringf(";\n");
1453 if (ff
.sig_clr
[i
].wire
== NULL
)
1455 sig_clr_name
= next_auto_id();
1456 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_clr_name
.c_str());
1457 dump_const(f
, ff
.sig_clr
[i
].data
);
1458 f
<< stringf(";\n");
1460 } else if (ff
.has_arst
) {
1461 if (ff
.sig_arst
[0].wire
== NULL
)
1463 sig_arst_name
= next_auto_id();
1464 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_arst_name
.c_str());
1465 dump_const(f
, ff
.sig_arst
[0].data
);
1466 f
<< stringf(";\n");
1468 } else if (ff
.has_aload
) {
1469 if (ff
.sig_aload
[0].wire
== NULL
)
1471 sig_aload_name
= next_auto_id();
1472 f
<< stringf("%s" "wire %s = ", indent
.c_str(), sig_aload_name
.c_str());
1473 dump_const(f
, ff
.sig_aload
[0].data
);
1474 f
<< stringf(";\n");
1479 dump_attributes(f
, indent
, cell
->attributes
);
1483 f
<< stringf("%s" "always%s @(%sedge ", indent
.c_str(), systemverilog
? "_ff" : "", ff
.pol_clk
? "pos" : "neg");
1484 dump_sigspec(f
, ff
.sig_clk
);
1486 f
<< stringf(", %sedge ", ff
.pol_set
? "pos" : "neg");
1487 if (ff
.sig_set
[i
].wire
== NULL
)
1488 f
<< stringf("%s", sig_set_name
.c_str());
1490 dump_sigspec(f
, ff
.sig_set
[i
]);
1492 f
<< stringf(", %sedge ", ff
.pol_clr
? "pos" : "neg");
1493 if (ff
.sig_clr
[i
].wire
== NULL
)
1494 f
<< stringf("%s", sig_clr_name
.c_str());
1496 dump_sigspec(f
, ff
.sig_clr
[i
]);
1497 } else if (ff
.has_arst
) {
1498 f
<< stringf(", %sedge ", ff
.pol_arst
? "pos" : "neg");
1499 if (ff
.sig_arst
[0].wire
== NULL
)
1500 f
<< stringf("%s", sig_arst_name
.c_str());
1502 dump_sigspec(f
, ff
.sig_arst
);
1503 } else if (ff
.has_aload
) {
1504 f
<< stringf(", %sedge ", ff
.pol_aload
? "pos" : "neg");
1505 if (ff
.sig_aload
[0].wire
== NULL
)
1506 f
<< stringf("%s", sig_aload_name
.c_str());
1508 dump_sigspec(f
, ff
.sig_aload
);
1510 f
<< stringf(")\n");
1512 f
<< stringf("%s" " ", indent
.c_str());
1514 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1515 if (ff
.sig_clr
[i
].wire
== NULL
)
1516 f
<< stringf("%s", sig_clr_name
.c_str());
1518 dump_sigspec(f
, ff
.sig_clr
[i
]);
1519 f
<< stringf(") %s <= 1'b0;\n", reg_bit_name
.c_str());
1520 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1521 if (ff
.sig_set
[i
].wire
== NULL
)
1522 f
<< stringf("%s", sig_set_name
.c_str());
1524 dump_sigspec(f
, ff
.sig_set
[i
]);
1525 f
<< stringf(") %s <= 1'b1;\n", reg_bit_name
.c_str());
1526 f
<< stringf("%s" " else ", indent
.c_str());
1527 } else if (ff
.has_arst
) {
1528 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1529 if (ff
.sig_arst
[0].wire
== NULL
)
1530 f
<< stringf("%s", sig_arst_name
.c_str());
1532 dump_sigspec(f
, ff
.sig_arst
);
1533 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1534 dump_sigspec(f
, val_arst
);
1535 f
<< stringf(";\n");
1536 f
<< stringf("%s" " else ", indent
.c_str());
1537 } else if (ff
.has_aload
) {
1538 f
<< stringf("if (%s", ff
.pol_aload
? "" : "!");
1539 if (ff
.sig_aload
[0].wire
== NULL
)
1540 f
<< stringf("%s", sig_aload_name
.c_str());
1542 dump_sigspec(f
, ff
.sig_aload
);
1543 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1544 dump_sigspec(f
, sig_ad
);
1545 f
<< stringf(";\n");
1546 f
<< stringf("%s" " else ", indent
.c_str());
1549 if (ff
.has_srst
&& ff
.has_ce
&& ff
.ce_over_srst
) {
1550 f
<< stringf("if (%s", ff
.pol_ce
? "" : "!");
1551 dump_sigspec(f
, ff
.sig_ce
);
1552 f
<< stringf(")\n");
1553 f
<< stringf("%s" " if (%s", indent
.c_str(), ff
.pol_srst
? "" : "!");
1554 dump_sigspec(f
, ff
.sig_srst
);
1555 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1556 dump_sigspec(f
, val_srst
);
1557 f
<< stringf(";\n");
1558 f
<< stringf("%s" " else ", indent
.c_str());
1561 f
<< stringf("if (%s", ff
.pol_srst
? "" : "!");
1562 dump_sigspec(f
, ff
.sig_srst
);
1563 f
<< stringf(") %s <= ", reg_bit_name
.c_str());
1564 dump_sigspec(f
, val_srst
);
1565 f
<< stringf(";\n");
1566 f
<< stringf("%s" " else ", indent
.c_str());
1569 f
<< stringf("if (%s", ff
.pol_ce
? "" : "!");
1570 dump_sigspec(f
, ff
.sig_ce
);
1575 f
<< stringf("%s <= ", reg_bit_name
.c_str());
1576 dump_sigspec(f
, sig_d
);
1577 f
<< stringf(";\n");
1582 f
<< stringf("%s" "always%s\n", indent
.c_str(), systemverilog
? "_latch" : " @*");
1584 f
<< stringf("%s" " ", indent
.c_str());
1586 f
<< stringf("if (%s", ff
.pol_clr
? "" : "!");
1587 dump_sigspec(f
, ff
.sig_clr
[i
]);
1588 f
<< stringf(") %s = 1'b0;\n", reg_bit_name
.c_str());
1589 f
<< stringf("%s" " else if (%s", indent
.c_str(), ff
.pol_set
? "" : "!");
1590 dump_sigspec(f
, ff
.sig_set
[i
]);
1591 f
<< stringf(") %s = 1'b1;\n", reg_bit_name
.c_str());
1593 f
<< stringf("%s" " else ", indent
.c_str());
1594 } else if (ff
.has_arst
) {
1595 f
<< stringf("if (%s", ff
.pol_arst
? "" : "!");
1596 dump_sigspec(f
, ff
.sig_arst
);
1597 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1598 dump_sigspec(f
, val_arst
);
1599 f
<< stringf(";\n");
1601 f
<< stringf("%s" " else ", indent
.c_str());
1604 f
<< stringf("if (%s", ff
.pol_aload
? "" : "!");
1605 dump_sigspec(f
, ff
.sig_aload
);
1606 f
<< stringf(") %s = ", reg_bit_name
.c_str());
1607 dump_sigspec(f
, sig_ad
);
1608 f
<< stringf(";\n");
1613 if (!out_is_reg_wire
) {
1614 f
<< stringf("%s" "assign ", indent
.c_str());
1615 dump_sigspec(f
, ff
.sig_q
);
1616 f
<< stringf(" = %s;\n", reg_name
.c_str());
1622 if (cell
->type
.in(ID($
assert), ID($assume
), ID($cover
)))
1624 f
<< stringf("%s" "always%s if (", indent
.c_str(), systemverilog
? "_comb" : " @*");
1625 dump_sigspec(f
, cell
->getPort(ID::EN
));
1626 f
<< stringf(") %s(", cell
->type
.c_str()+1);
1627 dump_sigspec(f
, cell
->getPort(ID::A
));
1628 f
<< stringf(");\n");
1632 if (cell
->type
.in(ID($specify2
), ID($specify3
)))
1634 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1636 SigSpec en
= cell
->getPort(ID::EN
);
1637 if (en
!= State::S1
) {
1638 f
<< stringf("if (");
1639 dump_sigspec(f
, cell
->getPort(ID::EN
));
1644 if (cell
->type
== ID($specify3
) && cell
->getParam(ID::EDGE_EN
).as_bool())
1645 f
<< (cell
->getParam(ID::EDGE_POL
).as_bool() ? "posedge ": "negedge ");
1647 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1650 if (cell
->getParam(ID::SRC_DST_PEN
).as_bool())
1651 f
<< (cell
->getParam(ID::SRC_DST_POL
).as_bool() ? "+": "-");
1652 f
<< (cell
->getParam(ID::FULL
).as_bool() ? "*> ": "=> ");
1654 if (cell
->type
== ID($specify3
)) {
1656 dump_sigspec(f
, cell
->getPort(ID::DST
));
1658 if (cell
->getParam(ID::DAT_DST_PEN
).as_bool())
1659 f
<< (cell
->getParam(ID::DAT_DST_POL
).as_bool() ? "+": "-");
1661 dump_sigspec(f
, cell
->getPort(ID::DAT
));
1664 dump_sigspec(f
, cell
->getPort(ID::DST
));
1667 bool bak_decimal
= decimal
;
1671 dump_const(f
, cell
->getParam(ID::T_RISE_MIN
));
1673 dump_const(f
, cell
->getParam(ID::T_RISE_TYP
));
1675 dump_const(f
, cell
->getParam(ID::T_RISE_MAX
));
1677 dump_const(f
, cell
->getParam(ID::T_FALL_MIN
));
1679 dump_const(f
, cell
->getParam(ID::T_FALL_TYP
));
1681 dump_const(f
, cell
->getParam(ID::T_FALL_MAX
));
1684 decimal
= bak_decimal
;
1686 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1690 if (cell
->type
== ID($specrule
))
1692 f
<< stringf("%s" "specify\n%s ", indent
.c_str(), indent
.c_str());
1694 IdString spec_type
= cell
->getParam(ID::TYPE
).decode_string();
1695 f
<< stringf("%s(", spec_type
.c_str());
1697 if (cell
->getParam(ID::SRC_PEN
).as_bool())
1698 f
<< (cell
->getParam(ID::SRC_POL
).as_bool() ? "posedge ": "negedge ");
1699 dump_sigspec(f
, cell
->getPort(ID::SRC
));
1701 if (cell
->getPort(ID::SRC_EN
) != State::S1
) {
1703 dump_sigspec(f
, cell
->getPort(ID::SRC_EN
));
1707 if (cell
->getParam(ID::DST_PEN
).as_bool())
1708 f
<< (cell
->getParam(ID::DST_POL
).as_bool() ? "posedge ": "negedge ");
1709 dump_sigspec(f
, cell
->getPort(ID::DST
));
1711 if (cell
->getPort(ID::DST_EN
) != State::S1
) {
1713 dump_sigspec(f
, cell
->getPort(ID::DST_EN
));
1716 bool bak_decimal
= decimal
;
1720 dump_const(f
, cell
->getParam(ID::T_LIMIT_MIN
));
1722 dump_const(f
, cell
->getParam(ID::T_LIMIT_TYP
));
1724 dump_const(f
, cell
->getParam(ID::T_LIMIT_MAX
));
1726 if (spec_type
.in(ID($setuphold
), ID($recrem
), ID($fullskew
))) {
1728 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MIN
));
1730 dump_const(f
, cell
->getParam(ID::T_LIMIT2_TYP
));
1732 dump_const(f
, cell
->getParam(ID::T_LIMIT2_MAX
));
1736 decimal
= bak_decimal
;
1738 f
<< stringf("%s" "endspecify\n", indent
.c_str());
1747 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1749 // Handled by dump_memory
1750 if (cell
->is_mem_cell())
1753 if (cell
->type
[0] == '$' && !noexpr
) {
1754 if (dump_cell_expr(f
, indent
, cell
))
1758 dump_attributes(f
, indent
, cell
->attributes
);
1759 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1761 if (!defparam
&& cell
->parameters
.size() > 0) {
1762 f
<< stringf(" #(");
1763 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1764 if (it
!= cell
->parameters
.begin())
1766 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1767 dump_const(f
, it
->second
);
1770 f
<< stringf("\n%s" ")", indent
.c_str());
1773 std::string cell_name
= cellname(cell
);
1774 if (cell_name
!= id(cell
->name
))
1775 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1777 f
<< stringf(" %s (", cell_name
.c_str());
1779 bool first_arg
= true;
1780 std::set
<RTLIL::IdString
> numbered_ports
;
1781 for (int i
= 1; true; i
++) {
1783 snprintf(str
, 16, "$%d", i
);
1784 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1785 if (it
->first
!= str
)
1790 f
<< stringf("\n%s ", indent
.c_str());
1791 dump_sigspec(f
, it
->second
);
1792 numbered_ports
.insert(it
->first
);
1793 goto found_numbered_port
;
1796 found_numbered_port
:;
1798 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1799 if (numbered_ports
.count(it
->first
))
1804 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1805 if (it
->second
.size() > 0)
1806 dump_sigspec(f
, it
->second
);
1809 f
<< stringf("\n%s" ");\n", indent
.c_str());
1811 if (defparam
&& cell
->parameters
.size() > 0) {
1812 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1813 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1814 dump_const(f
, it
->second
);
1815 f
<< stringf(";\n");
1819 if (siminit
&& RTLIL::builtin_ff_cell_types().count(cell
->type
) && cell
->hasPort(ID::Q
) && !cell
->type
.in(ID($ff
), ID($_FF_
))) {
1820 std::stringstream ss
;
1821 dump_reg_init(ss
, cell
->getPort(ID::Q
));
1822 if (!ss
.str().empty()) {
1823 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1830 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1834 for (auto &chunk
: left
.chunks()) {
1835 f
<< stringf("%s" "assign ", indent
.c_str());
1836 dump_sigspec(f
, chunk
);
1837 f
<< stringf(" = ");
1838 dump_sigspec(f
, right
.extract(offset
, GetSize(chunk
)));
1839 f
<< stringf(";\n");
1840 offset
+= GetSize(chunk
);
1843 f
<< stringf("%s" "assign ", indent
.c_str());
1844 dump_sigspec(f
, left
);
1845 f
<< stringf(" = ");
1846 dump_sigspec(f
, right
);
1847 f
<< stringf(";\n");
1851 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1853 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1855 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1857 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1858 f
<< stringf("%s" "begin\n", indent
.c_str());
1860 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1861 if (it
->first
.size() == 0)
1863 f
<< stringf("%s ", indent
.c_str());
1864 dump_sigspec(f
, it
->first
);
1865 f
<< stringf(" = ");
1866 dump_sigspec(f
, it
->second
);
1867 f
<< stringf(";\n");
1870 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1871 dump_proc_switch(f
, indent
+ " ", *it
);
1873 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1874 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1876 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1877 f
<< stringf("%s" "end\n", indent
.c_str());
1880 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1882 if (sw
->signal
.size() == 0) {
1883 f
<< stringf("%s" "begin\n", indent
.c_str());
1884 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1885 if ((*it
)->compare
.size() == 0)
1886 dump_case_body(f
, indent
+ " ", *it
);
1888 f
<< stringf("%s" "end\n", indent
.c_str());
1892 dump_attributes(f
, indent
, sw
->attributes
);
1893 f
<< stringf("%s" "casez (", indent
.c_str());
1894 dump_sigspec(f
, sw
->signal
);
1895 f
<< stringf(")\n");
1897 bool got_default
= false;
1898 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1899 dump_attributes(f
, indent
+ " ", (*it
)->attributes
, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1900 if ((*it
)->compare
.size() == 0) {
1903 f
<< stringf("%s default", indent
.c_str());
1906 f
<< stringf("%s ", indent
.c_str());
1907 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1910 dump_sigspec(f
, (*it
)->compare
[i
]);
1913 f
<< stringf(":\n");
1914 dump_case_body(f
, indent
+ " ", *it
);
1917 f
<< stringf("%s" "endcase\n", indent
.c_str());
1920 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1922 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1923 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1924 case_body_find_regs(*it2
);
1926 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1927 for (auto &c
: it
->first
.chunks())
1929 reg_wires
.insert(c
.wire
->name
);
1933 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1936 case_body_find_regs(&proc
->root_case
);
1937 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1938 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1939 for (auto &c
: it2
->first
.chunks())
1941 reg_wires
.insert(c
.wire
->name
);
1946 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1948 f
<< indent
+ " " << "if (" << id(initial_id
) << ") begin end\n";
1949 dump_case_body(f
, indent
, &proc
->root_case
, true);
1951 std::string backup_indent
= indent
;
1953 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1955 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1956 indent
= backup_indent
;
1958 if (sync
->type
== RTLIL::STa
) {
1959 f
<< stringf("%s" "always%s begin\n", indent
.c_str(), systemverilog
? "_comb" : " @*");
1960 } else if (sync
->type
== RTLIL::STi
) {
1961 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1963 f
<< stringf("%s" "always%s @(", indent
.c_str(), systemverilog
? "_ff" : "");
1964 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1965 f
<< stringf("posedge ");
1966 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1967 f
<< stringf("negedge ");
1968 dump_sigspec(f
, sync
->signal
);
1969 f
<< stringf(") begin\n");
1971 std::string ends
= indent
+ "end\n";
1974 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1975 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1976 dump_sigspec(f
, sync
->signal
);
1977 f
<< stringf(") begin\n");
1978 ends
= indent
+ "end\n" + ends
;
1982 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1983 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1984 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1985 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1986 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1987 dump_sigspec(f
, sync2
->signal
);
1988 f
<< stringf(") begin\n");
1989 ends
= indent
+ "end\n" + ends
;
1995 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1996 if (it
->first
.size() == 0)
1998 f
<< stringf("%s ", indent
.c_str());
1999 dump_sigspec(f
, it
->first
);
2000 f
<< stringf(" <= ");
2001 dump_sigspec(f
, it
->second
);
2002 f
<< stringf(";\n");
2005 f
<< stringf("%s", ends
.c_str());
2009 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
2012 reset_auto_counter(module
);
2013 active_module
= module
;
2014 active_sigmap
.set(module
);
2015 active_initdata
.clear();
2017 for (auto wire
: module
->wires())
2018 if (wire
->attributes
.count(ID::init
)) {
2019 SigSpec sig
= active_sigmap(wire
);
2020 Const val
= wire
->attributes
.at(ID::init
);
2021 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
2022 if (val
[i
] == State::S0
|| val
[i
] == State::S1
)
2023 active_initdata
[sig
[i
]] = val
[i
];
2026 if (!module
->processes
.empty())
2027 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
2028 "can't always be mapped directly to Verilog always blocks. Unintended\n"
2029 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
2030 "processes to logic networks and registers.\n", log_id(module
));
2033 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
2034 dump_process(f
, indent
+ " ", it
->second
, true);
2038 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
2039 for (auto cell
: module
->cells())
2041 if (!RTLIL::builtin_ff_cell_types().count(cell
->type
) || !cell
->hasPort(ID::Q
) || cell
->type
.in(ID($ff
), ID($_FF_
)))
2044 RTLIL::SigSpec sig
= cell
->getPort(ID::Q
);
2046 if (sig
.is_chunk()) {
2047 RTLIL::SigChunk chunk
= sig
.as_chunk();
2048 if (chunk
.wire
!= NULL
)
2049 for (int i
= 0; i
< chunk
.width
; i
++)
2050 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
2053 for (auto wire
: module
->wires())
2055 for (int i
= 0; i
< wire
->width
; i
++)
2056 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
2057 goto this_wire_aint_reg
;
2059 reg_wires
.insert(wire
->name
);
2060 this_wire_aint_reg
:;
2064 dump_attributes(f
, indent
, module
->attributes
, '\n', /*modattr=*/true);
2065 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
2066 bool keep_running
= true;
2068 for (int port_id
= 1; keep_running
; port_id
++) {
2069 keep_running
= false;
2070 for (auto wire
: module
->wires()) {
2071 if (wire
->port_id
== port_id
) {
2074 f
<< stringf("%s", id(wire
->name
).c_str());
2075 keep_running
= true;
2076 if (cnt
==20) { f
<< stringf("\n"); cnt
= 0; } else cnt
++;
2081 f
<< stringf(");\n");
2082 if (!systemverilog
&& !module
->processes
.empty()) {
2083 initial_id
= NEW_ID
;
2084 f
<< indent
+ " " << "reg " << id(initial_id
) << " = 0;\n";
2087 for (auto w
: module
->wires())
2088 dump_wire(f
, indent
+ " ", w
);
2090 for (auto &mem
: Mem::get_all_memories(module
))
2091 dump_memory(f
, indent
+ " ", mem
);
2093 for (auto cell
: module
->cells())
2094 dump_cell(f
, indent
+ " ", cell
);
2096 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
2097 dump_process(f
, indent
+ " ", it
->second
);
2099 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
2100 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
2102 f
<< stringf("%s" "endmodule\n", indent
.c_str());
2103 active_module
= NULL
;
2104 active_sigmap
.clear();
2105 active_initdata
.clear();
2108 struct VerilogBackend
: public Backend
{
2109 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
2110 void help() override
2112 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2114 log(" write_verilog [options] [filename]\n");
2116 log("Write the current design to a Verilog file.\n");
2119 log(" with this option, SystemVerilog constructs like always_comb are used\n");
2121 log(" -norename\n");
2122 log(" without this option all internal object names (the ones with a dollar\n");
2123 log(" instead of a backslash prefix) are changed to short names in the\n");
2124 log(" format '_<number>_'.\n");
2126 log(" -renameprefix <prefix>\n");
2127 log(" insert this prefix in front of auto-generated instance names\n");
2130 log(" with this option no attributes are included in the output\n");
2132 log(" -attr2comment\n");
2133 log(" with this option attributes are included as comments in the output\n");
2136 log(" without this option all internal cells are converted to Verilog\n");
2137 log(" expressions.\n");
2140 log(" add initial statements with hierarchical refs to initialize FFs when\n");
2141 log(" in -noexpr mode.\n");
2144 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
2145 log(" not bit pattern. This option deactivates this feature and instead\n");
2146 log(" will write out all constants in binary.\n");
2149 log(" dump 32-bit constants in decimal and without size and radix\n");
2152 log(" constant values that are compatible with hex output are usually\n");
2153 log(" dumped as hex values. This option deactivates this feature and\n");
2154 log(" instead will write out all constants in binary.\n");
2157 log(" Parameters and attributes that are specified as strings in the\n");
2158 log(" original input will be output as strings by this back-end. This\n");
2159 log(" deactivates this feature and instead will write string constants\n");
2160 log(" as binary numbers.\n");
2162 log(" -simple-lhs\n");
2163 log(" Connection assignments with simple left hand side without concatenations.\n");
2166 log(" instead of initializing memories using assignments to individual\n");
2167 log(" elements, use the '$readmemh' function to read initialization data\n");
2168 log(" from a file. This data is written to a file named by appending\n");
2169 log(" a sequential index to the Verilog filename and replacing the extension\n");
2170 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
2171 log(" 'foo-2.mem' and so on.\n");
2173 log(" -defparam\n");
2174 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
2175 log(" cell parameters.\n");
2177 log(" -blackboxes\n");
2178 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
2179 log(" this option set only the modules with the 'blackbox' attribute\n");
2180 log(" are written to the output file.\n");
2182 log(" -selected\n");
2183 log(" only write selected modules. modules must be selected entirely or\n");
2184 log(" not at all.\n");
2187 log(" verbose output (print new names of all renamed wires and cells)\n");
2189 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
2190 log("always blocks. This frontend should only be used to export an RTLIL\n");
2191 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
2192 log("processes to logic networks and registers. A warning is generated when\n");
2193 log("this command is called on a design with RTLIL processes.\n");
2196 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
2198 log_header(design
, "Executing Verilog backend.\n");
2203 attr2comment
= false;
2215 bool blackboxes
= false;
2216 bool selected
= false;
2218 auto_name_map
.clear();
2222 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
2223 std::string arg
= args
[argidx
];
2225 systemverilog
= true;
2228 if (arg
== "-norename") {
2232 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
2233 auto_prefix
= args
[++argidx
];
2236 if (arg
== "-noattr") {
2240 if (arg
== "-attr2comment") {
2241 attr2comment
= true;
2244 if (arg
== "-noexpr") {
2248 if (arg
== "-nodec") {
2252 if (arg
== "-nohex") {
2256 if (arg
== "-nostr") {
2260 if (arg
== "-extmem") {
2265 if (arg
== "-defparam") {
2269 if (arg
== "-decimal") {
2273 if (arg
== "-siminit") {
2277 if (arg
== "-blackboxes") {
2281 if (arg
== "-selected") {
2285 if (arg
== "-simple-lhs") {
2295 extra_args(f
, filename
, args
, argidx
);
2298 if (filename
== "<stdout>")
2299 log_cmd_error("Option -extmem must be used with a filename.\n");
2300 extmem_prefix
= filename
.substr(0, filename
.rfind('.'));
2303 Pass::call(design
, "clean_zerowidth");
2307 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
2308 for (auto module
: design
->modules()) {
2309 if (module
->get_blackbox_attribute() != blackboxes
)
2311 if (selected
&& !design
->selected_whole_module(module
->name
)) {
2312 if (design
->selected_module(module
->name
))
2313 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module
->name
));
2316 log("Dumping module `%s'.\n", module
->name
.c_str());
2317 dump_module(*f
, "", module
);
2320 auto_name_map
.clear();
2325 PRIVATE_NAMESPACE_END