1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
5 *
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.
9 *
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.
17 *
18 * ---
19 *
20 * A simple and straightforward Verilog backend.
21 *
22 */
23
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"
30 #include <string>
31 #include <sstream>
32 #include <set>
33 #include <map>
34
35 USING_YOSYS_NAMESPACE
36 PRIVATE_NAMESPACE_BEGIN
37
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;
43
44 RTLIL::Module *active_module;
45 dict<RTLIL::SigBit, RTLIL::State> active_initdata;
46 SigMap active_sigmap;
47 IdString initial_id;
48
reset_auto_counter_id(RTLIL::IdString id,bool may_rename)49 void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
50 {
51 const char *str = id.c_str();
52
53 if (*str == '$' && may_rename && !norename)
54 auto_name_map[id] = auto_name_counter++;
55
56 if (str[0] != '\\' || str[1] != '_' || str[2] == 0)
57 return;
58
59 for (int i = 2; str[i] != 0; i++) {
60 if (str[i] == '_' && str[i+1] == 0)
61 continue;
62 if (str[i] < '0' || str[i] > '9')
63 return;
64 }
65
66 int num = atoi(str+2);
67 if (num >= auto_name_offset)
68 auto_name_offset = num + 1;
69 }
70
reset_auto_counter(RTLIL::Module * module)71 void reset_auto_counter(RTLIL::Module *module)
72 {
73 auto_name_map.clear();
74 auto_name_counter = 0;
75 auto_name_offset = 0;
76
77 reset_auto_counter_id(module->name, false);
78
79 for (auto w : module->wires())
80 reset_auto_counter_id(w->name, true);
81
82 for (auto cell : module->cells()) {
83 reset_auto_counter_id(cell->name, true);
84 reset_auto_counter_id(cell->type, false);
85 }
86
87 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
88 reset_auto_counter_id(it->second->name, false);
89
90 auto_name_digits = 1;
91 for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
92 auto_name_digits++;
93
94 if (verbose)
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);
97 }
98
next_auto_id()99 std::string next_auto_id()
100 {
101 return stringf("%s_%0*d_", auto_prefix.c_str(), auto_name_digits, auto_name_offset + auto_name_counter++);
102 }
103
id(RTLIL::IdString internal_id,bool may_rename=true)104 std::string id(RTLIL::IdString internal_id, bool may_rename = true)
105 {
106 const char *str = internal_id.c_str();
107 bool do_escape = false;
108
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]);
111
112 if (*str == '\\')
113 str++;
114
115 if ('0' <= *str && *str <= '9')
116 do_escape = true;
117
118 for (int i = 0; str[i]; i++)
119 {
120 if ('0' <= str[i] && str[i] <= '9')
121 continue;
122 if ('a' <= str[i] && str[i] <= 'z')
123 continue;
124 if ('A' <= str[i] && str[i] <= 'Z')
125 continue;
126 if (str[i] == '_')
127 continue;
128 do_escape = true;
129 break;
130 }
131
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",
155 };
156 if (keywords.count(str))
157 do_escape = true;
158
159 if (do_escape)
160 return "\\" + std::string(str) + " ";
161 return std::string(str);
162 }
163
is_reg_wire(RTLIL::SigSpec sig,std::string & reg_name)164 bool is_reg_wire(RTLIL::SigSpec sig, std::string ®_name)
165 {
166 if (!sig.is_chunk() || sig.as_chunk().wire == NULL)
167 return false;
168
169 RTLIL::SigChunk chunk = sig.as_chunk();
170
171 if (reg_wires.count(chunk.wire->name) == 0)
172 return false;
173
174 reg_name = id(chunk.wire->name);
175 if (sig.size() != chunk.wire->width) {
176 if (sig.size() == 1)
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);
181 else
182 reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1,
183 chunk.wire->start_offset + chunk.offset);
184 }
185
186 return true;
187 }
188
dump_const(std::ostream & f,const RTLIL::Const & data,int width=-1,int offset=0,bool no_decimal=false,bool escape_comment=false)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)
190 {
191 bool set_signed = (data.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
192 if (width < 0)
193 width = data.bits.size() - offset;
194 if (width == 0) {
195 // See IEEE 1364-2005 Clause 5.1.14.
196 f << "{0{1'b0}}";
197 return;
198 }
199 if (nostr)
200 goto dump_hex;
201 if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
202 if (width == 32 && !no_decimal && !nodec) {
203 int32_t val = 0;
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)
207 goto dump_hex;
208 if (data.bits[i] == State::S1)
209 val |= 1 << (i - offset);
210 }
211 if (decimal)
212 f << stringf("%d", val);
213 else if (set_signed && val < 0)
214 f << stringf("-32'sd%u", -val);
215 else
216 f << stringf("32'%sd%u", set_signed ? "s" : "", val);
217 } else {
218 dump_hex:
219 if (nohex)
220 goto dump_bin;
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.");
231 }
232 }
233 if (GetSize(bin_digits) == 0)
234 goto dump_bin;
235 while (GetSize(bin_digits) % 4 != 0)
236 if (bin_digits.back() == '1')
237 bin_digits.push_back('0');
238 else
239 bin_digits.push_back(bin_digits.back());
240 for (int i = 0; i < GetSize(bin_digits); i += 4)
241 {
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')
248 goto dump_bin;
249 hex_digits.push_back('x');
250 continue;
251 }
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')
254 goto dump_bin;
255 hex_digits.push_back('z');
256 continue;
257 }
258 if (bit_3 == '?' || bit_2 == '?' || bit_1 == '?' || bit_0 == '?') {
259 if (bit_3 != '?' || bit_2 != '?' || bit_1 != '?' || bit_0 != '?')
260 goto dump_bin;
261 hex_digits.push_back('?');
262 continue;
263 }
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);
266 }
267 f << stringf("%d'%sh", width, set_signed ? "s" : "");
268 for (int i = GetSize(hex_digits)-1; i >= 0; i--)
269 f << hex_digits[i];
270 }
271 if (0) {
272 dump_bin:
273 f << stringf("%d'%sb", width, set_signed ? "s" : "");
274 if (width == 0)
275 f << stringf("0");
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.");
285 }
286 }
287 }
288 } else {
289 if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
290 f << stringf("\"");
291 std::string str = data.decode_string();
292 for (size_t i = 0; i < str.size(); i++) {
293 if (str[i] == '\n')
294 f << stringf("\\n");
295 else if (str[i] == '\t')
296 f << stringf("\\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] == '*')
304 f << stringf("\\/");
305 else
306 f << str[i];
307 }
308 if ((data.flags & RTLIL::CONST_FLAG_REAL) == 0)
309 f << stringf("\"");
310 }
311 }
312
dump_reg_init(std::ostream & f,SigSpec sig)313 void dump_reg_init(std::ostream &f, SigSpec sig)
314 {
315 Const initval;
316 bool gotinit = false;
317
318 for (auto bit : active_sigmap(sig)) {
319 if (active_initdata.count(bit)) {
320 initval.bits.push_back(active_initdata.at(bit));
321 gotinit = true;
322 } else {
323 initval.bits.push_back(State::Sx);
324 }
325 }
326
327 if (gotinit) {
328 f << " = ";
329 dump_const(f, initval);
330 }
331 }
332
dump_sigchunk(std::ostream & f,const RTLIL::SigChunk & chunk,bool no_decimal=false)333 void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
334 {
335 if (chunk.wire == NULL) {
336 dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal);
337 } else {
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);
343 else
344 f << stringf("%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset);
345 } else {
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);
350 else
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);
354 }
355 }
356 }
357
dump_sigspec(std::ostream & f,const RTLIL::SigSpec & sig)358 void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
359 {
360 if (GetSize(sig) == 0) {
361 f << "\"\"";
362 return;
363 }
364 if (sig.is_chunk()) {
365 dump_sigchunk(f, sig.as_chunk());
366 } else {
367 f << stringf("{ ");
368 for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); ++it) {
369 if (it != sig.chunks().rbegin())
370 f << stringf(", ");
371 dump_sigchunk(f, *it, true);
372 }
373 f << stringf(" }");
374 }
375 }
376
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)377 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)
378 {
379 if (noattr)
380 return;
381 if (attr2comment)
382 as_comment = true;
383 for (auto it = attributes.begin(); it != attributes.end(); ++it) {
384 if (it->first == ID::init && regattr) continue;
385 f << stringf("%s" "%s %s", indent.c_str(), as_comment ? "/*" : "(*", id(it->first).c_str());
386 f << stringf(" = ");
387 if (modattr && (it->second == State::S0 || it->second == Const(0)))
388 f << stringf(" 0 ");
389 else if (modattr && (it->second == State::S1 || it->second == Const(1)))
390 f << stringf(" 1 ");
391 else
392 dump_const(f, it->second, -1, 0, false, as_comment);
393 f << stringf(" %s%c", as_comment ? "*/" : "*)", term);
394 }
395 }
396
dump_wire(std::ostream & f,std::string indent,RTLIL::Wire * wire)397 void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
398 {
399 dump_attributes(f, indent, wire->attributes, '\n', /*modattr=*/false, /*regattr=*/reg_wires.count(wire->name));
400 #if 0
401 if (wire->port_input && !wire->port_output)
402 f << stringf("%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
403 else if (!wire->port_input && wire->port_output)
404 f << stringf("%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
405 else if (wire->port_input && wire->port_output)
406 f << stringf("%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
407 else
408 f << stringf("%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire");
409 if (wire->width != 1)
410 f << stringf("[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset);
411 f << stringf("%s;\n", id(wire->name).c_str());
412 #else
413 // do not use Verilog-2k "output reg" syntax in Verilog export
414 std::string range = "";
415 if (wire->width != 1) {
416 if (wire->upto)
417 range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
418 else
419 range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
420 }
421 if (wire->port_input && !wire->port_output)
422 f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
423 if (!wire->port_input && wire->port_output)
424 f << stringf("%s" "output%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
425 if (wire->port_input && wire->port_output)
426 f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
427 if (reg_wires.count(wire->name)) {
428 f << stringf("%s" "reg%s %s", indent.c_str(), range.c_str(), id(wire->name).c_str());
429 if (wire->attributes.count(ID::init)) {
430 f << stringf(" = ");
431 dump_const(f, wire->attributes.at(ID::init));
432 }
433 f << stringf(";\n");
434 } else if (!wire->port_input && !wire->port_output)
435 f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
436 #endif
437 }
438
dump_memory(std::ostream & f,std::string indent,Mem & mem)439 void dump_memory(std::ostream &f, std::string indent, Mem &mem)
440 {
441 std::string mem_id = id(mem.memid);
442
443 dump_attributes(f, indent, mem.attributes);
444 f << stringf("%s" "reg [%d:0] %s [%d:%d];\n", indent.c_str(), mem.width-1, mem_id.c_str(), mem.size+mem.start_offset-1, mem.start_offset);
445
446 // for memory block make something like:
447 // reg [7:0] memid [3:0];
448 // initial begin
449 // memid[0] = ...
450 // end
451 if (!mem.inits.empty())
452 {
453 if (extmem)
454 {
455 std::string extmem_filename = stringf("%s-%d.mem", extmem_prefix.c_str(), extmem_counter++);
456
457 std::string extmem_filename_esc;
458 for (auto c : extmem_filename)
459 {
460 if (c == '\n')
461 extmem_filename_esc += "\\n";
462 else if (c == '\t')
463 extmem_filename_esc += "\\t";
464 else if (c < 32)
465 extmem_filename_esc += stringf("\\%03o", c);
466 else if (c == '"')
467 extmem_filename_esc += "\\\"";
468 else if (c == '\\')
469 extmem_filename_esc += "\\\\";
470 else
471 extmem_filename_esc += c;
472 }
473 f << stringf("%s" "initial $readmemb(\"%s\", %s);\n", indent.c_str(), extmem_filename_esc.c_str(), mem_id.c_str());
474
475 std::ofstream extmem_f(extmem_filename, std::ofstream::trunc);
476 if (extmem_f.fail())
477 log_error("Can't open file `%s' for writing: %s\n", extmem_filename.c_str(), strerror(errno));
478 else
479 {
480 Const data = mem.get_init_data();
481 for (int i=0; i<mem.size; i++)
482 {
483 RTLIL::Const element = data.extract(i*mem.width, mem.width);
484 for (int j=0; j<element.size(); j++)
485 {
486 switch (element[element.size()-j-1])
487 {
488 case State::S0: extmem_f << '0'; break;
489 case State::S1: extmem_f << '1'; break;
490 case State::Sx: extmem_f << 'x'; break;
491 case State::Sz: extmem_f << 'z'; break;
492 case State::Sa: extmem_f << '_'; break;
493 case State::Sm: log_error("Found marker state in final netlist.");
494 }
495 }
496 extmem_f << '\n';
497 }
498 }
499 }
500 else
501 {
502 f << stringf("%s" "initial begin\n", indent.c_str());
503 for (auto &init : mem.inits) {
504 int words = GetSize(init.data) / mem.width;
505 int start = init.addr.as_int();
506 for (int i=0; i<words; i++)
507 {
508 for (int j = 0; j < mem.width; j++)
509 {
510 if (init.en[j] != State::S1)
511 continue;
512
513 int start_j = j, width = 1;
514
515 while (j+1 < mem.width && init.en[j+1] == State::S1)
516 j++, width++;
517
518 if (width == mem.width) {
519 f << stringf("%s" " %s[%d] = ", indent.c_str(), mem_id.c_str(), i + start);
520 } else {
521 f << stringf("%s" " %s[%d][%d:%d] = ", indent.c_str(), mem_id.c_str(), i + start, j, start_j);
522 }
523 dump_const(f, init.data.extract(i*mem.width+start_j, width));
524 f << stringf(";\n");
525 }
526 }
527 }
528 f << stringf("%s" "end\n", indent.c_str());
529 }
530 }
531
532 // create a map : "edge clk" -> expressions within that clock domain
533 dict<std::string, std::vector<std::string>> clk_to_lof_body;
534 dict<std::string, std::string> clk_to_arst_cond;
535 dict<std::string, std::vector<std::string>> clk_to_arst_body;
536 clk_to_lof_body[""] = std::vector<std::string>();
537 std::string clk_domain_str;
538 // create a list of reg declarations
539 std::vector<std::string> lof_reg_declarations;
540
541 // read ports
542 for (auto &port : mem.rd_ports)
543 {
544 if (port.clk_enable)
545 {
546 {
547 std::ostringstream os;
548 dump_sigspec(os, port.clk);
549 clk_domain_str = stringf("%sedge %s", port.clk_polarity ? "pos" : "neg", os.str().c_str());
550 if (port.arst != State::S0) {
551 std::ostringstream os2;
552 dump_sigspec(os2, port.arst);
553 clk_domain_str += stringf(", posedge %s", os2.str().c_str());
554 clk_to_arst_cond[clk_domain_str] = os2.str();
555 }
556 }
557
558 // Decide how to represent the transparency; same idea as Mem::extract_rdff.
559 bool trans_use_addr = true;
560 for (auto bit : port.transparency_mask)
561 if (!bit)
562 trans_use_addr = false;
563
564 if (GetSize(mem.wr_ports) == 0)
565 trans_use_addr = false;
566
567 if (port.en != State::S1 || port.srst != State::S0 || port.arst != State::S0 || !port.init_value.is_fully_undef())
568 trans_use_addr = false;
569
570 if (!trans_use_addr)
571 {
572 // for clocked read ports make something like:
573 // reg [..] temp_id;
574 // always @(posedge clk)
575 // if (rd_en) temp_id <= array_reg[r_addr];
576 // assign r_data = temp_id;
577 std::string temp_id = next_auto_id();
578 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", port.data.size() - 1, temp_id.c_str()) );
579
580 bool has_indent = false;
581
582 if (port.arst != State::S0) {
583 std::ostringstream os;
584 os << stringf("%s <= ", temp_id.c_str());
585 dump_sigspec(os, port.arst_value);
586 os << ";\n";
587 clk_to_arst_body[clk_domain_str].push_back(os.str());
588 }
589
590 if (port.srst != State::S0 && !port.ce_over_srst) {
591 std::ostringstream os;
592 os << stringf("if (");
593 dump_sigspec(os, port.srst);
594 os << stringf(")\n");
595 clk_to_lof_body[clk_domain_str].push_back(os.str());
596 std::ostringstream os2;
597 os2 << stringf("%s" "%s <= ", indent.c_str(), temp_id.c_str());
598 dump_sigspec(os2, port.srst_value);
599 os2 << ";\n";
600 clk_to_lof_body[clk_domain_str].push_back(os2.str());
601 std::ostringstream os3;
602 if (port.en == State::S1) {
603 os3 << "else begin\n";
604 } else {
605 os3 << "else if (";
606 dump_sigspec(os3, port.en);
607 os3 << ") begin\n";
608 }
609 clk_to_lof_body[clk_domain_str].push_back(os3.str());
610 has_indent = true;
611 } else if (port.en != State::S1) {
612 std::ostringstream os;
613 os << stringf("if (");
614 dump_sigspec(os, port.en);
615 os << stringf(") begin\n");
616 clk_to_lof_body[clk_domain_str].push_back(os.str());
617 has_indent = true;
618 }
619
620 for (int sub = 0; sub < (1 << port.wide_log2); sub++)
621 {
622 SigSpec addr = port.sub_addr(sub);
623 std::ostringstream os;
624 if (has_indent)
625 os << indent;
626 os << temp_id;
627 if (port.wide_log2)
628 os << stringf("[%d:%d]", (sub + 1) * mem.width - 1, sub * mem.width);
629 os << stringf(" <= %s[", mem_id.c_str());
630 dump_sigspec(os, addr);
631 os << stringf("];\n");
632 clk_to_lof_body[clk_domain_str].push_back(os.str());
633 }
634
635 for (int i = 0; i < GetSize(mem.wr_ports); i++) {
636 auto &wport = mem.wr_ports[i];
637 if (!port.transparency_mask[i] && !port.collision_x_mask[i])
638 continue;
639 int min_wide_log2 = std::min(port.wide_log2, wport.wide_log2);
640 int max_wide_log2 = std::max(port.wide_log2, wport.wide_log2);
641 bool wide_write = wport.wide_log2 > port.wide_log2;
642 for (int sub = 0; sub < (1 << max_wide_log2); sub += (1 << min_wide_log2)) {
643 SigSpec raddr = port.addr;
644 SigSpec waddr = wport.addr;
645 if (wide_write)
646 waddr = wport.sub_addr(sub);
647 else
648 raddr = port.sub_addr(sub);
649 int pos = 0;
650 int ewidth = mem.width << min_wide_log2;
651 int wsub = wide_write ? sub : 0;
652 int rsub = wide_write ? 0 : sub;
653 while (pos < ewidth) {
654 int epos = pos;
655 while (epos < ewidth && wport.en[epos + wsub * mem.width] == wport.en[pos + wsub * mem.width])
656 epos++;
657
658 std::ostringstream os;
659 if (has_indent)
660 os << indent;
661 os << "if (";
662 dump_sigspec(os, wport.en[pos + wsub * mem.width]);
663 if (raddr != waddr) {
664 os << " && ";
665 dump_sigspec(os, raddr);
666 os << " == ";
667 dump_sigspec(os, waddr);
668 }
669 os << ")\n";
670 clk_to_lof_body[clk_domain_str].push_back(os.str());
671
672 std::ostringstream os2;
673 if (has_indent)
674 os2 << indent;
675 os2 << indent;
676 os2 << temp_id;
677 if (epos-pos != GetSize(port.data))
678 os2 << stringf("[%d:%d]", rsub * mem.width + epos-1, rsub * mem.width + pos);
679 os2 << " <= ";
680 if (port.transparency_mask[i])
681 dump_sigspec(os2, wport.data.extract(wsub * mem.width + pos, epos-pos));
682 else
683 dump_sigspec(os2, Const(State::Sx, epos - pos));
684 os2 << ";\n";
685 clk_to_lof_body[clk_domain_str].push_back(os2.str());
686
687 pos = epos;
688 }
689 }
690 }
691
692 if (port.srst != State::S0 && port.ce_over_srst)
693 {
694 std::ostringstream os;
695 if (has_indent)
696 os << indent;
697 os << stringf("if (");
698 dump_sigspec(os, port.srst);
699 os << stringf(")\n");
700 clk_to_lof_body[clk_domain_str].push_back(os.str());
701 std::ostringstream os2;
702 if (has_indent)
703 os2 << indent;
704 os2 << stringf("%s" "%s <= ", indent.c_str(), temp_id.c_str());
705 dump_sigspec(os2, port.srst_value);
706 os2 << ";\n";
707 clk_to_lof_body[clk_domain_str].push_back(os2.str());
708 }
709
710 if (has_indent)
711 clk_to_lof_body[clk_domain_str].push_back("end\n");
712
713 if (!port.init_value.is_fully_undef())
714 {
715 std::ostringstream os;
716 dump_sigspec(os, port.init_value);
717 std::string line = stringf("initial %s = %s;\n", temp_id.c_str(), os.str().c_str());
718 clk_to_lof_body[""].push_back(line);
719 }
720
721 {
722 std::ostringstream os;
723 dump_sigspec(os, port.data);
724 std::string line = stringf("assign %s = %s;\n", os.str().c_str(), temp_id.c_str());
725 clk_to_lof_body[""].push_back(line);
726 }
727 }
728 else
729 {
730 // for rd-transparent read-ports make something like:
731 // reg [..] temp_id;
732 // always @(posedge clk)
733 // temp_id <= r_addr;
734 // assign r_data = array_reg[temp_id];
735 std::string temp_id = next_auto_id();
736 lof_reg_declarations.push_back( stringf("reg [%d:0] %s;\n", port.addr.size() - 1 - port.wide_log2, temp_id.c_str()) );
737 {
738 std::ostringstream os;
739 dump_sigspec(os, port.addr.extract_end(port.wide_log2));
740 std::string line = stringf("%s <= %s;\n", temp_id.c_str(), os.str().c_str());
741 clk_to_lof_body[clk_domain_str].push_back(line);
742 }
743 for (int sub = 0; sub < (1 << port.wide_log2); sub++)
744 {
745 std::ostringstream os;
746 os << "assign ";
747 dump_sigspec(os, port.data.extract(sub * mem.width, mem.width));
748 os << stringf(" = %s[", mem_id.c_str());;
749 if (port.wide_log2) {
750 Const addr_lo;
751 for (int i = 0; i < port.wide_log2; i++)
752 addr_lo.bits.push_back(State(sub >> i & 1));
753 os << "{";
754 os << temp_id;
755 os << ", ";
756 dump_const(os, addr_lo);
757 os << "}";
758 } else {
759 os << temp_id;
760 }
761 os << "];\n";
762 clk_to_lof_body[""].push_back(os.str());
763 }
764 }
765 } else {
766 // for non-clocked read-ports make something like:
767 // assign r_data = array_reg[r_addr];
768 for (int sub = 0; sub < (1 << port.wide_log2); sub++)
769 {
770 SigSpec addr = port.sub_addr(sub);
771
772 std::ostringstream os, os2;
773 dump_sigspec(os, port.data.extract(sub * mem.width, mem.width));
774 dump_sigspec(os2, addr);
775 std::string line = stringf("assign %s = %s[%s];\n", os.str().c_str(), mem_id.c_str(), os2.str().c_str());
776 clk_to_lof_body[""].push_back(line);
777 }
778 }
779 }
780
781 // Write ports. Those are messy because we try to preserve priority, as much as we can:
782 //
783 // 1. We split all ports into several disjoint processes.
784 // 2. If a port has priority over another port, the two ports need to share
785 // a process, so that priority can be reconstructed on the other end.
786 // 3. We want each process to be as small as possible, to avoid extra
787 // priorities inferred on the other end.
788 pool<int> wr_ports_done;
789 for (int ridx = 0; ridx < GetSize(mem.wr_ports); ridx++)
790 {
791 if (wr_ports_done.count(ridx))
792 continue;
793
794 auto &root = mem.wr_ports[ridx];
795
796 // Start from a root.
797 pool<int> wr_ports_now;
798 wr_ports_now.insert(ridx);
799
800 // Transitively fill list of ports in this process by following priority edges.
801 while (true)
802 {
803 bool changed = false;
804
805 for (int i = 0; i < GetSize(mem.wr_ports); i++)
806 for (int j = 0; j < i; j++)
807 if (mem.wr_ports[i].priority_mask[j])
808 {
809 if (wr_ports_now.count(i) && !wr_ports_now.count(j)) {
810 wr_ports_now.insert(j);
811 changed = true;
812 }
813 if (!wr_ports_now.count(i) && wr_ports_now.count(j)) {
814 wr_ports_now.insert(i);
815 changed = true;
816 }
817 }
818
819 if (!changed)
820 break;
821 }
822
823 if (root.clk_enable) {
824 f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", root.clk_polarity ? "pos" : "neg");
825 dump_sigspec(f, root.clk);
826 f << ") begin\n";
827 } else {
828 f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_latch" : " @*");
829 }
830
831 for (int pidx = 0; pidx < GetSize(mem.wr_ports); pidx++)
832 {
833 if (!wr_ports_now.count(pidx))
834 continue;
835 wr_ports_done.insert(pidx);
836
837 auto &port = mem.wr_ports[pidx];
838 log_assert(port.clk_enable == root.clk_enable);
839 if (port.clk_enable) {
840 log_assert(port.clk == root.clk);
841 log_assert(port.clk_polarity == root.clk_polarity);
842 }
843
844 // make something like:
845 // always @(posedge clk)
846 // if (wr_en_bit) memid[w_addr][??] <= w_data[??];
847 // ...
848 for (int sub = 0; sub < (1 << port.wide_log2); sub++)
849 {
850 SigSpec addr = port.sub_addr(sub);
851 for (int i = 0; i < mem.width; i++)
852 {
853 int start_i = i, width = 1;
854 SigBit wen_bit = port.en[sub * mem.width + i];
855
856 while (i+1 < mem.width && active_sigmap(port.en[sub * mem.width + i+1]) == active_sigmap(wen_bit))
857 i++, width++;
858
859 if (wen_bit == State::S0)
860 continue;
861
862 f << stringf("%s%s", indent.c_str(), indent.c_str());
863 if (wen_bit != State::S1)
864 {
865 f << stringf("if (");
866 dump_sigspec(f, wen_bit);
867 f << stringf(")\n");
868 f << stringf("%s%s%s", indent.c_str(), indent.c_str(), indent.c_str());
869 }
870 f << stringf("%s[", mem_id.c_str());
871 dump_sigspec(f, addr);
872 if (width == GetSize(port.en))
873 f << stringf("] <= ");
874 else
875 f << stringf("][%d:%d] <= ", i, start_i);
876 dump_sigspec(f, port.data.extract(sub * mem.width + start_i, width));
877 f << stringf(";\n");
878 }
879 }
880 }
881
882 f << stringf("%s" "end\n", indent.c_str());
883 }
884 // Output Verilog that looks something like this:
885 // reg [..] _3_;
886 // always @(posedge CLK2) begin
887 // _3_ <= memory[D1ADDR];
888 // if (A1EN)
889 // memory[A1ADDR] <= A1DATA;
890 // if (A2EN)
891 // memory[A2ADDR] <= A2DATA;
892 // ...
893 // end
894 // always @(negedge CLK1) begin
895 // if (C1EN)
896 // memory[C1ADDR] <= C1DATA;
897 // end
898 // ...
899 // assign D1DATA = _3_;
900 // assign D2DATA <= memory[D2ADDR];
901
902 // the reg ... definitions
903 for(auto ® : lof_reg_declarations)
904 {
905 f << stringf("%s" "%s", indent.c_str(), reg.c_str());
906 }
907 // the block of expressions by clock domain
908 for(auto &pair : clk_to_lof_body)
909 {
910 std::string clk_domain = pair.first;
911 std::vector<std::string> lof_lines = pair.second;
912 if( clk_domain != "")
913 {
914 f << stringf("%s" "always%s @(%s) begin\n", indent.c_str(), systemverilog ? "_ff" : "", clk_domain.c_str());
915 bool has_arst = clk_to_arst_cond.count(clk_domain) != 0;
916 if (has_arst) {
917 f << stringf("%s%s" "if (%s) begin\n", indent.c_str(), indent.c_str(), clk_to_arst_cond[clk_domain].c_str());
918 for(auto &line : clk_to_arst_body[clk_domain])
919 f << stringf("%s%s%s" "%s", indent.c_str(), indent.c_str(), indent.c_str(), line.c_str());
920 f << stringf("%s%s" "end else begin\n", indent.c_str(), indent.c_str());
921 for(auto &line : lof_lines)
922 f << stringf("%s%s%s" "%s", indent.c_str(), indent.c_str(), indent.c_str(), line.c_str());
923 f << stringf("%s%s" "end\n", indent.c_str(), indent.c_str());
924 } else {
925 for(auto &line : lof_lines)
926 f << stringf("%s%s" "%s", indent.c_str(), indent.c_str(), line.c_str());
927 }
928 f << stringf("%s" "end\n", indent.c_str());
929 }
930 else
931 {
932 // the non-clocked assignments
933 for(auto &line : lof_lines)
934 f << stringf("%s" "%s", indent.c_str(), line.c_str());
935 }
936 }
937 }
938
dump_cell_expr_port(std::ostream & f,RTLIL::Cell * cell,std::string port,bool gen_signed=true)939 void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
940 {
941 if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) {
942 f << stringf("$signed(");
943 dump_sigspec(f, cell->getPort("\\" + port));
944 f << stringf(")");
945 } else
946 dump_sigspec(f, cell->getPort("\\" + port));
947 }
948
cellname(RTLIL::Cell * cell)949 std::string cellname(RTLIL::Cell *cell)
950 {
951 if (!norename && cell->name[0] == '$' && RTLIL::builtin_ff_cell_types().count(cell->type) && cell->hasPort(ID::Q) && !cell->type.in(ID($ff), ID($_FF_)))
952 {
953 RTLIL::SigSpec sig = cell->getPort(ID::Q);
954 if (GetSize(sig) != 1 || sig.is_fully_const())
955 goto no_special_reg_name;
956
957 RTLIL::Wire *wire = sig[0].wire;
958
959 if (wire->name[0] != '\\')
960 goto no_special_reg_name;
961
962 std::string cell_name = wire->name.str();
963
964 size_t pos = cell_name.find('[');
965 if (pos != std::string::npos)
966 cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos);
967 else
968 cell_name = cell_name + "_reg";
969
970 if (wire->width != 1)
971 cell_name += stringf("[%d]", wire->start_offset + sig[0].offset);
972
973 if (active_module && active_module->count_id(cell_name) > 0)
974 goto no_special_reg_name;
975
976 return id(cell_name);
977 }
978 else
979 {
980 no_special_reg_name:
981 return id(cell->name).c_str();
982 }
983 }
984
dump_cell_expr_uniop(std::ostream & f,std::string indent,RTLIL::Cell * cell,std::string op)985 void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
986 {
987 f << stringf("%s" "assign ", indent.c_str());
988 dump_sigspec(f, cell->getPort(ID::Y));
989 f << stringf(" = %s ", op.c_str());
990 dump_attributes(f, "", cell->attributes, ' ');
991 dump_cell_expr_port(f, cell, "A", true);
992 f << stringf(";\n");
993 }
994
dump_cell_expr_binop(std::ostream & f,std::string indent,RTLIL::Cell * cell,std::string op)995 void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
996 {
997 f << stringf("%s" "assign ", indent.c_str());
998 dump_sigspec(f, cell->getPort(ID::Y));
999 f << stringf(" = ");
1000 dump_cell_expr_port(f, cell, "A", true);
1001 f << stringf(" %s ", op.c_str());
1002 dump_attributes(f, "", cell->attributes, ' ');
1003 dump_cell_expr_port(f, cell, "B", true);
1004 f << stringf(";\n");
1005 }
1006
dump_cell_expr(std::ostream & f,std::string indent,RTLIL::Cell * cell)1007 bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
1008 {
1009 if (cell->type == ID($_NOT_)) {
1010 f << stringf("%s" "assign ", indent.c_str());
1011 dump_sigspec(f, cell->getPort(ID::Y));
1012 f << stringf(" = ");
1013 f << stringf("~");
1014 dump_attributes(f, "", cell->attributes, ' ');
1015 dump_cell_expr_port(f, cell, "A", false);
1016 f << stringf(";\n");
1017 return true;
1018 }
1019
1020 if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_OR_), ID($_NOR_), ID($_XOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_))) {
1021 f << stringf("%s" "assign ", indent.c_str());
1022 dump_sigspec(f, cell->getPort(ID::Y));
1023 f << stringf(" = ");
1024 if (cell->type.in(ID($_NAND_), ID($_NOR_), ID($_XNOR_)))
1025 f << stringf("~(");
1026 dump_cell_expr_port(f, cell, "A", false);
1027 f << stringf(" ");
1028 if (cell->type.in(ID($_AND_), ID($_NAND_), ID($_ANDNOT_)))
1029 f << stringf("&");
1030 if (cell->type.in(ID($_OR_), ID($_NOR_), ID($_ORNOT_)))
1031 f << stringf("|");
1032 if (cell->type.in(ID($_XOR_), ID($_XNOR_)))
1033 f << stringf("^");
1034 dump_attributes(f, "", cell->attributes, ' ');
1035 f << stringf(" ");
1036 if (cell->type.in(ID($_ANDNOT_), ID($_ORNOT_)))
1037 f << stringf("~(");
1038 dump_cell_expr_port(f, cell, "B", false);
1039 if (cell->type.in(ID($_NAND_), ID($_NOR_), ID($_XNOR_), ID($_ANDNOT_), ID($_ORNOT_)))
1040 f << stringf(")");
1041 f << stringf(";\n");
1042 return true;
1043 }
1044
1045 if (cell->type == ID($_MUX_)) {
1046 f << stringf("%s" "assign ", indent.c_str());
1047 dump_sigspec(f, cell->getPort(ID::Y));
1048 f << stringf(" = ");
1049 dump_cell_expr_port(f, cell, "S", false);
1050 f << stringf(" ? ");
1051 dump_attributes(f, "", cell->attributes, ' ');
1052 dump_cell_expr_port(f, cell, "B", false);
1053 f << stringf(" : ");
1054 dump_cell_expr_port(f, cell, "A", false);
1055 f << stringf(";\n");
1056 return true;
1057 }
1058
1059 if (cell->type == ID($_NMUX_)) {
1060 f << stringf("%s" "assign ", indent.c_str());
1061 dump_sigspec(f, cell->getPort(ID::Y));
1062 f << stringf(" = !(");
1063 dump_cell_expr_port(f, cell, "S", false);
1064 f << stringf(" ? ");
1065 dump_attributes(f, "", cell->attributes, ' ');
1066 dump_cell_expr_port(f, cell, "B", false);
1067 f << stringf(" : ");
1068 dump_cell_expr_port(f, cell, "A", false);
1069 f << stringf(");\n");
1070 return true;
1071 }
1072
1073 if (cell->type.in(ID($_AOI3_), ID($_OAI3_))) {
1074 f << stringf("%s" "assign ", indent.c_str());
1075 dump_sigspec(f, cell->getPort(ID::Y));
1076 f << stringf(" = ~((");
1077 dump_cell_expr_port(f, cell, "A", false);
1078 f << stringf(cell->type == ID($_AOI3_) ? " & " : " | ");
1079 dump_cell_expr_port(f, cell, "B", false);
1080 f << stringf(cell->type == ID($_AOI3_) ? ") |" : ") &");
1081 dump_attributes(f, "", cell->attributes, ' ');
1082 f << stringf(" ");
1083 dump_cell_expr_port(f, cell, "C", false);
1084 f << stringf(");\n");
1085 return true;
1086 }
1087
1088 if (cell->type.in(ID($_AOI4_), ID($_OAI4_))) {
1089 f << stringf("%s" "assign ", indent.c_str());
1090 dump_sigspec(f, cell->getPort(ID::Y));
1091 f << stringf(" = ~((");
1092 dump_cell_expr_port(f, cell, "A", false);
1093 f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
1094 dump_cell_expr_port(f, cell, "B", false);
1095 f << stringf(cell->type == ID($_AOI4_) ? ") |" : ") &");
1096 dump_attributes(f, "", cell->attributes, ' ');
1097 f << stringf(" (");
1098 dump_cell_expr_port(f, cell, "C", false);
1099 f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
1100 dump_cell_expr_port(f, cell, "D", false);
1101 f << stringf("));\n");
1102 return true;
1103 }
1104
1105 #define HANDLE_UNIOP(_type, _operator) \
1106 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
1107 #define HANDLE_BINOP(_type, _operator) \
1108 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
1109
1110 HANDLE_UNIOP(ID($not), "~")
1111 HANDLE_UNIOP(ID($pos), "+")
1112 HANDLE_UNIOP(ID($neg), "-")
1113
1114 HANDLE_BINOP(ID($and), "&")
1115 HANDLE_BINOP(ID($or), "|")
1116 HANDLE_BINOP(ID($xor), "^")
1117 HANDLE_BINOP(ID($xnor), "~^")
1118
1119 HANDLE_UNIOP(ID($reduce_and), "&")
1120 HANDLE_UNIOP(ID($reduce_or), "|")
1121 HANDLE_UNIOP(ID($reduce_xor), "^")
1122 HANDLE_UNIOP(ID($reduce_xnor), "~^")
1123 HANDLE_UNIOP(ID($reduce_bool), "|")
1124
1125 HANDLE_BINOP(ID($shl), "<<")
1126 HANDLE_BINOP(ID($shr), ">>")
1127 HANDLE_BINOP(ID($sshl), "<<<")
1128 HANDLE_BINOP(ID($sshr), ">>>")
1129
1130 HANDLE_BINOP(ID($lt), "<")
1131 HANDLE_BINOP(ID($le), "<=")
1132 HANDLE_BINOP(ID($eq), "==")
1133 HANDLE_BINOP(ID($ne), "!=")
1134 HANDLE_BINOP(ID($eqx), "===")
1135 HANDLE_BINOP(ID($nex), "!==")
1136 HANDLE_BINOP(ID($ge), ">=")
1137 HANDLE_BINOP(ID($gt), ">")
1138
1139 HANDLE_BINOP(ID($add), "+")
1140 HANDLE_BINOP(ID($sub), "-")
1141 HANDLE_BINOP(ID($mul), "*")
1142 HANDLE_BINOP(ID($div), "/")
1143 HANDLE_BINOP(ID($mod), "%")
1144 HANDLE_BINOP(ID($pow), "**")
1145
1146 HANDLE_UNIOP(ID($logic_not), "!")
1147 HANDLE_BINOP(ID($logic_and), "&&")
1148 HANDLE_BINOP(ID($logic_or), "||")
1149
1150 #undef HANDLE_UNIOP
1151 #undef HANDLE_BINOP
1152
1153 if (cell->type == ID($divfloor))
1154 {
1155 // wire [MAXLEN+1:0] _0_, _1_, _2_;
1156 // assign _0_ = $signed(A);
1157 // assign _1_ = $signed(B);
1158 // assign _2_ = (A[-1] == B[-1]) || A == 0 ? _0_ : $signed(_0_ - (B[-1] ? _1_ + 1 : _1_ - 1));
1159 // assign Y = $signed(_2_) / $signed(_1_);
1160
1161 if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) {
1162 SigSpec sig_a = cell->getPort(ID::A);
1163 SigSpec sig_b = cell->getPort(ID::B);
1164
1165 std::string buf_a = next_auto_id();
1166 std::string buf_b = next_auto_id();
1167 std::string buf_num = next_auto_id();
1168 int size_a = GetSize(sig_a);
1169 int size_b = GetSize(sig_b);
1170 int size_y = GetSize(cell->getPort(ID::Y));
1171 int size_max = std::max(size_a, std::max(size_b, size_y));
1172
1173 // intentionally one wider than maximum width
1174 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());
1175 f << stringf("%s" "assign %s = ", indent.c_str(), buf_a.c_str());
1176 dump_cell_expr_port(f, cell, "A", true);
1177 f << stringf(";\n");
1178 f << stringf("%s" "assign %s = ", indent.c_str(), buf_b.c_str());
1179 dump_cell_expr_port(f, cell, "B", true);
1180 f << stringf(";\n");
1181
1182 f << stringf("%s" "assign %s = ", indent.c_str(), buf_num.c_str());
1183 f << stringf("(");
1184 dump_sigspec(f, sig_a.extract(sig_a.size()-1));
1185 f << stringf(" == ");
1186 dump_sigspec(f, sig_b.extract(sig_b.size()-1));
1187 f << stringf(") || ");
1188 dump_sigspec(f, sig_a);
1189 f << stringf(" == 0 ? %s : ", buf_a.c_str());
1190 f << stringf("$signed(%s - (", buf_a.c_str());
1191 dump_sigspec(f, sig_b.extract(sig_b.size()-1));
1192 f << stringf(" ? %s + 1 : %s - 1));\n", buf_b.c_str(), buf_b.c_str());
1193
1194
1195 f << stringf("%s" "assign ", indent.c_str());
1196 dump_sigspec(f, cell->getPort(ID::Y));
1197 f << stringf(" = $signed(%s) / ", buf_num.c_str());
1198 dump_attributes(f, "", cell->attributes, ' ');
1199 f << stringf("$signed(%s);\n", buf_b.c_str());
1200 return true;
1201 } else {
1202 // same as truncating division
1203 dump_cell_expr_binop(f, indent, cell, "/");
1204 return true;
1205 }
1206 }
1207
1208 if (cell->type == ID($modfloor))
1209 {
1210 // wire truncated = $signed(A) % $signed(B);
1211 // assign Y = (A[-1] == B[-1]) || truncated == 0 ? truncated : $signed(B) + $signed(truncated);
1212
1213 if (cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) {
1214 SigSpec sig_a = cell->getPort(ID::A);
1215 SigSpec sig_b = cell->getPort(ID::B);
1216
1217 std::string temp_id = next_auto_id();
1218 f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str());
1219 dump_cell_expr_port(f, cell, "A", true);
1220 f << stringf(" %% ");
1221 dump_attributes(f, "", cell->attributes, ' ');
1222 dump_cell_expr_port(f, cell, "B", true);
1223 f << stringf(";\n");
1224
1225 f << stringf("%s" "assign ", indent.c_str());
1226 dump_sigspec(f, cell->getPort(ID::Y));
1227 f << stringf(" = (");
1228 dump_sigspec(f, sig_a.extract(sig_a.size()-1));
1229 f << stringf(" == ");
1230 dump_sigspec(f, sig_b.extract(sig_b.size()-1));
1231 f << stringf(") || %s == 0 ? %s : ", temp_id.c_str(), temp_id.c_str());
1232 dump_cell_expr_port(f, cell, "B", true);
1233 f << stringf(" + $signed(%s);\n", temp_id.c_str());
1234 return true;
1235 } else {
1236 // same as truncating modulo
1237 dump_cell_expr_binop(f, indent, cell, "%");
1238 return true;
1239 }
1240 }
1241
1242 if (cell->type == ID($shift))
1243 {
1244 f << stringf("%s" "assign ", indent.c_str());
1245 dump_sigspec(f, cell->getPort(ID::Y));
1246 f << stringf(" = ");
1247 if (cell->getParam(ID::B_SIGNED).as_bool())
1248 {
1249 dump_cell_expr_port(f, cell, "B", true);
1250 f << stringf(" < 0 ? ");
1251 dump_cell_expr_port(f, cell, "A", true);
1252 f << stringf(" << - ");
1253 dump_sigspec(f, cell->getPort(ID::B));
1254 f << stringf(" : ");
1255 dump_cell_expr_port(f, cell, "A", true);
1256 f << stringf(" >> ");
1257 dump_sigspec(f, cell->getPort(ID::B));
1258 }
1259 else
1260 {
1261 dump_cell_expr_port(f, cell, "A", true);
1262 f << stringf(" >> ");
1263 dump_sigspec(f, cell->getPort(ID::B));
1264 }
1265 f << stringf(";\n");
1266 return true;
1267 }
1268
1269 if (cell->type == ID($shiftx))
1270 {
1271 std::string temp_id = next_auto_id();
1272 f << stringf("%s" "wire [%d:0] %s = ", indent.c_str(), GetSize(cell->getPort(ID::A))-1, temp_id.c_str());
1273 dump_sigspec(f, cell->getPort(ID::A));
1274 f << stringf(";\n");
1275
1276 f << stringf("%s" "assign ", indent.c_str());
1277 dump_sigspec(f, cell->getPort(ID::Y));
1278 f << stringf(" = %s[", temp_id.c_str());
1279 if (cell->getParam(ID::B_SIGNED).as_bool())
1280 f << stringf("$signed(");
1281 dump_sigspec(f, cell->getPort(ID::B));
1282 if (cell->getParam(ID::B_SIGNED).as_bool())
1283 f << stringf(")");
1284 f << stringf(" +: %d", cell->getParam(ID::Y_WIDTH).as_int());
1285 f << stringf("];\n");
1286 return true;
1287 }
1288
1289 if (cell->type == ID($mux))
1290 {
1291 f << stringf("%s" "assign ", indent.c_str());
1292 dump_sigspec(f, cell->getPort(ID::Y));
1293 f << stringf(" = ");
1294 dump_sigspec(f, cell->getPort(ID::S));
1295 f << stringf(" ? ");
1296 dump_attributes(f, "", cell->attributes, ' ');
1297 dump_sigspec(f, cell->getPort(ID::B));
1298 f << stringf(" : ");
1299 dump_sigspec(f, cell->getPort(ID::A));
1300 f << stringf(";\n");
1301 return true;
1302 }
1303
1304 if (cell->type == ID($pmux))
1305 {
1306 int width = cell->parameters[ID::WIDTH].as_int();
1307 int s_width = cell->getPort(ID::S).size();
1308 std::string func_name = cellname(cell);
1309
1310 f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
1311 f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
1312 f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
1313 f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
1314
1315 dump_attributes(f, indent + " ", cell->attributes);
1316 if (!noattr)
1317 f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
1318 f << stringf("%s" " casez (s)", indent.c_str());
1319 f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
1320
1321 for (int i = 0; i < s_width; i++)
1322 {
1323 f << stringf("%s" " %d'b", indent.c_str(), s_width);
1324
1325 for (int j = s_width-1; j >= 0; j--)
1326 f << stringf("%c", j == i ? '1' : '?');
1327
1328 f << stringf(":\n");
1329 f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
1330 }
1331
1332 f << stringf("%s" " default:\n", indent.c_str());
1333 f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str());
1334
1335 f << stringf("%s" " endcase\n", indent.c_str());
1336 f << stringf("%s" "endfunction\n", indent.c_str());
1337
1338 f << stringf("%s" "assign ", indent.c_str());
1339 dump_sigspec(f, cell->getPort(ID::Y));
1340 f << stringf(" = %s(", func_name.c_str());
1341 dump_sigspec(f, cell->getPort(ID::A));
1342 f << stringf(", ");
1343 dump_sigspec(f, cell->getPort(ID::B));
1344 f << stringf(", ");
1345 dump_sigspec(f, cell->getPort(ID::S));
1346 f << stringf(");\n");
1347 return true;
1348 }
1349
1350 if (cell->type == ID($tribuf))
1351 {
1352 f << stringf("%s" "assign ", indent.c_str());
1353 dump_sigspec(f, cell->getPort(ID::Y));
1354 f << stringf(" = ");
1355 dump_sigspec(f, cell->getPort(ID::EN));
1356 f << stringf(" ? ");
1357 dump_sigspec(f, cell->getPort(ID::A));
1358 f << stringf(" : %d'bz;\n", cell->parameters.at(ID::WIDTH).as_int());
1359 return true;
1360 }
1361
1362 if (cell->type == ID($slice))
1363 {
1364 f << stringf("%s" "assign ", indent.c_str());
1365 dump_sigspec(f, cell->getPort(ID::Y));
1366 f << stringf(" = ");
1367 dump_sigspec(f, cell->getPort(ID::A));
1368 f << stringf(" >> %d;\n", cell->parameters.at(ID::OFFSET).as_int());
1369 return true;
1370 }
1371
1372 if (cell->type == ID($concat))
1373 {
1374 f << stringf("%s" "assign ", indent.c_str());
1375 dump_sigspec(f, cell->getPort(ID::Y));
1376 f << stringf(" = { ");
1377 dump_sigspec(f, cell->getPort(ID::B));
1378 f << stringf(" , ");
1379 dump_sigspec(f, cell->getPort(ID::A));
1380 f << stringf(" };\n");
1381 return true;
1382 }
1383
1384 if (cell->type == ID($lut))
1385 {
1386 f << stringf("%s" "assign ", indent.c_str());
1387 dump_sigspec(f, cell->getPort(ID::Y));
1388 f << stringf(" = ");
1389 dump_const(f, cell->parameters.at(ID::LUT));
1390 f << stringf(" >> ");
1391 dump_attributes(f, "", cell->attributes, ' ');
1392 dump_sigspec(f, cell->getPort(ID::A));
1393 f << stringf(";\n");
1394 return true;
1395 }
1396
1397 if (RTLIL::builtin_ff_cell_types().count(cell->type))
1398 {
1399 FfData ff(nullptr, cell);
1400
1401 // $ff / $_FF_ cell: not supported.
1402 if (ff.has_gclk)
1403 return false;
1404
1405 std::string reg_name = cellname(cell);
1406 bool out_is_reg_wire = is_reg_wire(ff.sig_q, reg_name);
1407
1408 if (!out_is_reg_wire) {
1409 if (ff.width == 1)
1410 f << stringf("%s" "reg %s", indent.c_str(), reg_name.c_str());
1411 else
1412 f << stringf("%s" "reg [%d:0] %s", indent.c_str(), ff.width-1, reg_name.c_str());
1413 dump_reg_init(f, ff.sig_q);
1414 f << ";\n";
1415 }
1416
1417 // If the FF has CLR/SET inputs, emit every bit slice separately.
1418 int chunks = ff.has_sr ? ff.width : 1;
1419 bool chunky = ff.has_sr && ff.width != 1;
1420
1421 for (int i = 0; i < chunks; i++)
1422 {
1423 SigSpec sig_d, sig_ad;
1424 Const val_arst, val_srst;
1425 std::string reg_bit_name, sig_set_name, sig_clr_name, sig_arst_name, sig_aload_name;
1426 if (chunky) {
1427 reg_bit_name = stringf("%s[%d]", reg_name.c_str(), i);
1428 if (ff.has_gclk || ff.has_clk)
1429 sig_d = ff.sig_d[i];
1430 if (ff.has_aload)
1431 sig_ad = ff.sig_ad[i];
1432 } else {
1433 reg_bit_name = reg_name;
1434 sig_d = ff.sig_d;
1435 sig_ad = ff.sig_ad;
1436 }
1437 if (ff.has_arst)
1438 val_arst = chunky ? ff.val_arst[i] : ff.val_arst;
1439 if (ff.has_srst)
1440 val_srst = chunky ? ff.val_srst[i] : ff.val_srst;
1441
1442 // If there are constants in the sensitivity list, replace them with an intermediate wire
1443 if (ff.has_clk) {
1444 if (ff.has_sr) {
1445 if (ff.sig_set[i].wire == NULL)
1446 {
1447 sig_set_name = next_auto_id();
1448 f << stringf("%s" "wire %s = ", indent.c_str(), sig_set_name.c_str());
1449 dump_const(f, ff.sig_set[i].data);
1450 f << stringf(";\n");
1451 }
1452 if (ff.sig_clr[i].wire == NULL)
1453 {
1454 sig_clr_name = next_auto_id();
1455 f << stringf("%s" "wire %s = ", indent.c_str(), sig_clr_name.c_str());
1456 dump_const(f, ff.sig_clr[i].data);
1457 f << stringf(";\n");
1458 }
1459 } else if (ff.has_arst) {
1460 if (ff.sig_arst[0].wire == NULL)
1461 {
1462 sig_arst_name = next_auto_id();
1463 f << stringf("%s" "wire %s = ", indent.c_str(), sig_arst_name.c_str());
1464 dump_const(f, ff.sig_arst[0].data);
1465 f << stringf(";\n");
1466 }
1467 } else if (ff.has_aload) {
1468 if (ff.sig_aload[0].wire == NULL)
1469 {
1470 sig_aload_name = next_auto_id();
1471 f << stringf("%s" "wire %s = ", indent.c_str(), sig_aload_name.c_str());
1472 dump_const(f, ff.sig_aload[0].data);
1473 f << stringf(";\n");
1474 }
1475 }
1476 }
1477
1478 dump_attributes(f, indent, cell->attributes);
1479 if (ff.has_clk)
1480 {
1481 // FFs.
1482 f << stringf("%s" "always%s @(%sedge ", indent.c_str(), systemverilog ? "_ff" : "", ff.pol_clk ? "pos" : "neg");
1483 dump_sigspec(f, ff.sig_clk);
1484 if (ff.has_sr) {
1485 f << stringf(", %sedge ", ff.pol_set ? "pos" : "neg");
1486 if (ff.sig_set[i].wire == NULL)
1487 f << stringf("%s", sig_set_name.c_str());
1488 else
1489 dump_sigspec(f, ff.sig_set[i]);
1490
1491 f << stringf(", %sedge ", ff.pol_clr ? "pos" : "neg");
1492 if (ff.sig_clr[i].wire == NULL)
1493 f << stringf("%s", sig_clr_name.c_str());
1494 else
1495 dump_sigspec(f, ff.sig_clr[i]);
1496 } else if (ff.has_arst) {
1497 f << stringf(", %sedge ", ff.pol_arst ? "pos" : "neg");
1498 if (ff.sig_arst[0].wire == NULL)
1499 f << stringf("%s", sig_arst_name.c_str());
1500 else
1501 dump_sigspec(f, ff.sig_arst);
1502 } else if (ff.has_aload) {
1503 f << stringf(", %sedge ", ff.pol_aload ? "pos" : "neg");
1504 if (ff.sig_aload[0].wire == NULL)
1505 f << stringf("%s", sig_aload_name.c_str());
1506 else
1507 dump_sigspec(f, ff.sig_aload);
1508 }
1509 f << stringf(")\n");
1510
1511 f << stringf("%s" " ", indent.c_str());
1512 if (ff.has_sr) {
1513 f << stringf("if (%s", ff.pol_clr ? "" : "!");
1514 if (ff.sig_clr[i].wire == NULL)
1515 f << stringf("%s", sig_clr_name.c_str());
1516 else
1517 dump_sigspec(f, ff.sig_clr[i]);
1518 f << stringf(") %s <= 1'b0;\n", reg_bit_name.c_str());
1519 f << stringf("%s" " else if (%s", indent.c_str(), ff.pol_set ? "" : "!");
1520 if (ff.sig_set[i].wire == NULL)
1521 f << stringf("%s", sig_set_name.c_str());
1522 else
1523 dump_sigspec(f, ff.sig_set[i]);
1524 f << stringf(") %s <= 1'b1;\n", reg_bit_name.c_str());
1525 f << stringf("%s" " else ", indent.c_str());
1526 } else if (ff.has_arst) {
1527 f << stringf("if (%s", ff.pol_arst ? "" : "!");
1528 if (ff.sig_arst[0].wire == NULL)
1529 f << stringf("%s", sig_arst_name.c_str());
1530 else
1531 dump_sigspec(f, ff.sig_arst);
1532 f << stringf(") %s <= ", reg_bit_name.c_str());
1533 dump_sigspec(f, val_arst);
1534 f << stringf(";\n");
1535 f << stringf("%s" " else ", indent.c_str());
1536 } else if (ff.has_aload) {
1537 f << stringf("if (%s", ff.pol_aload ? "" : "!");
1538 if (ff.sig_aload[0].wire == NULL)
1539 f << stringf("%s", sig_aload_name.c_str());
1540 else
1541 dump_sigspec(f, ff.sig_aload);
1542 f << stringf(") %s <= ", reg_bit_name.c_str());
1543 dump_sigspec(f, sig_ad);
1544 f << stringf(";\n");
1545 f << stringf("%s" " else ", indent.c_str());
1546 }
1547
1548 if (ff.has_srst && ff.has_ce && ff.ce_over_srst) {
1549 f << stringf("if (%s", ff.pol_ce ? "" : "!");
1550 dump_sigspec(f, ff.sig_ce);
1551 f << stringf(")\n");
1552 f << stringf("%s" " if (%s", indent.c_str(), ff.pol_srst ? "" : "!");
1553 dump_sigspec(f, ff.sig_srst);
1554 f << stringf(") %s <= ", reg_bit_name.c_str());
1555 dump_sigspec(f, val_srst);
1556 f << stringf(";\n");
1557 f << stringf("%s" " else ", indent.c_str());
1558 } else {
1559 if (ff.has_srst) {
1560 f << stringf("if (%s", ff.pol_srst ? "" : "!");
1561 dump_sigspec(f, ff.sig_srst);
1562 f << stringf(") %s <= ", reg_bit_name.c_str());
1563 dump_sigspec(f, val_srst);
1564 f << stringf(";\n");
1565 f << stringf("%s" " else ", indent.c_str());
1566 }
1567 if (ff.has_ce) {
1568 f << stringf("if (%s", ff.pol_ce ? "" : "!");
1569 dump_sigspec(f, ff.sig_ce);
1570 f << stringf(") ");
1571 }
1572 }
1573
1574 f << stringf("%s <= ", reg_bit_name.c_str());
1575 dump_sigspec(f, sig_d);
1576 f << stringf(";\n");
1577 }
1578 else
1579 {
1580 // Latches.
1581 f << stringf("%s" "always%s\n", indent.c_str(), systemverilog ? "_latch" : " @*");
1582
1583 f << stringf("%s" " ", indent.c_str());
1584 if (ff.has_sr) {
1585 f << stringf("if (%s", ff.pol_clr ? "" : "!");
1586 dump_sigspec(f, ff.sig_clr[i]);
1587 f << stringf(") %s = 1'b0;\n", reg_bit_name.c_str());
1588 f << stringf("%s" " else if (%s", indent.c_str(), ff.pol_set ? "" : "!");
1589 dump_sigspec(f, ff.sig_set[i]);
1590 f << stringf(") %s = 1'b1;\n", reg_bit_name.c_str());
1591 if (ff.has_aload)
1592 f << stringf("%s" " else ", indent.c_str());
1593 } else if (ff.has_arst) {
1594 f << stringf("if (%s", ff.pol_arst ? "" : "!");
1595 dump_sigspec(f, ff.sig_arst);
1596 f << stringf(") %s = ", reg_bit_name.c_str());
1597 dump_sigspec(f, val_arst);
1598 f << stringf(";\n");
1599 if (ff.has_aload)
1600 f << stringf("%s" " else ", indent.c_str());
1601 }
1602 if (ff.has_aload) {
1603 f << stringf("if (%s", ff.pol_aload ? "" : "!");
1604 dump_sigspec(f, ff.sig_aload);
1605 f << stringf(") %s = ", reg_bit_name.c_str());
1606 dump_sigspec(f, sig_ad);
1607 f << stringf(";\n");
1608 }
1609 }
1610 }
1611
1612 if (!out_is_reg_wire) {
1613 f << stringf("%s" "assign ", indent.c_str());
1614 dump_sigspec(f, ff.sig_q);
1615 f << stringf(" = %s;\n", reg_name.c_str());
1616 }
1617
1618 return true;
1619 }
1620
1621 if (cell->type.in(ID($assert), ID($assume), ID($cover)))
1622 {
1623 f << stringf("%s" "always%s if (", indent.c_str(), systemverilog ? "_comb" : " @*");
1624 dump_sigspec(f, cell->getPort(ID::EN));
1625 f << stringf(") %s(", cell->type.c_str()+1);
1626 dump_sigspec(f, cell->getPort(ID::A));
1627 f << stringf(");\n");
1628 return true;
1629 }
1630
1631 if (cell->type.in(ID($specify2), ID($specify3)))
1632 {
1633 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1634
1635 SigSpec en = cell->getPort(ID::EN);
1636 if (en != State::S1) {
1637 f << stringf("if (");
1638 dump_sigspec(f, cell->getPort(ID::EN));
1639 f << stringf(") ");
1640 }
1641
1642 f << "(";
1643 if (cell->type == ID($specify3) && cell->getParam(ID::EDGE_EN).as_bool())
1644 f << (cell->getParam(ID::EDGE_POL).as_bool() ? "posedge ": "negedge ");
1645
1646 dump_sigspec(f, cell->getPort(ID::SRC));
1647
1648 f << " ";
1649 if (cell->getParam(ID::SRC_DST_PEN).as_bool())
1650 f << (cell->getParam(ID::SRC_DST_POL).as_bool() ? "+": "-");
1651 f << (cell->getParam(ID::FULL).as_bool() ? "*> ": "=> ");
1652
1653 if (cell->type == ID($specify3)) {
1654 f << "(";
1655 dump_sigspec(f, cell->getPort(ID::DST));
1656 f << " ";
1657 if (cell->getParam(ID::DAT_DST_PEN).as_bool())
1658 f << (cell->getParam(ID::DAT_DST_POL).as_bool() ? "+": "-");
1659 f << ": ";
1660 dump_sigspec(f, cell->getPort(ID::DAT));
1661 f << ")";
1662 } else {
1663 dump_sigspec(f, cell->getPort(ID::DST));
1664 }
1665
1666 bool bak_decimal = decimal;
1667 decimal = 1;
1668
1669 f << ") = (";
1670 dump_const(f, cell->getParam(ID::T_RISE_MIN));
1671 f << ":";
1672 dump_const(f, cell->getParam(ID::T_RISE_TYP));
1673 f << ":";
1674 dump_const(f, cell->getParam(ID::T_RISE_MAX));
1675 f << ", ";
1676 dump_const(f, cell->getParam(ID::T_FALL_MIN));
1677 f << ":";
1678 dump_const(f, cell->getParam(ID::T_FALL_TYP));
1679 f << ":";
1680 dump_const(f, cell->getParam(ID::T_FALL_MAX));
1681 f << ");\n";
1682
1683 decimal = bak_decimal;
1684
1685 f << stringf("%s" "endspecify\n", indent.c_str());
1686 return true;
1687 }
1688
1689 if (cell->type == ID($specrule))
1690 {
1691 f << stringf("%s" "specify\n%s ", indent.c_str(), indent.c_str());
1692
1693 IdString spec_type = cell->getParam(ID::TYPE).decode_string();
1694 f << stringf("%s(", spec_type.c_str());
1695
1696 if (cell->getParam(ID::SRC_PEN).as_bool())
1697 f << (cell->getParam(ID::SRC_POL).as_bool() ? "posedge ": "negedge ");
1698 dump_sigspec(f, cell->getPort(ID::SRC));
1699
1700 if (cell->getPort(ID::SRC_EN) != State::S1) {
1701 f << " &&& ";
1702 dump_sigspec(f, cell->getPort(ID::SRC_EN));
1703 }
1704
1705 f << ", ";
1706 if (cell->getParam(ID::DST_PEN).as_bool())
1707 f << (cell->getParam(ID::DST_POL).as_bool() ? "posedge ": "negedge ");
1708 dump_sigspec(f, cell->getPort(ID::DST));
1709
1710 if (cell->getPort(ID::DST_EN) != State::S1) {
1711 f << " &&& ";
1712 dump_sigspec(f, cell->getPort(ID::DST_EN));
1713 }
1714
1715 bool bak_decimal = decimal;
1716 decimal = 1;
1717
1718 f << ", ";
1719 dump_const(f, cell->getParam(ID::T_LIMIT_MIN));
1720 f << ": ";
1721 dump_const(f, cell->getParam(ID::T_LIMIT_TYP));
1722 f << ": ";
1723 dump_const(f, cell->getParam(ID::T_LIMIT_MAX));
1724
1725 if (spec_type.in(ID($setuphold), ID($recrem), ID($fullskew))) {
1726 f << ", ";
1727 dump_const(f, cell->getParam(ID::T_LIMIT2_MIN));
1728 f << ": ";
1729 dump_const(f, cell->getParam(ID::T_LIMIT2_TYP));
1730 f << ": ";
1731 dump_const(f, cell->getParam(ID::T_LIMIT2_MAX));
1732 }
1733
1734 f << ");\n";
1735 decimal = bak_decimal;
1736
1737 f << stringf("%s" "endspecify\n", indent.c_str());
1738 return true;
1739 }
1740
1741 // FIXME: $fsm
1742
1743 return false;
1744 }
1745
dump_cell(std::ostream & f,std::string indent,RTLIL::Cell * cell)1746 void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
1747 {
1748 // Handled by dump_memory
1749 if (cell->is_mem_cell())
1750 return;
1751
1752 if (cell->type[0] == '$' && !noexpr) {
1753 if (dump_cell_expr(f, indent, cell))
1754 return;
1755 }
1756
1757 dump_attributes(f, indent, cell->attributes);
1758 f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
1759
1760 if (!defparam && cell->parameters.size() > 0) {
1761 f << stringf(" #(");
1762 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1763 if (it != cell->parameters.begin())
1764 f << stringf(",");
1765 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1766 dump_const(f, it->second);
1767 f << stringf(")");
1768 }
1769 f << stringf("\n%s" ")", indent.c_str());
1770 }
1771
1772 std::string cell_name = cellname(cell);
1773 if (cell_name != id(cell->name))
1774 f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
1775 else
1776 f << stringf(" %s (", cell_name.c_str());
1777
1778 bool first_arg = true;
1779 std::set<RTLIL::IdString> numbered_ports;
1780 for (int i = 1; true; i++) {
1781 char str[16];
1782 snprintf(str, 16, "$%d", i);
1783 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1784 if (it->first != str)
1785 continue;
1786 if (!first_arg)
1787 f << stringf(",");
1788 first_arg = false;
1789 f << stringf("\n%s ", indent.c_str());
1790 dump_sigspec(f, it->second);
1791 numbered_ports.insert(it->first);
1792 goto found_numbered_port;
1793 }
1794 break;
1795 found_numbered_port:;
1796 }
1797 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
1798 if (numbered_ports.count(it->first))
1799 continue;
1800 if (!first_arg)
1801 f << stringf(",");
1802 first_arg = false;
1803 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
1804 if (it->second.size() > 0)
1805 dump_sigspec(f, it->second);
1806 f << stringf(")");
1807 }
1808 f << stringf("\n%s" ");\n", indent.c_str());
1809
1810 if (defparam && cell->parameters.size() > 0) {
1811 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); ++it) {
1812 f << stringf("%sdefparam %s.%s = ", indent.c_str(), cell_name.c_str(), id(it->first).c_str());
1813 dump_const(f, it->second);
1814 f << stringf(";\n");
1815 }
1816 }
1817
1818 if (siminit && RTLIL::builtin_ff_cell_types().count(cell->type) && cell->hasPort(ID::Q) && !cell->type.in(ID($ff), ID($_FF_))) {
1819 std::stringstream ss;
1820 dump_reg_init(ss, cell->getPort(ID::Q));
1821 if (!ss.str().empty()) {
1822 f << stringf("%sinitial %s.Q", indent.c_str(), cell_name.c_str());
1823 f << ss.str();
1824 f << ";\n";
1825 }
1826 }
1827 }
1828
dump_conn(std::ostream & f,std::string indent,const RTLIL::SigSpec & left,const RTLIL::SigSpec & right)1829 void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
1830 {
1831 if (simple_lhs) {
1832 int offset = 0;
1833 for (auto &chunk : left.chunks()) {
1834 f << stringf("%s" "assign ", indent.c_str());
1835 dump_sigspec(f, chunk);
1836 f << stringf(" = ");
1837 dump_sigspec(f, right.extract(offset, GetSize(chunk)));
1838 f << stringf(";\n");
1839 offset += GetSize(chunk);
1840 }
1841 } else {
1842 f << stringf("%s" "assign ", indent.c_str());
1843 dump_sigspec(f, left);
1844 f << stringf(" = ");
1845 dump_sigspec(f, right);
1846 f << stringf(";\n");
1847 }
1848 }
1849
1850 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
1851
dump_case_body(std::ostream & f,std::string indent,RTLIL::CaseRule * cs,bool omit_trailing_begin=false)1852 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
1853 {
1854 int number_of_stmts = cs->switches.size() + cs->actions.size();
1855
1856 if (!omit_trailing_begin && number_of_stmts >= 2)
1857 f << stringf("%s" "begin\n", indent.c_str());
1858
1859 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1860 if (it->first.size() == 0)
1861 continue;
1862 f << stringf("%s ", indent.c_str());
1863 dump_sigspec(f, it->first);
1864 f << stringf(" = ");
1865 dump_sigspec(f, it->second);
1866 f << stringf(";\n");
1867 }
1868
1869 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1870 dump_proc_switch(f, indent + " ", *it);
1871
1872 if (!omit_trailing_begin && number_of_stmts == 0)
1873 f << stringf("%s /* empty */;\n", indent.c_str());
1874
1875 if (omit_trailing_begin || number_of_stmts >= 2)
1876 f << stringf("%s" "end\n", indent.c_str());
1877 }
1878
dump_proc_switch(std::ostream & f,std::string indent,RTLIL::SwitchRule * sw)1879 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
1880 {
1881 if (sw->signal.size() == 0) {
1882 f << stringf("%s" "begin\n", indent.c_str());
1883 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1884 if ((*it)->compare.size() == 0)
1885 dump_case_body(f, indent + " ", *it);
1886 }
1887 f << stringf("%s" "end\n", indent.c_str());
1888 return;
1889 }
1890
1891 dump_attributes(f, indent, sw->attributes);
1892 f << stringf("%s" "casez (", indent.c_str());
1893 dump_sigspec(f, sw->signal);
1894 f << stringf(")\n");
1895
1896 bool got_default = false;
1897 for (auto it = sw->cases.begin(); it != sw->cases.end(); ++it) {
1898 dump_attributes(f, indent + " ", (*it)->attributes, '\n', /*modattr=*/false, /*regattr=*/false, /*as_comment=*/true);
1899 if ((*it)->compare.size() == 0) {
1900 if (got_default)
1901 continue;
1902 f << stringf("%s default", indent.c_str());
1903 got_default = true;
1904 } else {
1905 f << stringf("%s ", indent.c_str());
1906 for (size_t i = 0; i < (*it)->compare.size(); i++) {
1907 if (i > 0)
1908 f << stringf(", ");
1909 dump_sigspec(f, (*it)->compare[i]);
1910 }
1911 }
1912 f << stringf(":\n");
1913 dump_case_body(f, indent + " ", *it);
1914 }
1915
1916 f << stringf("%s" "endcase\n", indent.c_str());
1917 }
1918
case_body_find_regs(RTLIL::CaseRule * cs)1919 void case_body_find_regs(RTLIL::CaseRule *cs)
1920 {
1921 for (auto it = cs->switches.begin(); it != cs->switches.end(); ++it)
1922 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
1923 case_body_find_regs(*it2);
1924
1925 for (auto it = cs->actions.begin(); it != cs->actions.end(); ++it) {
1926 for (auto &c : it->first.chunks())
1927 if (c.wire != NULL)
1928 reg_wires.insert(c.wire->name);
1929 }
1930 }
1931
dump_process(std::ostream & f,std::string indent,RTLIL::Process * proc,bool find_regs=false)1932 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
1933 {
1934 if (find_regs) {
1935 case_body_find_regs(&proc->root_case);
1936 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); ++it)
1937 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
1938 for (auto &c : it2->first.chunks())
1939 if (c.wire != NULL)
1940 reg_wires.insert(c.wire->name);
1941 }
1942 return;
1943 }
1944
1945 f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*");
1946 if (!systemverilog)
1947 f << indent + " " << "if (" << id(initial_id) << ") begin end\n";
1948 dump_case_body(f, indent, &proc->root_case, true);
1949
1950 std::string backup_indent = indent;
1951
1952 for (size_t i = 0; i < proc->syncs.size(); i++)
1953 {
1954 RTLIL::SyncRule *sync = proc->syncs[i];
1955 indent = backup_indent;
1956
1957 if (sync->type == RTLIL::STa) {
1958 f << stringf("%s" "always%s begin\n", indent.c_str(), systemverilog ? "_comb" : " @*");
1959 } else if (sync->type == RTLIL::STi) {
1960 f << stringf("%s" "initial begin\n", indent.c_str());
1961 } else {
1962 f << stringf("%s" "always%s @(", indent.c_str(), systemverilog ? "_ff" : "");
1963 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
1964 f << stringf("posedge ");
1965 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
1966 f << stringf("negedge ");
1967 dump_sigspec(f, sync->signal);
1968 f << stringf(") begin\n");
1969 }
1970 std::string ends = indent + "end\n";
1971 indent += " ";
1972
1973 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
1974 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
1975 dump_sigspec(f, sync->signal);
1976 f << stringf(") begin\n");
1977 ends = indent + "end\n" + ends;
1978 indent += " ";
1979 }
1980
1981 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
1982 for (size_t j = 0; j < proc->syncs.size(); j++) {
1983 RTLIL::SyncRule *sync2 = proc->syncs[j];
1984 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
1985 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
1986 dump_sigspec(f, sync2->signal);
1987 f << stringf(") begin\n");
1988 ends = indent + "end\n" + ends;
1989 indent += " ";
1990 }
1991 }
1992 }
1993
1994 for (auto it = sync->actions.begin(); it != sync->actions.end(); ++it) {
1995 if (it->first.size() == 0)
1996 continue;
1997 f << stringf("%s ", indent.c_str());
1998 dump_sigspec(f, it->first);
1999 f << stringf(" <= ");
2000 dump_sigspec(f, it->second);
2001 f << stringf(";\n");
2002 }
2003
2004 f << stringf("%s", ends.c_str());
2005 }
2006 }
2007
dump_module(std::ostream & f,std::string indent,RTLIL::Module * module)2008 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
2009 {
2010 reg_wires.clear();
2011 reset_auto_counter(module);
2012 active_module = module;
2013 active_sigmap.set(module);
2014 active_initdata.clear();
2015
2016 for (auto wire : module->wires())
2017 if (wire->attributes.count(ID::init)) {
2018 SigSpec sig = active_sigmap(wire);
2019 Const val = wire->attributes.at(ID::init);
2020 for (int i = 0; i < GetSize(sig) && i < GetSize(val); i++)
2021 if (val[i] == State::S0 || val[i] == State::S1)
2022 active_initdata[sig[i]] = val[i];
2023 }
2024
2025 if (!module->processes.empty())
2026 log_warning("Module %s contains unmapped RTLIL processes. RTLIL processes\n"
2027 "can't always be mapped directly to Verilog always blocks. Unintended\n"
2028 "changes in simulation behavior are possible! Use \"proc\" to convert\n"
2029 "processes to logic networks and registers.\n", log_id(module));
2030
2031 f << stringf("\n");
2032 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
2033 dump_process(f, indent + " ", it->second, true);
2034
2035 if (!noexpr)
2036 {
2037 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
2038 for (auto cell : module->cells())
2039 {
2040 if (!RTLIL::builtin_ff_cell_types().count(cell->type) || !cell->hasPort(ID::Q) || cell->type.in(ID($ff), ID($_FF_)))
2041 continue;
2042
2043 RTLIL::SigSpec sig = cell->getPort(ID::Q);
2044
2045 if (sig.is_chunk()) {
2046 RTLIL::SigChunk chunk = sig.as_chunk();
2047 if (chunk.wire != NULL)
2048 for (int i = 0; i < chunk.width; i++)
2049 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
2050 }
2051 }
2052 for (auto wire : module->wires())
2053 {
2054 for (int i = 0; i < wire->width; i++)
2055 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
2056 goto this_wire_aint_reg;
2057 if (wire->width)
2058 reg_wires.insert(wire->name);
2059 this_wire_aint_reg:;
2060 }
2061 }
2062
2063 dump_attributes(f, indent, module->attributes, '\n', /*modattr=*/true);
2064 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
2065 bool keep_running = true;
2066 int cnt = 0;
2067 for (int port_id = 1; keep_running; port_id++) {
2068 keep_running = false;
2069 for (auto wire : module->wires()) {
2070 if (wire->port_id == port_id) {
2071 if (port_id != 1)
2072 f << stringf(", ");
2073 f << stringf("%s", id(wire->name).c_str());
2074 keep_running = true;
2075 if (cnt==20) { f << stringf("\n"); cnt = 0; } else cnt++;
2076 continue;
2077 }
2078 }
2079 }
2080 f << stringf(");\n");
2081 if (!systemverilog && !module->processes.empty()) {
2082 initial_id = NEW_ID;
2083 f << indent + " " << "reg " << id(initial_id) << " = 0;\n";
2084 }
2085
2086 for (auto w : module->wires())
2087 dump_wire(f, indent + " ", w);
2088
2089 for (auto &mem : Mem::get_all_memories(module))
2090 dump_memory(f, indent + " ", mem);
2091
2092 for (auto cell : module->cells())
2093 dump_cell(f, indent + " ", cell);
2094
2095 for (auto it = module->processes.begin(); it != module->processes.end(); ++it)
2096 dump_process(f, indent + " ", it->second);
2097
2098 for (auto it = module->connections().begin(); it != module->connections().end(); ++it)
2099 dump_conn(f, indent + " ", it->first, it->second);
2100
2101 f << stringf("%s" "endmodule\n", indent.c_str());
2102 active_module = NULL;
2103 active_sigmap.clear();
2104 active_initdata.clear();
2105 }
2106
2107 struct VerilogBackend : public Backend {
VerilogBackendVerilogBackend2108 VerilogBackend() : Backend("verilog", "write design to Verilog file") { }
helpVerilogBackend2109 void help() override
2110 {
2111 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
2112 log("\n");
2113 log(" write_verilog [options] [filename]\n");
2114 log("\n");
2115 log("Write the current design to a Verilog file.\n");
2116 log("\n");
2117 log(" -sv\n");
2118 log(" with this option, SystemVerilog constructs like always_comb are used\n");
2119 log("\n");
2120 log(" -norename\n");
2121 log(" without this option all internal object names (the ones with a dollar\n");
2122 log(" instead of a backslash prefix) are changed to short names in the\n");
2123 log(" format '_<number>_'.\n");
2124 log("\n");
2125 log(" -renameprefix <prefix>\n");
2126 log(" insert this prefix in front of auto-generated instance names\n");
2127 log("\n");
2128 log(" -noattr\n");
2129 log(" with this option no attributes are included in the output\n");
2130 log("\n");
2131 log(" -attr2comment\n");
2132 log(" with this option attributes are included as comments in the output\n");
2133 log("\n");
2134 log(" -noexpr\n");
2135 log(" without this option all internal cells are converted to Verilog\n");
2136 log(" expressions.\n");
2137 log("\n");
2138 log(" -siminit\n");
2139 log(" add initial statements with hierarchical refs to initialize FFs when\n");
2140 log(" in -noexpr mode.\n");
2141 log("\n");
2142 log(" -nodec\n");
2143 log(" 32-bit constant values are by default dumped as decimal numbers,\n");
2144 log(" not bit pattern. This option deactivates this feature and instead\n");
2145 log(" will write out all constants in binary.\n");
2146 log("\n");
2147 log(" -decimal\n");
2148 log(" dump 32-bit constants in decimal and without size and radix\n");
2149 log("\n");
2150 log(" -nohex\n");
2151 log(" constant values that are compatible with hex output are usually\n");
2152 log(" dumped as hex values. This option deactivates this feature and\n");
2153 log(" instead will write out all constants in binary.\n");
2154 log("\n");
2155 log(" -nostr\n");
2156 log(" Parameters and attributes that are specified as strings in the\n");
2157 log(" original input will be output as strings by this back-end. This\n");
2158 log(" deactivates this feature and instead will write string constants\n");
2159 log(" as binary numbers.\n");
2160 log("\n");
2161 log(" -simple-lhs\n");
2162 log(" Connection assignments with simple left hand side without concatenations.\n");
2163 log("\n");
2164 log(" -extmem\n");
2165 log(" instead of initializing memories using assignments to individual\n");
2166 log(" elements, use the '$readmemh' function to read initialization data\n");
2167 log(" from a file. This data is written to a file named by appending\n");
2168 log(" a sequential index to the Verilog filename and replacing the extension\n");
2169 log(" with '.mem', e.g. 'write_verilog -extmem foo.v' writes 'foo-1.mem',\n");
2170 log(" 'foo-2.mem' and so on.\n");
2171 log("\n");
2172 log(" -defparam\n");
2173 log(" use 'defparam' statements instead of the Verilog-2001 syntax for\n");
2174 log(" cell parameters.\n");
2175 log("\n");
2176 log(" -blackboxes\n");
2177 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
2178 log(" this option set only the modules with the 'blackbox' attribute\n");
2179 log(" are written to the output file.\n");
2180 log("\n");
2181 log(" -selected\n");
2182 log(" only write selected modules. modules must be selected entirely or\n");
2183 log(" not at all.\n");
2184 log("\n");
2185 log(" -v\n");
2186 log(" verbose output (print new names of all renamed wires and cells)\n");
2187 log("\n");
2188 log("Note that RTLIL processes can't always be mapped directly to Verilog\n");
2189 log("always blocks. This frontend should only be used to export an RTLIL\n");
2190 log("netlist, i.e. after the \"proc\" pass has been used to convert all\n");
2191 log("processes to logic networks and registers. A warning is generated when\n");
2192 log("this command is called on a design with RTLIL processes.\n");
2193 log("\n");
2194 }
executeVerilogBackend2195 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) override
2196 {
2197 log_header(design, "Executing Verilog backend.\n");
2198
2199 verbose = false;
2200 norename = false;
2201 noattr = false;
2202 attr2comment = false;
2203 noexpr = false;
2204 nodec = false;
2205 nohex = false;
2206 nostr = false;
2207 extmem = false;
2208 defparam = false;
2209 decimal = false;
2210 siminit = false;
2211 simple_lhs = false;
2212 auto_prefix = "";
2213
2214 bool blackboxes = false;
2215 bool selected = false;
2216
2217 auto_name_map.clear();
2218 reg_wires.clear();
2219
2220 size_t argidx;
2221 for (argidx = 1; argidx < args.size(); argidx++) {
2222 std::string arg = args[argidx];
2223 if (arg == "-sv") {
2224 systemverilog = true;
2225 continue;
2226 }
2227 if (arg == "-norename") {
2228 norename = true;
2229 continue;
2230 }
2231 if (arg == "-renameprefix" && argidx+1 < args.size()) {
2232 auto_prefix = args[++argidx];
2233 continue;
2234 }
2235 if (arg == "-noattr") {
2236 noattr = true;
2237 continue;
2238 }
2239 if (arg == "-attr2comment") {
2240 attr2comment = true;
2241 continue;
2242 }
2243 if (arg == "-noexpr") {
2244 noexpr = true;
2245 continue;
2246 }
2247 if (arg == "-nodec") {
2248 nodec = true;
2249 continue;
2250 }
2251 if (arg == "-nohex") {
2252 nohex = true;
2253 continue;
2254 }
2255 if (arg == "-nostr") {
2256 nostr = true;
2257 continue;
2258 }
2259 if (arg == "-extmem") {
2260 extmem = true;
2261 extmem_counter = 1;
2262 continue;
2263 }
2264 if (arg == "-defparam") {
2265 defparam = true;
2266 continue;
2267 }
2268 if (arg == "-decimal") {
2269 decimal = true;
2270 continue;
2271 }
2272 if (arg == "-siminit") {
2273 siminit = true;
2274 continue;
2275 }
2276 if (arg == "-blackboxes") {
2277 blackboxes = true;
2278 continue;
2279 }
2280 if (arg == "-selected") {
2281 selected = true;
2282 continue;
2283 }
2284 if (arg == "-simple-lhs") {
2285 simple_lhs = true;
2286 continue;
2287 }
2288 if (arg == "-v") {
2289 verbose = true;
2290 continue;
2291 }
2292 break;
2293 }
2294 extra_args(f, filename, args, argidx);
2295 if (extmem)
2296 {
2297 if (filename == "<stdout>")
2298 log_cmd_error("Option -extmem must be used with a filename.\n");
2299 extmem_prefix = filename.substr(0, filename.rfind('.'));
2300 }
2301
2302 design->sort();
2303
2304 *f << stringf("/* Generated by %s */\n", yosys_version_str);
2305 for (auto module : design->modules()) {
2306 if (module->get_blackbox_attribute() != blackboxes)
2307 continue;
2308 if (selected && !design->selected_whole_module(module->name)) {
2309 if (design->selected_module(module->name))
2310 log_cmd_error("Can't handle partially selected module %s!\n", log_id(module->name));
2311 continue;
2312 }
2313 log("Dumping module `%s'.\n", module->name.c_str());
2314 dump_module(*f, "", module);
2315 }
2316
2317 auto_name_map.clear();
2318 reg_wires.clear();
2319 }
2320 } VerilogBackend;
2321
2322 PRIVATE_NAMESPACE_END
2323