diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 17080ef2e..8f9cd941e 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -282,6 +282,7 @@ struct FlowGraph { CONNECT, CELL_SYNC, CELL_EVAL, + PRINT_SYNC, PROCESS_SYNC, PROCESS_CASE, MEM_RDPORT, @@ -472,6 +473,8 @@ struct FlowGraph { Node *node = new Node; node->type = Node::Type::CELL_EVAL; + if (cell->type == ID($print) && cell->getParam(ID::TRG_ENABLE).as_bool()) + node->type = Node::Type::PRINT_SYNC; node->cell = cell; nodes.push_back(node); add_cell_eval_defs_uses(node, cell); @@ -1043,9 +1046,49 @@ struct CxxrtlWorker { Fmt fmt = {}; fmt.parse_rtlil(cell); - f << indent << print_output; - fmt.emit_cxxrtl(f, [this](const RTLIL::SigSpec &sig) { dump_sigspec_rhs(sig); }); - f << ";\n"; + f << indent << "if ("; + dump_sigspec_rhs(cell->getPort(ID::EN)); + f << " == value<1>{1u}) {\n"; + inc_indent(); + f << indent << print_output; + fmt.emit_cxxrtl(f, [this](const RTLIL::SigSpec &sig) { dump_sigspec_rhs(sig); }); + f << ";\n"; + dec_indent(); + f << indent << "}\n"; + } + + void dump_sync_print(const RTLIL::SigSpec &trg, const RTLIL::Const &polarity, std::vector &cells) + { + f << indent << "if ("; + for (int i = 0; i < trg.size(); i++) { + RTLIL::SigBit trg_bit = trg[i]; + trg_bit = sigmaps[trg_bit.wire->module](trg_bit); + log_assert(trg_bit.wire); + + if (i != 0) + f << " || "; + + if (polarity[i] == State::S1) + f << "posedge_"; + else + f << "negedge_"; + f << mangle(trg_bit); + } + f << ") {\n"; + inc_indent(); + std::sort(cells.begin(), cells.end(), [](const RTLIL::Cell *a, const RTLIL::Cell *b) { + return a->getParam(ID::PRIORITY).as_int() > b->getParam(ID::PRIORITY).as_int(); + }); + for (auto cell : cells) { + log_assert(cell->getParam(ID::TRG_ENABLE).as_bool()); + std::vector inlined_cells; + collect_cell_eval(cell, /*for_debug=*/false, inlined_cells); + dump_inlined_cells(inlined_cells); + dump_print(cell); + } + dec_indent(); + + f << indent << "}\n"; } void dump_inlined_cells(const std::vector &cells) @@ -1218,47 +1261,21 @@ struct CxxrtlWorker { } else if (cell->type == ID($print)) { log_assert(!for_debug); - auto trg_enable = cell->getParam(ID::TRG_ENABLE).as_bool(); + // Sync $print cells become PRINT_SYNC in the FlowGraph, not CELL_EVAL. + log_assert(!cell->getParam(ID::TRG_ENABLE).as_bool()); - if (!trg_enable) { - f << indent << "auto " << mangle(cell) << "_curr = "; - dump_sigspec_rhs(cell->getPort(ID::EN)); - f << ".concat("; - dump_sigspec_rhs(cell->getPort(ID::ARGS)); - f << ").val();\n"; - } - - f << indent << "if ("; - if (trg_enable) { - f << '('; - for (size_t i = 0; i < (size_t)cell->getParam(ID::TRG_WIDTH).as_int(); i++) { - RTLIL::SigBit trg_bit = cell->getPort(ID::TRG)[i]; - trg_bit = sigmaps[trg_bit.wire->module](trg_bit); - log_assert(trg_bit.wire); - - if (i != 0) - f << " || "; - - if (cell->getParam(ID::TRG_POLARITY)[i] == State::S1) - f << "posedge_"; - else - f << "negedge_"; - f << mangle(trg_bit); - } - f << ") && "; - } else { - f << mangle(cell) << " != " << mangle(cell) << "_curr && "; - } + f << indent << "auto " << mangle(cell) << "_curr = "; dump_sigspec_rhs(cell->getPort(ID::EN)); - f << " == value<1>{1u}) {\n"; + f << ".concat("; + dump_sigspec_rhs(cell->getPort(ID::ARGS)); + f << ").val();\n"; + + f << indent << "if (" << mangle(cell) << " != " << mangle(cell) << "_curr) {\n"; inc_indent(); dump_print(cell); + f << indent << mangle(cell) << " = " << mangle(cell) << "_curr;\n"; dec_indent(); f << indent << "}\n"; - - if (!trg_enable) { - f << indent << mangle(cell) << " = " << mangle(cell) << "_curr;\n"; - } // Flip-flops } else if (is_ff_cell(cell->type)) { log_assert(!for_debug); @@ -1971,6 +1988,8 @@ struct CxxrtlWorker { void dump_eval_method(RTLIL::Module *module) { + std::map, std::vector> sync_print_cells; + inc_indent(); f << indent << "bool converged = " << (eval_converges.at(module) ? "true" : "false") << ";\n"; if (!module->get_bool_attribute(ID(cxxrtl_blackbox))) { @@ -2003,6 +2022,9 @@ struct CxxrtlWorker { case FlowGraph::Node::Type::CELL_EVAL: dump_cell_eval(node.cell); break; + case FlowGraph::Node::Type::PRINT_SYNC: + sync_print_cells[make_pair(node.cell->getPort(ID::TRG), node.cell->getParam(ID::TRG_POLARITY))].push_back(node.cell); + break; case FlowGraph::Node::Type::PROCESS_CASE: dump_process_case(node.process); break; @@ -2017,6 +2039,8 @@ struct CxxrtlWorker { break; } } + for (auto &it : sync_print_cells) + dump_sync_print(it.first.first, it.first.second, it.second); } f << indent << "return converged;\n"; dec_indent(); @@ -2808,6 +2832,8 @@ struct CxxrtlWorker { for (auto node : flow.nodes) { if (node->type == FlowGraph::Node::Type::CELL_EVAL && is_effectful_cell(node->cell->type)) worklist.insert(node); // node has effects + else if (node->type == FlowGraph::Node::Type::PRINT_SYNC) + worklist.insert(node); // node is sync $print else if (node->type == FlowGraph::Node::Type::MEM_WRPORTS) worklist.insert(node); // node is memory write else if (node->type == FlowGraph::Node::Type::PROCESS_SYNC && is_memwr_process(node->process)) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index ca119427f..7099c18c3 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -1006,7 +1006,7 @@ void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell f << stringf(";\n"); } -void dump_cell_expr_print(std::ostream &f, std::string indent, RTLIL::Cell *cell) +void dump_cell_expr_print(std::ostream &f, std::string indent, const RTLIL::Cell *cell) { Fmt fmt = {}; fmt.parse_rtlil(cell); @@ -1893,7 +1893,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) } } -void dump_sync_print(std::ostream &f, std::string indent, const RTLIL::SigSpec &trg, const RTLIL::Const &polarity, std::vector &cells) +void dump_sync_print(std::ostream &f, std::string indent, const RTLIL::SigSpec &trg, const RTLIL::Const &polarity, std::vector &cells) { f << stringf("%s" "always @(", indent.c_str()); for (int i = 0; i < trg.size(); i++) { @@ -2102,7 +2102,7 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) { - std::map, std::vector> sync_print_cells; + std::map, std::vector> sync_print_cells; reg_wires.clear(); reset_auto_counter(module); diff --git a/tests/fmt/run-test.sh b/tests/fmt/run-test.sh index ba5aea9f6..914a72347 100644 --- a/tests/fmt/run-test.sh +++ b/tests/fmt/run-test.sh @@ -50,7 +50,7 @@ test_roundtrip bin_signed -DBASE_HEX -DSIGN="signed" test_cxxrtl () { local subtest=$1; shift - ../../yosys -p "read_verilog ${subtest}.v; write_cxxrtl -print-output std::cerr yosys-${subtest}.cc" + ../../yosys -p "read_verilog ${subtest}.v; proc; clean; write_cxxrtl -print-output std::cerr yosys-${subtest}.cc" ${CC:-gcc} -std=c++11 -o yosys-${subtest} -I../.. ${subtest}_tb.cc -lstdc++ ./yosys-${subtest} 2>yosys-${subtest}.log iverilog -o iverilog-${subtest} ${subtest}.v ${subtest}_tb.v