Add fileinfo to firrtl backend for top-level circuit
[yosys.git] / backends / firrtl / firrtl.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 #include "kernel/rtlil.h"
21 #include "kernel/register.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/celltypes.h"
24 #include "kernel/cellaigs.h"
25 #include "kernel/log.h"
26 #include <algorithm>
27 #include <string>
28 #include <vector>
29 #include <cmath>
30
31 USING_YOSYS_NAMESPACE
32 PRIVATE_NAMESPACE_BEGIN
33
34 pool<string> used_names;
35 dict<IdString, string> namecache;
36 int autoid_counter;
37
38 typedef unsigned FDirection;
39 static const FDirection FD_NODIRECTION = 0x0;
40 static const FDirection FD_IN = 0x1;
41 static const FDirection FD_OUT = 0x2;
42 static const FDirection FD_INOUT = 0x3;
43 static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width
44
45 // Shamelessly copied from ilang_backend.cc. Something better is surely possible here.
46 void dump_const(std::ostream &f, const RTLIL::Const &data, int width = -1, int offset = 0, bool autoint = true)
47 {
48 if (width < 0)
49 width = data.bits.size() - offset;
50 if ((data.flags & RTLIL::CONST_FLAG_STRING) == 0 || width != (int)data.bits.size()) {
51 if (width == 32 && autoint) {
52 int32_t val = 0;
53 for (int i = 0; i < width; i++) {
54 log_assert(offset+i < (int)data.bits.size());
55 switch (data.bits[offset+i]) {
56 case RTLIL::S0: break;
57 case RTLIL::S1: val |= 1 << i; break;
58 default: val = -1; break;
59 }
60 }
61 if (val >= 0) {
62 f << stringf("%d", val);
63 return;
64 }
65 }
66 f << stringf("%d'", width);
67 for (int i = offset+width-1; i >= offset; i--) {
68 log_assert(i < (int)data.bits.size());
69 switch (data.bits[i]) {
70 case RTLIL::S0: f << stringf("0"); break;
71 case RTLIL::S1: f << stringf("1"); break;
72 case RTLIL::Sx: f << stringf("x"); break;
73 case RTLIL::Sz: f << stringf("z"); break;
74 case RTLIL::Sa: f << stringf("-"); break;
75 case RTLIL::Sm: f << stringf("m"); break;
76 }
77 }
78 } else {
79 f << stringf("\"");
80 std::string str = data.decode_string();
81 for (size_t i = 0; i < str.size(); i++) {
82 if (str[i] == '\n')
83 f << stringf("\\n");
84 else if (str[i] == '\t')
85 f << stringf("\\t");
86 else if (str[i] < 32)
87 f << stringf("\\%03o", str[i]);
88 else if (str[i] == '"')
89 f << stringf("\\\"");
90 else if (str[i] == '\\')
91 f << stringf("\\\\");
92 else
93 f << str[i];
94 }
95 f << stringf("\"");
96 }
97 }
98
99 // Get a port direction with respect to a specific module.
100 FDirection getPortFDirection(IdString id, Module *module)
101 {
102 Wire *wire = module->wires_.at(id);
103 FDirection direction = FD_NODIRECTION;
104 if (wire && wire->port_id)
105 {
106 if (wire->port_input)
107 direction |= FD_IN;
108 if (wire->port_output)
109 direction |= FD_OUT;
110 }
111 return direction;
112 }
113
114 string next_id()
115 {
116 string new_id;
117
118 while (1) {
119 new_id = stringf("_%d", autoid_counter++);
120 if (used_names.count(new_id) == 0) break;
121 }
122
123 used_names.insert(new_id);
124 return new_id;
125 }
126
127 const char *make_id(IdString id)
128 {
129 if (namecache.count(id) != 0)
130 return namecache.at(id).c_str();
131
132 string new_id = log_id(id);
133
134 for (int i = 0; i < GetSize(new_id); i++)
135 {
136 char &ch = new_id[i];
137 if ('a' <= ch && ch <= 'z') continue;
138 if ('A' <= ch && ch <= 'Z') continue;
139 if ('0' <= ch && ch <= '9' && i != 0) continue;
140 if ('_' == ch) continue;
141 ch = '_';
142 }
143
144 while (used_names.count(new_id) != 0)
145 new_id += '_';
146
147 namecache[id] = new_id;
148 used_names.insert(new_id);
149 return namecache.at(id).c_str();
150 }
151
152 struct FirrtlWorker
153 {
154 Module *module;
155 std::ostream &f;
156
157 dict<SigBit, pair<string, int>> reverse_wire_map;
158 string unconn_id;
159 RTLIL::Design *design;
160 std::string indent;
161
162 // Define read/write ports and memories.
163 // We'll collect their definitions and emit the corresponding FIRRTL definitions at the appropriate point in module construction.
164 // For the moment, we don't handle $readmemh or $readmemb.
165 // These will be part of a subsequent PR.
166 struct read_port {
167 string name;
168 bool clk_enable;
169 bool clk_parity;
170 bool transparent;
171 RTLIL::SigSpec clk;
172 RTLIL::SigSpec ena;
173 RTLIL::SigSpec addr;
174 read_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr) : name(name), clk_enable(clk_enable), clk_parity(clk_parity), transparent(transparent), clk(clk), ena(ena), addr(addr) {
175 // Current (3/13/2019) conventions:
176 // generate a constant 0 for clock and a constant 1 for enable if they are undefined.
177 if (!clk.is_fully_def())
178 this->clk = SigSpec(State::S0);
179 if (!ena.is_fully_def())
180 this->ena = SigSpec(State::S1);
181 }
182 string gen_read(const char * indent) {
183 string addr_expr = make_expr(addr);
184 string ena_expr = make_expr(ena);
185 string clk_expr = make_expr(clk);
186 string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
187 string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
188 string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
189 return addr_str + ena_str + clk_str;
190 }
191 };
192 struct write_port : read_port {
193 RTLIL::SigSpec mask;
194 write_port(string name, bool clk_enable, bool clk_parity, bool transparent, RTLIL::SigSpec clk, RTLIL::SigSpec ena, RTLIL::SigSpec addr, RTLIL::SigSpec mask) : read_port(name, clk_enable, clk_parity, transparent, clk, ena, addr), mask(mask) {
195 if (!clk.is_fully_def())
196 this->clk = SigSpec(RTLIL::Const(0));
197 if (!ena.is_fully_def())
198 this->ena = SigSpec(RTLIL::Const(0));
199 if (!mask.is_fully_def())
200 this->ena = SigSpec(RTLIL::Const(1));
201 }
202 string gen_read(const char * /* indent */) {
203 log_error("gen_read called on write_port: %s\n", name.c_str());
204 return stringf("gen_read called on write_port: %s\n", name.c_str());
205 }
206 string gen_write(const char * indent) {
207 string addr_expr = make_expr(addr);
208 string ena_expr = make_expr(ena);
209 string clk_expr = make_expr(clk);
210 string mask_expr = make_expr(mask);
211 string mask_str = stringf("%s%s.mask <= %s\n", indent, name.c_str(), mask_expr.c_str());
212 string addr_str = stringf("%s%s.addr <= %s\n", indent, name.c_str(), addr_expr.c_str());
213 string ena_str = stringf("%s%s.en <= %s\n", indent, name.c_str(), ena_expr.c_str());
214 string clk_str = stringf("%s%s.clk <= asClock(%s)\n", indent, name.c_str(), clk_expr.c_str());
215 return addr_str + ena_str + clk_str + mask_str;
216 }
217 };
218 /* Memories defined within this module. */
219 struct memory {
220 Cell *pCell; // for error reporting
221 string name; // memory name
222 int abits; // number of address bits
223 int size; // size (in units) of the memory
224 int width; // size (in bits) of each element
225 int read_latency;
226 int write_latency;
227 vector<read_port> read_ports;
228 vector<write_port> write_ports;
229 std::string init_file;
230 std::string init_file_srcFileSpec;
231 string srcLine;
232 memory(Cell *pCell, string name, int abits, int size, int width) : pCell(pCell), name(name), abits(abits), size(size), width(width), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec("") {
233 // Provide defaults for abits or size if one (but not the other) is specified.
234 if (this->abits == 0 && this->size != 0) {
235 this->abits = ceil_log2(this->size);
236 } else if (this->abits != 0 && this->size == 0) {
237 this->size = 1 << this->abits;
238 }
239 // Sanity-check this construction.
240 if (this->name == "") {
241 log_error("Nameless memory%s\n", this->atLine());
242 }
243 if (this->abits == 0 && this->size == 0) {
244 log_error("Memory %s has zero address bits and size%s\n", this->name.c_str(), this->atLine());
245 }
246 if (this->width == 0) {
247 log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine());
248 }
249 }
250 // We need a default constructor for the dict insert.
251 memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
252
253 const char *atLine() {
254 if (srcLine == "") {
255 if (pCell) {
256 auto p = pCell->attributes.find("\\src");
257 srcLine = " at " + p->second.decode_string();
258 }
259 }
260 return srcLine.c_str();
261 }
262 void add_memory_read_port(read_port &rp) {
263 read_ports.push_back(rp);
264 }
265 void add_memory_write_port(write_port &wp) {
266 write_ports.push_back(wp);
267 }
268 void add_memory_file(std::string init_file, std::string init_file_srcFileSpec) {
269 this->init_file = init_file;
270 this->init_file_srcFileSpec = init_file_srcFileSpec;
271 }
272
273 };
274 dict<string, memory> memories;
275
276 void register_memory(memory &m)
277 {
278 memories[m.name] = m;
279 }
280
281 void register_reverse_wire_map(string id, SigSpec sig)
282 {
283 for (int i = 0; i < GetSize(sig); i++)
284 reverse_wire_map[sig[i]] = make_pair(id, i);
285 }
286
287 FirrtlWorker(Module *module, std::ostream &f, RTLIL::Design *theDesign) : module(module), f(f), design(theDesign), indent(" ")
288 {
289 }
290
291 static string make_expr(const SigSpec &sig)
292 {
293 string expr;
294
295 for (auto chunk : sig.chunks())
296 {
297 string new_expr;
298
299 if (chunk.wire == nullptr)
300 {
301 std::vector<RTLIL::State> bits = chunk.data;
302 new_expr = stringf("UInt<%d>(\"h", GetSize(bits));
303
304 while (GetSize(bits) % 4 != 0)
305 bits.push_back(State::S0);
306
307 for (int i = GetSize(bits)-4; i >= 0; i -= 4)
308 {
309 int val = 0;
310 if (bits[i+0] == State::S1) val += 1;
311 if (bits[i+1] == State::S1) val += 2;
312 if (bits[i+2] == State::S1) val += 4;
313 if (bits[i+3] == State::S1) val += 8;
314 new_expr.push_back(val < 10 ? '0' + val : 'a' + val - 10);
315 }
316
317 new_expr += "\")";
318 }
319 else if (chunk.offset == 0 && chunk.width == chunk.wire->width)
320 {
321 new_expr = make_id(chunk.wire->name);
322 }
323 else
324 {
325 string wire_id = make_id(chunk.wire->name);
326 new_expr = stringf("bits(%s, %d, %d)", wire_id.c_str(), chunk.offset + chunk.width - 1, chunk.offset);
327 }
328
329 if (expr.empty())
330 expr = new_expr;
331 else
332 expr = "cat(" + new_expr + ", " + expr + ")";
333 }
334
335 return expr;
336 }
337
338 std::string fid(RTLIL::IdString internal_id)
339 {
340 return make_id(internal_id);
341 }
342
343 std::string cellname(RTLIL::Cell *cell)
344 {
345 return fid(cell->name).c_str();
346 }
347
348 void process_instance(RTLIL::Cell *cell, vector<string> &wire_exprs)
349 {
350 std::string cell_type = fid(cell->type);
351 std::string instanceOf;
352 // If this is a parameterized module, its parent module is encoded in the cell type
353 if (cell->type.begins_with("$paramod"))
354 {
355 std::string::iterator it;
356 for (it = cell_type.begin(); it < cell_type.end(); it++)
357 {
358 switch (*it) {
359 case '\\': /* FALL_THROUGH */
360 case '=': /* FALL_THROUGH */
361 case '\'': /* FALL_THROUGH */
362 case '$': instanceOf.append("_"); break;
363 default: instanceOf.append(1, *it); break;
364 }
365 }
366 }
367 else
368 {
369 instanceOf = cell_type;
370 }
371
372 std::string cell_name = cellname(cell);
373 std::string cell_name_comment;
374 if (cell_name != fid(cell->name))
375 cell_name_comment = " /* " + fid(cell->name) + " */ ";
376 else
377 cell_name_comment = "";
378 // Find the module corresponding to this instance.
379 auto instModule = design->module(cell->type);
380 // If there is no instance for this, just return.
381 if (instModule == NULL)
382 {
383 log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
384 return;
385 }
386 wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str()));
387
388 for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
389 if (it->second.size() > 0) {
390 const SigSpec &secondSig = it->second;
391 const std::string firstName = cell_name + "." + make_id(it->first);
392 const std::string secondExpr = make_expr(secondSig);
393 // Find the direction for this port.
394 FDirection dir = getPortFDirection(it->first, instModule);
395 std::string sourceExpr, sinkExpr;
396 const SigSpec *sinkSig = nullptr;
397 switch (dir) {
398 case FD_INOUT:
399 log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second));
400 /* FALLTHRU */
401 case FD_OUT:
402 sourceExpr = firstName;
403 sinkExpr = secondExpr;
404 sinkSig = &secondSig;
405 break;
406 case FD_NODIRECTION:
407 log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second));
408 /* FALLTHRU */
409 case FD_IN:
410 sourceExpr = secondExpr;
411 sinkExpr = firstName;
412 break;
413 default:
414 log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir);
415 break;
416 }
417 // Check for subfield assignment.
418 std::string bitsString = "bits(";
419 if (sinkExpr.compare(0, bitsString.length(), bitsString) == 0) {
420 if (sinkSig == nullptr)
421 log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str());
422 // Don't generate the assignment here.
423 // Add the source and sink to the "reverse_wire_map" and we'll output the assignment
424 // as part of the coalesced subfield assignments for this wire.
425 register_reverse_wire_map(sourceExpr, *sinkSig);
426 } else {
427 wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str()));
428 }
429 }
430 }
431 wire_exprs.push_back(stringf("\n"));
432
433 }
434
435 // Given an expression for a shift amount, and a maximum width,
436 // generate the FIRRTL expression for equivalent dynamic shift taking into account FIRRTL shift semantics.
437 std::string gen_dshl(const string b_expr, const int b_width)
438 {
439 string result = b_expr;
440 if (b_width >= FIRRTL_MAX_DSH_WIDTH_ERROR) {
441 int max_shift_width_bits = FIRRTL_MAX_DSH_WIDTH_ERROR - 1;
442 string max_shift_string = stringf("UInt<%d>(%d)", max_shift_width_bits, (1<<max_shift_width_bits) - 1);
443 // Deal with the difference in semantics between FIRRTL and verilog
444 result = stringf("mux(gt(%s, %s), %s, bits(%s, %d, 0))", b_expr.c_str(), max_shift_string.c_str(), max_shift_string.c_str(), b_expr.c_str(), max_shift_width_bits - 1);
445 }
446 return result;
447 }
448
449 void run()
450 {
451 f << stringf(" module %s:\n", make_id(module->name));
452 vector<string> port_decls, wire_decls, cell_exprs, wire_exprs;
453
454 for (auto wire : module->wires())
455 {
456 const auto wireName = make_id(wire->name);
457 // If a wire has initial data, issue a warning since FIRRTL doesn't currently support it.
458 if (wire->attributes.count("\\init")) {
459 log_warning("Initial value (%s) for (%s.%s) not supported\n",
460 wire->attributes.at("\\init").as_string().c_str(),
461 log_id(module), log_id(wire));
462 }
463 if (wire->port_id)
464 {
465 if (wire->port_input && wire->port_output)
466 log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
467 port_decls.push_back(stringf(" %s %s: UInt<%d>\n", wire->port_input ? "input" : "output",
468 wireName, wire->width));
469 }
470 else
471 {
472 wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", wireName, wire->width));
473 }
474 }
475
476 for (auto cell : module->cells())
477 {
478 static Const ndef(0, 0);
479
480 // Is this cell is a module instance?
481 if (cell->type[0] != '$')
482 {
483 process_instance(cell, wire_exprs);
484 continue;
485 }
486 // Not a module instance. Set up cell properties
487 bool extract_y_bits = false; // Assume no extraction of final bits will be required.
488 int a_width = cell->parameters.at("\\A_WIDTH", ndef).as_int(); // The width of "A"
489 int b_width = cell->parameters.at("\\B_WIDTH", ndef).as_int(); // The width of "A"
490 const int y_width = cell->parameters.at("\\Y_WIDTH", ndef).as_int(); // The width of the result
491 const bool a_signed = cell->parameters.at("\\A_SIGNED", ndef).as_bool();
492 const bool b_signed = cell->parameters.at("\\B_SIGNED", ndef).as_bool();
493 bool firrtl_is_signed = a_signed; // The result is signed (subsequent code may change this).
494 int firrtl_width = 0;
495 string primop;
496 bool always_uint = false;
497 string y_id = make_id(cell->name);
498
499 if (cell->type.in("$not", "$logic_not", "$neg", "$reduce_and", "$reduce_or", "$reduce_xor", "$reduce_bool", "$reduce_xnor"))
500 {
501 string a_expr = make_expr(cell->getPort("\\A"));
502 wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
503
504 if (a_signed) {
505 a_expr = "asSInt(" + a_expr + ")";
506 }
507
508 // Don't use the results of logical operations (a single bit) to control padding
509 if (!(cell->type.in("$eq", "$eqx", "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$reduce_bool", "$logic_not") && y_width == 1) ) {
510 a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
511 }
512
513 // Assume the FIRRTL width is a single bit.
514 firrtl_width = 1;
515 if (cell->type == "$not") primop = "not";
516 else if (cell->type == "$neg") {
517 primop = "neg";
518 firrtl_is_signed = true; // Result of "neg" is signed (an SInt).
519 firrtl_width = a_width;
520 } else if (cell->type == "$logic_not") {
521 primop = "eq";
522 a_expr = stringf("%s, UInt(0)", a_expr.c_str());
523 }
524 else if (cell->type == "$reduce_and") primop = "andr";
525 else if (cell->type == "$reduce_or") primop = "orr";
526 else if (cell->type == "$reduce_xor") primop = "xorr";
527 else if (cell->type == "$reduce_xnor") {
528 primop = "not";
529 a_expr = stringf("xorr(%s)", a_expr.c_str());
530 }
531 else if (cell->type == "$reduce_bool") {
532 primop = "neq";
533 // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
534 a_expr = stringf("%s, %cInt<%d>(0)", a_expr.c_str(), a_signed ? 'S' : 'U', a_width);
535 }
536
537 string expr = stringf("%s(%s)", primop.c_str(), a_expr.c_str());
538
539 if ((firrtl_is_signed && !always_uint))
540 expr = stringf("asUInt(%s)", expr.c_str());
541
542 cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
543 register_reverse_wire_map(y_id, cell->getPort("\\Y"));
544
545 continue;
546 }
547 if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or", "$eq", "$eqx",
548 "$gt", "$ge", "$lt", "$le", "$ne", "$nex", "$shr", "$sshr", "$sshl", "$shl",
549 "$logic_and", "$logic_or", "$pow"))
550 {
551 string a_expr = make_expr(cell->getPort("\\A"));
552 string b_expr = make_expr(cell->getPort("\\B"));
553 wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
554
555 if (a_signed) {
556 a_expr = "asSInt(" + a_expr + ")";
557 // Expand the "A" operand to the result width
558 if (a_width < y_width) {
559 a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
560 a_width = y_width;
561 }
562 }
563 // Shift amount is always unsigned, and needn't be padded to result width,
564 // otherwise, we need to cast the b_expr appropriately
565 if (b_signed && !cell->type.in("$shr", "$sshr", "$shl", "$sshl", "$pow")) {
566 b_expr = "asSInt(" + b_expr + ")";
567 // Expand the "B" operand to the result width
568 if (b_width < y_width) {
569 b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
570 b_width = y_width;
571 }
572 }
573
574 // For the arithmetic ops, expand operand widths to result widths befor performing the operation.
575 // This corresponds (according to iverilog) to what verilog compilers implement.
576 if (cell->type.in("$add", "$sub", "$mul", "$div", "$mod", "$xor", "$xnor", "$and", "$or"))
577 {
578 if (a_width < y_width) {
579 a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
580 a_width = y_width;
581 }
582 if (b_width < y_width) {
583 b_expr = stringf("pad(%s, %d)", b_expr.c_str(), y_width);
584 b_width = y_width;
585 }
586 }
587 // Assume the FIRRTL width is the width of "A"
588 firrtl_width = a_width;
589 auto a_sig = cell->getPort("\\A");
590
591 if (cell->type == "$add") {
592 primop = "add";
593 firrtl_is_signed = a_signed | b_signed;
594 firrtl_width = max(a_width, b_width);
595 } else if (cell->type == "$sub") {
596 primop = "sub";
597 firrtl_is_signed = true;
598 int a_widthInc = (!a_signed && b_signed) ? 2 : (a_signed && !b_signed) ? 1 : 0;
599 int b_widthInc = (a_signed && !b_signed) ? 2 : (!a_signed && b_signed) ? 1 : 0;
600 firrtl_width = max(a_width + a_widthInc, b_width + b_widthInc);
601 } else if (cell->type == "$mul") {
602 primop = "mul";
603 firrtl_is_signed = a_signed | b_signed;
604 firrtl_width = a_width + b_width;
605 } else if (cell->type == "$div") {
606 primop = "div";
607 firrtl_is_signed = a_signed | b_signed;
608 firrtl_width = a_width;
609 } else if (cell->type == "$mod") {
610 primop = "rem";
611 firrtl_width = min(a_width, b_width);
612 } else if (cell->type == "$and") {
613 primop = "and";
614 always_uint = true;
615 firrtl_width = max(a_width, b_width);
616 }
617 else if (cell->type == "$or" ) {
618 primop = "or";
619 always_uint = true;
620 firrtl_width = max(a_width, b_width);
621 }
622 else if (cell->type == "$xor") {
623 primop = "xor";
624 always_uint = true;
625 firrtl_width = max(a_width, b_width);
626 }
627 else if (cell->type == "$xnor") {
628 primop = "xnor";
629 always_uint = true;
630 firrtl_width = max(a_width, b_width);
631 }
632 else if ((cell->type == "$eq") | (cell->type == "$eqx")) {
633 primop = "eq";
634 always_uint = true;
635 firrtl_width = 1;
636 }
637 else if ((cell->type == "$ne") | (cell->type == "$nex")) {
638 primop = "neq";
639 always_uint = true;
640 firrtl_width = 1;
641 }
642 else if (cell->type == "$gt") {
643 primop = "gt";
644 always_uint = true;
645 firrtl_width = 1;
646 }
647 else if (cell->type == "$ge") {
648 primop = "geq";
649 always_uint = true;
650 firrtl_width = 1;
651 }
652 else if (cell->type == "$lt") {
653 primop = "lt";
654 always_uint = true;
655 firrtl_width = 1;
656 }
657 else if (cell->type == "$le") {
658 primop = "leq";
659 always_uint = true;
660 firrtl_width = 1;
661 }
662 else if ((cell->type == "$shl") | (cell->type == "$sshl")) {
663 // FIRRTL will widen the result (y) by the amount of the shift.
664 // We'll need to offset this by extracting the un-widened portion as Verilog would do.
665 extract_y_bits = true;
666 // Is the shift amount constant?
667 auto b_sig = cell->getPort("\\B");
668 if (b_sig.is_fully_const()) {
669 primop = "shl";
670 int shift_amount = b_sig.as_int();
671 b_expr = std::to_string(shift_amount);
672 firrtl_width = a_width + shift_amount;
673 } else {
674 primop = "dshl";
675 // Convert from FIRRTL left shift semantics.
676 b_expr = gen_dshl(b_expr, b_width);
677 firrtl_width = a_width + (1 << b_width) - 1;
678 }
679 }
680 else if ((cell->type == "$shr") | (cell->type == "$sshr")) {
681 // We don't need to extract a specific range of bits.
682 extract_y_bits = false;
683 // Is the shift amount constant?
684 auto b_sig = cell->getPort("\\B");
685 if (b_sig.is_fully_const()) {
686 primop = "shr";
687 int shift_amount = b_sig.as_int();
688 b_expr = std::to_string(shift_amount);
689 firrtl_width = max(1, a_width - shift_amount);
690 } else {
691 primop = "dshr";
692 firrtl_width = a_width;
693 }
694 // We'll need to do some special fixups if the source (and thus result) is signed.
695 if (firrtl_is_signed) {
696 // If this is a "logical" shift right, pretend the source is unsigned.
697 if (cell->type == "$shr") {
698 a_expr = "asUInt(" + a_expr + ")";
699 }
700 }
701 }
702 else if ((cell->type == "$logic_and")) {
703 primop = "and";
704 a_expr = "neq(" + a_expr + ", UInt(0))";
705 b_expr = "neq(" + b_expr + ", UInt(0))";
706 always_uint = true;
707 firrtl_width = 1;
708 }
709 else if ((cell->type == "$logic_or")) {
710 primop = "or";
711 a_expr = "neq(" + a_expr + ", UInt(0))";
712 b_expr = "neq(" + b_expr + ", UInt(0))";
713 always_uint = true;
714 firrtl_width = 1;
715 }
716 else if ((cell->type == "$pow")) {
717 if (a_sig.is_fully_const() && a_sig.as_int() == 2) {
718 // We'll convert this to a shift. To simplify things, change the a_expr to "1"
719 // so we can use b_expr directly as a shift amount.
720 // Only support 2 ** N (i.e., shift left)
721 // FIRRTL will widen the result (y) by the amount of the shift.
722 // We'll need to offset this by extracting the un-widened portion as Verilog would do.
723 a_expr = firrtl_is_signed ? "SInt(1)" : "UInt(1)";
724 extract_y_bits = true;
725 // Is the shift amount constant?
726 auto b_sig = cell->getPort("\\B");
727 if (b_sig.is_fully_const()) {
728 primop = "shl";
729 int shiftAmount = b_sig.as_int();
730 if (shiftAmount < 0) {
731 log_error("Negative power exponent - %d: %s.%s\n", shiftAmount, log_id(module), log_id(cell));
732 }
733 b_expr = std::to_string(shiftAmount);
734 firrtl_width = a_width + shiftAmount;
735 } else {
736 primop = "dshl";
737 // Convert from FIRRTL left shift semantics.
738 b_expr = gen_dshl(b_expr, b_width);
739 firrtl_width = a_width + (1 << b_width) - 1;
740 }
741 } else {
742 log_error("Non power 2: %s.%s\n", log_id(module), log_id(cell));
743 }
744 }
745
746 if (!cell->parameters.at("\\B_SIGNED").as_bool()) {
747 b_expr = "asUInt(" + b_expr + ")";
748 }
749
750 string expr;
751 // Deal with $xnor == ~^ (not xor)
752 if (primop == "xnor") {
753 expr = stringf("not(xor(%s, %s))", a_expr.c_str(), b_expr.c_str());
754 } else {
755 expr = stringf("%s(%s, %s)", primop.c_str(), a_expr.c_str(), b_expr.c_str());
756 }
757
758 // Deal with FIRRTL's "shift widens" semantics, or the need to widen the FIRRTL result.
759 // If the operation is signed, the FIRRTL width will be 1 one bit larger.
760 if (extract_y_bits) {
761 expr = stringf("bits(%s, %d, 0)", expr.c_str(), y_width - 1);
762 } else if (firrtl_is_signed && (firrtl_width + 1) < y_width) {
763 expr = stringf("pad(%s, %d)", expr.c_str(), y_width);
764 }
765
766 if ((firrtl_is_signed && !always_uint))
767 expr = stringf("asUInt(%s)", expr.c_str());
768
769 cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
770 register_reverse_wire_map(y_id, cell->getPort("\\Y"));
771
772 continue;
773 }
774
775 if (cell->type.in("$mux"))
776 {
777 int width = cell->parameters.at("\\WIDTH").as_int();
778 string a_expr = make_expr(cell->getPort("\\A"));
779 string b_expr = make_expr(cell->getPort("\\B"));
780 string s_expr = make_expr(cell->getPort("\\S"));
781 wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), width));
782
783 string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
784
785 cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
786 register_reverse_wire_map(y_id, cell->getPort("\\Y"));
787
788 continue;
789 }
790
791 if (cell->type.in("$mem"))
792 {
793 string mem_id = make_id(cell->name);
794 int abits = cell->parameters.at("\\ABITS").as_int();
795 int width = cell->parameters.at("\\WIDTH").as_int();
796 int size = cell->parameters.at("\\SIZE").as_int();
797 memory m(cell, mem_id, abits, size, width);
798 int rd_ports = cell->parameters.at("\\RD_PORTS").as_int();
799 int wr_ports = cell->parameters.at("\\WR_PORTS").as_int();
800
801 Const initdata = cell->parameters.at("\\INIT");
802 for (State bit : initdata.bits)
803 if (bit != State::Sx)
804 log_error("Memory with initialization data: %s.%s\n", log_id(module), log_id(cell));
805
806 Const rd_clk_enable = cell->parameters.at("\\RD_CLK_ENABLE");
807 Const wr_clk_enable = cell->parameters.at("\\WR_CLK_ENABLE");
808 Const wr_clk_polarity = cell->parameters.at("\\WR_CLK_POLARITY");
809
810 int offset = cell->parameters.at("\\OFFSET").as_int();
811 if (offset != 0)
812 log_error("Memory with nonzero offset: %s.%s\n", log_id(module), log_id(cell));
813
814 for (int i = 0; i < rd_ports; i++)
815 {
816 if (rd_clk_enable[i] != State::S0)
817 log_error("Clocked read port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
818
819 SigSpec addr_sig = cell->getPort("\\RD_ADDR").extract(i*abits, abits);
820 SigSpec data_sig = cell->getPort("\\RD_DATA").extract(i*width, width);
821 string addr_expr = make_expr(addr_sig);
822 string name(stringf("%s.r%d", m.name.c_str(), i));
823 bool clk_enable = false;
824 bool clk_parity = true;
825 bool transparency = false;
826 SigSpec ena_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
827 SigSpec clk_sig = RTLIL::SigSpec(RTLIL::State::S0, 1);
828 read_port rp(name, clk_enable, clk_parity, transparency, clk_sig, ena_sig, addr_sig);
829 m.add_memory_read_port(rp);
830 cell_exprs.push_back(rp.gen_read(indent.c_str()));
831 register_reverse_wire_map(stringf("%s.data", name.c_str()), data_sig);
832 }
833
834 for (int i = 0; i < wr_ports; i++)
835 {
836 if (wr_clk_enable[i] != State::S1)
837 log_error("Unclocked write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
838
839 if (wr_clk_polarity[i] != State::S1)
840 log_error("Negedge write port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
841
842 string name(stringf("%s.w%d", m.name.c_str(), i));
843 bool clk_enable = true;
844 bool clk_parity = true;
845 bool transparency = false;
846 SigSpec addr_sig =cell->getPort("\\WR_ADDR").extract(i*abits, abits);
847 string addr_expr = make_expr(addr_sig);
848 SigSpec data_sig =cell->getPort("\\WR_DATA").extract(i*width, width);
849 string data_expr = make_expr(data_sig);
850 SigSpec clk_sig = cell->getPort("\\WR_CLK").extract(i);
851 string clk_expr = make_expr(clk_sig);
852
853 SigSpec wen_sig = cell->getPort("\\WR_EN").extract(i*width, width);
854 string wen_expr = make_expr(wen_sig[0]);
855
856 for (int i = 1; i < GetSize(wen_sig); i++)
857 if (wen_sig[0] != wen_sig[i])
858 log_error("Complex write enable on port %d on memory %s.%s.\n", i, log_id(module), log_id(cell));
859
860 SigSpec mask_sig = RTLIL::SigSpec(RTLIL::State::S1, 1);
861 write_port wp(name, clk_enable, clk_parity, transparency, clk_sig, wen_sig[0], addr_sig, mask_sig);
862 m.add_memory_write_port(wp);
863 cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), name.c_str(), data_expr.c_str()));
864 cell_exprs.push_back(wp.gen_write(indent.c_str()));
865 }
866 register_memory(m);
867 continue;
868 }
869
870 if (cell->type.in("$memwr", "$memrd", "$meminit"))
871 {
872 std::string cell_type = fid(cell->type);
873 std::string mem_id = make_id(cell->parameters["\\MEMID"].decode_string());
874 int abits = cell->parameters.at("\\ABITS").as_int();
875 int width = cell->parameters.at("\\WIDTH").as_int();
876 memory *mp = nullptr;
877 if (cell->type == "$meminit" ) {
878 log_error("$meminit (%s.%s.%s) currently unsupported\n", log_id(module), log_id(cell), mem_id.c_str());
879 } else {
880 // It's a $memwr or $memrd. Remember the read/write port parameters for the eventual FIRRTL memory definition.
881 auto addrSig = cell->getPort("\\ADDR");
882 auto dataSig = cell->getPort("\\DATA");
883 auto enableSig = cell->getPort("\\EN");
884 auto clockSig = cell->getPort("\\CLK");
885 Const clk_enable = cell->parameters.at("\\CLK_ENABLE");
886 Const clk_polarity = cell->parameters.at("\\CLK_POLARITY");
887
888 // Do we already have an entry for this memory?
889 if (memories.count(mem_id) == 0) {
890 memory m(cell, mem_id, abits, 0, width);
891 register_memory(m);
892 }
893 mp = &memories.at(mem_id);
894 int portNum = 0;
895 bool transparency = false;
896 string data_expr = make_expr(dataSig);
897 if (cell->type.in("$memwr")) {
898 portNum = (int) mp->write_ports.size();
899 write_port wp(stringf("%s.w%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig, dataSig);
900 mp->add_memory_write_port(wp);
901 cell_exprs.push_back(stringf("%s%s.data <= %s\n", indent.c_str(), wp.name.c_str(), data_expr.c_str()));
902 cell_exprs.push_back(wp.gen_write(indent.c_str()));
903 } else if (cell->type.in("$memrd")) {
904 portNum = (int) mp->read_ports.size();
905 read_port rp(stringf("%s.r%d", mem_id.c_str(), portNum), clk_enable.as_bool(), clk_polarity.as_bool(), transparency, clockSig, enableSig, addrSig);
906 mp->add_memory_read_port(rp);
907 cell_exprs.push_back(rp.gen_read(indent.c_str()));
908 register_reverse_wire_map(stringf("%s.data", rp.name.c_str()), dataSig);
909 }
910 }
911 continue;
912 }
913
914 if (cell->type.in("$dff"))
915 {
916 bool clkpol = cell->parameters.at("\\CLK_POLARITY").as_bool();
917 if (clkpol == false)
918 log_error("Negative edge clock on FF %s.%s.\n", log_id(module), log_id(cell));
919
920 int width = cell->parameters.at("\\WIDTH").as_int();
921 string expr = make_expr(cell->getPort("\\D"));
922 string clk_expr = "asClock(" + make_expr(cell->getPort("\\CLK")) + ")";
923
924 wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s\n", y_id.c_str(), width, clk_expr.c_str()));
925
926 cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
927 register_reverse_wire_map(y_id, cell->getPort("\\Q"));
928
929 continue;
930 }
931
932 // This may be a parameterized module - paramod.
933 if (cell->type.begins_with("$paramod"))
934 {
935 process_instance(cell, wire_exprs);
936 continue;
937 }
938 if (cell->type == "$shiftx") {
939 // assign y = a[b +: y_width];
940 // We'll extract the correct bits as part of the primop.
941
942 string a_expr = make_expr(cell->getPort("\\A"));
943 // Get the initial bit selector
944 string b_expr = make_expr(cell->getPort("\\B"));
945 wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
946
947 if (cell->getParam("\\B_SIGNED").as_bool()) {
948 // Use validif to constrain the selection (test the sign bit)
949 auto b_string = b_expr.c_str();
950 int b_sign = cell->parameters.at("\\B_WIDTH").as_int() - 1;
951 b_expr = stringf("validif(not(bits(%s, %d, %d)), %s)", b_string, b_sign, b_sign, b_string);
952 }
953 string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str());
954
955 cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
956 register_reverse_wire_map(y_id, cell->getPort("\\Y"));
957 continue;
958 }
959 if (cell->type == "$shift") {
960 // assign y = a >> b;
961 // where b may be negative
962
963 string a_expr = make_expr(cell->getPort("\\A"));
964 string b_expr = make_expr(cell->getPort("\\B"));
965 auto b_string = b_expr.c_str();
966 string expr;
967 wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
968
969 if (cell->getParam("\\B_SIGNED").as_bool()) {
970 // We generate a left or right shift based on the sign of b.
971 std::string dshl = stringf("bits(dshl(%s, %s), 0, %d)", a_expr.c_str(), gen_dshl(b_expr, b_width).c_str(), y_width);
972 std::string dshr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
973 expr = stringf("mux(%s < 0, %s, %s)",
974 b_string,
975 dshl.c_str(),
976 dshr.c_str()
977 );
978 } else {
979 expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
980 }
981 cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
982 register_reverse_wire_map(y_id, cell->getPort("\\Y"));
983 continue;
984 }
985 if (cell->type == "$pos") {
986 // assign y = a;
987 // printCell(cell);
988 string a_expr = make_expr(cell->getPort("\\A"));
989 // Verilog appears to treat the result as signed, so if the result is wider than "A",
990 // we need to pad.
991 if (a_width < y_width) {
992 a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
993 }
994 wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
995 cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), a_expr.c_str()));
996 register_reverse_wire_map(y_id, cell->getPort("\\Y"));
997 continue;
998 }
999 log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell));
1000 }
1001
1002 for (auto conn : module->connections())
1003 {
1004 string y_id = next_id();
1005 int y_width = GetSize(conn.first);
1006 string expr = make_expr(conn.second);
1007
1008 wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
1009 cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
1010 register_reverse_wire_map(y_id, conn.first);
1011 }
1012
1013 for (auto wire : module->wires())
1014 {
1015 string expr;
1016
1017 if (wire->port_input)
1018 continue;
1019
1020 int cursor = 0;
1021 bool is_valid = false;
1022 bool make_unconn_id = false;
1023
1024 while (cursor < wire->width)
1025 {
1026 int chunk_width = 1;
1027 string new_expr;
1028
1029 SigBit start_bit(wire, cursor);
1030
1031 if (reverse_wire_map.count(start_bit))
1032 {
1033 pair<string, int> start_map = reverse_wire_map.at(start_bit);
1034
1035 while (cursor+chunk_width < wire->width)
1036 {
1037 SigBit stop_bit(wire, cursor+chunk_width);
1038
1039 if (reverse_wire_map.count(stop_bit) == 0)
1040 break;
1041
1042 pair<string, int> stop_map = reverse_wire_map.at(stop_bit);
1043 stop_map.second -= chunk_width;
1044
1045 if (start_map != stop_map)
1046 break;
1047
1048 chunk_width++;
1049 }
1050
1051 new_expr = stringf("bits(%s, %d, %d)", start_map.first.c_str(),
1052 start_map.second + chunk_width - 1, start_map.second);
1053 is_valid = true;
1054 }
1055 else
1056 {
1057 if (unconn_id.empty()) {
1058 unconn_id = next_id();
1059 make_unconn_id = true;
1060 }
1061 new_expr = unconn_id;
1062 }
1063
1064 if (expr.empty())
1065 expr = new_expr;
1066 else
1067 expr = "cat(" + new_expr + ", " + expr + ")";
1068
1069 cursor += chunk_width;
1070 }
1071
1072 if (is_valid) {
1073 if (make_unconn_id) {
1074 wire_decls.push_back(stringf(" wire %s: UInt<1>\n", unconn_id.c_str()));
1075 wire_decls.push_back(stringf(" %s is invalid\n", unconn_id.c_str()));
1076 }
1077 wire_exprs.push_back(stringf(" %s <= %s\n", make_id(wire->name), expr.c_str()));
1078 } else {
1079 if (make_unconn_id) {
1080 unconn_id.clear();
1081 }
1082 wire_decls.push_back(stringf(" %s is invalid\n", make_id(wire->name)));
1083 }
1084 }
1085
1086 for (auto str : port_decls)
1087 f << str;
1088
1089 f << stringf("\n");
1090
1091 for (auto str : wire_decls)
1092 f << str;
1093
1094 f << stringf("\n");
1095
1096 // If we have any memory definitions, output them.
1097 for (auto kv : memories) {
1098 memory &m = kv.second;
1099 f << stringf(" mem %s:\n", m.name.c_str());
1100 f << stringf(" data-type => UInt<%d>\n", m.width);
1101 f << stringf(" depth => %d\n", m.size);
1102 for (int i = 0; i < (int) m.read_ports.size(); i += 1) {
1103 f << stringf(" reader => r%d\n", i);
1104 }
1105 for (int i = 0; i < (int) m.write_ports.size(); i += 1) {
1106 f << stringf(" writer => w%d\n", i);
1107 }
1108 f << stringf(" read-latency => %d\n", m.read_latency);
1109 f << stringf(" write-latency => %d\n", m.write_latency);
1110 f << stringf(" read-under-write => undefined\n");
1111 }
1112 f << stringf("\n");
1113
1114 for (auto str : cell_exprs)
1115 f << str;
1116
1117 f << stringf("\n");
1118
1119 for (auto str : wire_exprs)
1120 f << str;
1121 }
1122 };
1123
1124 struct FirrtlBackend : public Backend {
1125 FirrtlBackend() : Backend("firrtl", "write design to a FIRRTL file") { }
1126 void help() YS_OVERRIDE
1127 {
1128 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1129 log("\n");
1130 log(" write_firrtl [options] [filename]\n");
1131 log("\n");
1132 log("Write a FIRRTL netlist of the current design.\n");
1133 log("The following commands are executed by this command:\n");
1134 log(" pmuxtree\n");
1135 log("\n");
1136 }
1137 void execute(std::ostream *&f, std::string filename, std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
1138 {
1139 size_t argidx = args.size(); // We aren't expecting any arguments.
1140
1141 // If we weren't explicitly passed a filename, use the last argument (if it isn't a flag).
1142 if (filename == "") {
1143 if (argidx > 0 && args[argidx - 1][0] != '-') {
1144 // extra_args and friends need to see this argument.
1145 argidx -= 1;
1146 filename = args[argidx];
1147 }
1148 }
1149 extra_args(f, filename, args, argidx);
1150
1151 if (!design->full_selection())
1152 log_cmd_error("This command only operates on fully selected designs!\n");
1153
1154 log_header(design, "Executing FIRRTL backend.\n");
1155 log_push();
1156
1157 Pass::call(design, stringf("pmuxtree"));
1158
1159 namecache.clear();
1160 autoid_counter = 0;
1161
1162 // Get the top module, or a reasonable facsimile - we need something for the circuit name.
1163 Module *top = design->top_module();
1164 Module *last = nullptr;
1165 // Generate module and wire names.
1166 for (auto module : design->modules()) {
1167 make_id(module->name);
1168 last = module;
1169 if (top == nullptr && module->get_bool_attribute("\\top")) {
1170 top = module;
1171 }
1172 for (auto wire : module->wires())
1173 if (wire->port_id)
1174 make_id(wire->name);
1175 }
1176
1177 if (top == nullptr)
1178 top = last;
1179
1180 std::ostringstream fileinfo;
1181 for (auto &it : top->attributes) {
1182 if (it.first == "\\src") {
1183 dump_const(fileinfo, it.second);
1184 }
1185 }
1186
1187 *f << stringf("circuit %s: @[%s]\n", make_id(top->name), fileinfo.str().c_str());
1188
1189 for (auto module : design->modules())
1190 {
1191 FirrtlWorker worker(module, *f, design);
1192 worker.run();
1193 }
1194
1195 namecache.clear();
1196 autoid_counter = 0;
1197 }
1198 } FirrtlBackend;
1199
1200 PRIVATE_NAMESPACE_END