2 * yosys -- Yosys Open SYnthesis Suite
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include "kernel/register.h"
21 #include "kernel/log.h"
26 extern void proc_clean_case(RTLIL::CaseRule
*cs
, bool &did_something
, int &count
, int max_depth
);
30 PRIVATE_NAMESPACE_BEGIN
32 void proc_clean_switch(RTLIL::SwitchRule
*sw
, RTLIL::CaseRule
*parent
, bool &did_something
, int &count
, int max_depth
)
34 if (sw
->signal
.size() > 0 && sw
->signal
.is_fully_const())
36 int found_matching_case_idx
= -1;
37 for (int i
= 0; i
< int(sw
->cases
.size()) && found_matching_case_idx
< 0; i
++)
39 RTLIL::CaseRule
*cs
= sw
->cases
[i
];
40 if (cs
->compare
.size() == 0)
42 for (int j
= 0; j
< int(cs
->compare
.size()); j
++) {
43 RTLIL::SigSpec
&val
= cs
->compare
[j
];
44 if (!val
.is_fully_const())
46 if (val
== sw
->signal
) {
48 found_matching_case_idx
= i
;
51 cs
->compare
.erase(cs
->compare
.begin()+(j
--));
53 if (cs
->compare
.size() == 0 && found_matching_case_idx
< 0) {
54 sw
->cases
.erase(sw
->cases
.begin()+(i
--));
58 while (found_matching_case_idx
>= 0 && int(sw
->cases
.size()) > found_matching_case_idx
+1) {
59 delete sw
->cases
.back();
62 if (found_matching_case_idx
== 0)
63 sw
->signal
= RTLIL::SigSpec();
66 if (parent
->switches
.front() == sw
&& sw
->cases
.size() == 1 &&
67 (sw
->signal
.size() == 0 || sw
->cases
[0]->compare
.empty()))
70 for (auto &action
: sw
->cases
[0]->actions
)
71 parent
->actions
.push_back(action
);
72 parent
->switches
.insert(parent
->switches
.begin(), sw
->cases
[0]->switches
.begin(), sw
->cases
[0]->switches
.end());
73 sw
->cases
[0]->switches
.clear();
79 bool all_fully_def
= true;
80 for (auto cs
: sw
->cases
)
83 proc_clean_case(cs
, did_something
, count
, max_depth
-1);
85 for (auto cmp
: cs
->compare
)
88 if (!cmp
.is_fully_def())
89 all_fully_def
= false;
91 if (sw
->signal
.size() != size
)
92 all_fully_def
= false;
96 for (auto cs
= sw
->cases
.begin(); cs
!= sw
->cases
.end();)
100 did_something
= true;
102 cs
= sw
->cases
.erase(cs
);
109 while (!sw
->cases
.empty() && sw
->cases
.back()->empty())
111 did_something
= true;
112 delete sw
->cases
.back();
113 sw
->cases
.pop_back();
119 PRIVATE_NAMESPACE_END
120 YOSYS_NAMESPACE_BEGIN
122 void proc_clean_case(RTLIL::CaseRule
*cs
, bool &did_something
, int &count
, int max_depth
)
124 for (size_t i
= 0; i
< cs
->actions
.size(); i
++) {
125 if (cs
->actions
[i
].first
.size() == 0) {
126 did_something
= true;
127 cs
->actions
.erase(cs
->actions
.begin() + (i
--));
130 for (size_t i
= 0; i
< cs
->switches
.size(); i
++) {
131 RTLIL::SwitchRule
*sw
= cs
->switches
[i
];
133 cs
->switches
.erase(cs
->switches
.begin() + (i
--));
134 did_something
= true;
137 } else if (max_depth
!= 0)
138 proc_clean_switch(sw
, cs
, did_something
, count
, max_depth
-1);
143 PRIVATE_NAMESPACE_BEGIN
145 void proc_clean(RTLIL::Module
*mod
, RTLIL::Process
*proc
, int &total_count
, bool quiet
)
148 bool did_something
= true;
149 for (size_t i
= 0; i
< proc
->syncs
.size(); i
++) {
150 for (size_t j
= 0; j
< proc
->syncs
[i
]->actions
.size(); j
++)
151 if (proc
->syncs
[i
]->actions
[j
].first
.size() == 0)
152 proc
->syncs
[i
]->actions
.erase(proc
->syncs
[i
]->actions
.begin() + (j
--));
153 if (proc
->syncs
[i
]->actions
.size() == 0) {
154 delete proc
->syncs
[i
];
155 proc
->syncs
.erase(proc
->syncs
.begin() + (i
--));
158 while (did_something
) {
159 did_something
= false;
160 proc_clean_case(&proc
->root_case
, did_something
, count
, -1);
162 if (count
> 0 && !quiet
)
163 log("Found and cleaned up %d empty switch%s in `%s.%s'.\n", count
, count
== 1 ? "" : "es", mod
->name
.c_str(), proc
->name
.c_str());
164 total_count
+= count
;
167 struct ProcCleanPass
: public Pass
{
168 ProcCleanPass() : Pass("proc_clean", "remove empty parts of processes") { }
169 void help() YS_OVERRIDE
171 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
173 log(" proc_clean [options] [selection]\n");
176 log(" do not print any messages.\n");
178 log("This pass removes empty parts of processes and ultimately removes a process\n");
179 log("if it contains only empty structures.\n");
182 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
187 if (find(args
.begin(), args
.end(), "-quiet") == args
.end())
188 log_header(design
, "Executing PROC_CLEAN pass (remove empty switches from decision trees).\n");
191 for (argidx
= 1; argidx
< args
.size(); argidx
++)
193 if (args
[argidx
] == "-quiet") {
198 extra_args(args
, argidx
, design
);
200 for (auto mod
: design
->modules()) {
201 std::vector
<RTLIL::IdString
> delme
;
202 if (!design
->selected(mod
))
204 for (auto &proc_it
: mod
->processes
) {
205 if (!design
->selected(mod
, proc_it
.second
))
207 proc_clean(mod
, proc_it
.second
, total_count
, quiet
);
208 if (proc_it
.second
->syncs
.size() == 0 && proc_it
.second
->root_case
.switches
.size() == 0 &&
209 proc_it
.second
->root_case
.actions
.size() == 0) {
211 log("Removing empty process `%s.%s'.\n", log_id(mod
), proc_it
.second
->name
.c_str());
212 delme
.push_back(proc_it
.first
);
215 for (auto &id
: delme
) {
216 delete mod
->processes
[id
];
217 mod
->processes
.erase(id
);
222 log("Cleaned up %d empty switch%s.\n", total_count
, total_count
== 1 ? "" : "es");
226 PRIVATE_NAMESPACE_END