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/sigtools.h"
22 #include "kernel/consteval.h"
23 #include "kernel/log.h"
29 PRIVATE_NAMESPACE_BEGIN
31 RTLIL::SigSpec
find_any_lvalue(const RTLIL::Process
*proc
)
33 RTLIL::SigSpec lvalue
;
35 for (auto sync
: proc
->syncs
)
36 for (auto &action
: sync
->actions
)
37 if (action
.first
.size() > 0) {
38 lvalue
= action
.first
;
39 lvalue
.sort_and_unify();
43 for (auto sync
: proc
->syncs
) {
44 RTLIL::SigSpec this_lvalue
;
45 for (auto &action
: sync
->actions
)
46 this_lvalue
.append(action
.first
);
47 this_lvalue
.sort_and_unify();
48 RTLIL::SigSpec common_sig
= this_lvalue
.extract(lvalue
);
49 if (common_sig
.size() > 0)
56 void gen_dffsr_complex(RTLIL::Module
*mod
, RTLIL::SigSpec sig_d
, RTLIL::SigSpec sig_q
, RTLIL::SigSpec clk
, bool clk_polarity
,
57 std::map
<RTLIL::SigSpec
, std::set
<RTLIL::SyncRule
*>> &async_rules
, RTLIL::Process
*proc
)
59 RTLIL::SigSpec sig_sr_set
= RTLIL::SigSpec(0, sig_d
.size());
60 RTLIL::SigSpec sig_sr_clr
= RTLIL::SigSpec(0, sig_d
.size());
62 for (auto &it
: async_rules
)
64 RTLIL::SigSpec sync_value
= it
.first
;
65 RTLIL::SigSpec sync_value_inv
;
66 RTLIL::SigSpec sync_high_signals
;
67 RTLIL::SigSpec sync_low_signals
;
69 for (auto &it2
: it
.second
)
70 if (it2
->type
== RTLIL::SyncType::ST0
)
71 sync_low_signals
.append(it2
->signal
);
72 else if (it2
->type
== RTLIL::SyncType::ST1
)
73 sync_high_signals
.append(it2
->signal
);
77 if (sync_low_signals
.size() > 1) {
78 RTLIL::Cell
*cell
= mod
->addCell(NEW_ID
, "$reduce_or");
79 cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
80 cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(sync_low_signals
.size());
81 cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(1);
82 cell
->setPort("\\A", sync_low_signals
);
83 cell
->setPort("\\Y", sync_low_signals
= mod
->addWire(NEW_ID
));
86 if (sync_low_signals
.size() > 0) {
87 RTLIL::Cell
*cell
= mod
->addCell(NEW_ID
, "$not");
88 cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
89 cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(sync_low_signals
.size());
90 cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(1);
91 cell
->setPort("\\A", sync_low_signals
);
92 cell
->setPort("\\Y", mod
->addWire(NEW_ID
));
93 sync_high_signals
.append(cell
->getPort("\\Y"));
96 if (sync_high_signals
.size() > 1) {
97 RTLIL::Cell
*cell
= mod
->addCell(NEW_ID
, "$reduce_or");
98 cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
99 cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(sync_high_signals
.size());
100 cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(1);
101 cell
->setPort("\\A", sync_high_signals
);
102 cell
->setPort("\\Y", sync_high_signals
= mod
->addWire(NEW_ID
));
105 RTLIL::Cell
*inv_cell
= mod
->addCell(NEW_ID
, "$not");
106 inv_cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
107 inv_cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(sig_d
.size());
108 inv_cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(sig_d
.size());
109 inv_cell
->setPort("\\A", sync_value
);
110 inv_cell
->setPort("\\Y", sync_value_inv
= mod
->addWire(NEW_ID
, sig_d
.size()));
112 RTLIL::Cell
*mux_set_cell
= mod
->addCell(NEW_ID
, "$mux");
113 mux_set_cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_d
.size());
114 mux_set_cell
->setPort("\\A", sig_sr_set
);
115 mux_set_cell
->setPort("\\B", sync_value
);
116 mux_set_cell
->setPort("\\S", sync_high_signals
);
117 mux_set_cell
->setPort("\\Y", sig_sr_set
= mod
->addWire(NEW_ID
, sig_d
.size()));
119 RTLIL::Cell
*mux_clr_cell
= mod
->addCell(NEW_ID
, "$mux");
120 mux_clr_cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_d
.size());
121 mux_clr_cell
->setPort("\\A", sig_sr_clr
);
122 mux_clr_cell
->setPort("\\B", sync_value_inv
);
123 mux_clr_cell
->setPort("\\S", sync_high_signals
);
124 mux_clr_cell
->setPort("\\Y", sig_sr_clr
= mod
->addWire(NEW_ID
, sig_d
.size()));
127 std::stringstream sstr
;
128 sstr
<< "$procdff$" << (autoidx
++);
130 RTLIL::Cell
*cell
= mod
->addCell(sstr
.str(), "$dffsr");
131 cell
->attributes
= proc
->attributes
;
132 cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_d
.size());
133 cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity
, 1);
134 cell
->parameters
["\\SET_POLARITY"] = RTLIL::Const(true, 1);
135 cell
->parameters
["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
136 cell
->setPort("\\D", sig_d
);
137 cell
->setPort("\\Q", sig_q
);
138 cell
->setPort("\\CLK", clk
);
139 cell
->setPort("\\SET", sig_sr_set
);
140 cell
->setPort("\\CLR", sig_sr_clr
);
142 log(" created %s cell `%s' with %s edge clock and multiple level-sensitive resets.\n",
143 cell
->type
.c_str(), cell
->name
.c_str(), clk_polarity
? "positive" : "negative");
146 void gen_dffsr(RTLIL::Module
*mod
, RTLIL::SigSpec sig_in
, RTLIL::SigSpec sig_set
, RTLIL::SigSpec sig_out
,
147 bool clk_polarity
, bool set_polarity
, RTLIL::SigSpec clk
, RTLIL::SigSpec set
, RTLIL::Process
*proc
)
149 std::stringstream sstr
;
150 sstr
<< "$procdff$" << (autoidx
++);
152 RTLIL::SigSpec sig_set_inv
= mod
->addWire(NEW_ID
, sig_in
.size());
153 RTLIL::SigSpec sig_sr_set
= mod
->addWire(NEW_ID
, sig_in
.size());
154 RTLIL::SigSpec sig_sr_clr
= mod
->addWire(NEW_ID
, sig_in
.size());
156 RTLIL::Cell
*inv_set
= mod
->addCell(NEW_ID
, "$not");
157 inv_set
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
158 inv_set
->parameters
["\\A_WIDTH"] = RTLIL::Const(sig_in
.size());
159 inv_set
->parameters
["\\Y_WIDTH"] = RTLIL::Const(sig_in
.size());
160 inv_set
->setPort("\\A", sig_set
);
161 inv_set
->setPort("\\Y", sig_set_inv
);
163 RTLIL::Cell
*mux_sr_set
= mod
->addCell(NEW_ID
, "$mux");
164 mux_sr_set
->parameters
["\\WIDTH"] = RTLIL::Const(sig_in
.size());
165 mux_sr_set
->setPort(set_polarity
? "\\A" : "\\B", RTLIL::Const(0, sig_in
.size()));
166 mux_sr_set
->setPort(set_polarity
? "\\B" : "\\A", sig_set
);
167 mux_sr_set
->setPort("\\Y", sig_sr_set
);
168 mux_sr_set
->setPort("\\S", set
);
170 RTLIL::Cell
*mux_sr_clr
= mod
->addCell(NEW_ID
, "$mux");
171 mux_sr_clr
->parameters
["\\WIDTH"] = RTLIL::Const(sig_in
.size());
172 mux_sr_clr
->setPort(set_polarity
? "\\A" : "\\B", RTLIL::Const(0, sig_in
.size()));
173 mux_sr_clr
->setPort(set_polarity
? "\\B" : "\\A", sig_set_inv
);
174 mux_sr_clr
->setPort("\\Y", sig_sr_clr
);
175 mux_sr_clr
->setPort("\\S", set
);
177 RTLIL::Cell
*cell
= mod
->addCell(sstr
.str(), "$dffsr");
178 cell
->attributes
= proc
->attributes
;
179 cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_in
.size());
180 cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity
, 1);
181 cell
->parameters
["\\SET_POLARITY"] = RTLIL::Const(true, 1);
182 cell
->parameters
["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
183 cell
->setPort("\\D", sig_in
);
184 cell
->setPort("\\Q", sig_out
);
185 cell
->setPort("\\CLK", clk
);
186 cell
->setPort("\\SET", sig_sr_set
);
187 cell
->setPort("\\CLR", sig_sr_clr
);
189 log(" created %s cell `%s' with %s edge clock and %s level non-const reset.\n", cell
->type
.c_str(), cell
->name
.c_str(),
190 clk_polarity
? "positive" : "negative", set_polarity
? "positive" : "negative");
193 void gen_dff(RTLIL::Module
*mod
, RTLIL::SigSpec sig_in
, RTLIL::Const val_rst
, RTLIL::SigSpec sig_out
,
194 bool clk_polarity
, bool arst_polarity
, RTLIL::SigSpec clk
, RTLIL::SigSpec
*arst
, RTLIL::Process
*proc
)
196 std::stringstream sstr
;
197 sstr
<< "$procdff$" << (autoidx
++);
199 RTLIL::Cell
*cell
= mod
->addCell(sstr
.str(), clk
.empty() ? "$ff" : arst
? "$adff" : "$dff");
200 cell
->attributes
= proc
->attributes
;
202 cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_in
.size());
204 cell
->parameters
["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity
, 1);
205 cell
->parameters
["\\ARST_VALUE"] = val_rst
;
208 cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity
, 1);
211 cell
->setPort("\\D", sig_in
);
212 cell
->setPort("\\Q", sig_out
);
214 cell
->setPort("\\ARST", *arst
);
216 cell
->setPort("\\CLK", clk
);
219 log(" created %s cell `%s' with %s edge clock", cell
->type
.c_str(), cell
->name
.c_str(), clk_polarity
? "positive" : "negative");
221 log(" created %s cell `%s' with global clock", cell
->type
.c_str(), cell
->name
.c_str());
223 log(" and %s level reset", arst_polarity
? "positive" : "negative");
227 void proc_dff(RTLIL::Module
*mod
, RTLIL::Process
*proc
, ConstEval
&ce
)
231 RTLIL::SigSpec sig
= find_any_lvalue(proc
);
232 bool free_sync_level
= false;
237 log("Creating register for signal `%s.%s' using process `%s.%s'.\n",
238 mod
->name
.c_str(), log_signal(sig
), mod
->name
.c_str(), proc
->name
.c_str());
240 RTLIL::SigSpec insig
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.size());
241 RTLIL::SigSpec rstval
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.size());
242 RTLIL::SyncRule
*sync_level
= NULL
;
243 RTLIL::SyncRule
*sync_edge
= NULL
;
244 RTLIL::SyncRule
*sync_always
= NULL
;
245 bool global_clock
= false;
247 std::map
<RTLIL::SigSpec
, std::set
<RTLIL::SyncRule
*>> many_async_rules
;
249 for (auto sync
: proc
->syncs
)
250 for (auto &action
: sync
->actions
)
252 if (action
.first
.extract(sig
).size() == 0)
255 if (sync
->type
== RTLIL::SyncType::ST0
|| sync
->type
== RTLIL::SyncType::ST1
) {
256 if (sync_level
!= NULL
&& sync_level
!= sync
) {
257 // log_error("Multiple level sensitive events found for this signal!\n");
258 many_async_rules
[rstval
].insert(sync_level
);
259 rstval
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.size());
261 rstval
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.size());
262 sig
.replace(action
.first
, action
.second
, &rstval
);
265 else if (sync
->type
== RTLIL::SyncType::STp
|| sync
->type
== RTLIL::SyncType::STn
) {
266 if (sync_edge
!= NULL
&& sync_edge
!= sync
)
267 log_error("Multiple edge sensitive events found for this signal!\n");
268 sig
.replace(action
.first
, action
.second
, &insig
);
271 else if (sync
->type
== RTLIL::SyncType::STa
) {
272 if (sync_always
!= NULL
&& sync_always
!= sync
)
273 log_error("Multiple always events found for this signal!\n");
274 sig
.replace(action
.first
, action
.second
, &insig
);
277 else if (sync
->type
== RTLIL::SyncType::STg
) {
278 sig
.replace(action
.first
, action
.second
, &insig
);
282 log_error("Event with any-edge sensitivity found for this signal!\n");
285 action
.first
.remove2(sig
, &action
.second
);
288 if (many_async_rules
.size() > 0)
290 many_async_rules
[rstval
].insert(sync_level
);
291 if (many_async_rules
.size() == 1)
293 sync_level
= new RTLIL::SyncRule
;
294 sync_level
->type
= RTLIL::SyncType::ST1
;
295 sync_level
->signal
= mod
->addWire(NEW_ID
);
296 sync_level
->actions
.push_back(RTLIL::SigSig(sig
, rstval
));
297 free_sync_level
= true;
299 RTLIL::SigSpec inputs
, compare
;
300 for (auto &it
: many_async_rules
[rstval
]) {
301 inputs
.append(it
->signal
);
302 compare
.append(it
->type
== RTLIL::SyncType::ST0
? RTLIL::State::S1
: RTLIL::State::S0
);
304 log_assert(inputs
.size() == compare
.size());
306 RTLIL::Cell
*cell
= mod
->addCell(NEW_ID
, "$ne");
307 cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(false, 1);
308 cell
->parameters
["\\B_SIGNED"] = RTLIL::Const(false, 1);
309 cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(inputs
.size());
310 cell
->parameters
["\\B_WIDTH"] = RTLIL::Const(inputs
.size());
311 cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(1);
312 cell
->setPort("\\A", inputs
);
313 cell
->setPort("\\B", compare
);
314 cell
->setPort("\\Y", sync_level
->signal
);
316 many_async_rules
.clear();
320 rstval
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.size());
326 ce
.assign_map
.apply(insig
);
327 ce
.assign_map
.apply(rstval
);
328 ce
.assign_map
.apply(sig
);
331 rstval
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.size());
336 if (sync_edge
|| sync_level
|| many_async_rules
.size() > 0)
337 log_error("Mixed always event with edge and/or level sensitive events!\n");
338 log(" created direct connection (no actual register cell created).\n");
339 mod
->connect(RTLIL::SigSig(sig
, insig
));
343 if (!sync_edge
&& !global_clock
)
344 log_error("Missing edge-sensitive event for this signal!\n");
346 if (many_async_rules
.size() > 0)
348 log_warning("Complex async reset for dff `%s'.\n", log_signal(sig
));
349 gen_dffsr_complex(mod
, insig
, sig
, sync_edge
->signal
, sync_edge
->type
== RTLIL::SyncType::STp
, many_async_rules
, proc
);
351 else if (!rstval
.is_fully_const() && !ce
.eval(rstval
))
353 log_warning("Async reset value `%s' is not constant!\n", log_signal(rstval
));
354 gen_dffsr(mod
, insig
, rstval
, sig_q
,
355 sync_edge
->type
== RTLIL::SyncType::STp
,
356 sync_level
&& sync_level
->type
== RTLIL::SyncType::ST1
,
357 sync_edge
->signal
, sync_level
->signal
, proc
);
360 gen_dff(mod
, insig
, rstval
.as_const(), sig_q
,
361 sync_edge
&& sync_edge
->type
== RTLIL::SyncType::STp
,
362 sync_level
&& sync_level
->type
== RTLIL::SyncType::ST1
,
363 sync_edge
? sync_edge
->signal
: SigSpec(),
364 sync_level
? &sync_level
->signal
: NULL
, proc
);
371 struct ProcDffPass
: public Pass
{
372 ProcDffPass() : Pass("proc_dff", "extract flip-flops from processes") { }
375 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
377 log(" proc_dff [selection]\n");
379 log("This pass identifies flip-flops in the processes and converts them to\n");
380 log("d-type flip-flop cells.\n");
383 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
385 log_header(design
, "Executing PROC_DFF pass (convert process syncs to FFs).\n");
387 extra_args(args
, 1, design
);
389 for (auto mod
: design
->modules())
390 if (design
->selected(mod
)) {
392 for (auto &proc_it
: mod
->processes
)
393 if (design
->selected(mod
, proc_it
.second
))
394 proc_dff(mod
, proc_it
.second
, ce
);
399 PRIVATE_NAMESPACE_END