From 4eb2d06676e7980bb3add066073bd98794689625 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:24:38 +1300 Subject: [PATCH 1/5] cutpoint: Add -blackbox option Replace the contents of all blackboxes in the design with a formal cut point. Includes test script. --- passes/sat/cutpoint.cc | 30 +++++++++++++++++++++++++-- tests/various/cutpoint_blackbox.ys | 33 ++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 tests/various/cutpoint_blackbox.ys diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index bca6a5ec6..0ca422bfa 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -37,10 +37,15 @@ struct CutpointPass : public Pass { log(" set cupoint nets to undef (x). the default behavior is to create a\n"); log(" $anyseq cell and drive the cutpoint net from that\n"); log("\n"); + log(" cutpoint -blackbox [options]\n"); + log("\n"); + log("Replace the contents of all blackboxes in the design with a formal cut point.\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { - bool flag_undef = false; + bool flag_undef = false; + bool flag_blackbox = false; log_header(design, "Executing CUTPOINT pass.\n"); @@ -51,12 +56,29 @@ struct CutpointPass : public Pass { flag_undef = true; continue; } + if (args[argidx] == "-blackbox") { + flag_blackbox = true; + continue; + } break; } extra_args(args, argidx, design); - for (auto module : design->selected_modules()) + if (flag_blackbox) { + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + RTLIL::Selection module_boxes(false); + for (auto module : design->modules()) + if (module->get_blackbox_attribute()) + module_boxes.select(module); + design->selection_stack.push_back(module_boxes); + } + + for (auto module : design->modules()) { + if (!design->selected_module(module)) + continue; + if (design->selected_whole_module(module->name)) { log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module)); module->new_connections(std::vector()); @@ -68,6 +90,10 @@ struct CutpointPass : public Pass { output_wires.push_back(wire); for (auto wire : output_wires) module->connect(wire, flag_undef ? Const(State::Sx, GetSize(wire)) : module->Anyseq(NEW_ID, GetSize(wire))); + if (module->get_blackbox_attribute()) { + module->set_bool_attribute(ID::blackbox, false); + module->set_bool_attribute(ID::whitebox, false); + } continue; } diff --git a/tests/various/cutpoint_blackbox.ys b/tests/various/cutpoint_blackbox.ys new file mode 100644 index 000000000..78ee46db6 --- /dev/null +++ b/tests/various/cutpoint_blackbox.ys @@ -0,0 +1,33 @@ +read_verilog -specify << EOT +module top(input a, b, output o); + wire c, d; + bb bb1 (.a (a), .b (b), .o (c)); + wb wb1 (.a (a), .b (b), .o (d)); + some_mod some_inst (.a (c), .b (d), .o (o)); +endmodule + +(* blackbox *) +module bb(input a, b, output o); +assign o = a | b; +specify + (a => o) = 1; +endspecify +endmodule + +(* whitebox *) +module wb(input a, b, output o); +assign o = a ^ b; +endmodule + +module some_mod(input a, b, output o); +assign o = a & b; +endmodule +EOT + +select top + +select -assert-count 0 t:$anyseq +select -assert-count 2 =t:?b +cutpoint -blackbox =* +select -assert-count 2 t:$anyseq +select -assert-count 2 t:?b From 8e9c96518c3bb953f3e2ccf74f88f03e5e2dc4db Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 17 Jan 2025 11:46:07 +1300 Subject: [PATCH 2/5] cutpoint: Add $scopeinfo cell Also adds "blackbox" as a valid TYPE. --- kernel/rtlil.cc | 2 +- passes/sat/cutpoint.cc | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index cb0f7da78..075a9bf6b 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2012,7 +2012,7 @@ namespace { param(ID::TYPE); check_expected(); std::string scope_type = cell->getParam(ID::TYPE).decode_string(); - if (scope_type != "module" && scope_type != "struct") + if (scope_type != "module" && scope_type != "struct" && scope_type != "blackbox") error(__LINE__); return; } diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index 0ca422bfa..510363d3a 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -93,6 +93,8 @@ struct CutpointPass : public Pass { if (module->get_blackbox_attribute()) { module->set_bool_attribute(ID::blackbox, false); module->set_bool_attribute(ID::whitebox, false); + auto scopeinfo = module->addCell(NEW_ID, ID($scopeinfo)); + scopeinfo->setParam(ID::TYPE, RTLIL::Const("blackbox")); } continue; } From cd7ac4f9c4658c129109867e1df2d06e73f63e9d Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Fri, 17 Jan 2025 12:15:13 +1300 Subject: [PATCH 3/5] cutpoint: Test -blackbox with parameter Modify `cutpoint_blackbox.ys` to check that parameters on blackbox modules are maintained after the cutpoint. Also adjusts the test to check that each instance gets the `$anyseq` cell. --- tests/various/cutpoint_blackbox.ys | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/various/cutpoint_blackbox.ys b/tests/various/cutpoint_blackbox.ys index 78ee46db6..ee7a18c6a 100644 --- a/tests/various/cutpoint_blackbox.ys +++ b/tests/various/cutpoint_blackbox.ys @@ -1,13 +1,14 @@ read_verilog -specify << EOT module top(input a, b, output o); - wire c, d; - bb bb1 (.a (a), .b (b), .o (c)); - wb wb1 (.a (a), .b (b), .o (d)); - some_mod some_inst (.a (c), .b (d), .o (o)); + wire c, d, e; + bb #(.SOME_PARAM(1)) bb1 (.a (a), .b (b), .o (c)); + bb #(.SOME_PARAM(2)) bb2 (.a (a), .b (b), .o (d)); + wb wb1 (.a (a), .b (b), .o (e)); + some_mod some_inst (.a (c), .b (d), .c (e), .o (o)); endmodule (* blackbox *) -module bb(input a, b, output o); +module bb #( parameter SOME_PARAM=0 ) (input a, b, output o); assign o = a | b; specify (a => o) = 1; @@ -19,15 +20,20 @@ module wb(input a, b, output o); assign o = a ^ b; endmodule -module some_mod(input a, b, output o); -assign o = a & b; +module some_mod(input a, b, c, output o); +assign o = a & (b | c); endmodule EOT -select top +hierarchy -top top select -assert-count 0 t:$anyseq -select -assert-count 2 =t:?b -cutpoint -blackbox =* -select -assert-count 2 t:$anyseq -select -assert-count 2 t:?b +select -assert-count 3 =t:?b +cutpoint -blackbox + +select -assert-count 3 =t:?b +select -assert-count 2 r:SOME_PARAM +select -assert-count 1 r:SOME_PARAM=1 + +flatten +select -assert-count 3 t:$anyseq From 7ffe610b4c72c058d94495229ee933024e557d8e Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:03:29 +1300 Subject: [PATCH 4/5] cutpoint: Add -blackbox -instances Replace module instances instead of module contents. This fixes parametrisable width mismatch with read_verilog frontend, but not verific frontend. --- passes/sat/cutpoint.cc | 49 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index 510363d3a..c83a212d0 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -41,11 +41,15 @@ struct CutpointPass : public Pass { log("\n"); log("Replace the contents of all blackboxes in the design with a formal cut point.\n"); log("\n"); + log(" -instances\n"); + log(" replace instances of blackboxes instead of the modules\n"); + log("\n"); } void execute(std::vector args, RTLIL::Design *design) override { bool flag_undef = false; bool flag_blackbox = false; + bool flag_instances = false; log_header(design, "Executing CUTPOINT pass.\n"); @@ -60,18 +64,34 @@ struct CutpointPass : public Pass { flag_blackbox = true; continue; } + if (args[argidx] == "-instances") { + flag_instances = true; + continue; + } break; } extra_args(args, argidx, design); + if (flag_instances && !flag_blackbox) { + log_cmd_error("-instances flag only valid with -blackbox!\n"); + } + if (flag_blackbox) { if (!design->full_selection()) log_cmd_error("This command only operates on fully selected designs!\n"); - RTLIL::Selection module_boxes(false); + RTLIL::Selection boxes(false); for (auto module : design->modules()) - if (module->get_blackbox_attribute()) - module_boxes.select(module); - design->selection_stack.push_back(module_boxes); + if (flag_instances) { + for (auto cell : module->cells()) { + auto mod = design->module(cell->type); + if (mod != nullptr && mod->get_blackbox_attribute()) + boxes.select(module, cell); + } + } else { + if (module->get_blackbox_attribute()) + boxes.select(module); + } + design->selection_stack.push_back(boxes); } for (auto module : design->modules()) @@ -79,7 +99,7 @@ struct CutpointPass : public Pass { if (!design->selected_module(module)) continue; - if (design->selected_whole_module(module->name)) { + if (design->selected_whole_module(module->name) && !flag_instances) { log("Making all outputs of module %s cut points, removing module contents.\n", log_id(module)); module->new_connections(std::vector()); for (auto cell : vector(module->cells())) @@ -110,7 +130,26 @@ struct CutpointPass : public Pass { if (cell->output(conn.first)) module->connect(conn.second, flag_undef ? Const(State::Sx, GetSize(conn.second)) : module->Anyseq(NEW_ID, GetSize(conn.second))); } + + RTLIL::Cell *scopeinfo = nullptr; + auto cell_name = cell->name; + if (flag_instances && cell_name.isPublic()) { + auto scopeinfo = module->addCell(NEW_ID, ID($scopeinfo)); + scopeinfo->setParam(ID::TYPE, RTLIL::Const("blackbox")); + + for (auto const &attr : cell->attributes) + { + if (attr.first == ID::hdlname) + scopeinfo->attributes.insert(attr); + else + scopeinfo->attributes.emplace(stringf("\\cell_%s", RTLIL::unescape_id(attr.first).c_str()), attr.second); + } + } + module->remove(cell); + + if (scopeinfo != nullptr) + module->rename(scopeinfo, cell_name); } for (auto wire : module->selected_wires()) { From 9e9213c011d2900efa7ab88e58daf764a67b3939 Mon Sep 17 00:00:00 2001 From: Krystine Sherwin <93062060+KrystalDelusion@users.noreply.github.com> Date: Tue, 21 Jan 2025 12:45:12 +1300 Subject: [PATCH 5/5] hierarchy: Ignore width mismatch from verific But only if it's also a blackbox module with parameters (i.e. it *could* be parametrizable width). --- passes/hierarchy/hierarchy.cc | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 8372c0339..d94b5cef6 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -978,6 +978,11 @@ struct HierarchyPass : public Pass { } } + bool verific_mod = false; +#ifdef YOSYS_ENABLE_VERIFIC + verific_mod = verific_import_pending; +#endif + if (top_mod == nullptr && !load_top_mod.empty()) { #ifdef YOSYS_ENABLE_VERIFIC if (verific_import_pending) { @@ -1418,13 +1423,18 @@ struct HierarchyPass : public Pass { if (m == nullptr) continue; - if (m->get_blackbox_attribute() && !cell->parameters.empty() && m->get_bool_attribute(ID::dynports)) { - IdString new_m_name = m->derive(design, cell->parameters, true); - if (new_m_name.empty()) - continue; - if (new_m_name != m->name) { - m = design->module(new_m_name); - blackbox_derivatives.insert(m); + bool boxed_params = false; + if (m->get_blackbox_attribute() && !cell->parameters.empty()) { + if (m->get_bool_attribute(ID::dynports)) { + IdString new_m_name = m->derive(design, cell->parameters, true); + if (new_m_name.empty()) + continue; + if (new_m_name != m->name) { + m = design->module(new_m_name); + blackbox_derivatives.insert(m); + } + } else { + boxed_params = true; } } @@ -1440,8 +1450,12 @@ struct HierarchyPass : public Pass { SigSpec sig = conn.second; - if (!keep_portwidths && GetSize(w) != GetSize(conn.second)) - { + bool resize_widths = !keep_portwidths && GetSize(w) != GetSize(conn.second); + if (resize_widths && verific_mod && boxed_params) + log_warning("Ignoring width mismatch on %s.%s.%s from verific, is port width parametrizable?\n", + log_id(module), log_id(cell), log_id(conn.first) + ); + else if (resize_widths) { if (GetSize(w) < GetSize(conn.second)) { int n = GetSize(conn.second) - GetSize(w);