namespace Yosys
[yosys.git] / backends / verilog / verilog_backend.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
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 * Note that RTLIL processes can't always be mapped easily to a Verilog
23 * process. Therefore this frontend should only be used to export a
24 * Verilog netlist (i.e. after the "proc" pass has converted all processes
25 * to logic networks and registers).
26 *
27 */
28
29 #include "kernel/register.h"
30 #include "kernel/celltypes.h"
31 #include "kernel/log.h"
32 #include <string>
33 #include <sstream>
34 #include <set>
35 #include <map>
36
37 USING_YOSYS_NAMESPACE
38 PRIVATE_NAMESPACE_BEGIN
39
40 bool norename, noattr, attr2comment, noexpr;
41 int auto_name_counter, auto_name_offset, auto_name_digits;
42 std::map<RTLIL::IdString, int> auto_name_map;
43 std::set<RTLIL::IdString> reg_wires, reg_ct;
44
45 RTLIL::Module *active_module;
46
47 void reset_auto_counter_id(RTLIL::IdString id, bool may_rename)
48 {
49 const char *str = id.c_str();
50
51 if (*str == '$' && may_rename && !norename)
52 auto_name_map[id] = auto_name_counter++;
53
54 if (str[0] != '_' && str[1] != 0)
55 return;
56 for (int i = 0; str[i] != 0; i++) {
57 if (str[i] == '_')
58 continue;
59 if (str[i] < '0' || str[i] > '9')
60 return;
61 }
62
63 int num = atoi(str+1);
64 if (num >= auto_name_offset)
65 auto_name_offset = num + 1;
66 }
67
68 void reset_auto_counter(RTLIL::Module *module)
69 {
70 auto_name_map.clear();
71 auto_name_counter = 0;
72 auto_name_offset = 0;
73
74 reset_auto_counter_id(module->name, false);
75
76 for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
77 reset_auto_counter_id(it->second->name, true);
78
79 for (auto it = module->cells_.begin(); it != module->cells_.end(); it++) {
80 reset_auto_counter_id(it->second->name, true);
81 reset_auto_counter_id(it->second->type, false);
82 }
83
84 for (auto it = module->processes.begin(); it != module->processes.end(); it++)
85 reset_auto_counter_id(it->second->name, false);
86
87 auto_name_digits = 1;
88 for (size_t i = 10; i < auto_name_offset + auto_name_map.size(); i = i*10)
89 auto_name_digits++;
90
91 for (auto it = auto_name_map.begin(); it != auto_name_map.end(); it++)
92 log(" renaming `%s' to `_%0*d_'.\n", it->first.c_str(), auto_name_digits, auto_name_offset + it->second);
93 }
94
95 std::string id(RTLIL::IdString internal_id, bool may_rename = true)
96 {
97 const char *str = internal_id.c_str();
98 bool do_escape = false;
99
100 if (may_rename && auto_name_map.count(internal_id) != 0) {
101 char buffer[100];
102 snprintf(buffer, 100, "_%0*d_", auto_name_digits, auto_name_offset + auto_name_map[internal_id]);
103 return std::string(buffer);
104 }
105
106 if (*str == '\\')
107 str++;
108
109 if ('0' <= *str && *str <= '9')
110 do_escape = true;
111
112 for (int i = 0; str[i]; i++)
113 {
114 if ('0' <= str[i] && str[i] <= '9')
115 continue;
116 if ('a' <= str[i] && str[i] <= 'z')
117 continue;
118 if ('A' <= str[i] && str[i] <= 'Z')
119 continue;
120 if (str[i] == '_')
121 continue;
122 do_escape = true;
123 break;
124 }
125
126 if (do_escape)
127 return "\\" + std::string(str) + " ";
128 return std::string(str);
129 }
130
131 bool is_reg_wire(RTLIL::SigSpec sig, std::string &reg_name)
132 {
133 if (!sig.is_chunk() || sig.as_chunk().wire == NULL)
134 return false;
135
136 RTLIL::SigChunk chunk = sig.as_chunk();
137
138 if (reg_wires.count(chunk.wire->name) == 0)
139 return false;
140
141 reg_name = id(chunk.wire->name);
142 if (sig.size() != chunk.wire->width) {
143 if (sig.size() == 1)
144 reg_name += stringf("[%d]", chunk.wire->start_offset + chunk.offset);
145 else
146 reg_name += stringf("[%d:%d]", chunk.wire->start_offset + chunk.offset + chunk.width - 1,
147 chunk.wire->start_offset + chunk.offset);
148 }
149
150 return true;
151 }
152
153 void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool no_decimal = false, bool set_signed = false)
154 {
155 if (width < 0)
156 width = data.bits.size() - offset;
157 if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
158 if (width == 32 && !no_decimal) {
159 int32_t val = 0;
160 for (int i = offset+width-1; i >= offset; i--) {
161 log_assert(i < (int)data.bits.size());
162 if (data.bits[i] != RTLIL::S0 && data.bits[i] != RTLIL::S1)
163 goto dump_bits;
164 if (data.bits[i] == RTLIL::S1 && (i - offset) == 31)
165 goto dump_bits;
166 if (data.bits[i] == RTLIL::S1)
167 val |= 1 << (i - offset);
168 }
169 f << stringf("32'%sd%d", set_signed ? "s" : "", val);
170 } else {
171 dump_bits:
172 f << stringf("%d'%sb", width, set_signed ? "s" : "");
173 if (width == 0)
174 f << stringf("0");
175 for (int i = offset+width-1; i >= offset; i--) {
176 log_assert(i < (int)data.bits.size());
177 switch (data.bits[i]) {
178 case RTLIL::S0: f << stringf("0"); break;
179 case RTLIL::S1: f << stringf("1"); break;
180 case RTLIL::Sx: f << stringf("x"); break;
181 case RTLIL::Sz: f << stringf("z"); break;
182 case RTLIL::Sa: f << stringf("z"); break;
183 case RTLIL::Sm: log_error("Found marker state in final netlist.");
184 }
185 }
186 }
187 } else {
188 f << stringf("\"");
189 std::string str = data.decode_string();
190 for (size_t i = 0; i < str.size(); i++) {
191 if (str[i] == '\n')
192 f << stringf("\\n");
193 else if (str[i] == '\t')
194 f << stringf("\\t");
195 else if (str[i] < 32)
196 f << stringf("\\%03o", str[i]);
197 else if (str[i] == '"')
198 f << stringf("\\\"");
199 else if (str[i] == '\\')
200 f << stringf("\\\\");
201 else
202 f << str[i];
203 }
204 f << stringf("\"");
205 }
206 }
207
208 void dump_sigchunk(std::ostream &f, const RTLIL::SigChunk &chunk, bool no_decimal = false)
209 {
210 if (chunk.wire == NULL) {
211 dump_const(f, chunk.data, chunk.width, chunk.offset, no_decimal);
212 } else {
213 if (chunk.width == chunk.wire->width && chunk.offset == 0) {
214 f << stringf("%s", id(chunk.wire->name).c_str());
215 } else if (chunk.width == 1) {
216 if (chunk.wire->upto)
217 f << stringf("%s[%d]", id(chunk.wire->name).c_str(), (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
218 else
219 f << stringf("%s[%d]", id(chunk.wire->name).c_str(), chunk.offset + chunk.wire->start_offset);
220 } else {
221 if (chunk.wire->upto)
222 f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
223 (chunk.wire->width - (chunk.offset + chunk.width - 1) - 1) + chunk.wire->start_offset,
224 (chunk.wire->width - chunk.offset - 1) + chunk.wire->start_offset);
225 else
226 f << stringf("%s[%d:%d]", id(chunk.wire->name).c_str(),
227 (chunk.offset + chunk.width - 1) + chunk.wire->start_offset,
228 chunk.offset + chunk.wire->start_offset);
229 }
230 }
231 }
232
233 void dump_sigspec(std::ostream &f, const RTLIL::SigSpec &sig)
234 {
235 if (sig.is_chunk()) {
236 dump_sigchunk(f, sig.as_chunk());
237 } else {
238 f << stringf("{ ");
239 for (auto it = sig.chunks().rbegin(); it != sig.chunks().rend(); it++) {
240 if (it != sig.chunks().rbegin())
241 f << stringf(", ");
242 dump_sigchunk(f, *it, true);
243 }
244 f << stringf(" }");
245 }
246 }
247
248 void dump_attributes(std::ostream &f, std::string indent, std::map<RTLIL::IdString, RTLIL::Const> &attributes, char term = '\n')
249 {
250 if (noattr)
251 return;
252 for (auto it = attributes.begin(); it != attributes.end(); it++) {
253 f << stringf("%s" "%s %s", indent.c_str(), attr2comment ? "/*" : "(*", id(it->first).c_str());
254 f << stringf(" = ");
255 dump_const(f, it->second);
256 f << stringf(" %s%c", attr2comment ? "*/" : "*)", term);
257 }
258 }
259
260 void dump_wire(std::ostream &f, std::string indent, RTLIL::Wire *wire)
261 {
262 dump_attributes(f, indent, wire->attributes);
263 #if 0
264 if (wire->port_input && !wire->port_output)
265 f << stringf("%s" "input %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
266 else if (!wire->port_input && wire->port_output)
267 f << stringf("%s" "output %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
268 else if (wire->port_input && wire->port_output)
269 f << stringf("%s" "inout %s", indent.c_str(), reg_wires.count(wire->name) ? "reg " : "");
270 else
271 f << stringf("%s" "%s ", indent.c_str(), reg_wires.count(wire->name) ? "reg" : "wire");
272 if (wire->width != 1)
273 f << stringf("[%d:%d] ", wire->width - 1 + wire->start_offset, wire->start_offset);
274 f << stringf("%s;\n", id(wire->name).c_str());
275 #else
276 // do not use Verilog-2k "outut reg" syntax in verilog export
277 std::string range = "";
278 if (wire->width != 1) {
279 if (wire->upto)
280 range = stringf(" [%d:%d]", wire->start_offset, wire->width - 1 + wire->start_offset);
281 else
282 range = stringf(" [%d:%d]", wire->width - 1 + wire->start_offset, wire->start_offset);
283 }
284 if (wire->port_input && !wire->port_output)
285 f << stringf("%s" "input%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
286 if (!wire->port_input && wire->port_output)
287 f << stringf("%s" "output%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
288 if (wire->port_input && wire->port_output)
289 f << stringf("%s" "inout%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
290 if (reg_wires.count(wire->name))
291 f << stringf("%s" "reg%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
292 else if (!wire->port_input && !wire->port_output)
293 f << stringf("%s" "wire%s %s;\n", indent.c_str(), range.c_str(), id(wire->name).c_str());
294 #endif
295 }
296
297 void dump_memory(std::ostream &f, std::string indent, RTLIL::Memory *memory)
298 {
299 dump_attributes(f, indent, memory->attributes);
300 f << stringf("%s" "reg [%d:0] %s [%d:0];\n", indent.c_str(), memory->width-1, id(memory->name).c_str(), memory->size-1);
301 }
302
303 void dump_cell_expr_port(std::ostream &f, RTLIL::Cell *cell, std::string port, bool gen_signed = true)
304 {
305 if (gen_signed && cell->parameters.count("\\" + port + "_SIGNED") > 0 && cell->parameters["\\" + port + "_SIGNED"].as_bool()) {
306 f << stringf("$signed(");
307 dump_sigspec(f, cell->getPort("\\" + port));
308 f << stringf(")");
309 } else
310 dump_sigspec(f, cell->getPort("\\" + port));
311 }
312
313 std::string cellname(RTLIL::Cell *cell)
314 {
315 if (!norename && cell->name[0] == '$' && reg_ct.count(cell->type) && cell->hasPort("\\Q"))
316 {
317 RTLIL::SigSpec sig = cell->getPort("\\Q");
318 if (SIZE(sig) != 1 || sig.is_fully_const())
319 goto no_special_reg_name;
320
321 RTLIL::Wire *wire = sig[0].wire;
322
323 if (wire->name[0] != '\\')
324 goto no_special_reg_name;
325
326 std::string cell_name = wire->name.str();
327
328 size_t pos = cell_name.find('[');
329 if (pos != std::string::npos)
330 cell_name = cell_name.substr(0, pos) + "_reg" + cell_name.substr(pos);
331 else
332 cell_name = cell_name + "_reg";
333
334 if (wire->width != 1)
335 cell_name += stringf("[%d]", wire->start_offset + sig[0].offset);
336
337 if (active_module && active_module->count_id(cell_name) > 0)
338 goto no_special_reg_name;
339
340 return id(cell_name);
341 }
342 else
343 {
344 no_special_reg_name:
345 return id(cell->name).c_str();
346 }
347 }
348
349 void dump_cell_expr_uniop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
350 {
351 f << stringf("%s" "assign ", indent.c_str());
352 dump_sigspec(f, cell->getPort("\\Y"));
353 f << stringf(" = %s ", op.c_str());
354 dump_attributes(f, "", cell->attributes, ' ');
355 dump_cell_expr_port(f, cell, "A", true);
356 f << stringf(";\n");
357 }
358
359 void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell, std::string op)
360 {
361 f << stringf("%s" "assign ", indent.c_str());
362 dump_sigspec(f, cell->getPort("\\Y"));
363 f << stringf(" = ");
364 dump_cell_expr_port(f, cell, "A", true);
365 f << stringf(" %s ", op.c_str());
366 dump_attributes(f, "", cell->attributes, ' ');
367 dump_cell_expr_port(f, cell, "B", true);
368 f << stringf(";\n");
369 }
370
371 bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
372 {
373 if (cell->type == "$_NOT_") {
374 f << stringf("%s" "assign ", indent.c_str());
375 dump_sigspec(f, cell->getPort("\\Y"));
376 f << stringf(" = ");
377 f << stringf("~");
378 dump_attributes(f, "", cell->attributes, ' ');
379 dump_cell_expr_port(f, cell, "A", false);
380 f << stringf(";\n");
381 return true;
382 }
383
384 if (cell->type.in("$_AND_", "$_NAND_", "$_OR_", "$_NOR_", "$_XOR_", "$_XNOR_")) {
385 f << stringf("%s" "assign ", indent.c_str());
386 dump_sigspec(f, cell->getPort("\\Y"));
387 f << stringf(" = ");
388 if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
389 f << stringf("~(");
390 dump_cell_expr_port(f, cell, "A", false);
391 f << stringf(" ");
392 if (cell->type.in("$_AND_", "$_NAND_"))
393 f << stringf("&");
394 if (cell->type.in("$_OR_", "$_NOR_"))
395 f << stringf("|");
396 if (cell->type.in("$_XOR_", "$_XNOR_"))
397 f << stringf("^");
398 dump_attributes(f, "", cell->attributes, ' ');
399 f << stringf(" ");
400 dump_cell_expr_port(f, cell, "B", false);
401 if (cell->type.in("$_NAND_", "$_NOR_", "$_XNOR_"))
402 f << stringf(")");
403 f << stringf(";\n");
404 return true;
405 }
406
407 if (cell->type == "$_MUX_") {
408 f << stringf("%s" "assign ", indent.c_str());
409 dump_sigspec(f, cell->getPort("\\Y"));
410 f << stringf(" = ");
411 dump_cell_expr_port(f, cell, "S", false);
412 f << stringf(" ? ");
413 dump_attributes(f, "", cell->attributes, ' ');
414 dump_cell_expr_port(f, cell, "B", false);
415 f << stringf(" : ");
416 dump_cell_expr_port(f, cell, "A", false);
417 f << stringf(";\n");
418 return true;
419 }
420
421 if (cell->type.in("$_AOI3_", "$_OAI3_")) {
422 f << stringf("%s" "assign ", indent.c_str());
423 dump_sigspec(f, cell->getPort("\\Y"));
424 f << stringf(" = ~((");
425 dump_cell_expr_port(f, cell, "A", false);
426 f << stringf(cell->type == "$_AOI3_" ? " & " : " | ");
427 dump_cell_expr_port(f, cell, "B", false);
428 f << stringf(cell->type == "$_AOI3_" ? ") |" : ") &");
429 dump_attributes(f, "", cell->attributes, ' ');
430 f << stringf(" ");
431 dump_cell_expr_port(f, cell, "C", false);
432 f << stringf(");\n");
433 return true;
434 }
435
436 if (cell->type.in("$_AOI4_", "$_OAI4_")) {
437 f << stringf("%s" "assign ", indent.c_str());
438 dump_sigspec(f, cell->getPort("\\Y"));
439 f << stringf(" = ~((");
440 dump_cell_expr_port(f, cell, "A", false);
441 f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
442 dump_cell_expr_port(f, cell, "B", false);
443 f << stringf(cell->type == "$_AOI4_" ? ") |" : ") &");
444 dump_attributes(f, "", cell->attributes, ' ');
445 f << stringf(" (");
446 dump_cell_expr_port(f, cell, "C", false);
447 f << stringf(cell->type == "$_AOI4_" ? " & " : " | ");
448 dump_cell_expr_port(f, cell, "D", false);
449 f << stringf("));\n");
450 return true;
451 }
452
453 if (cell->type.substr(0, 6) == "$_DFF_")
454 {
455 std::string reg_name = cellname(cell);
456 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
457
458 if (!out_is_reg_wire)
459 f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
460
461 dump_attributes(f, indent, cell->attributes);
462 f << stringf("%s" "always @(%sedge ", indent.c_str(), cell->type[6] == 'P' ? "pos" : "neg");
463 dump_sigspec(f, cell->getPort("\\C"));
464 if (cell->type[7] != '_') {
465 f << stringf(" or %sedge ", cell->type[7] == 'P' ? "pos" : "neg");
466 dump_sigspec(f, cell->getPort("\\R"));
467 }
468 f << stringf(")\n");
469
470 if (cell->type[7] != '_') {
471 f << stringf("%s" " if (%s", indent.c_str(), cell->type[7] == 'P' ? "" : "!");
472 dump_sigspec(f, cell->getPort("\\R"));
473 f << stringf(")\n");
474 f << stringf("%s" " %s <= %c;\n", indent.c_str(), reg_name.c_str(), cell->type[8]);
475 f << stringf("%s" " else\n", indent.c_str());
476 }
477
478 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
479 dump_cell_expr_port(f, cell, "D", false);
480 f << stringf(";\n");
481
482 if (!out_is_reg_wire) {
483 f << stringf("%s" "assign ", indent.c_str());
484 dump_sigspec(f, cell->getPort("\\Q"));
485 f << stringf(" = %s;\n", reg_name.c_str());
486 }
487
488 return true;
489 }
490
491 if (cell->type.substr(0, 8) == "$_DFFSR_")
492 {
493 char pol_c = cell->type[8], pol_s = cell->type[9], pol_r = cell->type[10];
494
495 std::string reg_name = cellname(cell);
496 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
497
498 if (!out_is_reg_wire)
499 f << stringf("%s" "reg %s;\n", indent.c_str(), reg_name.c_str());
500
501 dump_attributes(f, indent, cell->attributes);
502 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_c == 'P' ? "pos" : "neg");
503 dump_sigspec(f, cell->getPort("\\C"));
504 f << stringf(" or %sedge ", pol_s == 'P' ? "pos" : "neg");
505 dump_sigspec(f, cell->getPort("\\S"));
506 f << stringf(" or %sedge ", pol_r == 'P' ? "pos" : "neg");
507 dump_sigspec(f, cell->getPort("\\R"));
508 f << stringf(")\n");
509
510 f << stringf("%s" " if (%s", indent.c_str(), pol_r == 'P' ? "" : "!");
511 dump_sigspec(f, cell->getPort("\\R"));
512 f << stringf(")\n");
513 f << stringf("%s" " %s <= 0;\n", indent.c_str(), reg_name.c_str());
514
515 f << stringf("%s" " else if (%s", indent.c_str(), pol_s == 'P' ? "" : "!");
516 dump_sigspec(f, cell->getPort("\\S"));
517 f << stringf(")\n");
518 f << stringf("%s" " %s <= 1;\n", indent.c_str(), reg_name.c_str());
519
520 f << stringf("%s" " else\n", indent.c_str());
521 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
522 dump_cell_expr_port(f, cell, "D", false);
523 f << stringf(";\n");
524
525 if (!out_is_reg_wire) {
526 f << stringf("%s" "assign ", indent.c_str());
527 dump_sigspec(f, cell->getPort("\\Q"));
528 f << stringf(" = %s;\n", reg_name.c_str());
529 }
530
531 return true;
532 }
533
534 #define HANDLE_UNIOP(_type, _operator) \
535 if (cell->type ==_type) { dump_cell_expr_uniop(f, indent, cell, _operator); return true; }
536 #define HANDLE_BINOP(_type, _operator) \
537 if (cell->type ==_type) { dump_cell_expr_binop(f, indent, cell, _operator); return true; }
538
539 HANDLE_UNIOP("$not", "~")
540 HANDLE_UNIOP("$pos", "+")
541 HANDLE_UNIOP("$neg", "-")
542
543 HANDLE_BINOP("$and", "&")
544 HANDLE_BINOP("$or", "|")
545 HANDLE_BINOP("$xor", "^")
546 HANDLE_BINOP("$xnor", "~^")
547
548 HANDLE_UNIOP("$reduce_and", "&")
549 HANDLE_UNIOP("$reduce_or", "|")
550 HANDLE_UNIOP("$reduce_xor", "^")
551 HANDLE_UNIOP("$reduce_xnor", "~^")
552 HANDLE_UNIOP("$reduce_bool", "|")
553
554 HANDLE_BINOP("$shl", "<<")
555 HANDLE_BINOP("$shr", ">>")
556 HANDLE_BINOP("$sshl", "<<<")
557 HANDLE_BINOP("$sshr", ">>>")
558
559 HANDLE_BINOP("$lt", "<")
560 HANDLE_BINOP("$le", "<=")
561 HANDLE_BINOP("$eq", "==")
562 HANDLE_BINOP("$ne", "!=")
563 HANDLE_BINOP("$eqx", "===")
564 HANDLE_BINOP("$nex", "!==")
565 HANDLE_BINOP("$ge", ">=")
566 HANDLE_BINOP("$gt", ">")
567
568 HANDLE_BINOP("$add", "+")
569 HANDLE_BINOP("$sub", "-")
570 HANDLE_BINOP("$mul", "*")
571 HANDLE_BINOP("$div", "/")
572 HANDLE_BINOP("$mod", "%")
573 HANDLE_BINOP("$pow", "**")
574
575 HANDLE_UNIOP("$logic_not", "!")
576 HANDLE_BINOP("$logic_and", "&&")
577 HANDLE_BINOP("$logic_or", "||")
578
579 #undef HANDLE_UNIOP
580 #undef HANDLE_BINOP
581
582 if (cell->type == "$mux")
583 {
584 f << stringf("%s" "assign ", indent.c_str());
585 dump_sigspec(f, cell->getPort("\\Y"));
586 f << stringf(" = ");
587 dump_sigspec(f, cell->getPort("\\S"));
588 f << stringf(" ? ");
589 dump_attributes(f, "", cell->attributes, ' ');
590 dump_sigspec(f, cell->getPort("\\B"));
591 f << stringf(" : ");
592 dump_sigspec(f, cell->getPort("\\A"));
593 f << stringf(";\n");
594 return true;
595 }
596
597 if (cell->type == "$pmux" || cell->type == "$pmux_safe")
598 {
599 int width = cell->parameters["\\WIDTH"].as_int();
600 int s_width = cell->getPort("\\S").size();
601 std::string func_name = cellname(cell);
602
603 f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
604 f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
605 f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
606 f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
607
608 dump_attributes(f, indent + " ", cell->attributes);
609 if (cell->type != "$pmux_safe" && !noattr)
610 f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
611 f << stringf("%s" " casez (s)", indent.c_str());
612 if (cell->type != "$pmux_safe")
613 f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
614
615 for (int i = 0; i < s_width; i++)
616 {
617 f << stringf("%s" " %d'b", indent.c_str(), s_width);
618
619 for (int j = s_width-1; j >= 0; j--)
620 f << stringf("%c", j == i ? '1' : cell->type == "$pmux_safe" ? '0' : '?');
621
622 f << stringf(":\n");
623 f << stringf("%s" " %s = b[%d:%d];\n", indent.c_str(), func_name.c_str(), (i+1)*width-1, i*width);
624 }
625
626 f << stringf("%s" " default:\n", indent.c_str());
627 f << stringf("%s" " %s = a;\n", indent.c_str(), func_name.c_str());
628
629 f << stringf("%s" " endcase\n", indent.c_str());
630 f << stringf("%s" "endfunction\n", indent.c_str());
631
632 f << stringf("%s" "assign ", indent.c_str());
633 dump_sigspec(f, cell->getPort("\\Y"));
634 f << stringf(" = %s(", func_name.c_str());
635 dump_sigspec(f, cell->getPort("\\A"));
636 f << stringf(", ");
637 dump_sigspec(f, cell->getPort("\\B"));
638 f << stringf(", ");
639 dump_sigspec(f, cell->getPort("\\S"));
640 f << stringf(");\n");
641 return true;
642 }
643
644 if (cell->type == "$slice")
645 {
646 f << stringf("%s" "assign ", indent.c_str());
647 dump_sigspec(f, cell->getPort("\\Y"));
648 f << stringf(" = ");
649 dump_sigspec(f, cell->getPort("\\A"));
650 f << stringf(" >> %d;\n", cell->parameters.at("\\OFFSET").as_int());
651 return true;
652 }
653
654 if (cell->type == "$concat")
655 {
656 f << stringf("%s" "assign ", indent.c_str());
657 dump_sigspec(f, cell->getPort("\\Y"));
658 f << stringf(" = { ");
659 dump_sigspec(f, cell->getPort("\\B"));
660 f << stringf(" , ");
661 dump_sigspec(f, cell->getPort("\\A"));
662 f << stringf(" };\n");
663 return true;
664 }
665
666 if (cell->type == "$dff" || cell->type == "$adff")
667 {
668 RTLIL::SigSpec sig_clk, sig_arst, val_arst;
669 bool pol_clk, pol_arst = false;
670
671 sig_clk = cell->getPort("\\CLK");
672 pol_clk = cell->parameters["\\CLK_POLARITY"].as_bool();
673
674 if (cell->type == "$adff") {
675 sig_arst = cell->getPort("\\ARST");
676 pol_arst = cell->parameters["\\ARST_POLARITY"].as_bool();
677 val_arst = RTLIL::SigSpec(cell->parameters["\\ARST_VALUE"]);
678 }
679
680 std::string reg_name = cellname(cell);
681 bool out_is_reg_wire = is_reg_wire(cell->getPort("\\Q"), reg_name);
682
683 if (!out_is_reg_wire)
684 f << stringf("%s" "reg [%d:0] %s;\n", indent.c_str(), cell->parameters["\\WIDTH"].as_int()-1, reg_name.c_str());
685
686 f << stringf("%s" "always @(%sedge ", indent.c_str(), pol_clk ? "pos" : "neg");
687 dump_sigspec(f, sig_clk);
688 if (cell->type == "$adff") {
689 f << stringf(" or %sedge ", pol_arst ? "pos" : "neg");
690 dump_sigspec(f, sig_arst);
691 }
692 f << stringf(")\n");
693
694 if (cell->type == "$adff") {
695 f << stringf("%s" " if (%s", indent.c_str(), pol_arst ? "" : "!");
696 dump_sigspec(f, sig_arst);
697 f << stringf(")\n");
698 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
699 dump_sigspec(f, val_arst);
700 f << stringf(";\n");
701 f << stringf("%s" " else\n", indent.c_str());
702 }
703
704 f << stringf("%s" " %s <= ", indent.c_str(), reg_name.c_str());
705 dump_cell_expr_port(f, cell, "D", false);
706 f << stringf(";\n");
707
708 if (!out_is_reg_wire) {
709 f << stringf("%s" "assign ", indent.c_str());
710 dump_sigspec(f, cell->getPort("\\Q"));
711 f << stringf(" = %s;\n", reg_name.c_str());
712 }
713
714 return true;
715 }
716
717 // FIXME: $_SR_[PN][PN]_, $_DLATCH_[PN]_, $_DLATCHSR_[PN][PN][PN]_
718 // FIXME: $sr, $dffsr, $dlatch, $memrd, $memwr, $mem, $fsm
719
720 return false;
721 }
722
723 void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell)
724 {
725 if (cell->type[0] == '$' && !noexpr) {
726 if (dump_cell_expr(f, indent, cell))
727 return;
728 }
729
730 dump_attributes(f, indent, cell->attributes);
731 f << stringf("%s" "%s", indent.c_str(), id(cell->type, false).c_str());
732
733 if (cell->parameters.size() > 0) {
734 f << stringf(" #(");
735 for (auto it = cell->parameters.begin(); it != cell->parameters.end(); it++) {
736 if (it != cell->parameters.begin())
737 f << stringf(",");
738 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
739 bool is_signed = (it->second.flags & RTLIL::CONST_FLAG_SIGNED) != 0;
740 dump_const(f, it->second, -1, 0, !is_signed, is_signed);
741 f << stringf(")");
742 }
743 f << stringf("\n%s" ")", indent.c_str());
744 }
745
746 std::string cell_name = cellname(cell);
747 if (cell_name != id(cell->name))
748 f << stringf(" %s /* %s */ (", cell_name.c_str(), id(cell->name).c_str());
749 else
750 f << stringf(" %s (", cell_name.c_str());
751
752 bool first_arg = true;
753 std::set<RTLIL::IdString> numbered_ports;
754 for (int i = 1; true; i++) {
755 char str[16];
756 snprintf(str, 16, "$%d", i);
757 for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
758 if (it->first != str)
759 continue;
760 if (!first_arg)
761 f << stringf(",");
762 first_arg = false;
763 f << stringf("\n%s ", indent.c_str());
764 dump_sigspec(f, it->second);
765 numbered_ports.insert(it->first);
766 goto found_numbered_port;
767 }
768 break;
769 found_numbered_port:;
770 }
771 for (auto it = cell->connections().begin(); it != cell->connections().end(); it++) {
772 if (numbered_ports.count(it->first))
773 continue;
774 if (!first_arg)
775 f << stringf(",");
776 first_arg = false;
777 f << stringf("\n%s .%s(", indent.c_str(), id(it->first).c_str());
778 if (it->second.size() > 0)
779 dump_sigspec(f, it->second);
780 f << stringf(")");
781 }
782 f << stringf("\n%s" ");\n", indent.c_str());
783 }
784
785 void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right)
786 {
787 f << stringf("%s" "assign ", indent.c_str());
788 dump_sigspec(f, left);
789 f << stringf(" = ");
790 dump_sigspec(f, right);
791 f << stringf(";\n");
792 }
793
794 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw);
795
796 void dump_case_body(std::ostream &f, std::string indent, RTLIL::CaseRule *cs, bool omit_trailing_begin = false)
797 {
798 int number_of_stmts = cs->switches.size() + cs->actions.size();
799
800 if (!omit_trailing_begin && number_of_stmts >= 2)
801 f << stringf("%s" "begin\n", indent.c_str());
802
803 for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
804 if (it->first.size() == 0)
805 continue;
806 f << stringf("%s ", indent.c_str());
807 dump_sigspec(f, it->first);
808 f << stringf(" = ");
809 dump_sigspec(f, it->second);
810 f << stringf(";\n");
811 }
812
813 for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
814 dump_proc_switch(f, indent + " ", *it);
815
816 if (!omit_trailing_begin && number_of_stmts == 0)
817 f << stringf("%s /* empty */;\n", indent.c_str());
818
819 if (omit_trailing_begin || number_of_stmts >= 2)
820 f << stringf("%s" "end\n", indent.c_str());
821 }
822
823 void dump_proc_switch(std::ostream &f, std::string indent, RTLIL::SwitchRule *sw)
824 {
825 if (sw->signal.size() == 0) {
826 f << stringf("%s" "begin\n", indent.c_str());
827 for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
828 if ((*it)->compare.size() == 0)
829 dump_case_body(f, indent + " ", *it);
830 }
831 f << stringf("%s" "end\n", indent.c_str());
832 return;
833 }
834
835 f << stringf("%s" "casez (", indent.c_str());
836 dump_sigspec(f, sw->signal);
837 f << stringf(")\n");
838
839 for (auto it = sw->cases.begin(); it != sw->cases.end(); it++) {
840 f << stringf("%s ", indent.c_str());
841 if ((*it)->compare.size() == 0)
842 f << stringf("default");
843 else {
844 for (size_t i = 0; i < (*it)->compare.size(); i++) {
845 if (i > 0)
846 f << stringf(", ");
847 dump_sigspec(f, (*it)->compare[i]);
848 }
849 }
850 f << stringf(":\n");
851 dump_case_body(f, indent + " ", *it);
852 }
853
854 f << stringf("%s" "endcase\n", indent.c_str());
855 }
856
857 void case_body_find_regs(RTLIL::CaseRule *cs)
858 {
859 for (auto it = cs->switches.begin(); it != cs->switches.end(); it++)
860 for (auto it2 = (*it)->cases.begin(); it2 != (*it)->cases.end(); it2++)
861 case_body_find_regs(*it2);
862
863 for (auto it = cs->actions.begin(); it != cs->actions.end(); it++) {
864 for (auto &c : it->first.chunks())
865 if (c.wire != NULL)
866 reg_wires.insert(c.wire->name);
867 }
868 }
869
870 void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, bool find_regs = false)
871 {
872 if (find_regs) {
873 case_body_find_regs(&proc->root_case);
874 for (auto it = proc->syncs.begin(); it != proc->syncs.end(); it++)
875 for (auto it2 = (*it)->actions.begin(); it2 != (*it)->actions.end(); it2++) {
876 for (auto &c : it2->first.chunks())
877 if (c.wire != NULL)
878 reg_wires.insert(c.wire->name);
879 }
880 return;
881 }
882
883 f << stringf("%s" "always @* begin\n", indent.c_str());
884 dump_case_body(f, indent, &proc->root_case, true);
885
886 std::string backup_indent = indent;
887
888 for (size_t i = 0; i < proc->syncs.size(); i++)
889 {
890 RTLIL::SyncRule *sync = proc->syncs[i];
891 indent = backup_indent;
892
893 if (sync->type == RTLIL::STa) {
894 f << stringf("%s" "always @* begin\n", indent.c_str());
895 } else {
896 f << stringf("%s" "always @(", indent.c_str());
897 if (sync->type == RTLIL::STp || sync->type == RTLIL::ST1)
898 f << stringf("posedge ");
899 if (sync->type == RTLIL::STn || sync->type == RTLIL::ST0)
900 f << stringf("negedge ");
901 dump_sigspec(f, sync->signal);
902 f << stringf(") begin\n");
903 }
904 std::string ends = indent + "end\n";
905 indent += " ";
906
907 if (sync->type == RTLIL::ST0 || sync->type == RTLIL::ST1) {
908 f << stringf("%s" "if (%s", indent.c_str(), sync->type == RTLIL::ST0 ? "!" : "");
909 dump_sigspec(f, sync->signal);
910 f << stringf(") begin\n");
911 ends = indent + "end\n" + ends;
912 indent += " ";
913 }
914
915 if (sync->type == RTLIL::STp || sync->type == RTLIL::STn) {
916 for (size_t j = 0; j < proc->syncs.size(); j++) {
917 RTLIL::SyncRule *sync2 = proc->syncs[j];
918 if (sync2->type == RTLIL::ST0 || sync2->type == RTLIL::ST1) {
919 f << stringf("%s" "if (%s", indent.c_str(), sync2->type == RTLIL::ST1 ? "!" : "");
920 dump_sigspec(f, sync2->signal);
921 f << stringf(") begin\n");
922 ends = indent + "end\n" + ends;
923 indent += " ";
924 }
925 }
926 }
927
928 for (auto it = sync->actions.begin(); it != sync->actions.end(); it++) {
929 if (it->first.size() == 0)
930 continue;
931 f << stringf("%s ", indent.c_str());
932 dump_sigspec(f, it->first);
933 f << stringf(" <= ");
934 dump_sigspec(f, it->second);
935 f << stringf(";\n");
936 }
937
938 f << stringf("%s", ends.c_str());
939 }
940 }
941
942 void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module)
943 {
944 reg_wires.clear();
945 reset_auto_counter(module);
946 active_module = module;
947
948 f << stringf("\n");
949 for (auto it = module->processes.begin(); it != module->processes.end(); it++)
950 dump_process(f, indent + " ", it->second, true);
951
952 if (!noexpr)
953 {
954 std::set<std::pair<RTLIL::Wire*,int>> reg_bits;
955 for (auto &it : module->cells_)
956 {
957 RTLIL::Cell *cell = it.second;
958 if (!reg_ct.count(cell->type) || !cell->hasPort("\\Q"))
959 continue;
960
961 RTLIL::SigSpec sig = cell->getPort("\\Q");
962
963 if (sig.is_chunk()) {
964 RTLIL::SigChunk chunk = sig.as_chunk();
965 if (chunk.wire != NULL)
966 for (int i = 0; i < chunk.width; i++)
967 reg_bits.insert(std::pair<RTLIL::Wire*,int>(chunk.wire, chunk.offset+i));
968 }
969 }
970 for (auto &it : module->wires_)
971 {
972 RTLIL::Wire *wire = it.second;
973 for (int i = 0; i < wire->width; i++)
974 if (reg_bits.count(std::pair<RTLIL::Wire*,int>(wire, i)) == 0)
975 goto this_wire_aint_reg;
976 if (wire->width)
977 reg_wires.insert(wire->name);
978 this_wire_aint_reg:;
979 }
980 }
981
982 dump_attributes(f, indent, module->attributes);
983 f << stringf("%s" "module %s(", indent.c_str(), id(module->name, false).c_str());
984 bool keep_running = true;
985 for (int port_id = 1; keep_running; port_id++) {
986 keep_running = false;
987 for (auto it = module->wires_.begin(); it != module->wires_.end(); it++) {
988 RTLIL::Wire *wire = it->second;
989 if (wire->port_id == port_id) {
990 if (port_id != 1)
991 f << stringf(", ");
992 f << stringf("%s", id(wire->name).c_str());
993 keep_running = true;
994 continue;
995 }
996 }
997 }
998 f << stringf(");\n");
999
1000 for (auto it = module->wires_.begin(); it != module->wires_.end(); it++)
1001 dump_wire(f, indent + " ", it->second);
1002
1003 for (auto it = module->memories.begin(); it != module->memories.end(); it++)
1004 dump_memory(f, indent + " ", it->second);
1005
1006 for (auto it = module->cells_.begin(); it != module->cells_.end(); it++)
1007 dump_cell(f, indent + " ", it->second);
1008
1009 for (auto it = module->processes.begin(); it != module->processes.end(); it++)
1010 dump_process(f, indent + " ", it->second);
1011
1012 for (auto it = module->connections().begin(); it != module->connections().end(); it++)
1013 dump_conn(f, indent + " ", it->first, it->second);
1014
1015 f << stringf("%s" "endmodule\n", indent.c_str());
1016 active_module = NULL;
1017 }
1018
1019 struct VerilogBackend : public Backend {
1020 VerilogBackend() : Backend("verilog", "write design to verilog file") { }
1021 virtual void help()
1022 {
1023 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1024 log("\n");
1025 log(" write_verilog [options] [filename]\n");
1026 log("\n");
1027 log("Write the current design to a verilog file.\n");
1028 log("\n");
1029 log(" -norename\n");
1030 log(" without this option all internal object names (the ones with a dollar\n");
1031 log(" instead of a backslash prefix) are changed to short names in the\n");
1032 log(" format '_<number>_'.\n");
1033 log("\n");
1034 log(" -noattr\n");
1035 log(" with this option no attributes are included in the output\n");
1036 log("\n");
1037 log(" -attr2comment\n");
1038 log(" with this option attributes are included as comments in the output\n");
1039 log("\n");
1040 log(" -noexpr\n");
1041 log(" without this option all internal cells are converted to verilog\n");
1042 log(" expressions.\n");
1043 log("\n");
1044 log(" -blackboxes\n");
1045 log(" usually modules with the 'blackbox' attribute are ignored. with\n");
1046 log(" this option set only the modules with the 'blackbox' attribute\n");
1047 log(" are written to the output file.\n");
1048 log("\n");
1049 log(" -selected\n");
1050 log(" only write selected modules. modules must be selected entirely or\n");
1051 log(" not at all.\n");
1052 log("\n");
1053 }
1054 virtual void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design)
1055 {
1056 log_header("Executing Verilog backend.\n");
1057
1058 norename = false;
1059 noattr = false;
1060 attr2comment = false;
1061 noexpr = false;
1062
1063 bool blackboxes = false;
1064 bool selected = false;
1065
1066 reg_ct.clear();
1067
1068 reg_ct.insert("$dff");
1069 reg_ct.insert("$adff");
1070
1071 reg_ct.insert("$_DFF_N_");
1072 reg_ct.insert("$_DFF_P_");
1073
1074 reg_ct.insert("$_DFF_NN0_");
1075 reg_ct.insert("$_DFF_NN1_");
1076 reg_ct.insert("$_DFF_NP0_");
1077 reg_ct.insert("$_DFF_NP1_");
1078 reg_ct.insert("$_DFF_PN0_");
1079 reg_ct.insert("$_DFF_PN1_");
1080 reg_ct.insert("$_DFF_PP0_");
1081 reg_ct.insert("$_DFF_PP1_");
1082
1083 reg_ct.insert("$_DFFSR_NNN_");
1084 reg_ct.insert("$_DFFSR_NNP_");
1085 reg_ct.insert("$_DFFSR_NPN_");
1086 reg_ct.insert("$_DFFSR_NPP_");
1087 reg_ct.insert("$_DFFSR_PNN_");
1088 reg_ct.insert("$_DFFSR_PNP_");
1089 reg_ct.insert("$_DFFSR_PPN_");
1090 reg_ct.insert("$_DFFSR_PPP_");
1091
1092 size_t argidx;
1093 for (argidx = 1; argidx < args.size(); argidx++) {
1094 std::string arg = args[argidx];
1095 if (arg == "-norename") {
1096 norename = true;
1097 continue;
1098 }
1099 if (arg == "-noattr") {
1100 noattr = true;
1101 continue;
1102 }
1103 if (arg == "-attr2comment") {
1104 attr2comment = true;
1105 continue;
1106 }
1107 if (arg == "-noexpr") {
1108 noexpr = true;
1109 continue;
1110 }
1111 if (arg == "-blackboxes") {
1112 blackboxes = true;
1113 continue;
1114 }
1115 if (arg == "-selected") {
1116 selected = true;
1117 continue;
1118 }
1119 break;
1120 }
1121 extra_args(f, filename, args, argidx);
1122
1123 *f << stringf("/* Generated by %s */\n", yosys_version_str);
1124 for (auto it = design->modules_.begin(); it != design->modules_.end(); it++) {
1125 if (it->second->get_bool_attribute("\\blackbox") != blackboxes)
1126 continue;
1127 if (selected && !design->selected_whole_module(it->first)) {
1128 if (design->selected_module(it->first))
1129 log_cmd_error("Can't handle partially selected module %s!\n", RTLIL::id2cstr(it->first));
1130 continue;
1131 }
1132 log("Dumping module `%s'.\n", it->first.c_str());
1133 dump_module(*f, "", it->second);
1134 }
1135
1136 reg_ct.clear();
1137 }
1138 } VerilogBackend;
1139
1140 PRIVATE_NAMESPACE_END