No need to replace Q of slice since $shiftx is autoremove-d
[yosys.git] / passes / pmgen / xilinx_srl.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 * (C) 2019 Eddie Hung <eddie@fpgeh.com>
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 *
19 */
20
21 #include "kernel/yosys.h"
22 #include "kernel/sigtools.h"
23
24 USING_YOSYS_NAMESPACE
25 PRIVATE_NAMESPACE_BEGIN
26
27 // for peepopt_pm
28 bool did_something;
29
30 #include "passes/pmgen/xilinx_srl_pm.h"
31 #include "passes/pmgen/peepopt_pm.h"
32
33 void run_fixed(xilinx_srl_pm &pm)
34 {
35 auto &st = pm.st_fixed;
36 auto &ud = pm.ud_fixed;
37 log("Found fixed chain of length %d (%s):\n", GetSize(ud.longest_chain), log_id(st.first->type));
38
39 SigSpec initval;
40 for (auto cell : ud.longest_chain) {
41 log_debug(" %s\n", log_id(cell));
42 if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) {
43 SigBit Q = cell->getPort(ID(Q));
44 log_assert(Q.wire);
45 auto it = Q.wire->attributes.find(ID(init));
46 if (it != Q.wire->attributes.end()) {
47 auto &i = it->second[Q.offset];
48 initval.append(i);
49 i = State::Sx;
50 }
51 else
52 initval.append(State::Sx);
53 }
54 else if (cell->type.in(ID(FDRE), ID(FDRE_1))) {
55 if (cell->parameters.at(ID(INIT), State::S0).as_bool())
56 initval.append(State::S1);
57 else
58 initval.append(State::S0);
59 }
60 else
61 log_abort();
62 pm.autoremove(cell);
63 }
64
65 auto first_cell = ud.longest_chain.back();
66 auto last_cell = ud.longest_chain.front();
67 Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
68 pm.module->swap_names(c, first_cell);
69
70 if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID(FDRE), ID(FDRE_1))) {
71 c->setParam(ID(DEPTH), GetSize(ud.longest_chain));
72 c->setParam(ID(INIT), initval.as_const());
73 if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
74 c->setParam(ID(CLKPOL), 1);
75 else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1)))
76 c->setParam(ID(CLKPOL), 0);
77 else if (first_cell->type.in(ID(FDRE))) {
78 if (!first_cell->parameters.at(ID(IS_C_INVERTED), State::S0).as_bool())
79 c->setParam(ID(CLKPOL), 1);
80 else
81 c->setParam(ID(CLKPOL), 0);
82 }
83 else
84 log_abort();
85 if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
86 c->setParam(ID(ENPOL), 1);
87 else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
88 c->setParam(ID(ENPOL), 0);
89 else
90 c->setParam(ID(ENPOL), 2);
91
92 c->setPort(ID(C), first_cell->getPort(ID(C)));
93 c->setPort(ID(D), first_cell->getPort(ID(D)));
94 c->setPort(ID(Q), last_cell->getPort(ID(Q)));
95 c->setPort(ID(L), GetSize(ud.longest_chain)-1);
96 if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
97 c->setPort(ID(E), State::S1);
98 else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
99 c->setPort(ID(E), first_cell->getPort(ID(E)));
100 else if (first_cell->type.in(ID(FDRE), ID(FDRE_1)))
101 c->setPort(ID(E), first_cell->getPort(ID(CE)));
102 else
103 log_abort();
104 }
105 else
106 log_abort();
107
108 log(" -> %s (%s)\n", log_id(c), log_id(c->type));
109 }
110
111 void run_variable(xilinx_srl_pm &pm)
112 {
113 auto &st = pm.st_variable;
114 auto &ud = pm.ud_variable;
115
116 log("Found variable chain of length %d (%s):\n", GetSize(ud.chain), log_id(st.first->type));
117
118 SigSpec initval;
119 for (const auto &i : ud.chain) {
120 auto cell = i.first;
121 auto slice = i.second;
122 log_debug(" %s\n", log_id(cell));
123 if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) {
124 SigBit Q = cell->getPort(ID(Q))[slice];
125 log_assert(Q.wire);
126 auto it = Q.wire->attributes.find(ID(init));
127 if (it != Q.wire->attributes.end()) {
128 auto &i = it->second[Q.offset];
129 initval.append(i);
130 i = State::Sx;
131 }
132 else
133 initval.append(State::Sx);
134 }
135 else
136 log_abort();
137 }
138 pm.autoremove(st.shiftx);
139
140 auto first_cell = ud.chain.back().first;
141 auto first_slice = ud.chain.back().second;
142
143 Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
144 pm.module->swap_names(c, first_cell);
145
146 if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_), ID($dff), ID($dffe))) {
147 c->setParam(ID(DEPTH), GetSize(ud.chain));
148 c->setParam(ID(INIT), initval.as_const());
149 Const clkpol, enpol;
150 if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
151 clkpol = 1;
152 else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_)))
153 clkpol = 0;
154 else if (first_cell->type.in(ID($dff), ID($dffe)))
155 clkpol = first_cell->getParam(ID(CLK_POLARITY));
156 else
157 log_abort();
158 if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
159 enpol = 1;
160 else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
161 enpol = 0;
162 else if (first_cell->type.in(ID($dffe)))
163 enpol = first_cell->getParam(ID(EN_POLARITY));
164 else
165 enpol = 2;
166 c->setParam(ID(CLKPOL), clkpol);
167 c->setParam(ID(ENPOL), enpol);
168
169 if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
170 c->setPort(ID(C), first_cell->getPort(ID(C)));
171 else if (first_cell->type.in(ID($dff), ID($dffe)))
172 c->setPort(ID(C), first_cell->getPort(ID(CLK)));
173 else
174 log_abort();
175 c->setPort(ID(D), first_cell->getPort(ID(D))[first_slice]);
176 c->setPort(ID(Q), st.shiftx->getPort(ID(Y)));
177 c->setPort(ID(L), st.shiftx->getPort(ID(B)));
178 if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($dff)))
179 c->setPort(ID(E), State::S1);
180 else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
181 c->setPort(ID(E), first_cell->getPort(ID(E)));
182 else if (first_cell->type.in(ID($dffe)))
183 c->setPort(ID(E), first_cell->getPort(ID(EN)));
184 else
185 log_abort();
186 }
187 else
188 log_abort();
189
190 log(" -> %s (%s)\n", log_id(c), log_id(c->type));
191 }
192
193 struct XilinxSrlPass : public Pass {
194 XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { }
195 void help() YS_OVERRIDE
196 {
197 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
198 log("\n");
199 log(" xilinx_srl [options] [selection]\n");
200 log("\n");
201 log("This pass converts chains of built-in flops (bit-level: $_DFF_[NP]_, $_DFFE_*\n");
202 log("and word-level: $dff, $dffe) as well as Xilinx flops (FDRE, FDRE_1) into a\n");
203 log("$__XILINX_SHREG cell. Chains must be of the same cell type, clock, clock polarity,\n");
204 log("enable, and enable polarity (where relevant).\n");
205 log("Flops with resets cannot be mapped to Xilinx devices and will not be inferred.");
206 log("\n");
207 log(" -minlen N\n");
208 log(" min length of shift register (default = 3)\n");
209 log("\n");
210 log(" -fixed\n");
211 log(" infer fixed-length shift registers.\n");
212 log("\n");
213 log(" -variable\n");
214 log(" infer variable-length shift registers (i.e. fixed-length shifts where\n");
215 log(" each element also fans-out to a $shiftx cell).\n");
216 log("\n");
217 }
218
219 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
220 {
221 log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n");
222
223 bool fixed = false;
224 bool variable = false;
225 int minlen = 3;
226
227 size_t argidx;
228 for (argidx = 1; argidx < args.size(); argidx++)
229 {
230 if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
231 minlen = atoi(args[++argidx].c_str());
232 continue;
233 }
234 if (args[argidx] == "-fixed") {
235 fixed = true;
236 continue;
237 }
238 if (args[argidx] == "-variable") {
239 variable = true;
240 continue;
241 }
242 break;
243 }
244 extra_args(args, argidx, design);
245
246 if (!fixed && !variable)
247 log_cmd_error("'-fixed' and/or '-variable' must be specified.\n");
248
249 for (auto module : design->selected_modules()) {
250 auto pm = xilinx_srl_pm(module, module->selected_cells());
251 pm.ud_fixed.minlen = minlen;
252 pm.ud_variable.minlen = minlen;
253
254 if (fixed)
255 pm.run_fixed(run_fixed);
256 if (variable)
257 pm.run_variable(run_variable);
258 }
259 }
260 } XilinxSrlPass;
261
262 PRIVATE_NAMESPACE_END