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

cxxrtl: simplify generated edge detection logic.

This commit changes the way edge detectors are represented in
generated code from a variable that is set in commit() and reset in
eval() to a function that considers .curr and .next of the clock
wire. Behavior remains the same. Besides being simpler to generate
and providing more opportunities for optimization, this commit paves
way for unbuffering module inputs.
This commit is contained in:
whitequark 2020-04-21 13:59:42 +00:00
parent 757cbb3c80
commit 12c5e9275c

View file

@ -915,7 +915,7 @@ struct CxxrtlWorker {
RTLIL::SigBit clk_bit = cell->getPort(ID::CLK)[0]; RTLIL::SigBit clk_bit = cell->getPort(ID::CLK)[0];
clk_bit = sigmaps[clk_bit.wire->module](clk_bit); clk_bit = sigmaps[clk_bit.wire->module](clk_bit);
f << indent << "if (" << (cell->getParam(ID::CLK_POLARITY).as_bool() ? "posedge_" : "negedge_") f << indent << "if (" << (cell->getParam(ID::CLK_POLARITY).as_bool() ? "posedge_" : "negedge_")
<< mangle(clk_bit) << ") {\n"; << mangle(clk_bit) << "()) {\n";
inc_indent(); inc_indent();
if (cell->type == ID($dffe)) { if (cell->type == ID($dffe)) {
f << indent << "if ("; f << indent << "if (";
@ -992,7 +992,7 @@ struct CxxrtlWorker {
RTLIL::SigBit clk_bit = cell->getPort(ID::CLK)[0]; RTLIL::SigBit clk_bit = cell->getPort(ID::CLK)[0];
clk_bit = sigmaps[clk_bit.wire->module](clk_bit); clk_bit = sigmaps[clk_bit.wire->module](clk_bit);
f << indent << "if (" << (cell->getParam(ID::CLK_POLARITY).as_bool() ? "posedge_" : "negedge_") f << indent << "if (" << (cell->getParam(ID::CLK_POLARITY).as_bool() ? "posedge_" : "negedge_")
<< mangle(clk_bit) << ") {\n"; << mangle(clk_bit) << "()) {\n";
inc_indent(); inc_indent();
} }
RTLIL::Memory *memory = cell->module->memories[cell->getParam(ID::MEMID).decode_string()]; RTLIL::Memory *memory = cell->module->memories[cell->getParam(ID::MEMID).decode_string()];
@ -1217,16 +1217,16 @@ struct CxxrtlWorker {
switch (sync->type) { switch (sync->type) {
case RTLIL::STp: case RTLIL::STp:
log_assert(sync_bit.wire != nullptr); log_assert(sync_bit.wire != nullptr);
events.insert("posedge_" + mangle(sync_bit)); events.insert("posedge_" + mangle(sync_bit) + "()");
break; break;
case RTLIL::STn: case RTLIL::STn:
log_assert(sync_bit.wire != nullptr); log_assert(sync_bit.wire != nullptr);
events.insert("negedge_" + mangle(sync_bit)); events.insert("negedge_" + mangle(sync_bit) + "()");
break; break;
case RTLIL::STe: case RTLIL::STe:
log_assert(sync_bit.wire != nullptr); log_assert(sync_bit.wire != nullptr);
events.insert("posedge_" + mangle(sync_bit)); events.insert("posedge_" + mangle(sync_bit) + "()");
events.insert("negedge_" + mangle(sync_bit)); events.insert("negedge_" + mangle(sync_bit) + "()");
break; break;
case RTLIL::STa: case RTLIL::STa:
@ -1290,10 +1290,23 @@ struct CxxrtlWorker {
if (sync_wires[wire]) { if (sync_wires[wire]) {
for (auto sync_type : sync_types) { for (auto sync_type : sync_types) {
if (sync_type.first.wire == wire) { if (sync_type.first.wire == wire) {
if (sync_type.second != RTLIL::STn) if (sync_type.second != RTLIL::STn) {
f << indent << "bool posedge_" << mangle(sync_type.first) << " = false;\n"; f << indent << "bool posedge_" << mangle(sync_type.first) << "() const {\n";
if (sync_type.second != RTLIL::STp) inc_indent();
f << indent << "bool negedge_" << mangle(sync_type.first) << " = false;\n"; f << indent << "return ";
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();
f << indent << "}\n";
} else {
f << indent << "bool negedge_" << mangle(sync_type.first) << "() const {\n";
inc_indent();
f << indent << "return ";
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();
f << indent << "}\n";
}
} }
} }
} }
@ -1365,14 +1378,6 @@ struct CxxrtlWorker {
} }
} }
} }
for (auto sync_type : sync_types) {
if (sync_type.first.wire->module == module) {
if (sync_type.second != RTLIL::STn)
f << indent << "posedge_" << mangle(sync_type.first) << " = false;\n";
if (sync_type.second != RTLIL::STp)
f << indent << "negedge_" << mangle(sync_type.first) << " = false;\n";
}
}
dec_indent(); dec_indent();
} }
@ -1383,39 +1388,8 @@ 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 (sync_wires[wire]) { if (!module->get_bool_attribute(ID(cxxrtl.blackbox)) || wire->port_id != 0)
std::string wire_prev = mangle(wire) + "_prev";
std::string wire_curr = mangle(wire) + ".curr";
std::string wire_edge = mangle(wire) + "_edge";
f << indent << "value<" << wire->width << "> " << wire_prev << " = " << wire_curr << ";\n";
f << indent << "if (" << mangle(wire) << ".commit()) {\n";
inc_indent();
f << indent << "value<" << wire->width << "> " << wire_edge << " = "
<< wire_prev << ".bit_xor(" << wire_curr << ");\n";
for (auto sync_type : sync_types) {
if (sync_type.first.wire != wire)
continue;
if (sync_type.second != RTLIL::STn) {
f << indent << "if (" << wire_edge << ".slice<" << sync_type.first.offset << ">().val() && "
<< wire_curr << ".slice<" << sync_type.first.offset << ">().val())\n";
inc_indent();
f << indent << "posedge_" << mangle(sync_type.first) << " = true;\n";
dec_indent();
}
if (sync_type.second != RTLIL::STp) {
f << indent << "if (" << wire_edge << ".slice<" << sync_type.first.offset << ">().val() && "
<< "!" << wire_curr << ".slice<" << sync_type.first.offset << ">().val())\n";
inc_indent();
f << indent << "negedge_" << mangle(sync_type.first) << " = true;\n";
dec_indent();
}
f << indent << "changed = true;\n";
}
dec_indent();
f << indent << "}\n";
} else 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";
}
} }
if (!module->get_bool_attribute(ID(cxxrtl.blackbox))) { if (!module->get_bool_attribute(ID(cxxrtl.blackbox))) {
for (auto memory : module->memories) { for (auto memory : module->memories) {
@ -2005,7 +1979,7 @@ struct CxxrtlBackend : public Backend {
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(" wire<1> p_clk;\n");
log(" bool posedge_p_clk = false;\n"); log(" bool posedge_p_clk() const { /* ... */ }\n");
log(" wire<1> p_en;\n"); log(" wire<1> p_en;\n");
log(" wire<8> p_data;\n"); log(" wire<8> p_data;\n");
log("\n"); log("\n");
@ -2023,7 +1997,7 @@ 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.curr)\n");
log(" fprintf(stderr, \"debug: %%02x\\n\", p_data.curr.data[0]);\n"); log(" fprintf(stderr, \"debug: %%02x\\n\", p_data.curr.data[0]);\n");
log(" bb_p_debug::eval();\n"); log(" bb_p_debug::eval();\n");
log(" }\n"); log(" }\n");
@ -2086,10 +2060,9 @@ struct CxxrtlBackend : public Backend {
log("\n"); log("\n");
log(" cxxrtl.edge\n"); log(" cxxrtl.edge\n");
log(" only valid on inputs of black boxes. must be one of \"p\", \"n\", \"a\".\n"); log(" only valid on inputs of black boxes. must be one of \"p\", \"n\", \"a\".\n");
log(" if specified on signal `clk`, the generated code includes boolean fields\n"); log(" if specified on signal `clk`, the generated code includes edge detectors\n");
log(" `posedge_p_clk` (if \"p\"), `negedge_p_clk` (if \"n\"), or both (if \"a\"),\n"); log(" `posedge_p_clk()` (if \"p\"), `negedge_p_clk()` (if \"n\"), or both (if\n");
log(" as well as edge detection logic, simplifying implementation of clocked\n"); log(" \"a\"), simplifying implementation of clocked black boxes.\n");
log(" black boxes.\n");
log("\n"); log("\n");
log(" cxxrtl.template\n"); log(" cxxrtl.template\n");
log(" only valid on black boxes. must contain a space separated sequence of\n"); log(" only valid on black boxes. must contain a space separated sequence of\n");