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