Add new builtin FF types
[yosys.git] / passes / cmds / chformal.cc
1 /*
2 * yosys -- Yosys Open SYnthesis Suite
3 *
4 * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at>
5 *
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.
9 *
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.
17 *
18 */
19
20 #include "kernel/yosys.h"
21 #include "kernel/sigtools.h"
22
23 USING_YOSYS_NAMESPACE
24 PRIVATE_NAMESPACE_BEGIN
25
26 struct ChformalPass : public Pass {
27 ChformalPass() : Pass("chformal", "change formal constraints of the design") { }
28 void help() override
29 {
30 // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
31 log("\n");
32 log(" chformal [types] [mode] [options] [selection]\n");
33 log("\n");
34 log("Make changes to the formal constraints of the design. The [types] options\n");
35 log("the type of constraint to operate on. If none of the following options are given,\n");
36 log("the command will operate on all constraint types:\n");
37 log("\n");
38 log(" -assert $assert cells, representing assert(...) constraints\n");
39 log(" -assume $assume cells, representing assume(...) constraints\n");
40 log(" -live $live cells, representing assert(s_eventually ...)\n");
41 log(" -fair $fair cells, representing assume(s_eventually ...)\n");
42 log(" -cover $cover cells, representing cover() statements\n");
43 log("\n");
44 log("Exactly one of the following modes must be specified:\n");
45 log("\n");
46 log(" -remove\n");
47 log(" remove the cells and thus constraints from the design\n");
48 log("\n");
49 log(" -early\n");
50 log(" bypass FFs that only delay the activation of a constraint\n");
51 log("\n");
52 log(" -delay <N>\n");
53 log(" delay activation of the constraint by <N> clock cycles\n");
54 log("\n");
55 log(" -skip <N>\n");
56 log(" ignore activation of the constraint in the first <N> clock cycles\n");
57 log("\n");
58 log(" -assert2assume\n");
59 log(" -assume2assert\n");
60 log(" -live2fair\n");
61 log(" -fair2live\n");
62 log(" change the roles of cells as indicated. these options can be combined\n");
63 log("\n");
64 }
65 void execute(std::vector<std::string> args, RTLIL::Design *design) override
66 {
67 bool assert2assume = false;
68 bool assume2assert = false;
69 bool live2fair = false;
70 bool fair2live = false;
71
72 pool<IdString> constr_types;
73 char mode = 0;
74 int mode_arg = 0;
75
76 size_t argidx;
77 for (argidx = 1; argidx < args.size(); argidx++)
78 {
79 if (args[argidx] == "-assert") {
80 constr_types.insert(ID($assert));
81 continue;
82 }
83 if (args[argidx] == "-assume") {
84 constr_types.insert(ID($assume));
85 continue;
86 }
87 if (args[argidx] == "-live") {
88 constr_types.insert(ID($live));
89 continue;
90 }
91 if (args[argidx] == "-fair") {
92 constr_types.insert(ID($fair));
93 continue;
94 }
95 if (args[argidx] == "-cover") {
96 constr_types.insert(ID($cover));
97 continue;
98 }
99 if (mode == 0 && args[argidx] == "-remove") {
100 mode = 'r';
101 continue;
102 }
103 if (mode == 0 && args[argidx] == "-early") {
104 mode = 'e';
105 continue;
106 }
107 if (mode == 0 && args[argidx] == "-delay" && argidx+1 < args.size()) {
108 mode = 'd';
109 mode_arg = atoi(args[++argidx].c_str());
110 continue;
111 }
112 if (mode == 0 && args[argidx] == "-skip" && argidx+1 < args.size()) {
113 mode = 's';
114 mode_arg = atoi(args[++argidx].c_str());
115 continue;
116 }
117 if ((mode == 0 || mode == 'c') && args[argidx] == "-assert2assume") {
118 assert2assume = true;
119 mode = 'c';
120 continue;
121 }
122 if ((mode == 0 || mode == 'c') && args[argidx] == "-assume2assert") {
123 assume2assert = true;
124 mode = 'c';
125 continue;
126 }
127 if ((mode == 0 || mode == 'c') && args[argidx] == "-live2fair") {
128 live2fair = true;
129 mode = 'c';
130 continue;
131 }
132 if ((mode == 0 || mode == 'c') && args[argidx] == "-fair2live") {
133 fair2live = true;
134 mode = 'c';
135 continue;
136 }
137 break;
138 }
139 extra_args(args, argidx, design);
140
141 if (constr_types.empty()) {
142 constr_types.insert(ID($assert));
143 constr_types.insert(ID($assume));
144 constr_types.insert(ID($live));
145 constr_types.insert(ID($fair));
146 constr_types.insert(ID($cover));
147 }
148
149 if (mode == 0)
150 log_cmd_error("Mode option is missing.\n");
151
152 for (auto module : design->selected_modules())
153 {
154 vector<Cell*> constr_cells;
155
156 for (auto cell : module->selected_cells())
157 if (constr_types.count(cell->type))
158 constr_cells.push_back(cell);
159
160 if (mode == 'r')
161 {
162 for (auto cell : constr_cells)
163 module->remove(cell);
164 }
165 else
166 if (mode == 'e')
167 {
168 SigMap sigmap(module);
169 dict<SigBit, pair<SigBit, pair<SigBit, bool>>> ffmap;
170 pool<SigBit> init_zero, init_one;
171
172 for (auto wire : module->wires())
173 {
174 if (wire->attributes.count(ID::init) == 0)
175 continue;
176
177 SigSpec initsig = sigmap(wire);
178 Const initval = wire->attributes.at(ID::init);
179
180 for (int i = 0; i < GetSize(initsig) && i < GetSize(initval); i++) {
181 if (initval[i] == State::S0)
182 init_zero.insert(initsig[i]);
183 if (initval[i] == State::S1)
184 init_one.insert(initsig[i]);
185 }
186 }
187
188 for (auto cell : module->selected_cells())
189 {
190 if (cell->type == ID($ff)) {
191 SigSpec D = sigmap(cell->getPort(ID::D));
192 SigSpec Q = sigmap(cell->getPort(ID::Q));
193 for (int i = 0; i < GetSize(D); i++)
194 ffmap[Q[i]] = make_pair(D[i], make_pair(State::Sm, false));
195 }
196 if (cell->type == ID($dff)) {
197 SigSpec D = sigmap(cell->getPort(ID::D));
198 SigSpec Q = sigmap(cell->getPort(ID::Q));
199 SigSpec C = sigmap(cell->getPort(ID::CLK));
200 bool clockpol = cell->getParam(ID::CLK_POLARITY).as_bool();
201 for (int i = 0; i < GetSize(D); i++)
202 ffmap[Q[i]] = make_pair(D[i], make_pair(C, clockpol));
203 }
204 }
205
206 for (auto cell : constr_cells)
207 while (true)
208 {
209 SigSpec A = sigmap(cell->getPort(ID::A));
210 SigSpec EN = sigmap(cell->getPort(ID::EN));
211
212 if (ffmap.count(A) == 0 || ffmap.count(EN) == 0)
213 break;
214
215 if (!init_zero.count(EN)) {
216 if (cell->type == ID($cover)) break;
217 if (cell->type.in(ID($assert), ID($assume)) && !init_one.count(A)) break;
218 }
219
220 const auto &A_map = ffmap.at(A);
221 const auto &EN_map = ffmap.at(EN);
222
223 if (A_map.second != EN_map.second)
224 break;
225
226 cell->setPort(ID::A, A_map.first);
227 cell->setPort(ID::EN, EN_map.first);
228 }
229 }
230 else
231 if (mode == 'd')
232 {
233 for (auto cell : constr_cells)
234 for (int i = 0; i < mode_arg; i++)
235 {
236 SigSpec orig_a = cell->getPort(ID::A);
237 SigSpec orig_en = cell->getPort(ID::EN);
238
239 Wire *new_a = module->addWire(NEW_ID);
240 Wire *new_en = module->addWire(NEW_ID);
241 new_en->attributes[ID::init] = State::S0;
242
243 module->addFf(NEW_ID, orig_a, new_a);
244 module->addFf(NEW_ID, orig_en, new_en);
245
246 cell->setPort(ID::A, new_a);
247 cell->setPort(ID::EN, new_en);
248 }
249 }
250 else
251 if (mode == 's')
252 {
253 SigSpec en = State::S1;
254
255 for (int i = 0; i < mode_arg; i++) {
256 Wire *w = module->addWire(NEW_ID);
257 w->attributes[ID::init] = State::S0;
258 module->addFf(NEW_ID, en, w);
259 en = w;
260 }
261
262 for (auto cell : constr_cells)
263 cell->setPort(ID::EN, module->LogicAnd(NEW_ID, en, cell->getPort(ID::EN)));
264 }
265 else
266 if (mode == 'c')
267 {
268 for (auto cell : constr_cells)
269 if (assert2assume && cell->type == ID($assert))
270 cell->type = ID($assume);
271 else if (assume2assert && cell->type == ID($assume))
272 cell->type = ID($assert);
273 else if (live2fair && cell->type == ID($live))
274 cell->type = ID($fair);
275 else if (fair2live && cell->type == ID($fair))
276 cell->type = ID($live);
277 }
278 }
279 }
280 } ChformalPass;
281
282 PRIVATE_NAMESPACE_END