diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 3b9a4a8b1..261510726 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -2052,7 +2052,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/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); diff --git a/passes/sat/cutpoint.cc b/passes/sat/cutpoint.cc index 88f995dda..c8f46d791 100644 --- a/passes/sat/cutpoint.cc +++ b/passes/sat/cutpoint.cc @@ -37,10 +37,19 @@ struct CutpointPass : public Pass { log(" set cutpoint nets to undef (x). the default behavior is to create\n"); log(" an $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"); + 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_undef = false; + bool flag_blackbox = false; + bool flag_instances = false; log_header(design, "Executing CUTPOINT pass.\n"); @@ -51,13 +60,46 @@ struct CutpointPass : public Pass { flag_undef = true; continue; } + if (args[argidx] == "-blackbox") { + flag_blackbox = true; + continue; + } + if (args[argidx] == "-instances") { + flag_instances = true; + continue; + } break; } extra_args(args, argidx, design); - for (auto module : design->selected_modules()) + 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 boxes(false); + for (auto module : design->modules()) + 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()) { - if (design->selected_whole_module(module->name)) { + if (!design->selected_module(module)) + continue; + + 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())) @@ -68,6 +110,12 @@ 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); + auto scopeinfo = module->addCell(NEW_ID, ID($scopeinfo)); + scopeinfo->setParam(ID::TYPE, RTLIL::Const("blackbox")); + } continue; } @@ -82,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()) { diff --git a/tests/various/cutpoint_blackbox.ys b/tests/various/cutpoint_blackbox.ys new file mode 100644 index 000000000..ee7a18c6a --- /dev/null +++ b/tests/various/cutpoint_blackbox.ys @@ -0,0 +1,39 @@ +read_verilog -specify << EOT +module top(input a, b, output 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 #( parameter SOME_PARAM=0 ) (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, c, output o); +assign o = a & (b | c); +endmodule +EOT + +hierarchy -top top + +select -assert-count 0 t:$anyseq +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