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 &reg_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 &reg : 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