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/yosys.h"
21 #include "kernel/sigtools.h"
22 #include "kernel/ffinit.h"
23 #include "kernel/ff.h"
26 PRIVATE_NAMESPACE_BEGIN
28 struct Clk2fflogicPass
: public Pass
{
29 Clk2fflogicPass() : Pass("clk2fflogic", "convert clocked FFs to generic $ff cells") { }
32 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
34 log(" clk2fflogic [options] [selection]\n");
36 log("This command replaces clocked flip-flops with generic $ff cells that use the\n");
37 log("implicit global clock. This is useful for formal verification of designs with\n");
38 log("multiple clocks.\n");
41 SigSpec
wrap_async_control(Module
*module
, SigSpec sig
, bool polarity
) {
42 Wire
*past_sig
= module
->addWire(NEW_ID
, GetSize(sig
));
43 module
->addFf(NEW_ID
, sig
, past_sig
);
45 sig
= module
->Or(NEW_ID
, sig
, past_sig
);
47 sig
= module
->And(NEW_ID
, sig
, past_sig
);
51 return module
->Not(NEW_ID
, sig
);
53 SigSpec
wrap_async_control_gate(Module
*module
, SigSpec sig
, bool polarity
) {
54 Wire
*past_sig
= module
->addWire(NEW_ID
);
55 module
->addFfGate(NEW_ID
, sig
, past_sig
);
57 sig
= module
->OrGate(NEW_ID
, sig
, past_sig
);
59 sig
= module
->AndGate(NEW_ID
, sig
, past_sig
);
63 return module
->NotGate(NEW_ID
, sig
);
65 void execute(std::vector
<std::string
> args
, RTLIL::Design
*design
) override
67 // bool flag_noinit = false;
69 log_header(design
, "Executing CLK2FFLOGIC pass (convert clocked FFs to generic $ff cells).\n");
72 for (argidx
= 1; argidx
< args
.size(); argidx
++)
74 // if (args[argidx] == "-noinit") {
75 // flag_noinit = true;
80 extra_args(args
, argidx
, design
);
82 for (auto module
: design
->selected_modules())
84 SigMap
sigmap(module
);
85 FfInitVals
initvals(&sigmap
, module
);
87 for (auto cell
: vector
<Cell
*>(module
->selected_cells()))
89 if (cell
->type
.in(ID($mem
)))
91 int abits
= cell
->getParam(ID::ABITS
).as_int();
92 int width
= cell
->getParam(ID::WIDTH
).as_int();
93 int rd_ports
= cell
->getParam(ID::RD_PORTS
).as_int();
94 int wr_ports
= cell
->getParam(ID::WR_PORTS
).as_int();
96 for (int i
= 0; i
< rd_ports
; i
++) {
97 if (cell
->getParam(ID::RD_CLK_ENABLE
).extract(i
).as_bool())
98 log_error("Read port %d of memory %s.%s is clocked. This is not supported by \"clk2fflogic\"! "
99 "Call \"memory\" with -nordff to avoid this error.\n", i
, log_id(cell
), log_id(module
));
102 Const wr_clk_en_param
= cell
->getParam(ID::WR_CLK_ENABLE
);
103 Const wr_clk_pol_param
= cell
->getParam(ID::WR_CLK_POLARITY
);
105 SigSpec wr_clk_port
= cell
->getPort(ID::WR_CLK
);
106 SigSpec wr_en_port
= cell
->getPort(ID::WR_EN
);
107 SigSpec wr_addr_port
= cell
->getPort(ID::WR_ADDR
);
108 SigSpec wr_data_port
= cell
->getPort(ID::WR_DATA
);
110 for (int wport
= 0; wport
< wr_ports
; wport
++)
112 bool clken
= wr_clk_en_param
[wport
] == State::S1
;
113 bool clkpol
= wr_clk_pol_param
[wport
] == State::S1
;
118 SigBit clk
= wr_clk_port
[wport
];
119 SigSpec en
= wr_en_port
.extract(wport
*width
, width
);
120 SigSpec addr
= wr_addr_port
.extract(wport
*abits
, abits
);
121 SigSpec data
= wr_data_port
.extract(wport
*width
, width
);
123 log("Modifying write port %d on memory %s.%s: CLK=%s, A=%s, D=%s\n",
124 wport
, log_id(module
), log_id(cell
), log_signal(clk
),
125 log_signal(addr
), log_signal(data
));
127 Wire
*past_clk
= module
->addWire(NEW_ID
);
128 past_clk
->attributes
[ID::init
] = clkpol
? State::S1
: State::S0
;
129 module
->addFf(NEW_ID
, clk
, past_clk
);
131 SigSpec clock_edge_pattern
;
134 clock_edge_pattern
.append(State::S0
);
135 clock_edge_pattern
.append(State::S1
);
137 clock_edge_pattern
.append(State::S1
);
138 clock_edge_pattern
.append(State::S0
);
141 SigSpec clock_edge
= module
->Eqx(NEW_ID
, {clk
, SigSpec(past_clk
)}, clock_edge_pattern
);
143 SigSpec en_q
= module
->addWire(NEW_ID
, GetSize(en
));
144 module
->addFf(NEW_ID
, en
, en_q
);
146 SigSpec addr_q
= module
->addWire(NEW_ID
, GetSize(addr
));
147 module
->addFf(NEW_ID
, addr
, addr_q
);
149 SigSpec data_q
= module
->addWire(NEW_ID
, GetSize(data
));
150 module
->addFf(NEW_ID
, data
, data_q
);
152 wr_clk_port
[wport
] = State::S0
;
153 wr_en_port
.replace(wport
*width
, module
->Mux(NEW_ID
, Const(0, GetSize(en_q
)), en_q
, clock_edge
));
154 wr_addr_port
.replace(wport
*abits
, addr_q
);
155 wr_data_port
.replace(wport
*width
, data_q
);
157 wr_clk_en_param
[wport
] = State::S0
;
158 wr_clk_pol_param
[wport
] = State::S0
;
161 cell
->setParam(ID::WR_CLK_ENABLE
, wr_clk_en_param
);
162 cell
->setParam(ID::WR_CLK_POLARITY
, wr_clk_pol_param
);
164 cell
->setPort(ID::WR_CLK
, wr_clk_port
);
165 cell
->setPort(ID::WR_EN
, wr_en_port
);
166 cell
->setPort(ID::WR_ADDR
, wr_addr_port
);
167 cell
->setPort(ID::WR_DATA
, wr_data_port
);
171 if (RTLIL::builtin_ff_cell_types().count(cell
->type
)) {
172 FfData
ff(&initvals
, cell
);
174 if (ff
.has_d
&& !ff
.has_clk
&& !ff
.has_en
) {
175 // Already a $ff or $_FF_ cell.
179 Wire
*past_q
= module
->addWire(NEW_ID
, ff
.width
);
181 module
->addFf(NEW_ID
, ff
.sig_q
, past_q
);
183 module
->addFfGate(NEW_ID
, ff
.sig_q
, past_q
);
185 if (!ff
.val_init
.is_fully_undef())
186 initvals
.set_init(past_q
, ff
.val_init
);
189 ff
.unmap_ce_srst(module
);
191 Wire
*past_clk
= module
->addWire(NEW_ID
);
192 initvals
.set_init(past_clk
, ff
.pol_clk
? State::S1
: State::S0
);
195 module
->addFf(NEW_ID
, ff
.sig_clk
, past_clk
);
197 module
->addFfGate(NEW_ID
, ff
.sig_clk
, past_clk
);
199 log("Replacing %s.%s (%s): CLK=%s, D=%s, Q=%s\n",
200 log_id(module
), log_id(cell
), log_id(cell
->type
),
201 log_signal(ff
.sig_clk
), log_signal(ff
.sig_d
), log_signal(ff
.sig_q
));
203 SigSpec clock_edge_pattern
;
206 clock_edge_pattern
.append(State::S0
);
207 clock_edge_pattern
.append(State::S1
);
209 clock_edge_pattern
.append(State::S1
);
210 clock_edge_pattern
.append(State::S0
);
213 SigSpec clock_edge
= module
->Eqx(NEW_ID
, {ff
.sig_clk
, SigSpec(past_clk
)}, clock_edge_pattern
);
215 Wire
*past_d
= module
->addWire(NEW_ID
, ff
.width
);
217 module
->addFf(NEW_ID
, ff
.sig_d
, past_d
);
219 module
->addFfGate(NEW_ID
, ff
.sig_d
, past_d
);
221 if (!ff
.val_init
.is_fully_undef())
222 initvals
.set_init(past_d
, ff
.val_init
);
225 qval
= module
->Mux(NEW_ID
, past_q
, past_d
, clock_edge
);
227 qval
= module
->MuxGate(NEW_ID
, past_q
, past_d
, clock_edge
);
228 } else if (ff
.has_d
) {
230 log("Replacing %s.%s (%s): EN=%s, D=%s, Q=%s\n",
231 log_id(module
), log_id(cell
), log_id(cell
->type
),
232 log_signal(ff
.sig_en
), log_signal(ff
.sig_d
), log_signal(ff
.sig_q
));
234 SigSpec sig_en
= wrap_async_control(module
, ff
.sig_en
, ff
.pol_en
);
237 qval
= module
->Mux(NEW_ID
, past_q
, ff
.sig_d
, sig_en
);
239 qval
= module
->MuxGate(NEW_ID
, past_q
, ff
.sig_d
, sig_en
);
242 log("Replacing %s.%s (%s): SET=%s, CLR=%s, Q=%s\n",
243 log_id(module
), log_id(cell
), log_id(cell
->type
),
244 log_signal(ff
.sig_set
), log_signal(ff
.sig_clr
), log_signal(ff
.sig_q
));
250 SigSpec setval
= wrap_async_control(module
, ff
.sig_set
, ff
.pol_set
);
251 SigSpec clrval
= wrap_async_control(module
, ff
.sig_clr
, ff
.pol_clr
);
253 clrval
= module
->Not(NEW_ID
, clrval
);
254 qval
= module
->Or(NEW_ID
, qval
, setval
);
255 module
->addAnd(NEW_ID
, qval
, clrval
, ff
.sig_q
);
257 clrval
= module
->NotGate(NEW_ID
, clrval
);
258 qval
= module
->OrGate(NEW_ID
, qval
, setval
);
259 module
->addAndGate(NEW_ID
, qval
, clrval
, ff
.sig_q
);
261 } else if (ff
.has_arst
) {
262 SigSpec arst
= wrap_async_control(module
, ff
.sig_arst
, ff
.pol_arst
);
264 module
->addMux(NEW_ID
, qval
, ff
.val_arst
, arst
, ff
.sig_q
);
266 module
->addMuxGate(NEW_ID
, qval
, ff
.val_arst
[0], arst
, ff
.sig_q
);
268 module
->connect(ff
.sig_q
, qval
);
271 initvals
.remove_init(ff
.sig_q
);
272 module
->remove(cell
);
281 PRIVATE_NAMESPACE_END