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/log.h"
21 #include "kernel/register.h"
22 #include "kernel/sigtools.h"
23 #include "kernel/consteval.h"
24 #include "kernel/celltypes.h"
28 PRIVATE_NAMESPACE_BEGIN
30 static RTLIL::Module
*module
;
31 static SigMap assign_map
;
32 typedef std::pair
<RTLIL::Cell
*, RTLIL::IdString
> sig2driver_entry_t
;
33 static SigSet
<sig2driver_entry_t
> sig2driver
, sig2user
;
34 static std::set
<RTLIL::Cell
*> muxtree_cells
;
35 static SigPool sig_at_port
;
37 static bool check_state_mux_tree(RTLIL::SigSpec old_sig
, RTLIL::SigSpec sig
, pool
<Cell
*> &recursion_monitor
)
39 if (sig
.is_fully_const() || old_sig
== sig
) {
43 if (sig_at_port
.check_any(assign_map(sig
))) {
47 std::set
<sig2driver_entry_t
> cellport_list
;
48 sig2driver
.find(sig
, cellport_list
);
49 for (auto &cellport
: cellport_list
)
51 if ((cellport
.first
->type
!= "$mux" && cellport
.first
->type
!= "$pmux") || cellport
.second
!= "\\Y") {
55 if (recursion_monitor
.count(cellport
.first
)) {
56 log_warning("logic loop in mux tree at signal %s in module %s.\n",
57 log_signal(sig
), RTLIL::id2cstr(module
->name
));
61 recursion_monitor
.insert(cellport
.first
);
63 RTLIL::SigSpec sig_a
= assign_map(cellport
.first
->getPort("\\A"));
64 RTLIL::SigSpec sig_b
= assign_map(cellport
.first
->getPort("\\B"));
66 if (!check_state_mux_tree(old_sig
, sig_a
, recursion_monitor
)) {
67 recursion_monitor
.erase(cellport
.first
);
71 for (int i
= 0; i
< sig_b
.size(); i
+= sig_a
.size())
72 if (!check_state_mux_tree(old_sig
, sig_b
.extract(i
, sig_a
.size()), recursion_monitor
)) {
73 recursion_monitor
.erase(cellport
.first
);
77 recursion_monitor
.erase(cellport
.first
);
78 muxtree_cells
.insert(cellport
.first
);
84 static bool check_state_users(RTLIL::SigSpec sig
)
86 if (sig_at_port
.check_any(assign_map(sig
)))
89 std::set
<sig2driver_entry_t
> cellport_list
;
90 sig2user
.find(sig
, cellport_list
);
91 for (auto &cellport
: cellport_list
) {
92 RTLIL::Cell
*cell
= cellport
.first
;
93 if (muxtree_cells
.count(cell
) > 0)
95 if (cell
->type
== "$logic_not" && assign_map(cell
->getPort("\\A")) == sig
)
97 if (cellport
.second
!= "\\A" && cellport
.second
!= "\\B")
99 if (!cell
->hasPort("\\A") || !cell
->hasPort("\\B") || !cell
->hasPort("\\Y"))
101 for (auto &port_it
: cell
->connections())
102 if (port_it
.first
!= "\\A" && port_it
.first
!= "\\B" && port_it
.first
!= "\\Y")
104 if (assign_map(cell
->getPort("\\A")) == sig
&& cell
->getPort("\\B").is_fully_const())
106 if (assign_map(cell
->getPort("\\B")) == sig
&& cell
->getPort("\\A").is_fully_const())
114 static void detect_fsm(RTLIL::Wire
*wire
)
116 bool has_fsm_encoding_attr
= wire
->attributes
.count("\\fsm_encoding") > 0 && wire
->attributes
.at("\\fsm_encoding").decode_string() != "none";
117 bool has_fsm_encoding_none
= wire
->attributes
.count("\\fsm_encoding") > 0 && wire
->attributes
.at("\\fsm_encoding").decode_string() == "none";
118 bool has_init_attr
= wire
->attributes
.count("\\init") > 0;
119 bool is_module_port
= sig_at_port
.check_any(assign_map(RTLIL::SigSpec(wire
)));
120 bool looks_like_state_reg
= false, looks_like_good_state_reg
= false;
121 bool is_self_resetting
= false;
123 if (has_fsm_encoding_none
)
126 if (wire
->width
<= 1) {
127 if (has_fsm_encoding_attr
) {
128 log_warning("Removing fsm_encoding attribute from 1-bit net: %s.%s\n", log_id(wire
->module
), log_id(wire
));
129 wire
->attributes
.erase("\\fsm_encoding");
134 std::set
<sig2driver_entry_t
> cellport_list
;
135 sig2driver
.find(RTLIL::SigSpec(wire
), cellport_list
);
137 for (auto &cellport
: cellport_list
)
139 if ((cellport
.first
->type
!= "$dff" && cellport
.first
->type
!= "$adff") || cellport
.second
!= "\\Q")
142 muxtree_cells
.clear();
143 pool
<Cell
*> recursion_monitor
;
144 RTLIL::SigSpec sig_q
= assign_map(cellport
.first
->getPort("\\Q"));
145 RTLIL::SigSpec sig_d
= assign_map(cellport
.first
->getPort("\\D"));
147 if (sig_q
!= assign_map(wire
))
150 looks_like_state_reg
= check_state_mux_tree(sig_q
, sig_d
, recursion_monitor
);
151 looks_like_good_state_reg
= check_state_users(sig_q
);
153 if (!looks_like_state_reg
)
156 ConstEval
ce(wire
->module
);
158 std::set
<sig2driver_entry_t
> cellport_list
;
159 sig2user
.find(sig_q
, cellport_list
);
161 for (auto &cellport
: cellport_list
)
163 RTLIL::Cell
*cell
= cellport
.first
;
164 bool set_output
= false, clr_output
= false;
166 if (cell
->type
== "$ne")
169 if (cell
->type
== "$eq")
172 if (!set_output
&& !clr_output
) {
174 for (auto &port_it
: cell
->connections())
175 if (port_it
.first
!= "\\A" || port_it
.first
!= "\\Y")
179 if (set_output
|| clr_output
) {
180 for (auto &port_it
: cell
->connections())
181 if (cell
->output(port_it
.first
)) {
182 SigSpec sig
= assign_map(port_it
.second
);
183 Const
val(set_output
? State::S1
: State::S0
, GetSize(sig
));
189 SigSpec sig_y
= sig_d
, sig_undef
;
190 if (ce
.eval(sig_y
, sig_undef
))
191 is_self_resetting
= true;
194 if (has_fsm_encoding_attr
)
196 vector
<string
> warnings
;
199 warnings
.push_back("Forcing FSM recoding on module port might result in larger circuit.\n");
201 if (!looks_like_good_state_reg
)
202 warnings
.push_back("Users of state reg look like FSM recoding might result in larger circuit.\n");
205 warnings
.push_back("Initialization value on FSM state register is ignored. Possible simulation-synthesis mismatch!\n");
207 if (!looks_like_state_reg
)
208 warnings
.push_back("Doesn't look like a proper FSM. Possible simulation-synthesis mismatch!\n");
210 if (is_self_resetting
)
211 warnings
.push_back("FSM seems to be self-resetting. Possible simulation-synthesis mismatch!\n");
213 if (!warnings
.empty()) {
214 string warnmsg
= stringf("Regarding the user-specified fsm_encoding attribute on %s.%s:\n", log_id(wire
->module
), log_id(wire
));
215 for (auto w
: warnings
) warnmsg
+= " " + w
;
216 log_warning("%s", warnmsg
.c_str());
218 log("FSM state register %s.%s already has fsm_encoding attribute.\n", log_id(wire
->module
), log_id(wire
));
222 if (looks_like_state_reg
&& looks_like_good_state_reg
&& !has_init_attr
&& !is_module_port
&& !is_self_resetting
)
224 log("Found FSM state register %s.%s.\n", log_id(wire
->module
), log_id(wire
));
225 wire
->attributes
["\\fsm_encoding"] = RTLIL::Const("auto");
228 if (looks_like_state_reg
)
230 log("Not marking %s.%s as FSM state register:\n", log_id(wire
->module
), log_id(wire
));
233 log(" Register is connected to module port.\n");
235 if (!looks_like_good_state_reg
)
236 log(" Users of register don't seem to benefit from recoding.\n");
239 log(" Register has an initialization value.\n");
241 if (is_self_resetting
)
242 log(" Circuit seems to be self-resetting.\n");
246 struct FsmDetectPass
: public Pass
{
247 FsmDetectPass() : Pass("fsm_detect", "finding FSMs in design") { }
248 void help() YS_OVERRIDE
250 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
252 log(" fsm_detect [selection]\n");
254 log("This pass detects finite state machines by identifying the state signal.\n");
255 log("The state signal is then marked by setting the attribute 'fsm_encoding'\n");
256 log("on the state signal to \"auto\".\n");
258 log("Existing 'fsm_encoding' attributes are not changed by this pass.\n");
260 log("Signals can be protected from being detected by this pass by setting the\n");
261 log("'fsm_encoding' attribute to \"none\".\n");
264 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) YS_OVERRIDE
266 log_header(design
, "Executing FSM_DETECT pass (finding FSMs in design).\n");
267 extra_args(args
, 1, design
);
270 ct
.setup_internals();
271 ct
.setup_internals_mem();
273 ct
.setup_stdcells_mem();
275 for (auto &mod_it
: design
->modules_
)
277 if (!design
->selected(mod_it
.second
))
280 module
= mod_it
.second
;
281 assign_map
.set(module
);
286 for (auto &cell_it
: module
->cells_
)
287 for (auto &conn_it
: cell_it
.second
->connections()) {
288 if (ct
.cell_output(cell_it
.second
->type
, conn_it
.first
) || !ct
.cell_known(cell_it
.second
->type
)) {
289 RTLIL::SigSpec sig
= conn_it
.second
;
290 assign_map
.apply(sig
);
291 sig2driver
.insert(sig
, sig2driver_entry_t(cell_it
.second
, conn_it
.first
));
293 if (!ct
.cell_known(cell_it
.second
->type
) || ct
.cell_input(cell_it
.second
->type
, conn_it
.first
)) {
294 RTLIL::SigSpec sig
= conn_it
.second
;
295 assign_map
.apply(sig
);
296 sig2user
.insert(sig
, sig2driver_entry_t(cell_it
.second
, conn_it
.first
));
300 for (auto &wire_it
: module
->wires_
)
301 if (wire_it
.second
->port_id
!= 0)
302 sig_at_port
.add(assign_map(RTLIL::SigSpec(wire_it
.second
)));
304 for (auto &wire_it
: module
->wires_
)
305 if (design
->selected(module
, wire_it
.second
))
306 detect_fsm(wire_it
.second
);
312 muxtree_cells
.clear();
316 PRIVATE_NAMESPACE_END