Merge pull request #1797 from epfl-vlsc/firrtl_backend_fileinfo

Keep file information when emitting firrtl
This commit is contained in:
Claire Wolf 2020-04-16 18:50:43 +02:00 committed by GitHub
commit 7a434cdd7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 51 additions and 29 deletions

View File

@ -42,6 +42,13 @@ static const FDirection FD_OUT = 0x2;
static const FDirection FD_INOUT = 0x3; static const FDirection FD_INOUT = 0x3;
static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width static const int FIRRTL_MAX_DSH_WIDTH_ERROR = 20; // For historic reasons, this is actually one greater than the maximum allowed shift width
std::string getFileinfo(const RTLIL::AttrObject *design_entity)
{
std::string src(design_entity->get_src_attribute());
std::string fileinfo_str = src.empty() ? "" : "@[" + src + "]";
return fileinfo_str;
}
// Get a port direction with respect to a specific module. // Get a port direction with respect to a specific module.
FDirection getPortFDirection(IdString id, Module *module) FDirection getPortFDirection(IdString id, Module *module)
{ {
@ -192,9 +199,10 @@ struct FirrtlWorker
if (this->width == 0) { if (this->width == 0) {
log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine()); log_error("Memory %s has zero width%s\n", this->name.c_str(), this->atLine());
} }
} }
// We need a default constructor for the dict insert. // We need a default constructor for the dict insert.
memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){} memory() : pCell(0), read_latency(0), write_latency(1), init_file(""), init_file_srcFileSpec(""){}
const char *atLine() { const char *atLine() {
if (srcLine == "") { if (srcLine == "") {
@ -329,7 +337,8 @@ 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;
} }
wire_exprs.push_back(stringf("%s" "inst %s%s of %s", indent.c_str(), cell_name.c_str(), cell_name_comment.c_str(), instanceOf.c_str())); 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()));
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) {
@ -370,7 +379,7 @@ struct FirrtlWorker
// as part of the coalesced subfield assignments for this wire. // as part of the coalesced subfield assignments for this wire.
register_reverse_wire_map(sourceExpr, *sinkSig); register_reverse_wire_map(sourceExpr, *sinkSig);
} else { } else {
wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str())); wire_exprs.push_back(stringf("\n%s%s <= %s %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str(), cellFileinfo.c_str()));
} }
} }
} }
@ -394,12 +403,15 @@ struct FirrtlWorker
void run() void run()
{ {
f << stringf(" module %s:\n", make_id(module->name)); std::string moduleFileinfo = getFileinfo(module);
f << stringf(" module %s: %s\n", make_id(module->name), moduleFileinfo.c_str());
vector<string> port_decls, wire_decls, cell_exprs, wire_exprs; vector<string> port_decls, wire_decls, cell_exprs, wire_exprs;
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
const auto wireName = make_id(wire->name); const auto wireName = make_id(wire->name);
std::string wireFileinfo = getFileinfo(wire);
// If a wire has initial data, issue a warning since FIRRTL doesn't currently support it. // If a wire has initial data, issue a warning since FIRRTL doesn't currently support it.
if (wire->attributes.count(ID::init)) { if (wire->attributes.count(ID::init)) {
log_warning("Initial value (%s) for (%s.%s) not supported\n", log_warning("Initial value (%s) for (%s.%s) not supported\n",
@ -410,12 +422,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>\n", wire->port_input ? "input" : "output", port_decls.push_back(stringf(" %s %s: UInt<%d> %s\n", wire->port_input ? "input" : "output",
wireName, wire->width)); wireName, wire->width, wireFileinfo.c_str()));
} }
else else
{ {
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", wireName, wire->width)); wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", wireName, wire->width, wireFileinfo.c_str()));
} }
} }
@ -423,7 +435,7 @@ struct FirrtlWorker
{ {
static Const ndef(0, 0); static Const ndef(0, 0);
// Is this cell is a module instance? // Is this cell is a module instance?
if (cell->type[0] != '$') if (cell->type[0] != '$')
{ {
process_instance(cell, wire_exprs); process_instance(cell, wire_exprs);
@ -441,11 +453,12 @@ struct FirrtlWorker
string primop; string primop;
bool always_uint = false; bool always_uint = false;
string y_id = make_id(cell->name); string y_id = make_id(cell->name);
std::string cellFileinfo = getFileinfo(cell);
if (cell->type.in(ID($not), ID($logic_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($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>\n", y_id.c_str(), y_width)); wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", 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 + ")";
@ -464,16 +477,16 @@ struct FirrtlWorker
firrtl_is_signed = true; // Result of "neg" is signed (an SInt). firrtl_is_signed = true; // Result of "neg" is signed (an SInt).
firrtl_width = a_width; firrtl_width = a_width;
} else if (cell->type == ID($logic_not)) { } else if (cell->type == ID($logic_not)) {
primop = "eq"; primop = "eq";
a_expr = stringf("%s, UInt(0)", a_expr.c_str()); a_expr = stringf("%s, UInt(0)", a_expr.c_str());
} }
else if (cell->type == ID($reduce_and)) primop = "andr"; else if (cell->type == ID($reduce_and)) primop = "andr";
else if (cell->type == ID($reduce_or)) primop = "orr"; else if (cell->type == ID($reduce_or)) primop = "orr";
else if (cell->type == ID($reduce_xor)) primop = "xorr"; else if (cell->type == ID($reduce_xor)) primop = "xorr";
else if (cell->type == ID($reduce_xnor)) { else if (cell->type == ID($reduce_xnor)) {
primop = "not"; primop = "not";
a_expr = stringf("xorr(%s)", a_expr.c_str()); a_expr = stringf("xorr(%s)", a_expr.c_str());
} }
else if (cell->type == ID($reduce_bool)) { else if (cell->type == ID($reduce_bool)) {
primop = "neq"; primop = "neq";
// Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand. // Use the sign of the a_expr and its width as the type (UInt/SInt) and width of the comparand.
@ -485,18 +498,19 @@ 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\n", y_id.c_str(), expr.c_str())); cell_exprs.push_back(stringf(" %s <= %s %s\n", 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;
} }
if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($xnor), ID($and), ID($or), ID($eq), ID($eqx), if (cell->type.in(ID($add), ID($sub), ID($mul), ID($div), ID($mod), ID($xor), ID($xnor), ID($and), ID($or), ID($eq), ID($eqx),
ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl), ID($gt), ID($ge), ID($lt), ID($le), ID($ne), ID($nex), ID($shr), ID($sshr), ID($sshl), ID($shl),
ID($logic_and), ID($logic_or), ID($pow))) ID($logic_and), ID($logic_or), ID($pow)))
{ {
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));
wire_decls.push_back(stringf(" wire %s: UInt<%d>\n", y_id.c_str(), y_width)); 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()));
if (a_signed) { if (a_signed) {
a_expr = "asSInt(" + a_expr + ")"; a_expr = "asSInt(" + a_expr + ")";
@ -579,7 +593,7 @@ struct FirrtlWorker
primop = "eq"; primop = "eq";
always_uint = true; always_uint = true;
firrtl_width = 1; firrtl_width = 1;
} }
else if ((cell->type == ID($ne)) | (cell->type == ID($nex))) { else if ((cell->type == ID($ne)) | (cell->type == ID($nex))) {
primop = "neq"; primop = "neq";
always_uint = true; always_uint = true;
@ -712,7 +726,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\n", y_id.c_str(), expr.c_str())); cell_exprs.push_back(stringf(" %s <= %s %s\n", 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;
@ -724,11 +738,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>\n", y_id.c_str(), width)); wire_decls.push_back(stringf(" wire %s: UInt<%d> %s\n", 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\n", y_id.c_str(), expr.c_str())); cell_exprs.push_back(stringf(" %s <= %s %s\n", 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;
@ -867,9 +881,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\n", y_id.c_str(), width, clk_expr.c_str())); wire_decls.push_back(stringf(" reg %s: UInt<%d>, %s %s\n", y_id.c_str(), width, clk_expr.c_str(), cellFileinfo.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", 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;
@ -959,6 +973,7 @@ struct FirrtlWorker
for (auto wire : module->wires()) for (auto wire : module->wires())
{ {
string expr; string expr;
std::string wireFileinfo = getFileinfo(wire);
if (wire->port_input) if (wire->port_input)
continue; continue;
@ -1017,14 +1032,20 @@ 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>\n", unconn_id.c_str())); wire_decls.push_back(stringf(" wire %s: UInt<1> %s\n", 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 is invalid\n", unconn_id.c_str()));
} }
wire_exprs.push_back(stringf(" %s <= %s\n", make_id(wire->name), expr.c_str())); wire_exprs.push_back(stringf(" %s <= %s %s\n", 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();
} }
// `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 is invalid\n", make_id(wire->name)));
} }
} }
@ -1123,7 +1144,8 @@ struct FirrtlBackend : public Backend {
if (top == nullptr) if (top == nullptr)
top = last; top = last;
*f << stringf("circuit %s:\n", make_id(top->name)); std::string circuitFileinfo = getFileinfo(top);
*f << stringf("circuit %s: %s\n", make_id(top->name), circuitFileinfo.c_str());
for (auto module : design->modules()) for (auto module : design->modules())
{ {