Do not use default_params dict, hardcode default values, cleanup
[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 auto first_cell = ud.longest_chain.back();
40
41 SigSpec initval;
42 for (auto cell : ud.longest_chain) {
43 log_debug(" %s\n", log_id(cell));
44 if (cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_))) {
45 SigBit Q = cell->getPort(ID(Q));
46 log_assert(Q.wire);
47 auto it = Q.wire->attributes.find(ID(init));
48 if (it != Q.wire->attributes.end()) {
49 auto &i = it->second[Q.offset];
50 initval.append(i);
51 i = State::Sx;
52 }
53 else
54 initval.append(State::Sx);
55 }
56 else if (cell->type.in(ID(FDRE), ID(FDRE_1))) {
57 if (cell->parameters.at(ID(INIT), State::S0).as_bool())
58 initval.append(State::S1);
59 else
60 initval.append(State::S0);
61 }
62 else
63 log_abort();
64 if (cell != first_cell)
65 pm.autoremove(cell);
66 }
67
68 auto last_cell = ud.longest_chain.front();
69 Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
70 pm.module->swap_names(c, first_cell);
71
72 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))) {
73 c->setParam(ID(DEPTH), GetSize(ud.longest_chain));
74 c->setParam(ID(INIT), initval.as_const());
75 if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
76 c->setParam(ID(CLKPOL), 1);
77 else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_), ID(FDRE_1)))
78 c->setParam(ID(CLKPOL), 0);
79 else if (first_cell->type.in(ID(FDRE))) {
80 if (!first_cell->parameters.at(ID(IS_C_INVERTED), State::S0).as_bool())
81 c->setParam(ID(CLKPOL), 1);
82 else
83 c->setParam(ID(CLKPOL), 0);
84 }
85 else
86 log_abort();
87 if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
88 c->setParam(ID(ENPOL), 1);
89 else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
90 c->setParam(ID(ENPOL), 0);
91 else
92 c->setParam(ID(ENPOL), 2);
93
94 c->setPort(ID(C), first_cell->getPort(ID(C)));
95 c->setPort(ID(D), first_cell->getPort(ID(D)));
96 c->setPort(ID(Q), last_cell->getPort(ID(Q)));
97 c->setPort(ID(L), GetSize(ud.longest_chain)-1);
98 if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_)))
99 c->setPort(ID(E), State::S1);
100 else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
101 c->setPort(ID(E), first_cell->getPort(ID(E)));
102 else if (first_cell->type.in(ID(FDRE), ID(FDRE_1)))
103 c->setPort(ID(E), first_cell->getPort(ID(CE)));
104 else
105 log_abort();
106 }
107 else
108 log_abort();
109
110 log(" -> %s (%s)\n", log_id(c), log_id(c->type));
111 }
112
113 void run_variable(xilinx_srl_pm &pm)
114 {
115 auto &st = pm.st_variable;
116 auto &ud = pm.ud_variable;
117
118 log("Found variable chain of length %d (%s):\n", GetSize(ud.chain), log_id(st.first->type));
119
120 auto first_cell = ud.chain.back().first;
121 auto first_slice = ud.chain.back().second;
122
123 SigSpec initval;
124 for (const auto &i : ud.chain) {
125 auto cell = i.first;
126 auto slice = i.second;
127 log_debug(" %s\n", log_id(cell));
128 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))) {
129 SigBit Q = cell->getPort(ID(Q))[slice];
130 log_assert(Q.wire);
131 auto it = Q.wire->attributes.find(ID(init));
132 if (it != Q.wire->attributes.end()) {
133 auto &i = it->second[Q.offset];
134 initval.append(i);
135 i = State::Sx;
136 }
137 else
138 initval.append(State::Sx);
139 }
140 else
141 log_abort();
142 if (cell != first_cell)
143 cell->connections_.at(ID(Q))[slice] = pm.module->addWire(NEW_ID);
144 }
145 pm.autoremove(st.shiftx);
146
147 Cell *c = pm.module->addCell(NEW_ID, ID($__XILINX_SHREG_));
148 pm.module->swap_names(c, first_cell);
149
150 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))) {
151 c->setParam(ID(DEPTH), GetSize(ud.chain));
152 c->setParam(ID(INIT), initval.as_const());
153 Const clkpol, enpol;
154 if (first_cell->type.in(ID($_DFF_P_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
155 clkpol = 1;
156 else if (first_cell->type.in(ID($_DFF_N_), ID($DFFE_NN_), ID($_DFFE_NP_)))
157 clkpol = 0;
158 else if (first_cell->type.in(ID($dff), ID($dffe)))
159 clkpol = first_cell->getParam(ID(CLK_POLARITY));
160 else
161 log_abort();
162 if (first_cell->type.in(ID($_DFFE_NP_), ID($_DFFE_PP_)))
163 enpol = 1;
164 else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_PN_)))
165 enpol = 0;
166 else if (first_cell->type.in(ID($dffe)))
167 enpol = first_cell->getParam(ID(EN_POLARITY));
168 else
169 enpol = 2;
170 c->setParam(ID(CLKPOL), clkpol);
171 c->setParam(ID(ENPOL), enpol);
172
173 if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
174 c->setPort(ID(C), first_cell->getPort(ID(C)));
175 else if (first_cell->type.in(ID($dff), ID($dffe)))
176 c->setPort(ID(C), first_cell->getPort(ID(CLK)));
177 else
178 log_abort();
179 c->setPort(ID(D), first_cell->getPort(ID(D))[first_slice]);
180 c->setPort(ID(Q), st.shiftx->getPort(ID(Y)));
181 c->setPort(ID(L), st.shiftx->getPort(ID(B)));
182 if (first_cell->type.in(ID($_DFF_N_), ID($_DFF_P_), ID($dff)))
183 c->setPort(ID(E), State::S1);
184 else if (first_cell->type.in(ID($_DFFE_NN_), ID($_DFFE_NP_), ID($_DFFE_PN_), ID($_DFFE_PP_)))
185 c->setPort(ID(E), first_cell->getPort(ID(E)));
186 else if (first_cell->type.in(ID($dffe)))
187 c->setPort(ID(E), first_cell->getPort(ID(EN)));
188 else
189 log_abort();
190 }
191 else
192 log_abort();
193
194 log(" -> %s (%s)\n", log_id(c), log_id(c->type));
195 }
196
197 struct XilinxSrlPass : public Pass {
198 XilinxSrlPass() : Pass("xilinx_srl", "Xilinx shift register extraction") { }
199 void help() YS_OVERRIDE
200 {
201 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
202 log("\n");
203 log(" xilinx_srl [options] [selection]\n");
204 log("\n");
205 log("This pass converts chains of built-in flops (bit-level: $_DFF_[NP]_, $_DFFE_*\n");
206 log("and word-level: $dff, $dffe) as well as Xilinx flops (FDRE, FDRE_1) into a\n");
207 log("$__XILINX_SHREG cell. Chains must be of the same cell type, clock, clock polarity,\n");
208 log("enable, and enable polarity (where relevant).\n");
209 log("Flops with resets cannot be mapped to Xilinx devices and will not be inferred.");
210 log("\n");
211 log(" -minlen N\n");
212 log(" min length of shift register (default = 3)\n");
213 log("\n");
214 log(" -fixed\n");
215 log(" infer fixed-length shift registers.\n");
216 log("\n");
217 log(" -variable\n");
218 log(" infer variable-length shift registers (i.e. fixed-length shifts where\n");
219 log(" each element also fans-out to a $shiftx cell).\n");
220 log("\n");
221 }
222
223 void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
224 {
225 log_header(design, "Executing XILINX_SRL pass (Xilinx shift register extraction).\n");
226
227 bool fixed = false;
228 bool variable = false;
229 int minlen = 3;
230
231 size_t argidx;
232 for (argidx = 1; argidx < args.size(); argidx++)
233 {
234 if (args[argidx] == "-minlen" && argidx+1 < args.size()) {
235 minlen = atoi(args[++argidx].c_str());
236 continue;
237 }
238 if (args[argidx] == "-fixed") {
239 fixed = true;
240 continue;
241 }
242 if (args[argidx] == "-variable") {
243 variable = true;
244 continue;
245 }
246 break;
247 }
248 extra_args(args, argidx, design);
249
250 if (!fixed && !variable)
251 log_cmd_error("'-fixed' and/or '-variable' must be specified.\n");
252
253 for (auto module : design->selected_modules()) {
254 auto pm = xilinx_srl_pm(module, module->selected_cells());
255 pm.ud_fixed.minlen = minlen;
256 pm.ud_variable.minlen = minlen;
257
258 if (fixed)
259 pm.run_fixed(run_fixed);
260 if (variable)
261 pm.run_variable(run_variable);
262 }
263 }
264 } XilinxSrlPass;
265
266 PRIVATE_NAMESPACE_END