Various improvements in ModIndex
[yosys.git] / kernel / modtools.h
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 #ifndef MODTOOLS_H
21 #define MODTOOLS_H
22
23 #include "kernel/yosys.h"
24 #include "kernel/sigtools.h"
25 #include "kernel/celltypes.h"
26
27 YOSYS_NAMESPACE_BEGIN
28
29 struct ModIndex : public RTLIL::Monitor
30 {
31 struct PortInfo {
32 RTLIL::Cell* cell;
33 RTLIL::IdString port;
34 int offset;
35
36 PortInfo() : cell(), port(), offset() { }
37 PortInfo(RTLIL::Cell* _c, RTLIL::IdString _p, int _o) : cell(_c), port(_p), offset(_o) { }
38
39 bool operator<(const PortInfo &other) const {
40 if (cell != other.cell)
41 return cell < other.cell;
42 if (offset != other.offset)
43 return offset < other.offset;
44 return port < other.port;
45 }
46
47 bool operator==(const PortInfo &other) const {
48 return cell == other.cell && port == other.port && offset == other.offset;
49 }
50
51 unsigned int hash() const {
52 return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
53 }
54 };
55
56 struct SigBitInfo
57 {
58 bool is_input, is_output;
59 pool<PortInfo> ports;
60
61 SigBitInfo() : is_input(false), is_output(false) { }
62
63 void merge(const SigBitInfo &other)
64 {
65 is_input = is_input || other.is_input;
66 is_output = is_output || other.is_output;
67 ports.insert(other.ports.begin(), other.ports.end());
68 }
69 };
70
71 SigMap sigmap;
72 RTLIL::Module *module;
73 dict<RTLIL::SigBit, SigBitInfo> database;
74 bool auto_reload_module;
75
76 void port_add(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
77 {
78 for (int i = 0; i < GetSize(sig); i++) {
79 RTLIL::SigBit bit = sigmap(sig[i]);
80 if (bit.wire)
81 database[bit].ports.insert(PortInfo(cell, port, i));
82 }
83 }
84
85 void port_del(RTLIL::Cell *cell, RTLIL::IdString port, const RTLIL::SigSpec &sig)
86 {
87 for (int i = 0; i < GetSize(sig); i++) {
88 RTLIL::SigBit bit = sigmap(sig[i]);
89 if (bit.wire)
90 database[bit].ports.erase(PortInfo(cell, port, i));
91 }
92 }
93
94 const SigBitInfo &info(RTLIL::SigBit bit)
95 {
96 return database[sigmap(bit)];
97 }
98
99 void reload_module()
100 {
101 sigmap.clear();
102 sigmap.set(module);
103
104 database.clear();
105 for (auto wire : module->wires())
106 if (wire->port_input || wire->port_output)
107 for (int i = 0; i < GetSize(wire); i++) {
108 RTLIL::SigBit bit = sigmap(RTLIL::SigBit(wire, i));
109 if (bit.wire && wire->port_input)
110 database[bit].is_input = true;
111 if (bit.wire && wire->port_output)
112 database[bit].is_output = true;
113 }
114 for (auto cell : module->cells())
115 for (auto &conn : cell->connections())
116 port_add(cell, conn.first, conn.second);
117
118 auto_reload_module = false;
119 // log("Auto-reload in ModIndex -- possible performance bug!\n");
120 }
121
122 virtual void notify_connect(RTLIL::Cell *cell, const RTLIL::IdString &port, const RTLIL::SigSpec &old_sig, RTLIL::SigSpec &sig) YS_OVERRIDE
123 {
124 log_assert(module == cell->module);
125
126 if (auto_reload_module)
127 return;
128
129 port_del(cell, port, old_sig);
130 port_add(cell, port, sig);
131 }
132
133 virtual void notify_connect(RTLIL::Module *mod, const RTLIL::SigSig &sigsig) YS_OVERRIDE
134 {
135 log_assert(module == mod);
136
137 if (auto_reload_module)
138 return;
139
140 for (int i = 0; i < GetSize(sigsig.first); i++)
141 {
142 RTLIL::SigBit lhs = sigmap(sigsig.first[i]);
143 RTLIL::SigBit rhs = sigmap(sigsig.second[i]);
144 bool has_lhs = database.count(lhs);
145 bool has_rhs = database.count(rhs);
146
147 if (!has_lhs && !has_rhs) {
148 sigmap.add(lhs, rhs);
149 } else
150 if (!has_rhs) {
151 SigBitInfo new_info = database.at(lhs);
152 database.erase(lhs);
153 sigmap.add(lhs, rhs);
154 database[sigmap(lhs)] = new_info;
155 } else
156 if (!has_lhs) {
157 SigBitInfo new_info = database.at(rhs);
158 database.erase(rhs);
159 sigmap.add(lhs, rhs);
160 database[sigmap(rhs)] = new_info;
161 } else {
162 #if 1
163 auto_reload_module = true;
164 return;
165 #else
166 SigBitInfo new_info = database.at(lhs);
167 new_info.merge(database.at(rhs));
168 database.erase(lhs);
169 database.erase(rhs);
170 sigmap.add(lhs, rhs);
171 database[sigmap(rhs)] = new_info;
172 #endif
173 }
174 }
175 }
176
177 virtual void notify_connect(RTLIL::Module *mod, const std::vector<RTLIL::SigSig>&) YS_OVERRIDE
178 {
179 log_assert(module == mod);
180 auto_reload_module = true;
181 }
182
183 virtual void notify_blackout(RTLIL::Module *mod) YS_OVERRIDE
184 {
185 log_assert(module == mod);
186 auto_reload_module = true;
187 }
188
189 ModIndex(RTLIL::Module *_m) : module(_m)
190 {
191 auto_reload_module = true;
192 module->monitors.insert(this);
193 }
194
195 ~ModIndex()
196 {
197 module->monitors.erase(this);
198 }
199
200 SigBitInfo *query(RTLIL::SigBit bit)
201 {
202 if (auto_reload_module)
203 reload_module();
204
205 auto it = database.find(sigmap(bit));
206 if (it == database.end())
207 return nullptr;
208 else
209 return &it->second;
210 }
211
212 bool query_is_input(RTLIL::SigBit bit)
213 {
214 const SigBitInfo *info = query(bit);
215 if (info == nullptr)
216 return false;
217 return info->is_input;
218 }
219
220 bool query_is_output(RTLIL::SigBit bit)
221 {
222 const SigBitInfo *info = query(bit);
223 if (info == nullptr)
224 return false;
225 return info->is_output;
226 }
227
228 pool<PortInfo> &query_ports(RTLIL::SigBit bit)
229 {
230 static pool<PortInfo> empty_result_set;
231 SigBitInfo *info = query(bit);
232 if (info == nullptr)
233 return empty_result_set;
234 return info->ports;
235 }
236 };
237
238 struct ModWalker
239 {
240 struct PortBit
241 {
242 RTLIL::Cell *cell;
243 RTLIL::IdString port;
244 int offset;
245
246 bool operator<(const PortBit &other) const {
247 if (cell != other.cell)
248 return cell < other.cell;
249 if (port != other.port)
250 return port < other.port;
251 return offset < other.offset;
252 }
253
254 bool operator==(const PortBit &other) const {
255 return cell == other.cell && port == other.port && offset == other.offset;
256 }
257
258 unsigned int hash() const {
259 return mkhash_add(mkhash(cell->name.hash(), port.hash()), offset);
260 }
261 };
262
263 RTLIL::Design *design;
264 RTLIL::Module *module;
265
266 CellTypes ct;
267 SigMap sigmap;
268
269 dict<RTLIL::SigBit, pool<PortBit>> signal_drivers;
270 dict<RTLIL::SigBit, pool<PortBit>> signal_consumers;
271 pool<RTLIL::SigBit> signal_inputs, signal_outputs;
272
273 dict<RTLIL::Cell*, pool<RTLIL::SigBit>, hash_obj_ops> cell_outputs, cell_inputs;
274
275 void add_wire(RTLIL::Wire *wire)
276 {
277 if (wire->port_input) {
278 std::vector<RTLIL::SigBit> bits = sigmap(wire);
279 for (auto bit : bits)
280 if (bit.wire != NULL)
281 signal_inputs.insert(bit);
282 }
283
284 if (wire->port_output) {
285 std::vector<RTLIL::SigBit> bits = sigmap(wire);
286 for (auto bit : bits)
287 if (bit.wire != NULL)
288 signal_outputs.insert(bit);
289 }
290 }
291
292 void add_cell_port(RTLIL::Cell *cell, RTLIL::IdString port, std::vector<RTLIL::SigBit> bits, bool is_output, bool is_input)
293 {
294 for (int i = 0; i < int(bits.size()); i++)
295 if (bits[i].wire != NULL) {
296 PortBit pbit = { cell, port, i };
297 if (is_output) {
298 signal_drivers[bits[i]].insert(pbit);
299 cell_outputs[cell].insert(bits[i]);
300 }
301 if (is_input) {
302 signal_consumers[bits[i]].insert(pbit);
303 cell_inputs[cell].insert(bits[i]);
304 }
305 }
306 }
307
308 void add_cell(RTLIL::Cell *cell)
309 {
310 if (ct.cell_known(cell->type)) {
311 for (auto &conn : cell->connections())
312 add_cell_port(cell, conn.first, sigmap(conn.second),
313 ct.cell_output(cell->type, conn.first),
314 ct.cell_input(cell->type, conn.first));
315 } else {
316 for (auto &conn : cell->connections())
317 add_cell_port(cell, conn.first, sigmap(conn.second), true, true);
318 }
319 }
320
321 ModWalker() : design(NULL), module(NULL)
322 {
323 }
324
325 ModWalker(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL)
326 {
327 setup(design, module, filter_ct);
328 }
329
330 void setup(RTLIL::Design *design, RTLIL::Module *module, CellTypes *filter_ct = NULL)
331 {
332 this->design = design;
333 this->module = module;
334
335 ct.clear();
336 ct.setup(design);
337 sigmap.set(module);
338
339 signal_drivers.clear();
340 signal_consumers.clear();
341 signal_inputs.clear();
342 signal_outputs.clear();
343
344 for (auto &it : module->wires_)
345 add_wire(it.second);
346 for (auto &it : module->cells_)
347 if (filter_ct == NULL || filter_ct->cell_known(it.second->type))
348 add_cell(it.second);
349 }
350
351 // get_* methods -- single RTLIL::SigBit
352
353 template<typename T>
354 inline bool get_drivers(pool<PortBit> &result, RTLIL::SigBit bit) const
355 {
356 bool found = false;
357 if (signal_drivers.count(bit)) {
358 const pool<PortBit> &r = signal_drivers.at(bit);
359 result.insert(r.begin(), r.end());
360 found = true;
361 }
362 return found;
363 }
364
365 template<typename T>
366 inline bool get_consumers(pool<PortBit> &result, RTLIL::SigBit bit) const
367 {
368 bool found = false;
369 if (signal_consumers.count(bit)) {
370 const pool<PortBit> &r = signal_consumers.at(bit);
371 result.insert(r.begin(), r.end());
372 found = true;
373 }
374 return found;
375 }
376
377 template<typename T>
378 inline bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
379 {
380 bool found = false;
381 if (signal_inputs.count(bit))
382 result.insert(bit), found = true;
383 return found;
384 }
385
386 template<typename T>
387 inline bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigBit bit) const
388 {
389 bool found = false;
390 if (signal_outputs.count(bit))
391 result.insert(bit), found = true;
392 return found;
393 }
394
395 // get_* methods -- container of RTLIL::SigBit's (always by reference)
396
397 template<typename T>
398 inline bool get_drivers(pool<PortBit> &result, const T &bits) const
399 {
400 bool found = false;
401 for (RTLIL::SigBit bit : bits)
402 if (signal_drivers.count(bit)) {
403 const pool<PortBit> &r = signal_drivers.at(bit);
404 result.insert(r.begin(), r.end());
405 found = true;
406 }
407 return found;
408 }
409
410 template<typename T>
411 inline bool get_consumers(pool<PortBit> &result, const T &bits) const
412 {
413 bool found = false;
414 for (RTLIL::SigBit bit : bits)
415 if (signal_consumers.count(bit)) {
416 const pool<PortBit> &r = signal_consumers.at(bit);
417 result.insert(r.begin(), r.end());
418 found = true;
419 }
420 return found;
421 }
422
423 template<typename T>
424 inline bool get_inputs(pool<RTLIL::SigBit> &result, const T &bits) const
425 {
426 bool found = false;
427 for (RTLIL::SigBit bit : bits)
428 if (signal_inputs.count(bit))
429 result.insert(bit), found = true;
430 return found;
431 }
432
433 template<typename T>
434 inline bool get_outputs(pool<RTLIL::SigBit> &result, const T &bits) const
435 {
436 bool found = false;
437 for (RTLIL::SigBit bit : bits)
438 if (signal_outputs.count(bit))
439 result.insert(bit), found = true;
440 return found;
441 }
442
443 // get_* methods -- call by RTLIL::SigSpec (always by value)
444
445 bool get_drivers(pool<PortBit> &result, RTLIL::SigSpec signal) const
446 {
447 std::vector<RTLIL::SigBit> bits = sigmap(signal);
448 return get_drivers(result, bits);
449 }
450
451 bool get_consumers(pool<PortBit> &result, RTLIL::SigSpec signal) const
452 {
453 std::vector<RTLIL::SigBit> bits = sigmap(signal);
454 return get_consumers(result, bits);
455 }
456
457 bool get_inputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
458 {
459 std::vector<RTLIL::SigBit> bits = sigmap(signal);
460 return get_inputs(result, bits);
461 }
462
463 bool get_outputs(pool<RTLIL::SigBit> &result, RTLIL::SigSpec signal) const
464 {
465 std::vector<RTLIL::SigBit> bits = sigmap(signal);
466 return get_outputs(result, bits);
467 }
468
469 // has_* methods -- call by reference
470
471 template<typename T>
472 inline bool has_drivers(const T &sig) const {
473 pool<PortBit> result;
474 return get_drivers(result, sig);
475 }
476
477 template<typename T>
478 inline bool has_consumers(const T &sig) const {
479 pool<PortBit> result;
480 return get_consumers(result, sig);
481 }
482
483 template<typename T>
484 inline bool has_inputs(const T &sig) const {
485 pool<RTLIL::SigBit> result;
486 return get_inputs(result, sig);
487 }
488
489 template<typename T>
490 inline bool has_outputs(const T &sig) const {
491 pool<RTLIL::SigBit> result;
492 return get_outputs(result, sig);
493 }
494
495 // has_* methods -- call by value
496
497 inline bool has_drivers(RTLIL::SigSpec sig) const {
498 pool<PortBit> result;
499 return get_drivers(result, sig);
500 }
501
502 inline bool has_consumers(RTLIL::SigSpec sig) const {
503 pool<PortBit> result;
504 return get_consumers(result, sig);
505 }
506
507 inline bool has_inputs(RTLIL::SigSpec sig) const {
508 pool<RTLIL::SigBit> result;
509 return get_inputs(result, sig);
510 }
511
512 inline bool has_outputs(RTLIL::SigSpec sig) const {
513 pool<RTLIL::SigBit> result;
514 return get_outputs(result, sig);
515 }
516 };
517
518 YOSYS_NAMESPACE_END
519
520 #endif