3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-12 20:18:20 +00:00

cxxrtl: unbuffer module input wires.

Module input wires are never set by the module, so it is unnecessary
to buffer them. Although important for all inputs, this is especially
critical for clocks, since after this commit, hierarchy levels no
longer add delta cycles. As a result, Minerva SRAM SoC runs ~73%
faster when flattened, and ~264% (!!) faster when hierarchical.
This commit is contained in:
whitequark 2020-04-21 14:49:36 +00:00
parent 12c5e9275c
commit 06985c3afd

View file

@ -360,6 +360,11 @@ struct FlowGraph {
} }
}; };
bool is_input_wire(const RTLIL::Wire *wire)
{
return wire->port_input && !wire->port_output;
}
bool is_cxxrtl_blackbox_cell(const RTLIL::Cell *cell) bool is_cxxrtl_blackbox_cell(const RTLIL::Cell *cell)
{ {
RTLIL::Module *cell_module = cell->module->design->module(cell->type); RTLIL::Module *cell_module = cell->module->design->module(cell->type);
@ -685,7 +690,7 @@ struct CxxrtlWorker {
default: default:
log_assert(false); log_assert(false);
} }
} else if (localized_wires[chunk.wire]) { } else if (localized_wires[chunk.wire] || is_input_wire(chunk.wire)) {
f << mangle(chunk.wire); f << mangle(chunk.wire);
} else { } else {
f << mangle(chunk.wire) << (is_lhs ? ".next" : ".curr"); f << mangle(chunk.wire) << (is_lhs ? ".next" : ".curr");
@ -1093,7 +1098,11 @@ struct CxxrtlWorker {
log_assert(cell->known()); log_assert(cell->known());
const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : "."; const char *access = is_cxxrtl_blackbox_cell(cell) ? "->" : ".";
for (auto conn : cell->connections()) for (auto conn : cell->connections())
if (cell->input(conn.first)) { if (cell->input(conn.first) && !cell->output(conn.first)) {
f << indent << mangle(cell) << access << mangle_wire_name(conn.first) << " = ";
dump_sigspec_rhs(conn.second);
f << ";\n";
} else if (cell->input(conn.first)) {
f << indent << mangle(cell) << access << mangle_wire_name(conn.first) << ".next = "; f << indent << mangle(cell) << access << mangle_wire_name(conn.first) << ".next = ";
dump_sigspec_rhs(conn.second); dump_sigspec_rhs(conn.second);
f << ";\n"; f << ";\n";
@ -1258,21 +1267,17 @@ struct CxxrtlWorker {
} }
} }
void dump_wire(const RTLIL::Wire *wire, bool is_local) void dump_wire(const RTLIL::Wire *wire, bool is_local_context)
{ {
if (elided_wires.count(wire)) if (elided_wires.count(wire))
return; return;
if (localized_wires.count(wire) != is_local_context)
return;
if (is_local) { if (is_local_context) {
if (!localized_wires.count(wire))
return;
dump_attrs(wire); dump_attrs(wire);
f << indent << "value<" << wire->width << "> " << mangle(wire) << ";\n"; f << indent << "value<" << wire->width << "> " << mangle(wire) << ";\n";
} else { } else {
if (localized_wires.count(wire))
return;
std::string width; std::string width;
if (wire->module->has_attribute(ID(cxxrtl.blackbox)) && wire->has_attribute(ID(cxxrtl.width))) { if (wire->module->has_attribute(ID(cxxrtl.blackbox)) && wire->has_attribute(ID(cxxrtl.width))) {
width = wire->get_string_attribute(ID(cxxrtl.width)); width = wire->get_string_attribute(ID(cxxrtl.width));
@ -1281,29 +1286,44 @@ struct CxxrtlWorker {
} }
dump_attrs(wire); dump_attrs(wire);
f << indent << "wire<" << width << "> " << mangle(wire); f << indent << (is_input_wire(wire) ? "value" : "wire") << "<" << width << "> " << mangle(wire);
if (wire->has_attribute(ID::init)) { if (wire->has_attribute(ID::init)) {
f << " "; f << " ";
dump_const_init(wire->attributes.at(ID::init)); dump_const_init(wire->attributes.at(ID::init));
} }
f << ";\n"; f << ";\n";
if (sync_wires[wire]) { if (sync_wires[wire]) {
if (is_input_wire(wire)) {
f << indent << "value<" << width << "> prev_" << mangle(wire);
if (wire->has_attribute(ID::init)) {
f << " ";
dump_const_init(wire->attributes.at(ID::init));
}
f << ";\n";
}
for (auto sync_type : sync_types) { for (auto sync_type : sync_types) {
if (sync_type.first.wire == wire) { if (sync_type.first.wire == wire) {
std::string prev, next;
if (is_input_wire(wire)) {
prev = "prev_" + mangle(sync_type.first.wire);
next = mangle(sync_type.first.wire);
} else {
prev = mangle(sync_type.first.wire) + ".curr";
next = mangle(sync_type.first.wire) + ".next";
}
prev += ".slice<" + std::to_string(sync_type.first.offset) + ">().val()";
next += ".slice<" + std::to_string(sync_type.first.offset) + ">().val()";
if (sync_type.second != RTLIL::STn) { if (sync_type.second != RTLIL::STn) {
f << indent << "bool posedge_" << mangle(sync_type.first) << "() const {\n"; f << indent << "bool posedge_" << mangle(sync_type.first) << "() const {\n";
inc_indent(); inc_indent();
f << indent << "return "; f << indent << "return !" << prev << " && " << next << ";\n";
f << "!" << mangle(sync_type.first.wire) << ".curr.slice<" << sync_type.first.offset << ">().val() && ";
f << mangle(sync_type.first.wire) << ".next.slice<" << sync_type.first.offset << ">().val();\n";
dec_indent(); dec_indent();
f << indent << "}\n"; f << indent << "}\n";
} else { }
if (sync_type.second != RTLIL::STp) {
f << indent << "bool negedge_" << mangle(sync_type.first) << "() const {\n"; f << indent << "bool negedge_" << mangle(sync_type.first) << "() const {\n";
inc_indent(); inc_indent();
f << indent << "return "; f << indent << "return " << prev << " && !" << next << ";\n";
f << mangle(sync_type.first.wire) << ".curr.slice<" << sync_type.first.offset << ">().val() && ";
f << "!" << mangle(sync_type.first.wire) << ".next.slice<" << sync_type.first.offset << ">().val();\n";
dec_indent(); dec_indent();
f << indent << "}\n"; f << indent << "}\n";
} }
@ -1363,7 +1383,7 @@ struct CxxrtlWorker {
inc_indent(); inc_indent();
if (!module->get_bool_attribute(ID(cxxrtl.blackbox))) { if (!module->get_bool_attribute(ID(cxxrtl.blackbox))) {
for (auto wire : module->wires()) for (auto wire : module->wires())
dump_wire(wire, /*is_local=*/true); dump_wire(wire, /*is_local_context=*/true);
for (auto node : schedule[module]) { for (auto node : schedule[module]) {
switch (node.type) { switch (node.type) {
case FlowGraph::Node::Type::CONNECT: case FlowGraph::Node::Type::CONNECT:
@ -1388,6 +1408,11 @@ struct CxxrtlWorker {
for (auto wire : module->wires()) { for (auto wire : module->wires()) {
if (elided_wires.count(wire) || localized_wires.count(wire)) if (elided_wires.count(wire) || localized_wires.count(wire))
continue; continue;
if (is_input_wire(wire)) {
if (sync_wires[wire])
f << indent << "prev_" << mangle(wire) << " = " << mangle(wire) << ";\n";
continue;
}
if (!module->get_bool_attribute(ID(cxxrtl.blackbox)) || wire->port_id != 0) if (!module->get_bool_attribute(ID(cxxrtl.blackbox)) || wire->port_id != 0)
f << indent << "changed |= " << mangle(wire) << ".commit();\n"; f << indent << "changed |= " << mangle(wire) << ".commit();\n";
} }
@ -1445,7 +1470,7 @@ struct CxxrtlWorker {
inc_indent(); inc_indent();
for (auto wire : module->wires()) { for (auto wire : module->wires()) {
if (wire->port_id != 0) if (wire->port_id != 0)
dump_wire(wire, /*is_local=*/false); dump_wire(wire, /*is_local_context=*/false);
} }
f << "\n"; f << "\n";
f << indent << "void eval() override {\n"; f << indent << "void eval() override {\n";
@ -1485,7 +1510,7 @@ struct CxxrtlWorker {
f << indent << "struct " << mangle(module) << " : public module {\n"; f << indent << "struct " << mangle(module) << " : public module {\n";
inc_indent(); inc_indent();
for (auto wire : module->wires()) for (auto wire : module->wires())
dump_wire(wire, /*is_local=*/false); dump_wire(wire, /*is_local_context=*/false);
f << "\n"; f << "\n";
bool has_memories = false; bool has_memories = false;
for (auto memory : module->memories) { for (auto memory : module->memories) {
@ -1948,9 +1973,9 @@ struct CxxrtlBackend : public Backend {
log(" top.step();\n"); log(" top.step();\n");
log(" while (1) {\n"); log(" while (1) {\n");
log(" /* user logic */\n"); log(" /* user logic */\n");
log(" top.p_clk.next = value<1> {0u};\n"); log(" top.p_clk = value<1> {0u};\n");
log(" top.step();\n"); log(" top.step();\n");
log(" top.p_clk.next = value<1> {1u};\n"); log(" top.p_clk = value<1> {1u};\n");
log(" top.step();\n"); log(" top.step();\n");
log(" }\n"); log(" }\n");
log(" }\n"); log(" }\n");
@ -1972,16 +1997,18 @@ struct CxxrtlBackend : public Backend {
log(" module debug(...);\n"); log(" module debug(...);\n");
log(" (* cxxrtl.edge = \"p\" *) input clk;\n"); log(" (* cxxrtl.edge = \"p\" *) input clk;\n");
log(" input en;\n"); log(" input en;\n");
log(" input [7:0] data;\n"); log(" input [7:0] i_data;\n");
log(" output [7:0] o_data;\n");
log(" endmodule\n"); log(" endmodule\n");
log("\n"); log("\n");
log("For this HDL interface, this backend will generate the following C++ interface:\n"); log("For this HDL interface, this backend will generate the following C++ interface:\n");
log("\n"); log("\n");
log(" struct bb_p_debug : public module {\n"); log(" struct bb_p_debug : public module {\n");
log(" wire<1> p_clk;\n"); log(" value<1> p_clk;\n");
log(" bool posedge_p_clk() const { /* ... */ }\n"); log(" bool posedge_p_clk() const { /* ... */ }\n");
log(" wire<1> p_en;\n"); log(" value<1> p_en;\n");
log(" wire<8> p_data;\n"); log(" value<8> p_i_data;\n");
log(" wire<8> p_o_data;\n");
log("\n"); log("\n");
log(" void eval() override;\n"); log(" void eval() override;\n");
log(" bool commit() override;\n"); log(" bool commit() override;\n");
@ -1997,8 +2024,9 @@ struct CxxrtlBackend : public Backend {
log("\n"); log("\n");
log(" struct stderr_debug : public bb_p_debug {\n"); log(" struct stderr_debug : public bb_p_debug {\n");
log(" void eval() override {\n"); log(" void eval() override {\n");
log(" if (posedge_p_clk() && p_en.curr)\n"); log(" if (posedge_p_clk() && p_en)\n");
log(" fprintf(stderr, \"debug: %%02x\\n\", p_data.curr.data[0]);\n"); log(" fprintf(stderr, \"debug: %%02x\\n\", p_i_data.data[0]);\n");
log(" p_o_data.next = p_i_data;\n");
log(" bb_p_debug::eval();\n"); log(" bb_p_debug::eval();\n");
log(" }\n"); log(" }\n");
log(" };\n"); log(" };\n");
@ -2020,7 +2048,8 @@ struct CxxrtlBackend : public Backend {
log(" parameter WIDTH = 8;\n"); log(" parameter WIDTH = 8;\n");
log(" (* cxxrtl.edge = \"p\" *) input clk;\n"); log(" (* cxxrtl.edge = \"p\" *) input clk;\n");
log(" input en;\n"); log(" input en;\n");
log(" (* cxxrtl.width = \"WIDTH\" *) input [WIDTH - 1:0] data;\n"); log(" (* cxxrtl.width = \"WIDTH\" *) input [WIDTH - 1:0] i_data;\n");
log(" (* cxxrtl.width = \"WIDTH\" *) output [WIDTH - 1:0] o_data;\n");
log(" endmodule\n"); log(" endmodule\n");
log("\n"); log("\n");
log("For this parametric HDL interface, this backend will generate the following C++\n"); log("For this parametric HDL interface, this backend will generate the following C++\n");
@ -2029,7 +2058,8 @@ struct CxxrtlBackend : public Backend {
log(" template<size_t WIDTH>\n"); log(" template<size_t WIDTH>\n");
log(" struct bb_p_debug : public module {\n"); log(" struct bb_p_debug : public module {\n");
log(" // ...\n"); log(" // ...\n");
log(" wire<WIDTH> p_data;\n"); log(" value<WIDTH> p_i_data;\n");
log(" wire<WIDTH> p_o_data;\n");
log(" // ...\n"); log(" // ...\n");
log(" static std::unique_ptr<bb_p_debug<WIDTH>>\n"); log(" static std::unique_ptr<bb_p_debug<WIDTH>>\n");
log(" create(std::string name, metadata_map parameters, metadata_map attributes);\n"); log(" create(std::string name, metadata_map parameters, metadata_map attributes);\n");