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();
|
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
|
struct FirrtlWorker
|
||||||
{
|
{
|
||||||
Module *module;
|
Module *module;
|
||||||
|
@ -328,8 +582,16 @@ struct FirrtlWorker
|
||||||
log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
|
log_warning("No instance for %s.%s\n", cell_type.c_str(), cell_name.c_str());
|
||||||
return;
|
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);
|
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) {
|
for (auto it = cell->connections().begin(); it != cell->connections().end(); ++it) {
|
||||||
if (it->second.size() > 0) {
|
if (it->second.size() > 0) {
|
||||||
|
@ -392,33 +654,6 @@ struct FirrtlWorker
|
||||||
return result;
|
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()
|
void emit_module()
|
||||||
{
|
{
|
||||||
std::string moduleFileinfo = getFileinfo(module);
|
std::string moduleFileinfo = getFileinfo(module);
|
||||||
|
@ -440,12 +675,12 @@ struct FirrtlWorker
|
||||||
{
|
{
|
||||||
if (wire->port_input && wire->port_output)
|
if (wire->port_input && wire->port_output)
|
||||||
log_error("Module port %s.%s is inout!\n", log_id(module), log_id(wire));
|
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()));
|
wireName, wire->width, wireFileinfo.c_str()));
|
||||||
}
|
}
|
||||||
else
|
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)))
|
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));
|
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) {
|
if (a_signed) {
|
||||||
a_expr = "asSInt(" + a_expr + ")";
|
a_expr = "asSInt(" + a_expr + ")";
|
||||||
|
@ -516,7 +751,7 @@ struct FirrtlWorker
|
||||||
if ((firrtl_is_signed && !always_uint))
|
if ((firrtl_is_signed && !always_uint))
|
||||||
expr = stringf("asUInt(%s)", expr.c_str());
|
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));
|
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -528,7 +763,7 @@ struct FirrtlWorker
|
||||||
string a_expr = make_expr(cell->getPort(ID::A));
|
string a_expr = make_expr(cell->getPort(ID::A));
|
||||||
string b_expr = make_expr(cell->getPort(ID::B));
|
string b_expr = make_expr(cell->getPort(ID::B));
|
||||||
std::string cellFileinfo = getFileinfo(cell);
|
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) {
|
if (a_signed) {
|
||||||
a_expr = "asSInt(" + a_expr + ")";
|
a_expr = "asSInt(" + a_expr + ")";
|
||||||
|
@ -746,7 +981,7 @@ struct FirrtlWorker
|
||||||
if ((firrtl_is_signed && !always_uint))
|
if ((firrtl_is_signed && !always_uint))
|
||||||
expr = stringf("asUInt(%s)", expr.c_str());
|
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));
|
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -759,11 +994,11 @@ struct FirrtlWorker
|
||||||
string a_expr = make_expr(cell->getPort(ID::A));
|
string a_expr = make_expr(cell->getPort(ID::A));
|
||||||
string b_expr = make_expr(cell->getPort(ID::B));
|
string b_expr = make_expr(cell->getPort(ID::B));
|
||||||
string s_expr = make_expr(cell->getPort(ID::S));
|
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());
|
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));
|
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -902,9 +1137,9 @@ struct FirrtlWorker
|
||||||
string expr = make_expr(cell->getPort(ID::D));
|
string expr = make_expr(cell->getPort(ID::D));
|
||||||
string clk_expr = "asClock(" + make_expr(cell->getPort(ID::CLK)) + ")";
|
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));
|
register_reverse_wire_map(y_id, cell->getPort(ID::Q));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
|
@ -923,7 +1158,7 @@ struct FirrtlWorker
|
||||||
string a_expr = make_expr(cell->getPort(ID::A));
|
string a_expr = make_expr(cell->getPort(ID::A));
|
||||||
// Get the initial bit selector
|
// Get the initial bit selector
|
||||||
string b_expr = make_expr(cell->getPort(ID::B));
|
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()) {
|
if (cell->getParam(ID::B_SIGNED).as_bool()) {
|
||||||
// Use validif to constrain the selection (test the sign bit)
|
// 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());
|
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));
|
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -945,7 +1180,7 @@ struct FirrtlWorker
|
||||||
string b_expr = make_expr(cell->getPort(ID::B));
|
string b_expr = make_expr(cell->getPort(ID::B));
|
||||||
auto b_string = b_expr.c_str();
|
auto b_string = b_expr.c_str();
|
||||||
string expr;
|
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()) {
|
if (cell->getParam(ID::B_SIGNED).as_bool()) {
|
||||||
// We generate a left or right shift based on the sign of b.
|
// We generate a left or right shift based on the sign of b.
|
||||||
|
@ -959,7 +1194,7 @@ struct FirrtlWorker
|
||||||
} else {
|
} else {
|
||||||
expr = stringf("dshr(%s, %s)", a_expr.c_str(), b_string);
|
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));
|
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -972,8 +1207,8 @@ struct FirrtlWorker
|
||||||
if (a_width < y_width) {
|
if (a_width < y_width) {
|
||||||
a_expr = stringf("pad(%s, %d)", a_expr.c_str(), 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));
|
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\n", y_id.c_str(), a_expr.c_str()));
|
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));
|
register_reverse_wire_map(y_id, cell->getPort(ID::Y));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -986,8 +1221,8 @@ struct FirrtlWorker
|
||||||
int y_width = GetSize(conn.first);
|
int y_width = GetSize(conn.first);
|
||||||
string expr = make_expr(conn.second);
|
string expr = make_expr(conn.second);
|
||||||
|
|
||||||
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));
|
||||||
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, conn.first);
|
register_reverse_wire_map(y_id, conn.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,13 +1288,13 @@ struct FirrtlWorker
|
||||||
|
|
||||||
if (is_valid) {
|
if (is_valid) {
|
||||||
if (make_unconn_id) {
|
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
|
// `invalid` is a firrtl construction for simulation so we will not
|
||||||
// tag it with a @[fileinfo] tag as it doesn't directly correspond to
|
// tag it with a @[fileinfo] tag as it doesn't directly correspond to
|
||||||
// a specific line of verilog code.
|
// 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 {
|
} else {
|
||||||
if (make_unconn_id) {
|
if (make_unconn_id) {
|
||||||
unconn_id.clear();
|
unconn_id.clear();
|
||||||
|
@ -1067,7 +1302,7 @@ struct FirrtlWorker
|
||||||
// `invalid` is a firrtl construction for simulation so we will not
|
// `invalid` is a firrtl construction for simulation so we will not
|
||||||
// tag it with a @[fileinfo] tag as it doesn't directly correspond to
|
// tag it with a @[fileinfo] tag as it doesn't directly correspond to
|
||||||
// a specific line of verilog code.
|
// 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()
|
void run()
|
||||||
{
|
{
|
||||||
// Blackboxes should be emitted as `extmodule`s in firrtl. Only ports are
|
emit_module();
|
||||||
// emitted in such a case.
|
|
||||||
if (module->get_blackbox_attribute())
|
|
||||||
emit_extmodule();
|
|
||||||
else
|
|
||||||
emit_module();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1180,10 +1410,16 @@ struct FirrtlBackend : public Backend {
|
||||||
std::string circuitFileinfo = getFileinfo(top);
|
std::string circuitFileinfo = getFileinfo(top);
|
||||||
*f << stringf("circuit %s: %s\n", make_id(top->name), circuitFileinfo.c_str());
|
*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())
|
for (auto module : design->modules())
|
||||||
{
|
{
|
||||||
FirrtlWorker worker(module, *f, design);
|
if (!module->get_blackbox_attribute())
|
||||||
worker.run();
|
{
|
||||||
|
FirrtlWorker worker(module, *f, design);
|
||||||
|
worker.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namecache.clear();
|
namecache.clear();
|
||||||
|
|
Loading…
Reference in New Issue