2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * A simple and straightforward Verilog backend.
24 #include "kernel/register.h"
25 #include "kernel/celltypes.h"
26 #include "kernel/log.h"
27 #include "kernel/sigtools.h"
34 PRIVATE_NAMESPACE_BEGIN
36 bool verbose
, norename
, noattr
, attr2comment
, noexpr
, nodec
, nohex
, nostr
, defparam
, decimal
, siminit
;
37 int auto_name_counter
, auto_name_offset
, auto_name_digits
;
38 std::map
<RTLIL::IdString
, int> auto_name_map
;
39 std::set
<RTLIL::IdString
> reg_wires
, reg_ct
;
40 std::string auto_prefix
;
42 RTLIL::Module
*active_module
;
43 dict
<RTLIL::SigBit
, RTLIL::State
> active_initdata
;
46 void reset_auto_counter_id(RTLIL::IdString id
, bool may_rename
)
48 const char *str
= id
.c_str();
50 if (*str
== '$' && may_rename
&& !norename
)
51 auto_name_map
[id
] = auto_name_counter
++;
53 if (str
[0] != '\\' || str
[1] != '_' || str
[2] == 0)
56 for (int i
= 2; str
[i
] != 0; i
++) {
57 if (str
[i
] == '_' && str
[i
+1] == 0)
59 if (str
[i
] < '0' || str
[i
] > '9')
63 int num
= atoi(str
+2);
64 if (num
>= auto_name_offset
)
65 auto_name_offset
= num
+ 1;
68 void reset_auto_counter(RTLIL::Module
*module
)
70 auto_name_map
.clear();
71 auto_name_counter
= 0;
74 reset_auto_counter_id(module
->name
, false);
76 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
77 reset_auto_counter_id(it
->second
->name
, true);
79 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
) {
80 reset_auto_counter_id(it
->second
->name
, true);
81 reset_auto_counter_id(it
->second
->type
, false);
84 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
85 reset_auto_counter_id(it
->second
->name
, false);
88 for (size_t i
= 10; i
< auto_name_offset
+ auto_name_map
.size(); i
= i
*10)
92 for (auto it
= auto_name_map
.begin(); it
!= auto_name_map
.end(); ++it
)
93 log(" renaming `%s' to `%s_%0*d_'.\n", it
->first
.c_str(), auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ it
->second
);
96 std::string
next_auto_id()
98 return stringf("%s_%0*d_", auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ auto_name_counter
++);
101 std::string
id(RTLIL::IdString internal_id
, bool may_rename
= true)
103 const char *str
= internal_id
.c_str();
104 bool do_escape
= false;
106 if (may_rename
&& auto_name_map
.count(internal_id
) != 0)
107 return stringf("%s_%0*d_", auto_prefix
.c_str(), auto_name_digits
, auto_name_offset
+ auto_name_map
[internal_id
]);
112 if ('0' <= *str
&& *str
<= '9')
115 for (int i
= 0; str
[i
]; i
++)
117 if ('0' <= str
[i
] && str
[i
] <= '9')
119 if ('a' <= str
[i
] && str
[i
] <= 'z')
121 if ('A' <= str
[i
] && str
[i
] <= 'Z')
129 const pool
<string
> keywords
= {
130 // IEEE 1800-2017 Annex B
131 "accept_on", "alias", "always", "always_comb", "always_ff", "always_latch", "and", "assert", "assign", "assume", "automatic", "before",
132 "begin", "bind", "bins", "binsof", "bit", "break", "buf", "bufif0", "bufif1", "byte", "case", "casex", "casez", "cell", "chandle",
133 "checker", "class", "clocking", "cmos", "config", "const", "constraint", "context", "continue", "cover", "covergroup", "coverpoint",
134 "cross", "deassign", "default", "defparam", "design", "disable", "dist", "do", "edge", "else", "end", "endcase", "endchecker",
135 "endclass", "endclocking", "endconfig", "endfunction", "endgenerate", "endgroup", "endinterface", "endmodule", "endpackage",
136 "endprimitive", "endprogram", "endproperty", "endsequence", "endspecify", "endtable", "endtask", "enum", "event", "eventually",
137 "expect", "export", "extends", "extern", "final", "first_match", "for", "force", "foreach", "forever", "fork", "forkjoin", "function",
138 "generate", "genvar", "global", "highz0", "highz1", "if", "iff", "ifnone", "ignore_bins", "illegal_bins", "implements", "implies",
139 "import", "incdir", "include", "initial", "inout", "input", "inside", "instance", "int", "integer", "interconnect", "interface",
140 "intersect", "join", "join_any", "join_none", "large", "let", "liblist", "library", "local", "localparam", "logic", "longint",
141 "macromodule", "matches", "medium", "modport", "module", "nand", "negedge", "nettype", "new", "nexttime", "nmos", "nor",
142 "noshowcancelled", "not", "notif0", "notif1", "null", "or", "output", "package", "packed", "parameter", "pmos", "posedge", "primitive",
143 "priority", "program", "property", "protected", "pull0", "pull1", "pulldown", "pullup", "pulsestyle_ondetect", "pulsestyle_onevent",
144 "pure", "rand", "randc", "randcase", "randsequence", "rcmos", "real", "realtime", "ref", "reg", "reject_on", "release", "repeat",
145 "restrict", "return", "rnmos", "rpmos", "rtran", "rtranif0", "rtranif1", "s_always", "s_eventually", "s_nexttime", "s_until",
146 "s_until_with", "scalared", "sequence", "shortint", "shortreal", "showcancelled", "signed", "small", "soft", "solve", "specify",
147 "specparam", "static", "string", "strong", "strong0", "strong1", "struct", "super", "supply0", "supply1", "sync_accept_on",
148 "sync_reject_on", "table", "tagged", "task", "this", "throughout", "time", "timeprecision", "timeunit", "tran", "tranif0", "tranif1",
149 "tri", "tri0", "tri1", "triand", "trior", "trireg", "type", "typedef", "union", "unique", "unique0", "unsigned", "until", "until_with",
150 "untyped", "use", "uwire", "var", "vectored", "virtual", "void", "wait", "wait_order", "wand", "weak", "weak0", "weak1", "while",
151 "wildcard", "wire", "with", "within", "wor", "xnor", "xor",
153 if (keywords
.count(str
))
157 return "\\" + std::string(str
) + " ";
158 return std::string(str
);
161 bool is_reg_wire(RTLIL::SigSpec sig
, std::string
®_name
)
163 if (!sig
.is_chunk() || sig
.as_chunk().wire
== NULL
)
166 RTLIL::SigChunk chunk
= sig
.as_chunk();
168 if (reg_wires
.count(chunk
.wire
->name
) == 0)
171 reg_name
= id(chunk
.wire
->name
);
172 if (sig
.size() != chunk
.wire
->width
) {
174 reg_name
+= stringf("[%d]", chunk
.wire
->start_offset
+ chunk
.offset
);
175 else if (chunk
.wire
->upto
)
176 reg_name
+= stringf("[%d:%d]", (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
177 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
179 reg_name
+= stringf("[%d:%d]", chunk
.wire
->start_offset
+ chunk
.offset
+ chunk
.width
- 1,
180 chunk
.wire
->start_offset
+ chunk
.offset
);
186 void dump_const(std::ostream
&f
, const RTLIL::Const
&data
, int width
= -1, int offset
= 0, bool no_decimal
= false, bool set_signed
= false, bool escape_comment
= false)
189 width
= data
.bits
.size() - offset
;
192 if ((data
.flags
& RTLIL::CONST_FLAG_STRING
) == 0 || width
!= (int)data
.bits
.size()) {
193 if (width
== 32 && !no_decimal
&& !nodec
) {
195 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
196 log_assert(i
< (int)data
.bits
.size());
197 if (data
.bits
[i
] != RTLIL::S0
&& data
.bits
[i
] != RTLIL::S1
)
199 if (data
.bits
[i
] == RTLIL::S1
)
200 val
|= 1 << (i
- offset
);
203 f
<< stringf("%d", val
);
204 else if (set_signed
&& val
< 0)
205 f
<< stringf("-32'sd%u", -val
);
207 f
<< stringf("32'%sd%u", set_signed
? "s" : "", val
);
212 vector
<char> bin_digits
, hex_digits
;
213 for (int i
= offset
; i
< offset
+width
; i
++) {
214 log_assert(i
< (int)data
.bits
.size());
215 switch (data
.bits
[i
]) {
216 case RTLIL::S0
: bin_digits
.push_back('0'); break;
217 case RTLIL::S1
: bin_digits
.push_back('1'); break;
218 case RTLIL::Sx
: bin_digits
.push_back('x'); break;
219 case RTLIL::Sz
: bin_digits
.push_back('z'); break;
220 case RTLIL::Sa
: bin_digits
.push_back('z'); break;
221 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
224 if (GetSize(bin_digits
) == 0)
226 while (GetSize(bin_digits
) % 4 != 0)
227 if (bin_digits
.back() == '1')
228 bin_digits
.push_back('0');
230 bin_digits
.push_back(bin_digits
.back());
231 for (int i
= 0; i
< GetSize(bin_digits
); i
+= 4)
233 char bit_3
= bin_digits
[i
+3];
234 char bit_2
= bin_digits
[i
+2];
235 char bit_1
= bin_digits
[i
+1];
236 char bit_0
= bin_digits
[i
+0];
237 if (bit_3
== 'x' || bit_2
== 'x' || bit_1
== 'x' || bit_0
== 'x') {
238 if (bit_3
!= 'x' || bit_2
!= 'x' || bit_1
!= 'x' || bit_0
!= 'x')
240 hex_digits
.push_back('x');
243 if (bit_3
== 'z' || bit_2
== 'z' || bit_1
== 'z' || bit_0
== 'z') {
244 if (bit_3
!= 'z' || bit_2
!= 'z' || bit_1
!= 'z' || bit_0
!= 'z')
246 hex_digits
.push_back('z');
249 int val
= 8*(bit_3
- '0') + 4*(bit_2
- '0') + 2*(bit_1
- '0') + (bit_0
- '0');
250 hex_digits
.push_back(val
< 10 ? '0' + val
: 'a' + val
- 10);
252 f
<< stringf("%d'%sh", width
, set_signed
? "s" : "");
253 for (int i
= GetSize(hex_digits
)-1; i
>= 0; i
--)
258 f
<< stringf("%d'%sb", width
, set_signed
? "s" : "");
261 for (int i
= offset
+width
-1; i
>= offset
; i
--) {
262 log_assert(i
< (int)data
.bits
.size());
263 switch (data
.bits
[i
]) {
264 case RTLIL::S0
: f
<< stringf("0"); break;
265 case RTLIL::S1
: f
<< stringf("1"); break;
266 case RTLIL::Sx
: f
<< stringf("x"); break;
267 case RTLIL::Sz
: f
<< stringf("z"); break;
268 case RTLIL::Sa
: f
<< stringf("z"); break;
269 case RTLIL::Sm
: log_error("Found marker state in final netlist.");
275 std::string str
= data
.decode_string();
276 for (size_t i
= 0; i
< str
.size(); i
++) {
279 else if (str
[i
] == '\t')
281 else if (str
[i
] < 32)
282 f
<< stringf("\\%03o", str
[i
]);
283 else if (str
[i
] == '"')
284 f
<< stringf("\\\"");
285 else if (str
[i
] == '\\')
286 f
<< stringf("\\\\");
287 else if (str
[i
] == '/' && escape_comment
&& i
> 0 && str
[i
-1] == '*')
296 void dump_reg_init(std::ostream
&f
, SigSpec sig
)
299 bool gotinit
= false;
301 for (auto bit
: active_sigmap(sig
)) {
302 if (active_initdata
.count(bit
)) {
303 initval
.bits
.push_back(active_initdata
.at(bit
));
306 initval
.bits
.push_back(State::Sx
);
312 dump_const(f
, initval
);
316 void dump_sigchunk(std::ostream
&f
, const RTLIL::SigChunk
&chunk
, bool no_decimal
= false)
318 if (chunk
.wire
== NULL
) {
319 dump_const(f
, chunk
.data
, chunk
.width
, chunk
.offset
, no_decimal
);
321 if (chunk
.width
== chunk
.wire
->width
&& chunk
.offset
== 0) {
322 f
<< stringf("%s", id(chunk
.wire
->name
).c_str());
323 } else if (chunk
.width
== 1) {
324 if (chunk
.wire
->upto
)
325 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
327 f
<< stringf("%s[%d]", id(chunk
.wire
->name
).c_str(), chunk
.offset
+ chunk
.wire
->start_offset
);
329 if (chunk
.wire
->upto
)
330 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
331 (chunk
.wire
->width
- (chunk
.offset
+ chunk
.width
- 1) - 1) + chunk
.wire
->start_offset
,
332 (chunk
.wire
->width
- chunk
.offset
- 1) + chunk
.wire
->start_offset
);
334 f
<< stringf("%s[%d:%d]", id(chunk
.wire
->name
).c_str(),
335 (chunk
.offset
+ chunk
.width
- 1) + chunk
.wire
->start_offset
,
336 chunk
.offset
+ chunk
.wire
->start_offset
);
341 void dump_sigspec(std::ostream
&f
, const RTLIL::SigSpec
&sig
)
343 if (sig
.is_chunk()) {
344 dump_sigchunk(f
, sig
.as_chunk());
347 for (auto it
= sig
.chunks().rbegin(); it
!= sig
.chunks().rend(); ++it
) {
348 if (it
!= sig
.chunks().rbegin())
350 dump_sigchunk(f
, *it
, true);
356 void dump_attributes(std::ostream
&f
, std::string indent
, dict
<RTLIL::IdString
, RTLIL::Const
> &attributes
, char term
= '\n', bool modattr
= false)
360 for (auto it
= attributes
.begin(); it
!= attributes
.end(); ++it
) {
361 f
<< stringf("%s" "%s %s", indent
.c_str(), attr2comment
? "/*" : "(*", id(it
->first
).c_str());
363 if (modattr
&& (it
->second
== Const(0, 1) || it
->second
== Const(0)))
365 else if (modattr
&& (it
->second
== Const(1, 1) || it
->second
== Const(1)))
368 dump_const(f
, it
->second
, -1, 0, false, false, attr2comment
);
369 f
<< stringf(" %s%c", attr2comment
? "*/" : "*)", term
);
373 void dump_wire(std::ostream
&f
, std::string indent
, RTLIL::Wire
*wire
)
375 dump_attributes(f
, indent
, wire
->attributes
);
377 if (wire
->port_input
&& !wire
->port_output
)
378 f
<< stringf("%s" "input %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
379 else if (!wire
->port_input
&& wire
->port_output
)
380 f
<< stringf("%s" "output %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
381 else if (wire
->port_input
&& wire
->port_output
)
382 f
<< stringf("%s" "inout %s", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg " : "");
384 f
<< stringf("%s" "%s ", indent
.c_str(), reg_wires
.count(wire
->name
) ? "reg" : "wire");
385 if (wire
->width
!= 1)
386 f
<< stringf("[%d:%d] ", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
387 f
<< stringf("%s;\n", id(wire
->name
).c_str());
389 // do not use Verilog-2k "output reg" syntax in Verilog export
390 std::string range
= "";
391 if (wire
->width
!= 1) {
393 range
= stringf(" [%d:%d]", wire
->start_offset
, wire
->width
- 1 + wire
->start_offset
);
395 range
= stringf(" [%d:%d]", wire
->width
- 1 + wire
->start_offset
, wire
->start_offset
);
397 if (wire
->port_input
&& !wire
->port_output
)
398 f
<< stringf("%s" "input%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
399 if (!wire
->port_input
&& wire
->port_output
)
400 f
<< stringf("%s" "output%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
401 if (wire
->port_input
&& wire
->port_output
)
402 f
<< stringf("%s" "inout%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
403 if (reg_wires
.count(wire
->name
)) {
404 f
<< stringf("%s" "reg%s %s", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
405 if (wire
->attributes
.count("\\init")) {
407 dump_const(f
, wire
->attributes
.at("\\init"));
410 } else if (!wire
->port_input
&& !wire
->port_output
)
411 f
<< stringf("%s" "wire%s %s;\n", indent
.c_str(), range
.c_str(), id(wire
->name
).c_str());
415 void dump_memory(std::ostream
&f
, std::string indent
, RTLIL::Memory
*memory
)
417 dump_attributes(f
, indent
, memory
->attributes
);
418 f
<< stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent
.c_str(), memory
->width
-1, id(memory
->name
).c_str(), memory
->size
+memory
->start_offset
-1, memory
->start_offset
);
421 void dump_cell_expr_port(std::ostream
&f
, RTLIL::Cell
*cell
, std::string port
, bool gen_signed
= true)
423 if (gen_signed
&& cell
->parameters
.count("\\" + port
+ "_SIGNED") > 0 && cell
->parameters
["\\" + port
+ "_SIGNED"].as_bool()) {
424 f
<< stringf("$signed(");
425 dump_sigspec(f
, cell
->getPort("\\" + port
));
428 dump_sigspec(f
, cell
->getPort("\\" + port
));
431 std::string
cellname(RTLIL::Cell
*cell
)
433 if (!norename
&& cell
->name
[0] == '$' && reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q"))
435 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
436 if (GetSize(sig
) != 1 || sig
.is_fully_const())
437 goto no_special_reg_name
;
439 RTLIL::Wire
*wire
= sig
[0].wire
;
441 if (wire
->name
[0] != '\\')
442 goto no_special_reg_name
;
444 std::string cell_name
= wire
->name
.str();
446 size_t pos
= cell_name
.find('[');
447 if (pos
!= std::string::npos
)
448 cell_name
= cell_name
.substr(0, pos
) + "_reg" + cell_name
.substr(pos
);
450 cell_name
= cell_name
+ "_reg";
452 if (wire
->width
!= 1)
453 cell_name
+= stringf("[%d]", wire
->start_offset
+ sig
[0].offset
);
455 if (active_module
&& active_module
->count_id(cell_name
) > 0)
456 goto no_special_reg_name
;
458 return id(cell_name
);
463 return id(cell
->name
).c_str();
467 void dump_cell_expr_uniop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
469 f
<< stringf("%s" "assign ", indent
.c_str());
470 dump_sigspec(f
, cell
->getPort("\\Y"));
471 f
<< stringf(" = %s ", op
.c_str());
472 dump_attributes(f
, "", cell
->attributes
, ' ');
473 dump_cell_expr_port(f
, cell
, "A", true);
477 void dump_cell_expr_binop(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
, std::string op
)
479 f
<< stringf("%s" "assign ", indent
.c_str());
480 dump_sigspec(f
, cell
->getPort("\\Y"));
482 dump_cell_expr_port(f
, cell
, "A", true);
483 f
<< stringf(" %s ", op
.c_str());
484 dump_attributes(f
, "", cell
->attributes
, ' ');
485 dump_cell_expr_port(f
, cell
, "B", true);
489 bool dump_cell_expr(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
491 if (cell
->type
== "$_NOT_") {
492 f
<< stringf("%s" "assign ", indent
.c_str());
493 dump_sigspec(f
, cell
->getPort("\\Y"));
496 dump_attributes(f
, "", cell
->attributes
, ' ');
497 dump_cell_expr_port(f
, cell
, "A", false);
502 if (cell
->type
.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_")) {
503 f
<< stringf("%s" "assign ", indent
.c_str());
504 dump_sigspec(f
, cell
->getPort("\\Y"));
506 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_"))
508 dump_cell_expr_port(f
, cell
, "A", false);
510 if (cell
->type
.in("$_AND_", "$_NAND_", "$_ANDNOT_"))
512 if (cell
->type
.in("$_OR_", "$_NOR_", "$_ORNOT_"))
514 if (cell
->type
.in("$_XOR_", "$_XNOR_"))
516 dump_attributes(f
, "", cell
->attributes
, ' ');
518 if (cell
->type
.in("$_ANDNOT_", "$_ORNOT_"))
520 dump_cell_expr_port(f
, cell
, "B", false);
521 if (cell
->type
.in("$_NAND_", "$_NOR_", "$_XNOR_", "$_ANDNOT_", "$_ORNOT_"))
527 if (cell
->type
== "$_MUX_") {
528 f
<< stringf("%s" "assign ", indent
.c_str());
529 dump_sigspec(f
, cell
->getPort("\\Y"));
531 dump_cell_expr_port(f
, cell
, "S", false);
533 dump_attributes(f
, "", cell
->attributes
, ' ');
534 dump_cell_expr_port(f
, cell
, "B", false);
536 dump_cell_expr_port(f
, cell
, "A", false);
541 if (cell
->type
.in("$_AOI3_", "$_OAI3_")) {
542 f
<< stringf("%s" "assign ", indent
.c_str());
543 dump_sigspec(f
, cell
->getPort("\\Y"));
544 f
<< stringf(" = ~((");
545 dump_cell_expr_port(f
, cell
, "A", false);
546 f
<< stringf(cell
->type
== "$_AOI3_" ? " & " : " | ");
547 dump_cell_expr_port(f
, cell
, "B", false);
548 f
<< stringf(cell
->type
== "$_AOI3_" ? ") |" : ") &");
549 dump_attributes(f
, "", cell
->attributes
, ' ');
551 dump_cell_expr_port(f
, cell
, "C", false);
552 f
<< stringf(");\n");
556 if (cell
->type
.in("$_AOI4_", "$_OAI4_")) {
557 f
<< stringf("%s" "assign ", indent
.c_str());
558 dump_sigspec(f
, cell
->getPort("\\Y"));
559 f
<< stringf(" = ~((");
560 dump_cell_expr_port(f
, cell
, "A", false);
561 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
562 dump_cell_expr_port(f
, cell
, "B", false);
563 f
<< stringf(cell
->type
== "$_AOI4_" ? ") |" : ") &");
564 dump_attributes(f
, "", cell
->attributes
, ' ');
566 dump_cell_expr_port(f
, cell
, "C", false);
567 f
<< stringf(cell
->type
== "$_AOI4_" ? " & " : " | ");
568 dump_cell_expr_port(f
, cell
, "D", false);
569 f
<< stringf("));\n");
573 if (cell
->type
.substr(0, 6) == "$_DFF_")
575 std::string reg_name
= cellname(cell
);
576 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
578 if (!out_is_reg_wire
) {
579 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
580 dump_reg_init(f
, cell
->getPort("\\Q"));
584 dump_attributes(f
, indent
, cell
->attributes
);
585 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), cell
->type
[6] == 'P' ? "pos" : "neg");
586 dump_sigspec(f
, cell
->getPort("\\C"));
587 if (cell
->type
[7] != '_') {
588 f
<< stringf(" or %sedge ", cell
->type
[7] == 'P' ? "pos" : "neg");
589 dump_sigspec(f
, cell
->getPort("\\R"));
593 if (cell
->type
[7] != '_') {
594 f
<< stringf("%s" " if (%s", indent
.c_str(), cell
->type
[7] == 'P' ? "" : "!");
595 dump_sigspec(f
, cell
->getPort("\\R"));
597 f
<< stringf("%s" " %s <= %c;\n", indent
.c_str(), reg_name
.c_str(), cell
->type
[8]);
598 f
<< stringf("%s" " else\n", indent
.c_str());
601 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
602 dump_cell_expr_port(f
, cell
, "D", false);
605 if (!out_is_reg_wire
) {
606 f
<< stringf("%s" "assign ", indent
.c_str());
607 dump_sigspec(f
, cell
->getPort("\\Q"));
608 f
<< stringf(" = %s;\n", reg_name
.c_str());
614 if (cell
->type
.substr(0, 8) == "$_DFFSR_")
616 char pol_c
= cell
->type
[8], pol_s
= cell
->type
[9], pol_r
= cell
->type
[10];
618 std::string reg_name
= cellname(cell
);
619 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
621 if (!out_is_reg_wire
) {
622 f
<< stringf("%s" "reg %s", indent
.c_str(), reg_name
.c_str());
623 dump_reg_init(f
, cell
->getPort("\\Q"));
627 dump_attributes(f
, indent
, cell
->attributes
);
628 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_c
== 'P' ? "pos" : "neg");
629 dump_sigspec(f
, cell
->getPort("\\C"));
630 f
<< stringf(" or %sedge ", pol_s
== 'P' ? "pos" : "neg");
631 dump_sigspec(f
, cell
->getPort("\\S"));
632 f
<< stringf(" or %sedge ", pol_r
== 'P' ? "pos" : "neg");
633 dump_sigspec(f
, cell
->getPort("\\R"));
636 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_r
== 'P' ? "" : "!");
637 dump_sigspec(f
, cell
->getPort("\\R"));
639 f
<< stringf("%s" " %s <= 0;\n", indent
.c_str(), reg_name
.c_str());
641 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_s
== 'P' ? "" : "!");
642 dump_sigspec(f
, cell
->getPort("\\S"));
644 f
<< stringf("%s" " %s <= 1;\n", indent
.c_str(), reg_name
.c_str());
646 f
<< stringf("%s" " else\n", indent
.c_str());
647 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
648 dump_cell_expr_port(f
, cell
, "D", false);
651 if (!out_is_reg_wire
) {
652 f
<< stringf("%s" "assign ", indent
.c_str());
653 dump_sigspec(f
, cell
->getPort("\\Q"));
654 f
<< stringf(" = %s;\n", reg_name
.c_str());
660 #define HANDLE_UNIOP(_type, _operator) \
661 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
662 #define HANDLE_BINOP(_type, _operator) \
663 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
665 HANDLE_UNIOP("$not", "~")
666 HANDLE_UNIOP("$pos", "+")
667 HANDLE_UNIOP("$neg", "-")
669 HANDLE_BINOP("$and", "&")
670 HANDLE_BINOP("$or", "|")
671 HANDLE_BINOP("$xor", "^")
672 HANDLE_BINOP("$xnor", "~^")
674 HANDLE_UNIOP("$reduce_and", "&")
675 HANDLE_UNIOP("$reduce_or", "|")
676 HANDLE_UNIOP("$reduce_xor", "^")
677 HANDLE_UNIOP("$reduce_xnor", "~^")
678 HANDLE_UNIOP("$reduce_bool", "|")
680 HANDLE_BINOP("$shl", "<<")
681 HANDLE_BINOP("$shr", ">>")
682 HANDLE_BINOP("$sshl", "<<<")
683 HANDLE_BINOP("$sshr", ">>>")
685 HANDLE_BINOP("$lt", "<")
686 HANDLE_BINOP("$le", "<=")
687 HANDLE_BINOP("$eq", "==")
688 HANDLE_BINOP("$ne", "!=")
689 HANDLE_BINOP("$eqx", "===")
690 HANDLE_BINOP("$nex", "!==")
691 HANDLE_BINOP("$ge", ">=")
692 HANDLE_BINOP("$gt", ">")
694 HANDLE_BINOP("$add", "+")
695 HANDLE_BINOP("$sub", "-")
696 HANDLE_BINOP("$mul", "*")
697 HANDLE_BINOP("$div", "/")
698 HANDLE_BINOP("$mod", "%")
699 HANDLE_BINOP("$pow", "**")
701 HANDLE_UNIOP("$logic_not", "!")
702 HANDLE_BINOP("$logic_and", "&&")
703 HANDLE_BINOP("$logic_or", "||")
708 if (cell
->type
== "$shift")
710 f
<< stringf("%s" "assign ", indent
.c_str());
711 dump_sigspec(f
, cell
->getPort("\\Y"));
713 if (cell
->getParam("\\B_SIGNED").as_bool())
715 f
<< stringf("$signed(");
716 dump_sigspec(f
, cell
->getPort("\\B"));
718 f
<< stringf(" < 0 ? ");
719 dump_sigspec(f
, cell
->getPort("\\A"));
720 f
<< stringf(" << - ");
721 dump_sigspec(f
, cell
->getPort("\\B"));
723 dump_sigspec(f
, cell
->getPort("\\A"));
724 f
<< stringf(" >> ");
725 dump_sigspec(f
, cell
->getPort("\\B"));
729 dump_sigspec(f
, cell
->getPort("\\A"));
730 f
<< stringf(" >> ");
731 dump_sigspec(f
, cell
->getPort("\\B"));
737 if (cell
->type
== "$shiftx")
739 std::string temp_id
= next_auto_id();
740 f
<< stringf("%s" "wire [%d:0] %s = ", indent
.c_str(), GetSize(cell
->getPort("\\A"))-1, temp_id
.c_str());
741 dump_sigspec(f
, cell
->getPort("\\A"));
744 f
<< stringf("%s" "assign ", indent
.c_str());
745 dump_sigspec(f
, cell
->getPort("\\Y"));
746 f
<< stringf(" = %s[", temp_id
.c_str());
747 if (cell
->getParam("\\B_SIGNED").as_bool())
748 f
<< stringf("$signed(");
749 dump_sigspec(f
, cell
->getPort("\\B"));
750 if (cell
->getParam("\\B_SIGNED").as_bool())
752 f
<< stringf(" +: %d", cell
->getParam("\\Y_WIDTH").as_int());
753 f
<< stringf("];\n");
757 if (cell
->type
== "$mux")
759 f
<< stringf("%s" "assign ", indent
.c_str());
760 dump_sigspec(f
, cell
->getPort("\\Y"));
762 dump_sigspec(f
, cell
->getPort("\\S"));
764 dump_attributes(f
, "", cell
->attributes
, ' ');
765 dump_sigspec(f
, cell
->getPort("\\B"));
767 dump_sigspec(f
, cell
->getPort("\\A"));
772 if (cell
->type
== "$pmux" || cell
->type
== "$pmux_safe")
774 int width
= cell
->parameters
["\\WIDTH"].as_int();
775 int s_width
= cell
->getPort("\\S").size();
776 std::string func_name
= cellname(cell
);
778 f
<< stringf("%s" "function [%d:0] %s;\n", indent
.c_str(), width
-1, func_name
.c_str());
779 f
<< stringf("%s" " input [%d:0] a;\n", indent
.c_str(), width
-1);
780 f
<< stringf("%s" " input [%d:0] b;\n", indent
.c_str(), s_width
*width
-1);
781 f
<< stringf("%s" " input [%d:0] s;\n", indent
.c_str(), s_width
-1);
783 dump_attributes(f
, indent
+ " ", cell
->attributes
);
784 if (cell
->type
!= "$pmux_safe" && !noattr
)
785 f
<< stringf("%s" " (* parallel_case *)\n", indent
.c_str());
786 f
<< stringf("%s" " casez (s)", indent
.c_str());
787 if (cell
->type
!= "$pmux_safe")
788 f
<< stringf(noattr
? " // synopsys parallel_case\n" : "\n");
790 for (int i
= 0; i
< s_width
; i
++)
792 f
<< stringf("%s" " %d'b", indent
.c_str(), s_width
);
794 for (int j
= s_width
-1; j
>= 0; j
--)
795 f
<< stringf("%c", j
== i
? '1' : cell
->type
== "$pmux_safe" ? '0' : '?');
798 f
<< stringf("%s" " %s = b[%d:%d];\n", indent
.c_str(), func_name
.c_str(), (i
+1)*width
-1, i
*width
);
801 f
<< stringf("%s" " default:\n", indent
.c_str());
802 f
<< stringf("%s" " %s = a;\n", indent
.c_str(), func_name
.c_str());
804 f
<< stringf("%s" " endcase\n", indent
.c_str());
805 f
<< stringf("%s" "endfunction\n", indent
.c_str());
807 f
<< stringf("%s" "assign ", indent
.c_str());
808 dump_sigspec(f
, cell
->getPort("\\Y"));
809 f
<< stringf(" = %s(", func_name
.c_str());
810 dump_sigspec(f
, cell
->getPort("\\A"));
812 dump_sigspec(f
, cell
->getPort("\\B"));
814 dump_sigspec(f
, cell
->getPort("\\S"));
815 f
<< stringf(");\n");
819 if (cell
->type
== "$tribuf")
821 f
<< stringf("%s" "assign ", indent
.c_str());
822 dump_sigspec(f
, cell
->getPort("\\Y"));
824 dump_sigspec(f
, cell
->getPort("\\EN"));
826 dump_sigspec(f
, cell
->getPort("\\A"));
827 f
<< stringf(" : %d'bz;\n", cell
->parameters
.at("\\WIDTH").as_int());
831 if (cell
->type
== "$slice")
833 f
<< stringf("%s" "assign ", indent
.c_str());
834 dump_sigspec(f
, cell
->getPort("\\Y"));
836 dump_sigspec(f
, cell
->getPort("\\A"));
837 f
<< stringf(" >> %d;\n", cell
->parameters
.at("\\OFFSET").as_int());
841 if (cell
->type
== "$concat")
843 f
<< stringf("%s" "assign ", indent
.c_str());
844 dump_sigspec(f
, cell
->getPort("\\Y"));
845 f
<< stringf(" = { ");
846 dump_sigspec(f
, cell
->getPort("\\B"));
848 dump_sigspec(f
, cell
->getPort("\\A"));
849 f
<< stringf(" };\n");
853 if (cell
->type
== "$lut")
855 f
<< stringf("%s" "assign ", indent
.c_str());
856 dump_sigspec(f
, cell
->getPort("\\Y"));
858 dump_const(f
, cell
->parameters
.at("\\LUT"));
859 f
<< stringf(" >> ");
860 dump_attributes(f
, "", cell
->attributes
, ' ');
861 dump_sigspec(f
, cell
->getPort("\\A"));
866 if (cell
->type
== "$dffsr")
868 SigSpec sig_clk
= cell
->getPort("\\CLK");
869 SigSpec sig_set
= cell
->getPort("\\SET");
870 SigSpec sig_clr
= cell
->getPort("\\CLR");
871 SigSpec sig_d
= cell
->getPort("\\D");
872 SigSpec sig_q
= cell
->getPort("\\Q");
874 int width
= cell
->parameters
["\\WIDTH"].as_int();
875 bool pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
876 bool pol_set
= cell
->parameters
["\\SET_POLARITY"].as_bool();
877 bool pol_clr
= cell
->parameters
["\\CLR_POLARITY"].as_bool();
879 std::string reg_name
= cellname(cell
);
880 bool out_is_reg_wire
= is_reg_wire(sig_q
, reg_name
);
882 if (!out_is_reg_wire
) {
883 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), width
-1, reg_name
.c_str());
884 dump_reg_init(f
, sig_q
);
888 for (int i
= 0; i
< width
; i
++) {
889 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
890 dump_sigspec(f
, sig_clk
);
891 f
<< stringf(", %sedge ", pol_set
? "pos" : "neg");
892 dump_sigspec(f
, sig_set
);
893 f
<< stringf(", %sedge ", pol_clr
? "pos" : "neg");
894 dump_sigspec(f
, sig_clr
);
897 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_clr
? "" : "!");
898 dump_sigspec(f
, sig_clr
);
899 f
<< stringf(") %s[%d] <= 1'b0;\n", reg_name
.c_str(), i
);
901 f
<< stringf("%s" " else if (%s", indent
.c_str(), pol_set
? "" : "!");
902 dump_sigspec(f
, sig_set
);
903 f
<< stringf(") %s[%d] <= 1'b1;\n", reg_name
.c_str(), i
);
905 f
<< stringf("%s" " else %s[%d] <= ", indent
.c_str(), reg_name
.c_str(), i
);
906 dump_sigspec(f
, sig_d
[i
]);
910 if (!out_is_reg_wire
) {
911 f
<< stringf("%s" "assign ", indent
.c_str());
912 dump_sigspec(f
, sig_q
);
913 f
<< stringf(" = %s;\n", reg_name
.c_str());
919 if (cell
->type
== "$dff" || cell
->type
== "$adff" || cell
->type
== "$dffe")
921 RTLIL::SigSpec sig_clk
, sig_arst
, sig_en
, val_arst
;
922 bool pol_clk
, pol_arst
= false, pol_en
= false;
924 sig_clk
= cell
->getPort("\\CLK");
925 pol_clk
= cell
->parameters
["\\CLK_POLARITY"].as_bool();
927 if (cell
->type
== "$adff") {
928 sig_arst
= cell
->getPort("\\ARST");
929 pol_arst
= cell
->parameters
["\\ARST_POLARITY"].as_bool();
930 val_arst
= RTLIL::SigSpec(cell
->parameters
["\\ARST_VALUE"]);
933 if (cell
->type
== "$dffe") {
934 sig_en
= cell
->getPort("\\EN");
935 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
938 std::string reg_name
= cellname(cell
);
939 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
941 if (!out_is_reg_wire
) {
942 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
943 dump_reg_init(f
, cell
->getPort("\\Q"));
947 f
<< stringf("%s" "always @(%sedge ", indent
.c_str(), pol_clk
? "pos" : "neg");
948 dump_sigspec(f
, sig_clk
);
949 if (cell
->type
== "$adff") {
950 f
<< stringf(" or %sedge ", pol_arst
? "pos" : "neg");
951 dump_sigspec(f
, sig_arst
);
955 if (cell
->type
== "$adff") {
956 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_arst
? "" : "!");
957 dump_sigspec(f
, sig_arst
);
959 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
960 dump_sigspec(f
, val_arst
);
962 f
<< stringf("%s" " else\n", indent
.c_str());
965 if (cell
->type
== "$dffe") {
966 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
967 dump_sigspec(f
, sig_en
);
971 f
<< stringf("%s" " %s <= ", indent
.c_str(), reg_name
.c_str());
972 dump_cell_expr_port(f
, cell
, "D", false);
975 if (!out_is_reg_wire
) {
976 f
<< stringf("%s" "assign ", indent
.c_str());
977 dump_sigspec(f
, cell
->getPort("\\Q"));
978 f
<< stringf(" = %s;\n", reg_name
.c_str());
984 if (cell
->type
== "$dlatch")
986 RTLIL::SigSpec sig_en
;
989 sig_en
= cell
->getPort("\\EN");
990 pol_en
= cell
->parameters
["\\EN_POLARITY"].as_bool();
992 std::string reg_name
= cellname(cell
);
993 bool out_is_reg_wire
= is_reg_wire(cell
->getPort("\\Q"), reg_name
);
995 if (!out_is_reg_wire
) {
996 f
<< stringf("%s" "reg [%d:0] %s", indent
.c_str(), cell
->parameters
["\\WIDTH"].as_int()-1, reg_name
.c_str());
997 dump_reg_init(f
, cell
->getPort("\\Q"));
1001 f
<< stringf("%s" "always @*\n", indent
.c_str());
1003 f
<< stringf("%s" " if (%s", indent
.c_str(), pol_en
? "" : "!");
1004 dump_sigspec(f
, sig_en
);
1005 f
<< stringf(")\n");
1007 f
<< stringf("%s" " %s = ", indent
.c_str(), reg_name
.c_str());
1008 dump_cell_expr_port(f
, cell
, "D", false);
1009 f
<< stringf(";\n");
1011 if (!out_is_reg_wire
) {
1012 f
<< stringf("%s" "assign ", indent
.c_str());
1013 dump_sigspec(f
, cell
->getPort("\\Q"));
1014 f
<< stringf(" = %s;\n", reg_name
.c_str());
1020 if (cell
->type
== "$mem")
1022 RTLIL::IdString memid
= cell
->parameters
["\\MEMID"].decode_string();
1023 std::string mem_id
= id(cell
->parameters
["\\MEMID"].decode_string());
1024 int abits
= cell
->parameters
["\\ABITS"].as_int();
1025 int size
= cell
->parameters
["\\SIZE"].as_int();
1026 int offset
= cell
->parameters
["\\OFFSET"].as_int();
1027 int width
= cell
->parameters
["\\WIDTH"].as_int();
1028 bool use_init
= !(RTLIL::SigSpec(cell
->parameters
["\\INIT"]).is_fully_undef());
1030 // for memory block make something like:
1031 // reg [7:0] memid [3:0];
1035 f
<< stringf("%s" "reg [%d:%d] %s [%d:%d];\n", indent
.c_str(), width
-1, 0, mem_id
.c_str(), size
+offset
-1, offset
);
1038 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1039 for (int i
=0; i
<size
; i
++)
1041 f
<< stringf("%s" " %s[%d] = ", indent
.c_str(), mem_id
.c_str(), i
);
1042 dump_const(f
, cell
->parameters
["\\INIT"].extract(i
*width
, width
));
1043 f
<< stringf(";\n");
1045 f
<< stringf("%s" "end\n", indent
.c_str());
1048 // create a map : "edge clk" -> expressions within that clock domain
1049 dict
<std::string
, std::vector
<std::string
>> clk_to_lof_body
;
1050 clk_to_lof_body
[""] = std::vector
<std::string
>();
1051 std::string clk_domain_str
;
1052 // create a list of reg declarations
1053 std::vector
<std::string
> lof_reg_declarations
;
1055 int nread_ports
= cell
->parameters
["\\RD_PORTS"].as_int();
1056 RTLIL::SigSpec sig_rd_clk
, sig_rd_en
, sig_rd_data
, sig_rd_addr
;
1057 bool use_rd_clk
, rd_clk_posedge
, rd_transparent
;
1059 for (int i
=0; i
< nread_ports
; i
++)
1061 sig_rd_clk
= cell
->getPort("\\RD_CLK").extract(i
);
1062 sig_rd_en
= cell
->getPort("\\RD_EN").extract(i
);
1063 sig_rd_data
= cell
->getPort("\\RD_DATA").extract(i
*width
, width
);
1064 sig_rd_addr
= cell
->getPort("\\RD_ADDR").extract(i
*abits
, abits
);
1065 use_rd_clk
= cell
->parameters
["\\RD_CLK_ENABLE"].extract(i
).as_bool();
1066 rd_clk_posedge
= cell
->parameters
["\\RD_CLK_POLARITY"].extract(i
).as_bool();
1067 rd_transparent
= cell
->parameters
["\\RD_TRANSPARENT"].extract(i
).as_bool();
1071 std::ostringstream os
;
1072 dump_sigspec(os
, sig_rd_clk
);
1073 clk_domain_str
= stringf("%sedge %s", rd_clk_posedge
? "pos" : "neg", os
.str().c_str());
1074 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1075 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1077 if (!rd_transparent
)
1079 // for clocked read ports make something like:
1080 // reg [..] temp_id;
1081 // always @(posedge clk)
1082 // if (rd_en) temp_id <= array_reg[r_addr];
1083 // assign r_data = temp_id;
1084 std::string temp_id
= next_auto_id();
1085 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_data
.size() - 1, temp_id
.c_str()) );
1087 std::ostringstream os
;
1088 if (sig_rd_en
!= RTLIL::SigBit(true))
1090 os
<< stringf("if (");
1091 dump_sigspec(os
, sig_rd_en
);
1092 os
<< stringf(") ");
1094 os
<< stringf("%s <= %s[", temp_id
.c_str(), mem_id
.c_str());
1095 dump_sigspec(os
, sig_rd_addr
);
1096 os
<< stringf("];\n");
1097 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1100 std::ostringstream os
;
1101 dump_sigspec(os
, sig_rd_data
);
1102 std::string line
= stringf("assign %s = %s;\n", os
.str().c_str(), temp_id
.c_str());
1103 clk_to_lof_body
[""].push_back(line
);
1108 // for rd-transparent read-ports make something like:
1109 // reg [..] temp_id;
1110 // always @(posedge clk)
1111 // temp_id <= r_addr;
1112 // assign r_data = array_reg[temp_id];
1113 std::string temp_id
= next_auto_id();
1114 lof_reg_declarations
.push_back( stringf("reg [%d:0] %s;\n", sig_rd_addr
.size() - 1, temp_id
.c_str()) );
1116 std::ostringstream os
;
1117 dump_sigspec(os
, sig_rd_addr
);
1118 std::string line
= stringf("%s <= %s;\n", temp_id
.c_str(), os
.str().c_str());
1119 clk_to_lof_body
[clk_domain_str
].push_back(line
);
1122 std::ostringstream os
;
1123 dump_sigspec(os
, sig_rd_data
);
1124 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), temp_id
.c_str());
1125 clk_to_lof_body
[""].push_back(line
);
1129 // for non-clocked read-ports make something like:
1130 // assign r_data = array_reg[r_addr];
1131 std::ostringstream os
, os2
;
1132 dump_sigspec(os
, sig_rd_data
);
1133 dump_sigspec(os2
, sig_rd_addr
);
1134 std::string line
= stringf("assign %s = %s[%s];\n", os
.str().c_str(), mem_id
.c_str(), os2
.str().c_str());
1135 clk_to_lof_body
[""].push_back(line
);
1139 int nwrite_ports
= cell
->parameters
["\\WR_PORTS"].as_int();
1140 RTLIL::SigSpec sig_wr_clk
, sig_wr_data
, sig_wr_addr
, sig_wr_en
;
1141 bool wr_clk_posedge
;
1144 for (int i
=0; i
< nwrite_ports
; i
++)
1146 sig_wr_clk
= cell
->getPort("\\WR_CLK").extract(i
);
1147 sig_wr_data
= cell
->getPort("\\WR_DATA").extract(i
*width
, width
);
1148 sig_wr_addr
= cell
->getPort("\\WR_ADDR").extract(i
*abits
, abits
);
1149 sig_wr_en
= cell
->getPort("\\WR_EN").extract(i
*width
, width
);
1150 wr_clk_posedge
= cell
->parameters
["\\WR_CLK_POLARITY"].extract(i
).as_bool();
1152 std::ostringstream os
;
1153 dump_sigspec(os
, sig_wr_clk
);
1154 clk_domain_str
= stringf("%sedge %s", wr_clk_posedge
? "pos" : "neg", os
.str().c_str());
1155 if( clk_to_lof_body
.count(clk_domain_str
) == 0 )
1156 clk_to_lof_body
[clk_domain_str
] = std::vector
<std::string
>();
1158 // make something like:
1159 // always @(posedge clk)
1160 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
1162 for (int i
= 0; i
< GetSize(sig_wr_en
); i
++)
1164 int start_i
= i
, width
= 1;
1165 SigBit wen_bit
= sig_wr_en
[i
];
1167 while (i
+1 < GetSize(sig_wr_en
) && active_sigmap(sig_wr_en
[i
+1]) == active_sigmap(wen_bit
))
1170 if (wen_bit
== State::S0
)
1173 std::ostringstream os
;
1174 if (wen_bit
!= State::S1
)
1176 os
<< stringf("if (");
1177 dump_sigspec(os
, wen_bit
);
1178 os
<< stringf(") ");
1180 os
<< stringf("%s[", mem_id
.c_str());
1181 dump_sigspec(os
, sig_wr_addr
);
1182 if (width
== GetSize(sig_wr_en
))
1183 os
<< stringf("] <= ");
1185 os
<< stringf("][%d:%d] <= ", i
, start_i
);
1186 dump_sigspec(os
, sig_wr_data
.extract(start_i
, width
));
1187 os
<< stringf(";\n");
1188 clk_to_lof_body
[clk_domain_str
].push_back(os
.str());
1191 // Output Verilog that looks something like this:
1193 // always @(posedge CLK2) begin
1194 // _3_ <= memory[D1ADDR];
1196 // memory[A1ADDR] <= A1DATA;
1198 // memory[A2ADDR] <= A2DATA;
1201 // always @(negedge CLK1) begin
1203 // memory[C1ADDR] <= C1DATA;
1206 // assign D1DATA = _3_;
1207 // assign D2DATA <= memory[D2ADDR];
1209 // the reg ... definitions
1210 for(auto ®
: lof_reg_declarations
)
1212 f
<< stringf("%s" "%s", indent
.c_str(), reg
.c_str());
1214 // the block of expressions by clock domain
1215 for(auto &pair
: clk_to_lof_body
)
1217 std::string clk_domain
= pair
.first
;
1218 std::vector
<std::string
> lof_lines
= pair
.second
;
1219 if( clk_domain
!= "")
1221 f
<< stringf("%s" "always @(%s) begin\n", indent
.c_str(), clk_domain
.c_str());
1222 for(auto &line
: lof_lines
)
1223 f
<< stringf("%s%s" "%s", indent
.c_str(), indent
.c_str(), line
.c_str());
1224 f
<< stringf("%s" "end\n", indent
.c_str());
1228 // the non-clocked assignments
1229 for(auto &line
: lof_lines
)
1230 f
<< stringf("%s" "%s", indent
.c_str(), line
.c_str());
1237 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
1238 // FIXME: $sr, $dlatch, $memrd, $memwr, $fsm
1243 void dump_cell(std::ostream
&f
, std::string indent
, RTLIL::Cell
*cell
)
1245 if (cell
->type
[0] == '$' && !noexpr
) {
1246 if (dump_cell_expr(f
, indent
, cell
))
1250 dump_attributes(f
, indent
, cell
->attributes
);
1251 f
<< stringf("%s" "%s", indent
.c_str(), id(cell
->type
, false).c_str());
1253 if (!defparam
&& cell
->parameters
.size() > 0) {
1254 f
<< stringf(" #(");
1255 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1256 if (it
!= cell
->parameters
.begin())
1258 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1259 bool is_signed
= (it
->second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
1260 dump_const(f
, it
->second
, -1, 0, false, is_signed
);
1263 f
<< stringf("\n%s" ")", indent
.c_str());
1266 std::string cell_name
= cellname(cell
);
1267 if (cell_name
!= id(cell
->name
))
1268 f
<< stringf(" %s /* %s */ (", cell_name
.c_str(), id(cell
->name
).c_str());
1270 f
<< stringf(" %s (", cell_name
.c_str());
1272 bool first_arg
= true;
1273 std::set
<RTLIL::IdString
> numbered_ports
;
1274 for (int i
= 1; true; i
++) {
1276 snprintf(str
, 16, "$%d", i
);
1277 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1278 if (it
->first
!= str
)
1283 f
<< stringf("\n%s ", indent
.c_str());
1284 dump_sigspec(f
, it
->second
);
1285 numbered_ports
.insert(it
->first
);
1286 goto found_numbered_port
;
1289 found_numbered_port
:;
1291 for (auto it
= cell
->connections().begin(); it
!= cell
->connections().end(); ++it
) {
1292 if (numbered_ports
.count(it
->first
))
1297 f
<< stringf("\n%s .%s(", indent
.c_str(), id(it
->first
).c_str());
1298 if (it
->second
.size() > 0)
1299 dump_sigspec(f
, it
->second
);
1302 f
<< stringf("\n%s" ");\n", indent
.c_str());
1304 if (defparam
&& cell
->parameters
.size() > 0) {
1305 for (auto it
= cell
->parameters
.begin(); it
!= cell
->parameters
.end(); ++it
) {
1306 f
<< stringf("%sdefparam %s.%s = ", indent
.c_str(), cell_name
.c_str(), id(it
->first
).c_str());
1307 bool is_signed
= (it
->second
.flags
& RTLIL::CONST_FLAG_SIGNED
) != 0;
1308 dump_const(f
, it
->second
, -1, 0, false, is_signed
);
1309 f
<< stringf(";\n");
1313 if (siminit
&& reg_ct
.count(cell
->type
) && cell
->hasPort("\\Q")) {
1314 std::stringstream ss
;
1315 dump_reg_init(ss
, cell
->getPort("\\Q"));
1316 if (!ss
.str().empty()) {
1317 f
<< stringf("%sinitial %s.Q", indent
.c_str(), cell_name
.c_str());
1324 void dump_conn(std::ostream
&f
, std::string indent
, const RTLIL::SigSpec
&left
, const RTLIL::SigSpec
&right
)
1326 f
<< stringf("%s" "assign ", indent
.c_str());
1327 dump_sigspec(f
, left
);
1328 f
<< stringf(" = ");
1329 dump_sigspec(f
, right
);
1330 f
<< stringf(";\n");
1333 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
);
1335 void dump_case_body(std::ostream
&f
, std::string indent
, RTLIL::CaseRule
*cs
, bool omit_trailing_begin
= false)
1337 int number_of_stmts
= cs
->switches
.size() + cs
->actions
.size();
1339 if (!omit_trailing_begin
&& number_of_stmts
>= 2)
1340 f
<< stringf("%s" "begin\n", indent
.c_str());
1342 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1343 if (it
->first
.size() == 0)
1345 f
<< stringf("%s ", indent
.c_str());
1346 dump_sigspec(f
, it
->first
);
1347 f
<< stringf(" = ");
1348 dump_sigspec(f
, it
->second
);
1349 f
<< stringf(";\n");
1352 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1353 dump_proc_switch(f
, indent
+ " ", *it
);
1355 if (!omit_trailing_begin
&& number_of_stmts
== 0)
1356 f
<< stringf("%s /* empty */;\n", indent
.c_str());
1358 if (omit_trailing_begin
|| number_of_stmts
>= 2)
1359 f
<< stringf("%s" "end\n", indent
.c_str());
1362 void dump_proc_switch(std::ostream
&f
, std::string indent
, RTLIL::SwitchRule
*sw
)
1364 if (sw
->signal
.size() == 0) {
1365 f
<< stringf("%s" "begin\n", indent
.c_str());
1366 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1367 if ((*it
)->compare
.size() == 0)
1368 dump_case_body(f
, indent
+ " ", *it
);
1370 f
<< stringf("%s" "end\n", indent
.c_str());
1374 f
<< stringf("%s" "casez (", indent
.c_str());
1375 dump_sigspec(f
, sw
->signal
);
1376 f
<< stringf(")\n");
1378 bool got_default
= false;
1379 for (auto it
= sw
->cases
.begin(); it
!= sw
->cases
.end(); ++it
) {
1380 if ((*it
)->compare
.size() == 0) {
1383 f
<< stringf("%s default", indent
.c_str());
1386 f
<< stringf("%s ", indent
.c_str());
1387 for (size_t i
= 0; i
< (*it
)->compare
.size(); i
++) {
1390 dump_sigspec(f
, (*it
)->compare
[i
]);
1393 f
<< stringf(":\n");
1394 dump_case_body(f
, indent
+ " ", *it
);
1397 f
<< stringf("%s" "endcase\n", indent
.c_str());
1400 void case_body_find_regs(RTLIL::CaseRule
*cs
)
1402 for (auto it
= cs
->switches
.begin(); it
!= cs
->switches
.end(); ++it
)
1403 for (auto it2
= (*it
)->cases
.begin(); it2
!= (*it
)->cases
.end(); it2
++)
1404 case_body_find_regs(*it2
);
1406 for (auto it
= cs
->actions
.begin(); it
!= cs
->actions
.end(); ++it
) {
1407 for (auto &c
: it
->first
.chunks())
1409 reg_wires
.insert(c
.wire
->name
);
1413 void dump_process(std::ostream
&f
, std::string indent
, RTLIL::Process
*proc
, bool find_regs
= false)
1416 case_body_find_regs(&proc
->root_case
);
1417 for (auto it
= proc
->syncs
.begin(); it
!= proc
->syncs
.end(); ++it
)
1418 for (auto it2
= (*it
)->actions
.begin(); it2
!= (*it
)->actions
.end(); it2
++) {
1419 for (auto &c
: it2
->first
.chunks())
1421 reg_wires
.insert(c
.wire
->name
);
1426 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1427 dump_case_body(f
, indent
, &proc
->root_case
, true);
1429 std::string backup_indent
= indent
;
1431 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++)
1433 RTLIL::SyncRule
*sync
= proc
->syncs
[i
];
1434 indent
= backup_indent
;
1436 if (sync
->type
== RTLIL::STa
) {
1437 f
<< stringf("%s" "always @* begin\n", indent
.c_str());
1438 } else if (sync
->type
== RTLIL::STi
) {
1439 f
<< stringf("%s" "initial begin\n", indent
.c_str());
1441 f
<< stringf("%s" "always @(", indent
.c_str());
1442 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::ST1
)
1443 f
<< stringf("posedge ");
1444 if (sync
->type
== RTLIL::STn
|| sync
->type
== RTLIL::ST0
)
1445 f
<< stringf("negedge ");
1446 dump_sigspec(f
, sync
->signal
);
1447 f
<< stringf(") begin\n");
1449 std::string ends
= indent
+ "end\n";
1452 if (sync
->type
== RTLIL::ST0
|| sync
->type
== RTLIL::ST1
) {
1453 f
<< stringf("%s" "if (%s", indent
.c_str(), sync
->type
== RTLIL::ST0
? "!" : "");
1454 dump_sigspec(f
, sync
->signal
);
1455 f
<< stringf(") begin\n");
1456 ends
= indent
+ "end\n" + ends
;
1460 if (sync
->type
== RTLIL::STp
|| sync
->type
== RTLIL::STn
) {
1461 for (size_t j
= 0; j
< proc
->syncs
.size(); j
++) {
1462 RTLIL::SyncRule
*sync2
= proc
->syncs
[j
];
1463 if (sync2
->type
== RTLIL::ST0
|| sync2
->type
== RTLIL::ST1
) {
1464 f
<< stringf("%s" "if (%s", indent
.c_str(), sync2
->type
== RTLIL::ST1
? "!" : "");
1465 dump_sigspec(f
, sync2
->signal
);
1466 f
<< stringf(") begin\n");
1467 ends
= indent
+ "end\n" + ends
;
1473 for (auto it
= sync
->actions
.begin(); it
!= sync
->actions
.end(); ++it
) {
1474 if (it
->first
.size() == 0)
1476 f
<< stringf("%s ", indent
.c_str());
1477 dump_sigspec(f
, it
->first
);
1478 f
<< stringf(" <= ");
1479 dump_sigspec(f
, it
->second
);
1480 f
<< stringf(";\n");
1483 f
<< stringf("%s", ends
.c_str());
1487 void dump_module(std::ostream
&f
, std::string indent
, RTLIL::Module
*module
)
1490 reset_auto_counter(module
);
1491 active_module
= module
;
1492 active_sigmap
.set(module
);
1493 active_initdata
.clear();
1495 for (auto wire
: module
->wires())
1496 if (wire
->attributes
.count("\\init")) {
1497 SigSpec sig
= active_sigmap(wire
);
1498 Const val
= wire
->attributes
.at("\\init");
1499 for (int i
= 0; i
< GetSize(sig
) && i
< GetSize(val
); i
++)
1500 active_initdata
[sig
[i
]] = val
.bits
.at(i
);
1503 if (!module
->processes
.empty())
1504 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
1505 "can't always be mapped directly to Verilog always blocks. Unintended\n"
1506 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
1507 "processes to logic networks and registers.\n", log_id(module
));
1510 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1511 dump_process(f
, indent
+ " ", it
->second
, true);
1515 std::set
<std::pair
<RTLIL::Wire
*,int>> reg_bits
;
1516 for (auto &it
: module
->cells_
)
1518 RTLIL::Cell
*cell
= it
.second
;
1519 if (!reg_ct
.count(cell
->type
) || !cell
->hasPort("\\Q"))
1522 RTLIL::SigSpec sig
= cell
->getPort("\\Q");
1524 if (sig
.is_chunk()) {
1525 RTLIL::SigChunk chunk
= sig
.as_chunk();
1526 if (chunk
.wire
!= NULL
)
1527 for (int i
= 0; i
< chunk
.width
; i
++)
1528 reg_bits
.insert(std::pair
<RTLIL::Wire
*,int>(chunk
.wire
, chunk
.offset
+i
));
1531 for (auto &it
: module
->wires_
)
1533 RTLIL::Wire
*wire
= it
.second
;
1534 for (int i
= 0; i
< wire
->width
; i
++)
1535 if (reg_bits
.count(std::pair
<RTLIL::Wire
*,int>(wire
, i
)) == 0)
1536 goto this_wire_aint_reg
;
1538 reg_wires
.insert(wire
->name
);
1539 this_wire_aint_reg
:;
1543 dump_attributes(f
, indent
, module
->attributes
, '\n', true);
1544 f
<< stringf("%s" "module %s(", indent
.c_str(), id(module
->name
, false).c_str());
1545 bool keep_running
= true;
1546 for (int port_id
= 1; keep_running
; port_id
++) {
1547 keep_running
= false;
1548 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
) {
1549 RTLIL::Wire
*wire
= it
->second
;
1550 if (wire
->port_id
== port_id
) {
1553 f
<< stringf("%s", id(wire
->name
).c_str());
1554 keep_running
= true;
1559 f
<< stringf(");\n");
1561 for (auto it
= module
->wires_
.begin(); it
!= module
->wires_
.end(); ++it
)
1562 dump_wire(f
, indent
+ " ", it
->second
);
1564 for (auto it
= module
->memories
.begin(); it
!= module
->memories
.end(); ++it
)
1565 dump_memory(f
, indent
+ " ", it
->second
);
1567 for (auto it
= module
->cells_
.begin(); it
!= module
->cells_
.end(); ++it
)
1568 dump_cell(f
, indent
+ " ", it
->second
);
1570 for (auto it
= module
->processes
.begin(); it
!= module
->processes
.end(); ++it
)
1571 dump_process(f
, indent
+ " ", it
->second
);
1573 for (auto it
= module
->connections().begin(); it
!= module
->connections().end(); ++it
)
1574 dump_conn(f
, indent
+ " ", it
->first
, it
->second
);
1576 f
<< stringf("%s" "endmodule\n", indent
.c_str());
1577 active_module
= NULL
;
1578 active_sigmap
.clear();
1579 active_initdata
.clear();
1582 struct VerilogBackend
: public Backend
{
1583 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
1584 void help() YS_OVERRIDE
1586 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1588 log(" write_verilog [options] [filename]\n");
1590 log("Write the current design to a Verilog file.\n");
1592 log(" -norename\n");
1593 log(" without this option all internal object names (the ones with a dollar\n");
1594 log(" instead of a backslash prefix) are changed to short names in the\n");
1595 log(" format '_<number>_'.\n");
1597 log(" -renameprefix <prefix>\n");
1598 log(" insert this prefix in front of auto-generated instance names\n");
1601 log(" with this option no attributes are included in the output\n");
1603 log(" -attr2comment\n");
1604 log(" with this option attributes are included as comments in the output\n");
1607 log(" without this option all internal cells are converted to Verilog\n");
1608 log(" expressions.\n");
1611 log(" add initial statements with hierarchical refs to initialize FFs when\n");
1612 log(" in -noexpr mode.\n");
1615 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
1616 log(" not bit pattern. This option deactivates this feature and instead\n");
1617 log(" will write out all constants in binary.\n");
1620 log(" dump 32-bit constants in decimal and without size and radix\n");
1623 log(" constant values that are compatible with hex output are usually\n");
1624 log(" dumped as hex values. This option deactivates this feature and\n");
1625 log(" instead will write out all constants in binary.\n");
1628 log(" Parameters and attributes that are specified as strings in the\n");
1629 log(" original input will be output as strings by this back-end. This\n");
1630 log(" deactivates this feature and instead will write string constants\n");
1631 log(" as binary numbers.\n");
1633 log(" -defparam\n");
1634 log(" Use 'defparam' statements instead of the Verilog-2001 syntax for\n");
1635 log(" cell parameters.\n");
1637 log(" -blackboxes\n");
1638 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1639 log(" this option set only the modules with the 'blackbox' attribute\n");
1640 log(" are written to the output file.\n");
1642 log(" -selected\n");
1643 log(" only write selected modules. modules must be selected entirely or\n");
1644 log(" not at all.\n");
1647 log(" verbose output (print new names of all renamed wires and cells)\n");
1649 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
1650 log("always blocks. This frontend should only be used to export an RTLIL\n");
1651 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
1652 log("processes to logic networks and registers. A warning is generated when\n");
1653 log("this command is called on a design with RTLIL processes.\n");
1656 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
1658 log_header(design
, "Executing Verilog backend.\n");
1663 attr2comment
= false;
1673 bool blackboxes
= false;
1674 bool selected
= false;
1676 auto_name_map
.clear();
1680 reg_ct
.insert("$dff");
1681 reg_ct
.insert("$adff");
1682 reg_ct
.insert("$dffe");
1683 reg_ct
.insert("$dlatch");
1685 reg_ct
.insert("$_DFF_N_");
1686 reg_ct
.insert("$_DFF_P_");
1688 reg_ct
.insert("$_DFF_NN0_");
1689 reg_ct
.insert("$_DFF_NN1_");
1690 reg_ct
.insert("$_DFF_NP0_");
1691 reg_ct
.insert("$_DFF_NP1_");
1692 reg_ct
.insert("$_DFF_PN0_");
1693 reg_ct
.insert("$_DFF_PN1_");
1694 reg_ct
.insert("$_DFF_PP0_");
1695 reg_ct
.insert("$_DFF_PP1_");
1697 reg_ct
.insert("$_DFFSR_NNN_");
1698 reg_ct
.insert("$_DFFSR_NNP_");
1699 reg_ct
.insert("$_DFFSR_NPN_");
1700 reg_ct
.insert("$_DFFSR_NPP_");
1701 reg_ct
.insert("$_DFFSR_PNN_");
1702 reg_ct
.insert("$_DFFSR_PNP_");
1703 reg_ct
.insert("$_DFFSR_PPN_");
1704 reg_ct
.insert("$_DFFSR_PPP_");
1707 for (argidx
= 1; argidx
< args
.size(); argidx
++) {
1708 std::string arg
= args
[argidx
];
1709 if (arg
== "-norename") {
1713 if (arg
== "-renameprefix" && argidx
+1 < args
.size()) {
1714 auto_prefix
= args
[++argidx
];
1717 if (arg
== "-noattr") {
1721 if (arg
== "-attr2comment") {
1722 attr2comment
= true;
1725 if (arg
== "-noexpr") {
1729 if (arg
== "-nodec") {
1733 if (arg
== "-nohex") {
1737 if (arg
== "-nostr") {
1741 if (arg
== "-defparam") {
1745 if (arg
== "-decimal") {
1749 if (arg
== "-siminit") {
1753 if (arg
== "-blackboxes") {
1757 if (arg
== "-selected") {
1767 extra_args(f
, filename
, args
, argidx
);
1771 *f
<< stringf("/* Generated by %s */\n", yosys_version_str
);
1772 for (auto it
= design
->modules_
.begin(); it
!= design
->modules_
.end(); ++it
) {
1773 if (it
->second
->get_bool_attribute("\\blackbox") != blackboxes
)
1775 if (selected
&& !design
->selected_whole_module(it
->first
)) {
1776 if (design
->selected_module(it
->first
))
1777 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it
->first
));
1780 log("Dumping module `%s'.\n", it
->first
.c_str());
1781 dump_module(*f
, "", it
->second
);
1784 auto_name_map
.clear();
1790 PRIVATE_NAMESPACE_END