2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Claire Xenia Wolf <claire@yosyshq.com>
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.
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.
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"
33 PRIVATE_NAMESPACE_BEGIN
35 pool
<string
> used_names
;
36 dict
<IdString
, string
> namecache
;
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
46 std::string
getFileinfo(const RTLIL::AttrObject
*design_entity
)
48 std::string
src(design_entity
->get_src_attribute());
49 std::string fileinfo_str
= src
.empty() ? "" : "@[" + src
+ "]";
53 // Get a port direction with respect to a specific module.
54 FDirection
getPortFDirection(IdString id
, Module
*module
)
56 Wire
*wire
= module
->wires_
.at(id
);
57 FDirection direction
= FD_NODIRECTION
;
58 if (wire
&& wire
->port_id
)
62 if (wire
->port_output
)
73 new_id
= stringf("_%d", autoid_counter
++);
74 if (used_names
.count(new_id
) == 0) break;
77 used_names
.insert(new_id
);
81 const char *make_id(IdString id
)
83 if (namecache
.count(id
) != 0)
84 return namecache
.at(id
).c_str();
86 string new_id
= log_id(id
);
88 for (int i
= 0; i
< GetSize(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;
98 while (used_names
.count(new_id
) != 0)
101 namecache
[id
] = new_id
;
102 used_names
.insert(new_id
);
103 return namecache
.at(id
).c_str();
106 std::string
dump_const_string(const RTLIL::Const
&data
)
110 std::string str
= data
.decode_string();
111 for (size_t i
= 0; i
< str
.size(); i
++)
115 else if (str
[i
] == '\t')
117 else if (str
[i
] < 32)
118 res_str
+= stringf("\\%03o", str
[i
]);
119 else if (str
[i
] == '"')
121 else if (str
[i
] == '\\')
130 std::string
dump_const(const RTLIL::Const
&data
)
134 // // For debugging purposes to find out how Yosys encodes flags.
135 // res_str += stringf("flags_%x --> ", data.flags);
137 // Real-valued parameter.
138 if (data
.flags
& RTLIL::CONST_FLAG_REAL
)
140 // Yosys stores real values as strings, so we call the string dumping code.
141 res_str
+= dump_const_string(data
);
144 else if (data
.flags
& RTLIL::CONST_FLAG_STRING
)
147 res_str
+= dump_const_string(data
);
150 // Numeric (non-real) parameter.
153 int width
= data
.bits
.size();
155 // If a standard 32-bit int, then emit standard int value like "56" or
156 // "-56". Firrtl supports negative-valued int literals.
159 // : ( '+' | '-' ) PosInt
165 for (int i
= 0; i
< width
; i
++)
167 switch (data
.bits
[i
])
169 case State::S0
: break;
170 case State::S1
: int_val
|= (1 << i
); break;
172 log_error("Unexpected int value\n");
177 res_str
+= stringf("%d", int_val
);
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:
185 // Note that parameter may be defined as having a fixed width as follows:
187 // parameter signed [26:0] test_signed;
188 // parameter [26:0] test_unsigned;
189 // parameter signed [40:0] test_signed_large;
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.
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)
199 // We therefore may lose the precision of the original verilog literal if
200 // it was written without its bitwidth specifier.
202 // Emit binary prefix for string.
206 for (int i
= width
- 1; i
>= 0; i
--)
208 log_assert(i
< width
);
209 switch (data
.bits
[i
])
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;
227 std::string
extmodule_name(RTLIL::Cell
*cell
, RTLIL::Module
*mod_instance
)
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
;
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.
243 void emit_extmodule(RTLIL::Cell
*cell
, RTLIL::Module
*mod_instance
, std::ostream
&f
)
245 const std::string indent
= " ";
247 const std::string blackbox_name
= std::string(make_id(mod_instance
->name
));
248 const std::string exported_name
= extmodule_name(cell
, mod_instance
);
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
254 const std::string extmoduleFileinfo
= getFileinfo(cell
);
256 // Emit extmodule header.
257 f
<< stringf(" extmodule %s: %s\n", exported_name
.c_str(), extmoduleFileinfo
.c_str());
259 // Emit extmodule ports.
260 for (auto wire
: mod_instance
->wires())
262 const auto wireName
= make_id(wire
->name
);
263 const std::string wireFileinfo
= getFileinfo(wire
);
265 if (wire
->port_input
&& wire
->port_output
)
267 log_error("Module port %s.%s is inout!\n", log_id(mod_instance
), log_id(wire
));
270 const std::string portDecl
= stringf("%s%s %s: UInt<%d> %s\n",
272 wire
->port_input
? "input" : "output",
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
284 f
<< stringf("%sdefname = %s\n", indent
.c_str(), blackbox_name
.c_str());
286 // Emit extmodule generic parameters.
287 for (const auto &p
: cell
->parameters
)
289 const RTLIL::IdString p_id
= p
.first
;
290 const RTLIL::Const p_value
= p
.second
;
292 std::string
param_name(p_id
.c_str());
293 const std::string param_value
= dump_const(p_value
);
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.
301 std::remove(param_name
.begin(), param_name
.end(), '\\'),
305 f
<< stringf("%sparameter %s = %s\n", indent
.c_str(), param_name
.c_str(), param_value
.c_str());
312 * Emits extmodules for every instantiated blackbox in the design.
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
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
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
330 * <blackbox_name>_<instance_name>
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
336 void emit_elaborated_extmodules(RTLIL::Design
*design
, std::ostream
&f
)
338 for (auto module
: design
->modules())
340 for (auto cell
: module
->cells())
342 // Is this cell a module instance?
343 bool cellIsModuleInstance
= cell
->type
[0] != '$';
345 if (cellIsModuleInstance
)
347 // Find the module corresponding to this instance.
348 auto modInstance
= design
->module(cell
->type
);
349 bool modIsBlackbox
= modInstance
->get_blackbox_attribute();
353 emit_extmodule(cell
, modInstance
, f
);
365 dict
<SigBit
, pair
<string
, int>> reverse_wire_map
;
367 RTLIL::Design
*design
;
370 void register_reverse_wire_map(string id
, SigSpec sig
)
372 for (int i
= 0; i
< GetSize(sig
); i
++)
373 reverse_wire_map
[sig
[i
]] = make_pair(id
, i
);
376 FirrtlWorker(Module
*module
, std::ostream
&f
, RTLIL::Design
*theDesign
) : module(module
), f(f
), design(theDesign
), indent(" ")
380 static string
make_expr(const SigSpec
&sig
)
384 for (auto chunk
: sig
.chunks())
388 if (chunk
.wire
== nullptr)
390 std::vector
<RTLIL::State
> bits
= chunk
.data
;
391 new_expr
= stringf("UInt<%d>(\"h", GetSize(bits
));
393 while (GetSize(bits
) % 4 != 0)
394 bits
.push_back(State::S0
);
396 for (int i
= GetSize(bits
)-4; i
>= 0; i
-= 4)
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);
408 else if (chunk
.offset
== 0 && chunk
.width
== chunk
.wire
->width
)
410 new_expr
= make_id(chunk
.wire
->name
);
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
);
421 expr
= "cat(" + new_expr
+ ", " + expr
+ ")";
427 std::string
fid(RTLIL::IdString internal_id
)
429 return make_id(internal_id
);
432 std::string
cellname(RTLIL::Cell
*cell
)
434 return fid(cell
->name
).c_str();
437 void process_instance(RTLIL::Cell
*cell
, vector
<string
> &wire_exprs
)
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"))
444 log_assert(cell
->has_attribute(ID::hdlname
));
445 instanceOf
= cell
->get_string_attribute(ID::hdlname
);
449 instanceOf
= cell_type
;
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
) + " */ ";
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
)
463 log_warning("No instance for %s.%s\n", cell_type
.c_str(), cell_name
.c_str());
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
) :
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()));
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;
488 log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type
.c_str(), log_signal(it
->second
));
491 sourceExpr
= firstName
;
492 sinkExpr
= secondExpr
;
493 sinkSig
= &secondSig
;
496 log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type
.c_str(), log_signal(it
->second
));
499 sourceExpr
= secondExpr
;
500 sinkExpr
= firstName
;
503 log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type
.c_str(), log_signal(it
->second
), dir
);
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
);
516 wire_exprs
.push_back(stringf("\n%s%s <= %s %s", indent
.c_str(), sinkExpr
.c_str(), sourceExpr
.c_str(), cellFileinfo
.c_str()));
520 wire_exprs
.push_back(stringf("\n"));
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
)
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);
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
;
544 std::vector
<Mem
> memories
= Mem::get_all_memories(module
);
545 for (auto &mem
: memories
)
548 for (auto wire
: module
->wires())
550 const auto wireName
= make_id(wire
->name
);
551 std::string wireFileinfo
= getFileinfo(wire
);
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
));
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()));
568 wire_decls
.push_back(stringf("%swire %s: UInt<%d> %s\n", indent
.c_str(), wireName
, wire
->width
, wireFileinfo
.c_str()));
572 for (auto cell
: module
->cells())
576 // Is this cell is a module instance?
577 if (module
->design
->module(cell
->type
))
579 process_instance(cell
, wire_exprs
);
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;
593 bool always_uint
= false;
594 string y_id
= make_id(cell
->name
);
595 std::string cellFileinfo
= getFileinfo(cell
);
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
)))
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()));
603 a_expr
= "asSInt(" + a_expr
+ ")";
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
);
611 // Assume the FIRRTL width is a single bit.
613 if (cell
->type
.in(ID($
not), ID($_NOT_
))) primop
= "not";
614 else if (cell
->type
== ID($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
)) {
620 a_expr
= stringf("%s, UInt(0)", a_expr
.c_str());
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
)) {
627 a_expr
= stringf("xorr(%s)", a_expr
.c_str());
629 else if (cell
->type
== ID($reduce_bool
)) {
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
);
635 string expr
= stringf("%s(%s)", primop
.c_str(), a_expr
.c_str());
637 if ((firrtl_is_signed
&& !always_uint
))
638 expr
= stringf("asUInt(%s)", expr
.c_str());
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
));
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
)))
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()));
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
);
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
);
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_
)))
677 if (a_width
< y_width
) {
678 a_expr
= stringf("pad(%s, %d)", a_expr
.c_str(), y_width
);
681 if (b_width
< y_width
) {
682 b_expr
= stringf("pad(%s, %d)", b_expr
.c_str(), y_width
);
686 // Assume the FIRRTL width is the width of "A"
687 firrtl_width
= a_width
;
688 auto a_sig
= cell
->getPort(ID::A
);
690 if (cell
->type
== ID($add
)) {
692 firrtl_is_signed
= a_signed
| b_signed
;
693 firrtl_width
= max(a_width
, b_width
);
694 } else if (cell
->type
== ID($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
)) {
702 firrtl_is_signed
= a_signed
| b_signed
;
703 firrtl_width
= a_width
+ b_width
;
704 } else if (cell
->type
== ID($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
711 firrtl_width
= min(a_width
, b_width
);
712 } else if (cell
->type
.in(ID($
and), ID($_AND_
))) {
715 firrtl_width
= max(a_width
, b_width
);
717 else if (cell
->type
.in(ID($
or), ID($_OR_
))) {
720 firrtl_width
= max(a_width
, b_width
);
722 else if (cell
->type
.in(ID($
xor), ID($_XOR_
))) {
725 firrtl_width
= max(a_width
, b_width
);
727 else if (cell
->type
== ID($xnor
)) {
730 firrtl_width
= max(a_width
, b_width
);
732 else if ((cell
->type
== ID($eq
)) | (cell
->type
== ID($eqx
))) {
737 else if ((cell
->type
== ID($ne
)) | (cell
->type
== ID($nex
))) {
742 else if (cell
->type
== ID($gt
)) {
747 else if (cell
->type
== ID($ge
)) {
752 else if (cell
->type
== ID($lt
)) {
757 else if (cell
->type
== ID($le
)) {
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()) {
770 int shift_amount
= b_sig
.as_int();
771 b_expr
= std::to_string(shift_amount
);
772 firrtl_width
= a_width
+ shift_amount
;
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;
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()) {
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
);
792 firrtl_width
= a_width
;
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
+ ")";
802 else if ((cell
->type
== ID($logic_and
))) {
804 a_expr
= "neq(" + a_expr
+ ", UInt(0))";
805 b_expr
= "neq(" + b_expr
+ ", UInt(0))";
809 else if ((cell
->type
== ID($logic_or
))) {
811 a_expr
= "neq(" + a_expr
+ ", UInt(0))";
812 b_expr
= "neq(" + b_expr
+ ", UInt(0))";
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()) {
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
));
833 b_expr
= std::to_string(shiftAmount
);
834 firrtl_width
= a_width
+ shiftAmount
;
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;
842 log_error("Non power 2: %s.%s\n", log_id(module
), log_id(cell
));
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
+ ")";
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());
856 expr
= stringf("%s(%s, %s)", primop
.c_str(), a_expr
.c_str(), b_expr
.c_str());
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
);
867 if ((firrtl_is_signed
&& !always_uint
))
868 expr
= stringf("asUInt(%s)", expr
.c_str());
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
));
876 if (cell
->type
.in(ID($mux
), ID($_MUX_
)))
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()));
885 string expr
= stringf("mux(%s, %s, %s)", s_expr
.c_str(), b_expr
.c_str(), a_expr
.c_str());
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
));
893 if (cell
->is_mem_cell())
895 // Will be handled below, as part of a Mem.
899 if (cell
->type
.in(ID($dff
)))
901 bool clkpol
= cell
->parameters
.at(ID::CLK_POLARITY
).as_bool();
903 log_error("Negative edge clock on FF %s.%s.\n", log_id(module
), log_id(cell
));
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
)) + ")";
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()));
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
));
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.
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
));
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
);
932 string expr
= stringf("dshr(%s, %s)", a_expr
.c_str(), b_expr
.c_str());
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
));
938 if (cell
->type
== ID($shift
)) {
939 // assign y = a >> b;
940 // where b may be negative
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();
946 wire_decls
.push_back(stringf("%swire %s: UInt<%d>\n", indent
.c_str(), y_id
.c_str(), y_width
));
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)",
958 expr
= stringf("dshr(%s, %s)", a_expr
.c_str(), b_string
);
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
));
964 if (cell
->type
== ID($pos
)) {
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",
970 if (a_width
< y_width
) {
971 a_expr
= stringf("pad(%s, %d)", a_expr
.c_str(), y_width
);
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
));
978 log_error("Cell type not supported: %s (%s.%s)\n", log_id(cell
->type
), log_id(module
), log_id(cell
));
981 for (auto &mem
: memories
) {
982 string mem_id
= make_id(mem
.memid
);
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
));
988 if (mem
.start_offset
!= 0)
989 log_error("Memory with nonzero offset: %s.%s\n", log_id(module
), log_id(mem
.memid
));
991 for (int i
= 0; i
< GetSize(mem
.rd_ports
); i
++)
993 auto &port
= mem
.rd_ports
[i
];
994 string
port_name(stringf("%s.r%d", mem_id
.c_str(), i
));
997 log_error("Clocked read port %d on memory %s.%s.\n", i
, log_id(module
), log_id(mem
.memid
));
999 std::ostringstream rpe
;
1001 string addr_expr
= make_expr(port
.addr
);
1002 string ena_expr
= make_expr(State::S1
);
1003 string clk_expr
= make_expr(State::S0
);
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
);
1012 for (int i
= 0; i
< GetSize(mem
.wr_ports
); i
++)
1014 auto &port
= mem
.wr_ports
[i
];
1015 string
port_name(stringf("%s.w%d", mem_id
.c_str(), i
));
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
));
1025 std::ostringstream wpe
;
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());
1038 cell_exprs
.push_back(wpe
.str());
1041 std::ostringstream me
;
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");
1054 mem_exprs
.push_back(me
.str());
1057 for (auto conn
: module
->connections())
1059 string y_id
= next_id();
1060 int y_width
= GetSize(conn
.first
);
1061 string expr
= make_expr(conn
.second
);
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
);
1068 for (auto wire
: module
->wires())
1071 std::string wireFileinfo
= getFileinfo(wire
);
1073 if (wire
->port_input
)
1077 bool is_valid
= false;
1078 bool make_unconn_id
= false;
1080 while (cursor
< wire
->width
)
1082 int chunk_width
= 1;
1085 SigBit
start_bit(wire
, cursor
);
1087 if (reverse_wire_map
.count(start_bit
))
1089 pair
<string
, int> start_map
= reverse_wire_map
.at(start_bit
);
1091 while (cursor
+chunk_width
< wire
->width
)
1093 SigBit
stop_bit(wire
, cursor
+chunk_width
);
1095 if (reverse_wire_map
.count(stop_bit
) == 0)
1098 pair
<string
, int> stop_map
= reverse_wire_map
.at(stop_bit
);
1099 stop_map
.second
-= chunk_width
;
1101 if (start_map
!= stop_map
)
1107 new_expr
= stringf("bits(%s, %d, %d)", start_map
.first
.c_str(),
1108 start_map
.second
+ chunk_width
- 1, start_map
.second
);
1113 if (unconn_id
.empty()) {
1114 unconn_id
= next_id();
1115 make_unconn_id
= true;
1117 new_expr
= unconn_id
;
1123 expr
= "cat(" + new_expr
+ ", " + expr
+ ")";
1125 cursor
+= chunk_width
;
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()));
1136 wire_exprs
.push_back(stringf("%s%s <= %s %s\n", indent
.c_str(), make_id(wire
->name
), expr
.c_str(), wireFileinfo
.c_str()));
1138 if (make_unconn_id
) {
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
)));
1148 for (auto str
: port_decls
)
1153 for (auto str
: wire_decls
)
1158 for (auto str
: mem_exprs
)
1163 for (auto str
: cell_exprs
)
1168 for (auto str
: wire_exprs
)
1180 struct FirrtlBackend
: public Backend
{
1181 FirrtlBackend() : Backend("firrtl", "write design to a FIRRTL file") { }
1182 void help() override
1184 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
1186 log(" write_firrtl [options] [filename]\n");
1188 log("Write a FIRRTL netlist of the current design.\n");
1189 log("The following commands are executed by this command:\n");
1195 void execute(std::ostream
*&f
, std::string filename
, std::vector
<std::string
> args
, RTLIL::Design
*design
) override
1197 size_t argidx
= args
.size(); // We aren't expecting any arguments.
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.
1204 filename
= args
[argidx
];
1207 extra_args(f
, filename
, args
, argidx
);
1209 if (!design
->full_selection())
1210 log_cmd_error("This command only operates on fully selected designs!\n");
1212 log_header(design
, "Executing FIRRTL backend.\n");
1215 Pass::call(design
, "pmuxtree");
1216 Pass::call(design
, "bmuxmap");
1217 Pass::call(design
, "demuxmap");
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
);
1229 if (top
== nullptr && module
->get_bool_attribute(ID::top
)) {
1232 for (auto wire
: module
->wires())
1234 make_id(wire
->name
);
1240 std::string circuitFileinfo
= getFileinfo(top
);
1241 *f
<< stringf("circuit %s: %s\n", make_id(top
->name
), circuitFileinfo
.c_str());
1243 emit_elaborated_extmodules(design
, *f
);
1245 // Emit non-blackbox modules.
1246 for (auto module
: design
->modules())
1248 if (!module
->get_blackbox_attribute())
1250 FirrtlWorker
worker(module
, *f
, design
);
1260 PRIVATE_NAMESPACE_END