mirror of https://github.com/YosysHQ/yosys.git
Merge pull request #2295 from epfl-vlsc/firrtl_blackbox_generic_parameters
Add firrtl backend support for generic parameters in blackbox components
This commit is contained in:
commit
b8d3f13307
|
@ -102,6 +102,260 @@ const char *make_id(IdString id)
|
|||
return namecache.at(id).c_str();
|
||||
}
|
||||
|
||||
std::string dump_const_string(const RTLIL::Const &data)
|
||||
{
|
||||
std::string res_str;
|
||||
|
||||
std::string str = data.decode_string();
|
||||
for (size_t i = 0; i < str.size(); i++)
|
||||
{
|
||||
if (str[i] == '\n')
|
||||
res_str += "\\n";
|
||||
else if (str[i] == '\t')
|
||||
res_str += "\\t";
|
||||
else if (str[i] < 32)
|
||||
res_str += stringf("\\%03o", str[i]);
|
||||
else if (str[i] == '"')
|
||||
res_str += "\\\"";
|
||||
else if (str[i] == '\\')
|
||||
res_str += "\\\\";
|
||||
else
|
||||
res_str += str[i];
|
||||
}
|
||||
|
||||
return res_str;
|
||||
}
|
||||
|
||||
std::string dump_const(const RTLIL::Const &data)
|
||||
{
|
||||
std::string res_str;
|
||||
|
||||
// // For debugging purposes to find out how Yosys encodes flags.
|
||||
// res_str += stringf("flags_%x --> ", data.flags);
|
||||
|
||||
// Real-valued parameter.
|
||||
if (data.flags & RTLIL::CONST_FLAG_REAL)
|
||||
{
|
||||
// Yosys stores real values as strings, so we call the string dumping code.
|
||||
res_str += dump_const_string(data);
|
||||
}
|
||||
// String parameter.
|
||||
else if (data.flags & RTLIL::CONST_FLAG_STRING)
|
||||
{
|
||||
res_str += "\"";
|
||||
res_str += dump_const_string(data);
|
||||
res_str += "\"";
|
||||
}
|
||||
// Numeric (non-real) parameter.
|
||||
else
|
||||
{
|
||||
int width = data.bits.size();
|
||||
|
||||
// If a standard 32-bit int, then emit standard int value like "56" or
|
||||
// "-56". Firrtl supports negative-valued int literals.
|
||||
//
|
||||
// SignedInt
|
||||
// : ( '+' | '-' ) PosInt
|
||||
// ;
|
||||
if (width <= 32)
|
||||
{
|
||||
int32_t int_val = 0;
|
||||
|
||||
for (int i = 0; i < width; i++)
|
||||
{
|
||||
switch (data.bits[i])
|
||||
{
|
||||
case State::S0: break;
|
||||
case State::S1: int_val |= (1 << i); break;
|
||||
default:
|
||||
log_error("Unexpected int value\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res_str += stringf("%d", int_val);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If value is larger than 32 bits, then emit a binary representation of
|
||||
// the number as integers are not large enough to contain the result.
|
||||
// There is a caveat to this approach though:
|
||||
//
|
||||
// Note that parameter may be defined as having a fixed width as follows:
|
||||
//
|
||||
// parameter signed [26:0] test_signed;
|
||||
// parameter [26:0] test_unsigned;
|
||||
// parameter signed [40:0] test_signed_large;
|
||||
//
|
||||
// However, if you assign a value on the RHS without specifying the
|
||||
// precision, then yosys considers the value you used as an int and
|
||||
// assigns it a width of 32 bits regardless of the type of the parameter.
|
||||
//
|
||||
// defparam <inst_name> .test_signed = 49; (width = 32, though should be 27 based on definition)
|
||||
// defparam <inst_name> .test_unsigned = 40'd35; (width = 40, though should be 27 based on definition)
|
||||
// defparam <inst_name> .test_signed_large = 40'd12; (width = 40)
|
||||
//
|
||||
// We therefore may lose the precision of the original verilog literal if
|
||||
// it was written without its bitwidth specifier.
|
||||
|
||||
// Emit binary prefix for string.
|
||||
res_str += "\"b";
|
||||
|
||||
// Emit bits.
|
||||
for (int i = width - 1; i >= 0; i--)
|
||||
{
|
||||
log_assert(i < width);
|
||||
switch (data.bits[i])
|
||||
{
|
||||
case State::S0: res_str += "0"; break;
|
||||
case State::S1: res_str += "1"; break;
|
||||
case State::Sx: res_str += "x"; break;
|
||||
case State::Sz: res_str += "z"; break;
|
||||
case State::Sa: res_str += "-"; break;
|
||||
case State::Sm: res_str += "m"; break;
|
||||
}
|
||||
}
|
||||
|
||||
res_str += "\"";
|
||||
}
|
||||
}
|
||||
|
||||
return res_str;
|
||||
}
|
||||
|
||||
std::string extmodule_name(RTLIL::Cell *cell, RTLIL::Module *mod_instance)
|
||||
{
|
||||
// Since we are creating a custom extmodule for every cell that instantiates
|
||||
// this blackbox, we need to create a custom name for it. We just use the
|
||||
// name of the blackbox itself followed by the name of the cell.
|
||||
const std::string cell_name = std::string(make_id(cell->name));
|
||||
const std::string blackbox_name = std::string(make_id(mod_instance->name));
|
||||
const std::string extmodule_name = blackbox_name + "_" + cell_name;
|
||||
return extmodule_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits a parameterized extmodule. Instance parameters are obtained from
|
||||
* ''cell'' as it represents the instantiation of the blackbox defined by
|
||||
* ''mod_instance'' and therefore contains all its instance parameters.
|
||||
*/
|
||||
void emit_extmodule(RTLIL::Cell *cell, RTLIL::Module *mod_instance, std::ostream &f)
|
||||
{
|
||||
const std::string indent = " ";
|
||||
|
||||
const std::string blackbox_name = std::string(make_id(mod_instance->name));
|
||||
const std::string exported_name = extmodule_name(cell, mod_instance);
|
||||
|
||||
// We use the cell's fileinfo for this extmodule as its parameters come from
|
||||
// the cell and not from the module itself (the module contains default
|
||||
// parameters, not the instance-specific ones we're using to emit the
|
||||
// extmodule).
|
||||
const std::string extmoduleFileinfo = getFileinfo(cell);
|
||||
|
||||
// Emit extmodule header.
|
||||
f << stringf(" extmodule %s: %s\n", exported_name.c_str(), extmoduleFileinfo.c_str());
|
||||
|
||||
// Emit extmodule ports.
|
||||
for (auto wire : mod_instance->wires())
|
||||
{
|
||||
const auto wireName = make_id(wire->name);
|
||||
const std::string wireFileinfo = getFileinfo(wire);
|
||||
|
||||
if (wire->port_input && wire->port_output)
|
||||
{
|
||||
log_error("Module port %s.%s is inout!\n", log_id(mod_instance), log_id(wire));
|
||||
}
|
||||
|
||||
const std::string portDecl = stringf("%s%s %s: UInt<%d> %s\n",
|
||||
indent.c_str(),
|
||||
wire->port_input ? "input" : "output",
|
||||
wireName,
|
||||
wire->width,
|
||||
wireFileinfo.c_str()
|
||||
);
|
||||
|
||||
f << portDecl;
|
||||
}
|
||||
|
||||
// Emit extmodule "defname" field. This is the name of the verilog blackbox
|
||||
// that is used when verilog is emitted, so we use the name of mod_instance
|
||||
// here.
|
||||
f << stringf("%sdefname = %s\n", indent.c_str(), blackbox_name.c_str());
|
||||
|
||||
// Emit extmodule generic parameters.
|
||||
for (const auto &p : cell->parameters)
|
||||
{
|
||||
const RTLIL::IdString p_id = p.first;
|
||||
const RTLIL::Const p_value = p.second;
|
||||
|
||||
std::string param_name(p_id.c_str());
|
||||
const std::string param_value = dump_const(p_value);
|
||||
|
||||
// Remove backslashes from parameters as these come from the internal RTLIL
|
||||
// naming scheme, but should not exist in the emitted firrtl blackboxes.
|
||||
// When firrtl is converted to verilog and given to downstream synthesis
|
||||
// tools, these tools expect to find blackbox names and parameters as they
|
||||
// were originally defined, i.e. without the extra RTLIL naming conventions.
|
||||
param_name.erase(
|
||||
std::remove(param_name.begin(), param_name.end(), '\\'),
|
||||
param_name.end()
|
||||
);
|
||||
|
||||
f << stringf("%sparameter %s = %s\n", indent.c_str(), param_name.c_str(), param_value.c_str());
|
||||
}
|
||||
|
||||
f << "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits extmodules for every instantiated blackbox in the design.
|
||||
*
|
||||
* RTLIL stores instance parameters at the cell's instantiation location.
|
||||
* However, firrtl does not support module parameterization (everything is
|
||||
* already elaborated). Firrtl instead supports external modules (extmodule),
|
||||
* i.e. blackboxes that are defined by verilog and which have no body in
|
||||
* firrtl itself other than the declaration of the blackboxes ports and
|
||||
* parameters.
|
||||
*
|
||||
* Furthermore, firrtl does not support parameterization (even of extmodules)
|
||||
* at a module's instantiation location and users must instead declare
|
||||
* different extmodules with different instance parameters in the extmodule
|
||||
* definition itself.
|
||||
*
|
||||
* This function goes through the design to identify all RTLIL blackboxes
|
||||
* and emit parameterized extmodules with a unique name for each of them. The
|
||||
* name that's given to the extmodule is
|
||||
*
|
||||
* <blackbox_name>_<instance_name>
|
||||
*
|
||||
* Beware that it is therefore necessary for users to replace "parameterized"
|
||||
* instances in the RTLIL sense with these custom extmodules for the firrtl to
|
||||
* be valid.
|
||||
*/
|
||||
void emit_elaborated_extmodules(RTLIL::Design *design, std::ostream &f)
|
||||
{
|
||||
for (auto module : design->modules())
|
||||
{
|
||||
for (auto cell : module->cells())
|
||||
{
|
||||
// Is this cell a module instance?
|
||||
bool cellIsModuleInstance = cell->type[0] != '$';
|
||||
|
||||
if (cellIsModuleInstance)
|
||||
{
|
||||
// Find the module corresponding to this instance.
|
||||
auto modInstance = design->module(cell->type);
|
||||
bool modIsBlackbox = modInstance->get_blackbox_attribute();
|
||||
|
||||
if (modIsBlackbox)
|
||||
{
|
||||
emit_extmodule(cell, modInstance, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct FirrtlWorker
|
||||
{
|
||||
Module *module;
|
||||
|
@ -328,8 +582,16 @@ struct FirrtlWorker
|
|||
log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// If the instance is that of a blackbox, use the modified extmodule name
|
||||
// that contains per-instance parameterizations. These instances were
|
||||
// emitted earlier in the firrtl backend.
|
||||
const std::string instanceName = instModule->get_blackbox_attribute() ?
|
||||
extmodule_name(cell, instModule) :
|
||||
instanceOf;
|
||||
|
||||
std::string cellFileinfo = getFileinfo(cell);
|
||||
wire_exprs.push_back(stringf("%s" "inst %s%s of %s %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str(), cellFileinfo.c_str()));
|
||||
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()));
|
||||
|
||||
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
|
||||
if (it->second.size() > 0) {
|
||||
|
@ -392,33 +654,6 @@ struct FirrtlWorker
|
|||
return result;
|
||||
}
|
||||
|
||||
void emit_extmodule()
|
||||
{
|
||||
std::string moduleFileinfo = getFileinfo(module);
|
||||
f << stringf(" extmodule %s: %s\n", make_id(module->name), moduleFileinfo.c_str());
|
||||
vector<std::string> port_decls;
|
||||
|
||||
for (auto wire : module->wires())
|
||||
{
|
||||
const auto wireName = make_id(wire->name);
|
||||
std::string wireFileinfo = getFileinfo(wire);
|
||||
|
||||
if (wire->port_input && wire->port_output)
|
||||
{
|
||||
log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
|
||||
}
|
||||
port_decls.push_back(stringf(" %s %s: UInt<%d> %s\n", wire->port_input ? "input" : "output",
|
||||
wireName, wire->width, wireFileinfo.c_str()));
|
||||
}
|
||||
|
||||
for (auto &str : port_decls)
|
||||
{
|
||||
f << str;
|
||||
}
|
||||
|
||||
f << stringf("\n");
|
||||
}
|
||||
|
||||
void emit_module()
|
||||
{
|
||||
std::string moduleFileinfo = getFileinfo(module);
|
||||
|
@ -440,12 +675,12 @@ struct FirrtlWorker
|
|||
{
|
||||
if (wire->port_input && wire->port_output)
|
||||
log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
|
||||
port_decls.push_back(stringf(" %s %s: UInt<%d> %s\n", wire->port_input ? "input" : "output",
|
||||
port_decls.push_back(stringf("%s%s %s: UInt<%d> %s\n", indent.c_str(), wire->port_input ? "input" : "output",
|
||||
wireName, wire->width, wireFileinfo.c_str()));
|
||||
}
|
||||
else
|
||||
{
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", wireName, wire->width, wireFileinfo.c_str()));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), wireName, wire->width, wireFileinfo.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -476,7 +711,7 @@ struct FirrtlWorker
|
|||
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)))
|
||||
{
|
||||
string a_expr = make_expr(cell->getPort(ID::A));
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), y_width, cellFileinfo.c_str()));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str()));
|
||||
|
||||
if (a_signed) {
|
||||
a_expr = "asSInt(" + a_expr + ")";
|
||||
|
@ -516,7 +751,7 @@ struct FirrtlWorker
|
|||
if ((firrtl_is_signed && !always_uint))
|
||||
expr = stringf("asUInt(%s)", expr.c_str());
|
||||
|
||||
cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
|
||||
continue;
|
||||
|
@ -528,7 +763,7 @@ struct FirrtlWorker
|
|||
string a_expr = make_expr(cell->getPort(ID::A));
|
||||
string b_expr = make_expr(cell->getPort(ID::B));
|
||||
std::string cellFileinfo = getFileinfo(cell);
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), y_width, cellFileinfo.c_str()));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), y_width, cellFileinfo.c_str()));
|
||||
|
||||
if (a_signed) {
|
||||
a_expr = "asSInt(" + a_expr + ")";
|
||||
|
@ -746,7 +981,7 @@ struct FirrtlWorker
|
|||
if ((firrtl_is_signed && !always_uint))
|
||||
expr = stringf("asUInt(%s)", expr.c_str());
|
||||
|
||||
cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
|
||||
continue;
|
||||
|
@ -759,11 +994,11 @@ struct FirrtlWorker
|
|||
string a_expr = make_expr(cell->getPort(ID::A));
|
||||
string b_expr = make_expr(cell->getPort(ID::B));
|
||||
string s_expr = make_expr(cell->getPort(ID::S));
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", y_id.c_str(), width, cellFileinfo.c_str()));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d> %s\n", indent.c_str(), y_id.c_str(), width, cellFileinfo.c_str()));
|
||||
|
||||
string expr = stringf("mux(%s, %s, %s)", s_expr.c_str(), b_expr.c_str(), a_expr.c_str());
|
||||
|
||||
cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
|
||||
continue;
|
||||
|
@ -902,9 +1137,9 @@ struct FirrtlWorker
|
|||
string expr = make_expr(cell->getPort(ID::D));
|
||||
string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")";
|
||||
|
||||
wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s %s\n", y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.c_str()));
|
||||
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()));
|
||||
|
||||
cell_exprs.push_back(stringf(" %s <= %s %s\n", y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), y_id.c_str(), expr.c_str(), cellFileinfo.c_str()));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Q));
|
||||
|
||||
continue;
|
||||
|
@ -923,7 +1158,7 @@ struct FirrtlWorker
|
|||
string a_expr = make_expr(cell->getPort(ID::A));
|
||||
// Get the initial bit selector
|
||||
string b_expr = make_expr(cell->getPort(ID::B));
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width));
|
||||
|
||||
if (cell->getParam(ID::B_SIGNED).as_bool()) {
|
||||
// Use validif to constrain the selection (test the sign bit)
|
||||
|
@ -933,7 +1168,7 @@ struct FirrtlWorker
|
|||
}
|
||||
string expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_expr.c_str());
|
||||
|
||||
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str()));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
continue;
|
||||
}
|
||||
|
@ -945,7 +1180,7 @@ struct FirrtlWorker
|
|||
string b_expr = make_expr(cell->getPort(ID::B));
|
||||
auto b_string = b_expr.c_str();
|
||||
string expr;
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width));
|
||||
|
||||
if (cell->getParam(ID::B_SIGNED).as_bool()) {
|
||||
// We generate a left or right shift based on the sign of b.
|
||||
|
@ -959,7 +1194,7 @@ struct FirrtlWorker
|
|||
} else {
|
||||
expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
|
||||
}
|
||||
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str()));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
continue;
|
||||
}
|
||||
|
@ -972,8 +1207,8 @@ struct FirrtlWorker
|
|||
if (a_width < y_width) {
|
||||
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), y_width);
|
||||
}
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
|
||||
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), a_expr.c_str()));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), a_expr.c_str()));
|
||||
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||
continue;
|
||||
}
|
||||
|
@ -986,8 +1221,8 @@ struct FirrtlWorker
|
|||
int y_width = GetSize(conn.first);
|
||||
string expr = make_expr(conn.second);
|
||||
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width));
|
||||
cell_exprs.push_back(stringf(" %s <= %s\n", y_id.c_str(), expr.c_str()));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<%d>\n", indent.c_str(), y_id.c_str(), y_width));
|
||||
cell_exprs.push_back(stringf("%s%s <= %s\n", indent.c_str(), y_id.c_str(), expr.c_str()));
|
||||
register_reverse_wire_map(y_id, conn.first);
|
||||
}
|
||||
|
||||
|
@ -1053,13 +1288,13 @@ struct FirrtlWorker
|
|||
|
||||
if (is_valid) {
|
||||
if (make_unconn_id) {
|
||||
wire_decls.push_back(stringf(" wire %s: UInt<1> %s\n", unconn_id.c_str(), wireFileinfo.c_str()));
|
||||
wire_decls.push_back(stringf("%swire %s: UInt<1> %s\n", indent.c_str(), unconn_id.c_str(), wireFileinfo.c_str()));
|
||||
// `invalid` is a firrtl construction for simulation so we will not
|
||||
// tag it with a @[fileinfo] tag as it doesn't directly correspond to
|
||||
// a specific line of verilog code.
|
||||
wire_decls.push_back(stringf(" %s is invalid\n", unconn_id.c_str()));
|
||||
wire_decls.push_back(stringf("%s%s is invalid\n", indent.c_str(), unconn_id.c_str()));
|
||||
}
|
||||
wire_exprs.push_back(stringf(" %s <= %s %s\n", make_id(wire->name), expr.c_str(), wireFileinfo.c_str()));
|
||||
wire_exprs.push_back(stringf("%s%s <= %s %s\n", indent.c_str(), make_id(wire->name), expr.c_str(), wireFileinfo.c_str()));
|
||||
} else {
|
||||
if (make_unconn_id) {
|
||||
unconn_id.clear();
|
||||
|
@ -1067,7 +1302,7 @@ struct FirrtlWorker
|
|||
// `invalid` is a firrtl construction for simulation so we will not
|
||||
// tag it with a @[fileinfo] tag as it doesn't directly correspond to
|
||||
// a specific line of verilog code.
|
||||
wire_decls.push_back(stringf(" %s is invalid\n", make_id(wire->name)));
|
||||
wire_decls.push_back(stringf("%s%s is invalid\n", indent.c_str(), make_id(wire->name)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1112,12 +1347,7 @@ struct FirrtlWorker
|
|||
|
||||
void run()
|
||||
{
|
||||
// Blackboxes should be emitted as `extmodule`s in firrtl. Only ports are
|
||||
// emitted in such a case.
|
||||
if (module->get_blackbox_attribute())
|
||||
emit_extmodule();
|
||||
else
|
||||
emit_module();
|
||||
emit_module();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1180,10 +1410,16 @@ struct FirrtlBackend : public Backend {
|
|||
std::string circuitFileinfo = getFileinfo(top);
|
||||
*f << stringf("circuit %s: %s\n", make_id(top->name), circuitFileinfo.c_str());
|
||||
|
||||
emit_elaborated_extmodules(design, *f);
|
||||
|
||||
// Emit non-blackbox modules.
|
||||
for (auto module : design->modules())
|
||||
{
|
||||
FirrtlWorker worker(module, *f, design);
|
||||
worker.run();
|
||||
if (!module->get_blackbox_attribute())
|
||||
{
|
||||
FirrtlWorker worker(module, *f, design);
|
||||
worker.run();
|
||||
}
|
||||
}
|
||||
|
||||
namecache.clear();
|
||||
|
|
Loading…
Reference in New Issue