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 static RTLIL::SigSpec
find_any_lvalue(const RTLIL::Process
*proc
)
31 RTLIL::SigSpec lvalue
;
33 for (auto sync
: proc
->syncs
)
34 for (auto &action
: sync
->actions
)
35 if (action
.first
.width
> 0) {
36 lvalue
= action
.first
;
37 lvalue
.sort_and_unify();
41 for (auto sync
: proc
->syncs
) {
42 RTLIL::SigSpec this_lvalue
;
43 for (auto &action
: sync
->actions
)
44 this_lvalue
.append(action
.first
);
45 this_lvalue
.sort_and_unify();
46 RTLIL::SigSpec common_sig
= this_lvalue
.extract(lvalue
);
47 if (common_sig
.width
> 0)
54 static void gen_dffsr_complex(RTLIL::Module
*mod
, RTLIL::SigSpec sig_d
, RTLIL::SigSpec sig_q
, RTLIL::SigSpec clk
, bool clk_polarity
,
55 std::map
<RTLIL::SigSpec
, std::set
<RTLIL::SyncRule
*>> &async_rules
, RTLIL::Process
*proc
)
57 RTLIL::SigSpec sig_sr_set
= RTLIL::SigSpec(0, sig_d
.width
);
58 RTLIL::SigSpec sig_sr_clr
= RTLIL::SigSpec(0, sig_d
.width
);
60 for (auto &it
: async_rules
)
62 RTLIL::SigSpec sync_value
= it
.first
;
63 RTLIL::SigSpec sync_value_inv
;
64 RTLIL::SigSpec sync_high_signals
;
65 RTLIL::SigSpec sync_low_signals
;
67 for (auto &it2
: it
.second
)
68 if (it2
->type
== RTLIL::SyncType::ST0
)
69 sync_low_signals
.append(it2
->signal
);
70 else if (it2
->type
== RTLIL::SyncType::ST1
)
71 sync_high_signals
.append(it2
->signal
);
75 if (sync_low_signals
.width
> 1) {
76 RTLIL::Cell
*cell
= new RTLIL::Cell
;
78 cell
->type
= "$reduce_or";
79 cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
80 cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(sync_low_signals
.width
);
81 cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(1);
82 cell
->connections
["\\A"] = sync_low_signals
;
83 cell
->connections
["\\Y"] = sync_low_signals
= NEW_WIRE(mod
, 1);
87 if (sync_low_signals
.width
> 0) {
88 RTLIL::Cell
*cell
= new RTLIL::Cell
;
91 cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
92 cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(sync_low_signals
.width
);
93 cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(1);
94 cell
->connections
["\\A"] = sync_low_signals
;
95 cell
->connections
["\\Y"] = NEW_WIRE(mod
, 1);
96 sync_high_signals
.append(cell
->connections
["\\Y"]);
100 if (sync_high_signals
.width
> 1) {
101 RTLIL::Cell
*cell
= new RTLIL::Cell
;
103 cell
->type
= "$reduce_or";
104 cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
105 cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(sync_high_signals
.width
);
106 cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(1);
107 cell
->connections
["\\A"] = sync_high_signals
;
108 cell
->connections
["\\Y"] = sync_high_signals
= NEW_WIRE(mod
, 1);
112 RTLIL::Cell
*inv_cell
= new RTLIL::Cell
;
113 inv_cell
->name
= NEW_ID
;
114 inv_cell
->type
= "$not";
115 inv_cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
116 inv_cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(sig_d
.width
);
117 inv_cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(sig_d
.width
);
118 inv_cell
->connections
["\\A"] = sync_value
;
119 inv_cell
->connections
["\\Y"] = sync_value_inv
= NEW_WIRE(mod
, sig_d
.width
);
122 RTLIL::Cell
*mux_set_cell
= new RTLIL::Cell
;
123 mux_set_cell
->name
= NEW_ID
;
124 mux_set_cell
->type
= "$mux";
125 mux_set_cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_d
.width
);
126 mux_set_cell
->connections
["\\A"] = sig_sr_set
;
127 mux_set_cell
->connections
["\\B"] = sync_value
;
128 mux_set_cell
->connections
["\\S"] = sync_high_signals
;
129 mux_set_cell
->connections
["\\Y"] = sig_sr_set
= NEW_WIRE(mod
, sig_d
.width
);
130 mod
->add(mux_set_cell
);
132 RTLIL::Cell
*mux_clr_cell
= new RTLIL::Cell
;
133 mux_clr_cell
->name
= NEW_ID
;
134 mux_clr_cell
->type
= "$mux";
135 mux_clr_cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_d
.width
);
136 mux_clr_cell
->connections
["\\A"] = sig_sr_clr
;
137 mux_clr_cell
->connections
["\\B"] = sync_value_inv
;
138 mux_clr_cell
->connections
["\\S"] = sync_high_signals
;
139 mux_clr_cell
->connections
["\\Y"] = sig_sr_clr
= NEW_WIRE(mod
, sig_d
.width
);
140 mod
->add(mux_clr_cell
);
143 std::stringstream sstr
;
144 sstr
<< "$procdff$" << (RTLIL::autoidx
++);
146 RTLIL::Cell
*cell
= new RTLIL::Cell
;
147 cell
->name
= sstr
.str();
148 cell
->type
= "$dffsr";
149 cell
->attributes
= proc
->attributes
;
150 cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_d
.width
);
151 cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity
, 1);
152 cell
->parameters
["\\SET_POLARITY"] = RTLIL::Const(true, 1);
153 cell
->parameters
["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
154 cell
->connections
["\\D"] = sig_d
;
155 cell
->connections
["\\Q"] = sig_q
;
156 cell
->connections
["\\CLK"] = clk
;
157 cell
->connections
["\\SET"] = sig_sr_set
;
158 cell
->connections
["\\CLR"] = sig_sr_clr
;
161 log(" created %s cell `%s' with %s edge clock and multiple level-sensitive resets.\n",
162 cell
->type
.c_str(), cell
->name
.c_str(), clk_polarity
? "positive" : "negative");
165 static void gen_dffsr(RTLIL::Module
*mod
, RTLIL::SigSpec sig_in
, RTLIL::SigSpec sig_set
, RTLIL::SigSpec sig_out
,
166 bool clk_polarity
, bool set_polarity
, RTLIL::SigSpec clk
, RTLIL::SigSpec set
, RTLIL::Process
*proc
)
168 std::stringstream sstr
;
169 sstr
<< "$procdff$" << (RTLIL::autoidx
++);
171 RTLIL::SigSpec sig_set_inv
= NEW_WIRE(mod
, sig_in
.width
);
172 RTLIL::SigSpec sig_sr_set
= NEW_WIRE(mod
, sig_in
.width
);
173 RTLIL::SigSpec sig_sr_clr
= NEW_WIRE(mod
, sig_in
.width
);
175 RTLIL::Cell
*inv_set
= new RTLIL::Cell
;
176 inv_set
->name
= NEW_ID
;
177 inv_set
->type
= "$not";
178 inv_set
->parameters
["\\A_SIGNED"] = RTLIL::Const(0);
179 inv_set
->parameters
["\\A_WIDTH"] = RTLIL::Const(sig_in
.width
);
180 inv_set
->parameters
["\\Y_WIDTH"] = RTLIL::Const(sig_in
.width
);
181 inv_set
->connections
["\\A"] = sig_set
;
182 inv_set
->connections
["\\Y"] = sig_set_inv
;
185 RTLIL::Cell
*mux_sr_set
= new RTLIL::Cell
;
186 mux_sr_set
->name
= NEW_ID
;
187 mux_sr_set
->type
= "$mux";
188 mux_sr_set
->parameters
["\\WIDTH"] = RTLIL::Const(sig_in
.width
);
189 mux_sr_set
->connections
[set_polarity
? "\\A" : "\\B"] = RTLIL::Const(0, sig_in
.width
);
190 mux_sr_set
->connections
[set_polarity
? "\\B" : "\\A"] = sig_set
;
191 mux_sr_set
->connections
["\\Y"] = sig_sr_set
;
192 mux_sr_set
->connections
["\\S"] = set
;
193 mod
->add(mux_sr_set
);
195 RTLIL::Cell
*mux_sr_clr
= new RTLIL::Cell
;
196 mux_sr_clr
->name
= NEW_ID
;
197 mux_sr_clr
->type
= "$mux";
198 mux_sr_clr
->parameters
["\\WIDTH"] = RTLIL::Const(sig_in
.width
);
199 mux_sr_clr
->connections
[set_polarity
? "\\A" : "\\B"] = RTLIL::Const(0, sig_in
.width
);
200 mux_sr_clr
->connections
[set_polarity
? "\\B" : "\\A"] = sig_set_inv
;
201 mux_sr_clr
->connections
["\\Y"] = sig_sr_clr
;
202 mux_sr_clr
->connections
["\\S"] = set
;
203 mod
->add(mux_sr_clr
);
205 RTLIL::Cell
*cell
= new RTLIL::Cell
;
206 cell
->name
= sstr
.str();
207 cell
->type
= "$dffsr";
208 cell
->attributes
= proc
->attributes
;
209 cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_in
.width
);
210 cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity
, 1);
211 cell
->parameters
["\\SET_POLARITY"] = RTLIL::Const(true, 1);
212 cell
->parameters
["\\CLR_POLARITY"] = RTLIL::Const(true, 1);
213 cell
->connections
["\\D"] = sig_in
;
214 cell
->connections
["\\Q"] = sig_out
;
215 cell
->connections
["\\CLK"] = clk
;
216 cell
->connections
["\\SET"] = sig_sr_set
;
217 cell
->connections
["\\CLR"] = sig_sr_clr
;
220 log(" created %s cell `%s' with %s edge clock and %s level non-const reset.\n", cell
->type
.c_str(), cell
->name
.c_str(),
221 clk_polarity
? "positive" : "negative", set_polarity
? "positive" : "negative");
224 static void gen_dff(RTLIL::Module
*mod
, RTLIL::SigSpec sig_in
, RTLIL::Const val_rst
, RTLIL::SigSpec sig_out
,
225 bool clk_polarity
, bool arst_polarity
, RTLIL::SigSpec clk
, RTLIL::SigSpec
*arst
, RTLIL::Process
*proc
)
227 std::stringstream sstr
;
228 sstr
<< "$procdff$" << (RTLIL::autoidx
++);
230 RTLIL::Cell
*cell
= new RTLIL::Cell
;
231 cell
->name
= sstr
.str();
232 cell
->type
= arst
? "$adff" : "$dff";
233 cell
->attributes
= proc
->attributes
;
234 mod
->cells
[cell
->name
] = cell
;
236 cell
->parameters
["\\WIDTH"] = RTLIL::Const(sig_in
.width
);
238 cell
->parameters
["\\ARST_POLARITY"] = RTLIL::Const(arst_polarity
, 1);
239 cell
->parameters
["\\ARST_VALUE"] = val_rst
;
241 cell
->parameters
["\\CLK_POLARITY"] = RTLIL::Const(clk_polarity
, 1);
243 cell
->connections
["\\D"] = sig_in
;
244 cell
->connections
["\\Q"] = sig_out
;
246 cell
->connections
["\\ARST"] = *arst
;
247 cell
->connections
["\\CLK"] = clk
;
249 log(" created %s cell `%s' with %s edge clock", cell
->type
.c_str(), cell
->name
.c_str(), clk_polarity
? "positive" : "negative");
251 log(" and %s level reset", arst_polarity
? "positive" : "negative");
255 static void proc_dff(RTLIL::Module
*mod
, RTLIL::Process
*proc
, ConstEval
&ce
)
259 RTLIL::SigSpec sig
= find_any_lvalue(proc
);
260 bool free_sync_level
= false;
265 log("Creating register for signal `%s.%s' using process `%s.%s'.\n",
266 mod
->name
.c_str(), log_signal(sig
), mod
->name
.c_str(), proc
->name
.c_str());
268 RTLIL::SigSpec insig
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.width
);
269 RTLIL::SigSpec rstval
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.width
);
270 RTLIL::SyncRule
*sync_level
= NULL
;
271 RTLIL::SyncRule
*sync_edge
= NULL
;
272 RTLIL::SyncRule
*sync_always
= NULL
;
274 std::map
<RTLIL::SigSpec
, std::set
<RTLIL::SyncRule
*>> many_async_rules
;
276 for (auto sync
: proc
->syncs
)
277 for (auto &action
: sync
->actions
)
279 if (action
.first
.extract(sig
).width
== 0)
282 if (sync
->type
== RTLIL::SyncType::ST0
|| sync
->type
== RTLIL::SyncType::ST1
) {
283 if (sync_level
!= NULL
&& sync_level
!= sync
) {
284 // log_error("Multiple level sensitive events found for this signal!\n");
285 many_async_rules
[rstval
].insert(sync_level
);
286 rstval
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.width
);
288 rstval
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.width
);
289 sig
.replace(action
.first
, action
.second
, &rstval
);
292 else if (sync
->type
== RTLIL::SyncType::STp
|| sync
->type
== RTLIL::SyncType::STn
) {
293 if (sync_edge
!= NULL
&& sync_edge
!= sync
)
294 log_error("Multiple edge sensitive events found for this signal!\n");
295 sig
.replace(action
.first
, action
.second
, &insig
);
298 else if (sync
->type
== RTLIL::SyncType::STa
) {
299 if (sync_always
!= NULL
&& sync_always
!= sync
)
300 log_error("Multiple always events found for this signal!\n");
301 sig
.replace(action
.first
, action
.second
, &insig
);
305 log_error("Event with any-edge sensitivity found for this signal!\n");
308 action
.first
.remove2(sig
, &action
.second
);
311 if (many_async_rules
.size() > 0)
313 many_async_rules
[rstval
].insert(sync_level
);
314 if (many_async_rules
.size() == 1)
316 sync_level
= new RTLIL::SyncRule
;
317 sync_level
->type
= RTLIL::SyncType::ST1
;
318 sync_level
->signal
= NEW_WIRE(mod
, 1);
319 sync_level
->actions
.push_back(RTLIL::SigSig(sig
, rstval
));
320 free_sync_level
= true;
322 RTLIL::SigSpec inputs
, compare
;
323 for (auto &it
: many_async_rules
[rstval
]) {
324 inputs
.append(it
->signal
);
325 compare
.append(it
->type
== RTLIL::SyncType::ST0
? RTLIL::State::S1
: RTLIL::State::S0
);
327 assert(inputs
.width
== compare
.width
);
329 RTLIL::Cell
*cell
= new RTLIL::Cell
;
332 cell
->parameters
["\\A_SIGNED"] = RTLIL::Const(false, 1);
333 cell
->parameters
["\\B_SIGNED"] = RTLIL::Const(false, 1);
334 cell
->parameters
["\\A_WIDTH"] = RTLIL::Const(inputs
.width
);
335 cell
->parameters
["\\B_WIDTH"] = RTLIL::Const(inputs
.width
);
336 cell
->parameters
["\\Y_WIDTH"] = RTLIL::Const(1);
337 cell
->connections
["\\A"] = inputs
;
338 cell
->connections
["\\B"] = compare
;
339 cell
->connections
["\\Y"] = sync_level
->signal
;
342 many_async_rules
.clear();
346 rstval
= RTLIL::SigSpec(RTLIL::State::Sz
, sig
.width
);
351 ce
.assign_map
.apply(insig
);
352 ce
.assign_map
.apply(rstval
);
353 ce
.assign_map
.apply(sig
);
360 if (sync_edge
|| sync_level
|| many_async_rules
.size() > 0)
361 log_error("Mixed always event with edge and/or level sensitive events!\n");
362 log(" created direct connection (no actual register cell created).\n");
363 mod
->connections
.push_back(RTLIL::SigSig(sig
, insig
));
368 log_error("Missing edge-sensitive event for this signal!\n");
370 if (many_async_rules
.size() > 0)
372 log("WARNING: Complex async reset for dff `%s'.\n", log_signal(sig
));
373 gen_dffsr_complex(mod
, insig
, sig
, sync_edge
->signal
, sync_edge
->type
== RTLIL::SyncType::STp
, many_async_rules
, proc
);
375 else if (!rstval
.is_fully_const() && !ce
.eval(rstval
))
377 log("WARNING: Async reset value `%s' is not constant!\n", log_signal(rstval
));
378 gen_dffsr(mod
, insig
, rstval
, sig
,
379 sync_edge
->type
== RTLIL::SyncType::STp
,
380 sync_level
&& sync_level
->type
== RTLIL::SyncType::ST1
,
381 sync_edge
->signal
, sync_level
->signal
, proc
);
384 gen_dff(mod
, insig
, rstval
.chunks
[0].data
, sig
,
385 sync_edge
->type
== RTLIL::SyncType::STp
,
386 sync_level
&& sync_level
->type
== RTLIL::SyncType::ST1
,
387 sync_edge
->signal
, sync_level
? &sync_level
->signal
: NULL
, proc
);
394 struct ProcDffPass
: public Pass
{
395 ProcDffPass() : Pass("proc_dff", "extract flip-flops from processes") { }
398 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
400 log(" proc_dff [selection]\n");
402 log("This pass identifies flip-flops in the processes and converts them to\n");
403 log("d-type flip-flop cells.\n");
406 virtual void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
)
408 log_header("Executing PROC_DFF pass (convert process syncs to FFs).\n");
410 extra_args(args
, 1, design
);
412 for (auto &mod_it
: design
->modules
)
413 if (design
->selected(mod_it
.second
)) {
414 ConstEval
ce(mod_it
.second
);
415 for (auto &proc_it
: mod_it
.second
->processes
)
416 if (design
->selected(mod_it
.second
, proc_it
.second
))
417 proc_dff(mod_it
.second
, proc_it
.second
, ce
);