Skip to content

Commit 109d97b

Browse files
authored
Merge pull request #4706 from povik/keep_hierarchy-adjustalgo
Adjust `keep_hierarchy` behavior
2 parents 61a6567 + 6ad4918 commit 109d97b

File tree

3 files changed

+131
-15
lines changed

3 files changed

+131
-15
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,11 @@ Verilog Attributes and non-standard features
370370
- The ``keep_hierarchy`` attribute on cells and modules keeps the ``flatten``
371371
command from flattening the indicated cells and modules.
372372

373+
- The `gate_cost_equivalent` attribute on a module can be used to specify
374+
the estimated cost of the module as a number of basic gate instances. See
375+
the help message of command `keep_hierarchy` which interprets this
376+
attribute.
377+
373378
- The ``init`` attribute on wires is set by the frontend when a register is
374379
initialized "FPGA-style" with ``reg foo = val``. It can be used during
375380
synthesis to add the necessary reset logic.
@@ -591,7 +596,6 @@ Non-standard or SystemVerilog features for formal verification
591596
``@(posedge <netname>)`` or ``@(negedge <netname>)`` when ``<netname>``
592597
is marked with the ``(* gclk *)`` Verilog attribute.
593598

594-
595599
Supported features from SystemVerilog
596600
=====================================
597601

passes/hierarchy/keep_hierarchy.cc

Lines changed: 73 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,80 @@
2323
USING_YOSYS_NAMESPACE
2424
PRIVATE_NAMESPACE_BEGIN
2525

26+
struct ThresholdHierarchyKeeping {
27+
Design *design;
28+
CellCosts costs;
29+
dict<Module *, int> done;
30+
pool<Module *> in_progress;
31+
uint64_t threshold;
32+
33+
ThresholdHierarchyKeeping(Design *design, uint64_t threshold)
34+
: design(design), costs(design), threshold(threshold) {}
35+
36+
uint64_t visit(RTLIL::Module *module) {
37+
if (module->has_attribute(ID(gate_cost_equivalent)))
38+
return module->attributes[ID(gate_cost_equivalent)].as_int();
39+
40+
if (module->has_attribute(ID(keep_hierarchy)))
41+
return 0;
42+
43+
if (module->get_blackbox_attribute())
44+
log_error("Missing cost information on instanced blackbox %s\n", log_id(module));
45+
46+
if (done.count(module))
47+
return done.at(module);
48+
49+
if (in_progress.count(module))
50+
log_error("Circular hierarchy\n");
51+
in_progress.insert(module);
52+
53+
uint64_t size = 0;
54+
module->has_processes_warn();
55+
56+
for (auto cell : module->cells()) {
57+
if (!cell->type.isPublic()) {
58+
size += costs.get(cell);
59+
} else {
60+
RTLIL::Module *submodule = design->module(cell->type);
61+
if (!submodule)
62+
log_error("Hierarchy contains unknown module '%s' (instanced as %s in %s)\n",
63+
log_id(cell->type), log_id(cell), log_id(module));
64+
size += visit(submodule);
65+
}
66+
}
67+
68+
if (size > threshold) {
69+
log("Keeping %s (estimated size above threshold: %llu > %llu).\n", log_id(module), size, threshold);
70+
module->set_bool_attribute(ID::keep_hierarchy);
71+
size = 0;
72+
}
73+
74+
in_progress.erase(module);
75+
done[module] = size;
76+
return size;
77+
}
78+
};
79+
2680
struct KeepHierarchyPass : public Pass {
27-
KeepHierarchyPass() : Pass("keep_hierarchy", "add the keep_hierarchy attribute") {}
81+
KeepHierarchyPass() : Pass("keep_hierarchy", "selectively add the keep_hierarchy attribute") {}
2882
void help() override
2983
{
3084
// |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
3185
log("\n");
32-
log(" keep_hierarchy [options]\n");
86+
log(" keep_hierarchy [options] [selection]\n");
3387
log("\n");
3488
log("Add the keep_hierarchy attribute.\n");
3589
log("\n");
3690
log(" -min_cost <min_cost>\n");
37-
log(" only add the attribute to modules estimated to have more\n");
38-
log(" than <min_cost> gates after simple techmapping. Intended\n");
39-
log(" for tuning trade-offs between quality and yosys runtime.\n");
91+
log(" only add the attribute to modules estimated to have more than <min_cost>\n");
92+
log(" gates after simple techmapping. Intended for tuning trade-offs between\n");
93+
log(" quality and yosys runtime.\n");
94+
log("\n");
95+
log(" When evaluating a module's cost, gates which are within a submodule\n");
96+
log(" which is marked with the keep_hierarchy attribute are not counted\n");
97+
log(" towards the upper module's cost. This applies to both when the attribute\n");
98+
log(" was added by this command or was pre-existing.\n");
99+
log("\n");
40100
}
41101
void execute(std::vector<std::string> args, RTLIL::Design *design) override
42102
{
@@ -54,16 +114,15 @@ struct KeepHierarchyPass : public Pass {
54114
}
55115
extra_args(args, argidx, design);
56116

57-
CellCosts costs(design);
117+
if (min_cost) {
118+
RTLIL::Module *top = design->top_module();
119+
if (!top)
120+
log_cmd_error("'-min_cost' mode requires a single top module in the design\n");
58121

59-
for (auto module : design->selected_modules()) {
60-
if (min_cost) {
61-
unsigned int cost = costs.get(module);
62-
if (cost > min_cost) {
63-
log("Marking %s (module too big: %d > %d).\n", log_id(module), cost, min_cost);
64-
module->set_bool_attribute(ID::keep_hierarchy);
65-
}
66-
} else {
122+
ThresholdHierarchyKeeping worker(design, min_cost);
123+
worker.visit(top);
124+
} else {
125+
for (auto module : design->selected_modules()) {
67126
log("Marking %s.\n", log_id(module));
68127
module->set_bool_attribute(ID::keep_hierarchy);
69128
}

tests/various/keep_hierarchy.ys

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
read_verilog <<EOF
2+
(* blackbox *)
3+
(* gate_cost_equivalent=150 *)
4+
module macro;
5+
endmodule
6+
7+
module branch1;
8+
macro inst1();
9+
macro inst2();
10+
macro inst3();
11+
endmodule
12+
13+
module branch2;
14+
macro inst1();
15+
macro inst2();
16+
macro inst3();
17+
macro inst4();
18+
endmodule
19+
20+
// branch3_submod on its own doesn't meet the threshold
21+
module branch3_submod();
22+
wire [2:0] y;
23+
wire [2:0] a;
24+
wire [2:0] b;
25+
assign y = a * b;
26+
endmodule
27+
28+
// on the other hand four branch3_submods do
29+
module branch3;
30+
branch3_submod inst1();
31+
branch3_submod inst2();
32+
branch3_submod inst3();
33+
branch3_submod inst4();
34+
endmodule
35+
36+
// wrapper should have zero cost when branch3 is marked
37+
// keep_hierarchy
38+
module branch3_wrapper;
39+
branch3 inst();
40+
endmodule
41+
42+
module top;
43+
branch1 inst1();
44+
branch2 inst2();
45+
branch3_wrapper wrapper();
46+
endmodule
47+
EOF
48+
49+
hierarchy -top top
50+
keep_hierarchy -min_cost 500
51+
select -assert-mod-count 2 A:keep_hierarchy
52+
select -assert-any A:keep_hierarchy branch2 %i
53+
select -assert-any A:keep_hierarchy branch3 %i

0 commit comments

Comments
 (0)