Add -D to iverilog-vpi and update documentation.
[iverilog.git] / cprop.cc
blob07677be1713ddc10f8a474c7ac2dc8582ef38ace
1 /*
2 * Copyright (c) 1998-2005 Stephen Williams (steve@icarus.com)
4 * This source code is free software; you can redistribute it
5 * and/or modify it in source code form under the terms of the GNU
6 * General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option)
8 * any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20 # include "config.h"
22 # include "netlist.h"
23 # include "netmisc.h"
24 # include "functor.h"
25 # include "ivl_assert.h"
30 * The cprop function below invokes constant propagation where
31 * possible. The elaboration generates NetConst objects. I can remove
32 * these and replace the gates connected to it with simpler ones. I
33 * may even be able to replace nets with a new constant.
36 struct cprop_functor : public functor_t {
38 unsigned count;
40 virtual void signal(Design*des, NetNet*obj);
41 virtual void lpm_add_sub(Design*des, NetAddSub*obj);
42 virtual void lpm_compare(Design*des, NetCompare*obj);
43 virtual void lpm_compare_eq_(Design*des, NetCompare*obj);
44 virtual void lpm_ff(Design*des, NetFF*obj);
45 virtual void lpm_logic(Design*des, NetLogic*obj);
46 virtual void lpm_mux(Design*des, NetMux*obj);
49 void cprop_functor::signal(Design*des, NetNet*obj)
53 void cprop_functor::lpm_add_sub(Design*des, NetAddSub*obj)
57 void cprop_functor::lpm_compare(Design*des, NetCompare*obj)
59 if (obj->pin_AEB().is_linked()) {
60 assert( ! obj->pin_AGB().is_linked() );
61 assert( ! obj->pin_AGEB().is_linked() );
62 assert( ! obj->pin_ALB().is_linked() );
63 assert( ! obj->pin_ALEB().is_linked() );
64 assert( ! obj->pin_AGB().is_linked() );
65 assert( ! obj->pin_ANEB().is_linked() );
66 lpm_compare_eq_(des, obj);
67 return;
71 void cprop_functor::lpm_compare_eq_(Design*des, NetCompare*obj)
73 #if 0
74 /* XXXX Need to reimplement this code to account for vectors. */
75 NetScope*scope = obj->scope();
77 unsigned const_count = 0;
78 bool unknown_flag = false;
80 /* First, look for the case where constant bits on matching A
81 and B inputs are different. This this is so, the device can
82 be completely eliminated and replaced with a constant 0. */
84 for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
85 if (! obj->pin_DataA(idx).nexus()->drivers_constant())
86 continue;
87 if (! obj->pin_DataB(idx).nexus()->drivers_constant())
88 continue;
90 const_count += 1;
92 verinum::V abit = obj->pin_DataA(idx).nexus()->driven_value();
93 verinum::V bbit = obj->pin_DataB(idx).nexus()->driven_value();
95 if ((abit == verinum::V0) && (bbit == verinum::V0))
96 continue;
97 if ((abit == verinum::V1) && (bbit == verinum::V1))
98 continue;
100 unknown_flag = true;
101 if ((abit == verinum::Vz) || (abit == verinum::Vx))
102 continue;
103 if ((bbit == verinum::Vz) || (bbit == verinum::Vx))
104 continue;
106 NetConst*zero = new NetConst(scope, obj->name(), verinum::V0);
107 connect(zero->pin(0), obj->pin_AEB());
108 delete obj;
109 des->add_node(zero);
110 count += 1;
111 return;
114 /* If all the inputs are constant, then at this point the
115 result is either V1 or Vx. */
116 if (const_count == obj->width()) {
118 NetConst*val = new NetConst(scope, obj->name(),
119 unknown_flag
120 ? verinum::Vx
121 : verinum::V1);
122 connect(val->pin(0), obj->pin_AEB());
123 delete obj;
124 des->add_node(val);
125 count += 1;
126 return;
129 /* Still may need the gate. Run through the inputs again, and
130 look for pairs of constants. Those inputs can be removed. */
132 unsigned top = obj->width();
133 for (unsigned idx = 0 ; idx < top ; ) {
134 if (! obj->pin_DataA(idx).nexus()->drivers_constant()) {
135 idx += 1;
136 continue;
138 if (! obj->pin_DataB(idx).nexus()->drivers_constant()) {
139 idx += 1;
140 continue;
143 obj->pin_DataA(idx).unlink();
144 obj->pin_DataB(idx).unlink();
146 top -= 1;
147 for (unsigned jj = idx ; jj < top ; jj += 1) {
148 connect(obj->pin_DataA(jj), obj->pin_DataA(jj+1));
149 connect(obj->pin_DataB(jj), obj->pin_DataB(jj+1));
150 obj->pin_DataA(jj+1).unlink();
151 obj->pin_DataB(jj+1).unlink();
155 /* If we wound up disconnecting all the inputs, then remove
156 the device and replace it with a constant. */
157 if (top == 0) {
158 NetConst*one = new NetConst(scope, obj->name(), verinum::V1);
159 connect(one->pin(0), obj->pin_AEB());
160 delete obj;
161 des->add_node(one);
162 count += 1;
163 return;
166 /* If there is only one bit left, then replace the comparator
167 with a simple XOR gate. */
168 if (top == 1) {
169 NetLogic*tmp = new NetLogic(scope, obj->name(), 3,
170 NetLogic::XNOR, 1);
171 connect(tmp->pin(0), obj->pin_AEB());
172 connect(tmp->pin(1), obj->pin_DataA(0));
173 connect(tmp->pin(2), obj->pin_DataB(0));
174 delete obj;
175 des->add_node(tmp);
176 count += 1;
177 return;
181 if (top == obj->width())
182 return;
184 NetCompare*tmp = new NetCompare(scope, obj->name(), top);
185 connect(tmp->pin_AEB(), obj->pin_AEB());
186 for (unsigned idx = 0 ; idx < top ; idx += 1) {
187 connect(tmp->pin_DataA(idx), obj->pin_DataA(idx));
188 connect(tmp->pin_DataB(idx), obj->pin_DataB(idx));
190 delete obj;
191 des->add_node(tmp);
192 count += 1;
193 #endif
196 void cprop_functor::lpm_ff(Design*des, NetFF*obj)
198 // Look for and count unlinked FF outputs. Note that if the
199 // Data and Q pins are connected together, they can be removed
200 // from the circuit, since it doesn't do anything.
202 if (connected(obj->pin_Data(), obj->pin_Q())
203 && (! obj->pin_Sclr().is_linked())
204 && (! obj->pin_Sset().is_linked())
205 && (! obj->pin_Aclr().is_linked())
206 && (! obj->pin_Aset().is_linked())) {
207 obj->pin_Data().unlink();
208 obj->pin_Q().unlink();
209 delete obj;
213 void cprop_functor::lpm_logic(Design*des, NetLogic*obj)
215 #if 0
216 NetScope*scope = obj->scope();
217 #endif
219 switch (obj->type()) {
220 #if 0
221 /* XXXX This old code assumed that the individual bit
222 slices could be replaced with different gates. They
223 cannot when the device takes atomic vectors, so this
224 needs to be rewritten. XXXX */
225 case NetLogic::NAND:
226 case NetLogic::AND: {
227 unsigned top = obj->pin_count();
228 unsigned idx = 1;
229 unsigned xs = 0;
231 /* Eliminate all the 1 inputs. They have no effect
232 on the output of an AND gate. */
234 while (idx < top) {
235 if (! obj->pin(idx).nexus()->drivers_constant()) {
236 idx += 1;
237 continue;
240 if (obj->pin(idx).nexus()->driven_value()==verinum::V1) {
241 obj->pin(idx).unlink();
242 top -= 1;
243 if (idx < top) {
244 connect(obj->pin(idx), obj->pin(top));
245 obj->pin(top).unlink();
248 continue;
251 if (obj->pin(idx).nexus()->driven_value() != verinum::V0) {
252 idx += 1;
253 xs += 1;
254 continue;
257 /* Oops! We just stumbled on a driven-0 input
258 to the AND gate. That means we can replace
259 the whole bloody thing with a constant
260 driver and exit now. */
261 NetConst*tmp;
262 switch (obj->type()) {
263 case NetLogic::AND:
264 tmp = new NetConst(scope, obj->name(), verinum::V0);
265 break;
266 case NetLogic::NAND:
267 tmp = new NetConst(scope, obj->name(), verinum::V1);
268 break;
269 default:
270 assert(0);
273 tmp->rise_time(obj->rise_time());
274 tmp->fall_time(obj->fall_time());
275 tmp->decay_time(obj->decay_time());
277 des->add_node(tmp);
278 tmp->pin(0).drive0(obj->pin(0).drive0());
279 tmp->pin(0).drive1(obj->pin(0).drive1());
280 connect(obj->pin(0), tmp->pin(0));
282 delete obj;
283 count += 1;
284 return;
287 /* If all the inputs were eliminated, then replace
288 the gate with a constant 1 and I am done. */
289 if (top == 1) {
290 NetConst*tmp;
291 switch (obj->type()) {
292 case NetLogic::AND:
293 tmp = new NetConst(scope, obj->name(), verinum::V1);
294 break;
295 case NetLogic::NAND:
296 tmp = new NetConst(scope, obj->name(), verinum::V0);
297 break;
298 default:
299 assert(0);
302 tmp->rise_time(obj->rise_time());
303 tmp->fall_time(obj->fall_time());
304 tmp->decay_time(obj->decay_time());
306 des->add_node(tmp);
307 tmp->pin(0).drive0(obj->pin(0).drive0());
308 tmp->pin(0).drive1(obj->pin(0).drive1());
309 connect(obj->pin(0), tmp->pin(0));
311 delete obj;
312 count += 1;
313 return;
316 /* If all the inputs are unknowns, then replace the
317 gate with a Vx. */
318 if (xs == (top-1)) {
319 NetConst*tmp;
320 tmp = new NetConst(scope, obj->name(), verinum::Vx);
321 des->add_node(tmp);
322 tmp->pin(0).drive0(obj->pin(0).drive0());
323 tmp->pin(0).drive1(obj->pin(0).drive1());
324 connect(obj->pin(0), tmp->pin(0));
326 delete obj;
327 count += 1;
328 return;
331 /* If we are down to only one input, then replace
332 the AND with a BUF and exit now. */
333 if (top == 2) {
334 NetLogic*tmp;
335 switch (obj->type()) {
336 case NetLogic::AND:
337 tmp = new NetLogic(scope,
338 obj->name(), 2,
339 NetLogic::BUF, 1);
340 break;
341 case NetLogic::NAND:
342 tmp = new NetLogic(scope,
343 obj->name(), 2,
344 NetLogic::NOT, 1);
345 break;
346 default:
347 assert(0);
350 tmp->rise_time(obj->rise_time());
351 tmp->fall_time(obj->fall_time());
352 tmp->decay_time(obj->decay_time());
354 des->add_node(tmp);
355 tmp->pin(0).drive0(obj->pin(0).drive0());
356 tmp->pin(0).drive1(obj->pin(0).drive1());
357 connect(obj->pin(0), tmp->pin(0));
358 connect(obj->pin(1), tmp->pin(1));
359 delete obj;
360 count += 1;
361 return;
364 /* Finally, this cleans up the gate by creating a
365 new [N]AND gate that has the right number of
366 inputs, connected in the right place. */
367 if (top < obj->pin_count()) {
368 NetLogic*tmp = new NetLogic(scope,
369 obj->name(), top,
370 obj->type(), 1);
371 tmp->rise_time(obj->rise_time());
372 tmp->fall_time(obj->fall_time());
373 tmp->decay_time(obj->decay_time());
375 des->add_node(tmp);
376 tmp->pin(0).drive0(obj->pin(0).drive0());
377 tmp->pin(0).drive1(obj->pin(0).drive1());
378 for (unsigned idx = 0 ; idx < top ; idx += 1)
379 connect(tmp->pin(idx), obj->pin(idx));
381 delete obj;
382 count += 1;
383 return;
385 break;
387 #endif
388 #if 0
389 /* XXXX This old code assumed that the individual bit
390 slices could be replaced with different gates. They
391 cannot when the device takes atomic vectors, so this
392 needs to be rewritten. XXXX */
394 case NetLogic::NOR:
395 case NetLogic::OR: {
396 unsigned top = obj->pin_count();
397 unsigned idx = 1;
400 /* Eliminate all the 0 inputs. They have no effect
401 on the output of an OR gate. */
403 while (idx < top) {
404 if (! obj->pin(idx).nexus()->drivers_constant()) {
405 idx += 1;
406 continue;
409 if (obj->pin(idx).nexus()->driven_value() == verinum::V0) {
410 obj->pin(idx).unlink();
411 top -= 1;
412 if (idx < top) {
413 connect(obj->pin(idx), obj->pin(top));
414 obj->pin(top).unlink();
417 continue;
420 if (obj->pin(idx).nexus()->driven_value() != verinum::V1) {
421 idx += 1;
422 continue;
425 /* Oops! We just stumbled on a driven-1 input
426 to the OR gate. That means we can replace
427 the whole bloody thing with a constant
428 driver and exit now. */
429 NetConst*tmp;
430 switch (obj->type()) {
431 case NetLogic::OR:
432 tmp = new NetConst(scope, obj->name(), verinum::V1);
433 break;
434 case NetLogic::NOR:
435 tmp = new NetConst(scope, obj->name(), verinum::V0);
436 break;
437 default:
438 assert(0);
441 tmp->rise_time(obj->rise_time());
442 tmp->fall_time(obj->fall_time());
443 tmp->decay_time(obj->decay_time());
445 des->add_node(tmp);
446 tmp->pin(0).drive0(obj->pin(0).drive0());
447 tmp->pin(0).drive1(obj->pin(0).drive1());
448 connect(obj->pin(0), tmp->pin(0));
450 delete obj;
451 count += 1;
452 return;
455 /* If all the inputs were eliminated, then replace
456 the gate with a constant 0 and I am done. */
457 if (top == 1) {
458 NetConst*tmp;
459 switch (obj->type()) {
460 case NetLogic::OR:
461 tmp = new NetConst(scope, obj->name(), verinum::V0);
462 break;
463 case NetLogic::NOR:
464 tmp = new NetConst(scope, obj->name(), verinum::V1);
465 break;
466 default:
467 assert(0);
470 tmp->rise_time(obj->rise_time());
471 tmp->fall_time(obj->fall_time());
472 tmp->decay_time(obj->decay_time());
474 des->add_node(tmp);
475 tmp->pin(0).drive0(obj->pin(0).drive0());
476 tmp->pin(0).drive1(obj->pin(0).drive1());
477 connect(obj->pin(0), tmp->pin(0));
479 delete obj;
480 count += 1;
481 return;
484 /* If we are down to only one input, then replace
485 the OR with a BUF and exit now. */
486 if (top == 2) {
487 NetLogic*tmp;
488 switch (obj->type()) {
489 case NetLogic::OR:
490 tmp = new NetLogic(scope,
491 obj->name(), 2,
492 NetLogic::BUF, 1);
493 break;
494 case NetLogic::NOR:
495 tmp = new NetLogic(scope,
496 obj->name(), 2,
497 NetLogic::NOT, 1);
498 break;
499 default:
500 assert(0);
502 tmp->rise_time(obj->rise_time());
503 tmp->fall_time(obj->fall_time());
504 tmp->decay_time(obj->decay_time());
506 des->add_node(tmp);
507 tmp->pin(0).drive0(obj->pin(0).drive0());
508 tmp->pin(0).drive1(obj->pin(0).drive1());
509 connect(obj->pin(0), tmp->pin(0));
510 connect(obj->pin(1), tmp->pin(1));
511 delete obj;
512 count += 1;
513 return;
516 /* Finally, this cleans up the gate by creating a
517 new [N]OR gate that has the right number of
518 inputs, connected in the right place. */
519 if (top < obj->pin_count()) {
520 NetLogic*tmp = new NetLogic(scope,
521 obj->name(), top,
522 obj->type(), 1);
523 tmp->rise_time(obj->rise_time());
524 tmp->fall_time(obj->fall_time());
525 tmp->decay_time(obj->decay_time());
527 des->add_node(tmp);
528 tmp->pin(0).drive0(obj->pin(0).drive0());
529 tmp->pin(0).drive1(obj->pin(0).drive1());
530 for (unsigned idx = 0 ; idx < top ; idx += 1)
531 connect(tmp->pin(idx), obj->pin(idx));
533 delete obj;
534 count += 1;
535 return;
537 break;
539 #endif
540 #if 0
541 /* XXXX This old code assumed that the individual bit
542 slices could be replaced with different gates. They
543 cannot when the device takes atomic vectors, so this
544 needs to be rewritten. XXXX */
545 case NetLogic::XNOR:
546 case NetLogic::XOR: {
547 unsigned top = obj->pin_count();
548 unsigned idx = 1;
550 /* Eliminate all the 0 inputs. They have no effect
551 on the output of an XOR gate. The eliminate works
552 by unlinking the current input and relinking the
553 last input to this position. It's like bubbling
554 all the 0 inputs to the end. */
555 while (idx < top) {
556 if (! obj->pin(idx).nexus()->drivers_constant()) {
557 idx += 1;
558 continue;
561 if (obj->pin(idx).nexus()->driven_value() == verinum::V0) {
562 obj->pin(idx).unlink();
563 top -= 1;
564 if (idx < top) {
565 connect(obj->pin(idx), obj->pin(top));
566 obj->pin(top).unlink();
569 } else {
570 idx += 1;
574 /* Look for pairs of constant 1 inputs. If I find a
575 pair, then eliminate both. Each iteration through
576 the loop, the `one' variable holds the index to
577 the previous V1, or 0 if there is none.
579 The `ones' variable counts the number of V1
580 inputs. After this loop completes, `ones' will be
581 0 or 1. */
583 unsigned one = 0, ones = 0;
584 idx = 1;
585 while (idx < top) {
586 if (! obj->pin(idx).nexus()->drivers_constant()) {
587 idx += 1;
588 continue;
591 if (obj->pin(idx).nexus()->driven_value() == verinum::V1) {
592 if (one == 0) {
593 one = idx;
594 ones += 1;
595 idx += 1;
596 continue;
599 /* Here we found two constant V1
600 inputs. Unlink both. */
601 obj->pin(idx).unlink();
602 top -= 1;
603 if (idx < top) {
604 connect(obj->pin(idx), obj->pin(top));
605 obj->pin(top).unlink();
608 obj->pin(one).unlink();
609 top -= 1;
610 if (one < top) {
611 connect(obj->pin(one), obj->pin(top));
612 obj->pin(top).unlink();
615 /* Reset ones counter and one index,
616 start looking for the next pair. */
617 assert(ones == 1);
618 ones = 0;
619 one = 0;
620 continue;
623 idx += 1;
626 /* If all the inputs were eliminated, then replace
627 the gate with a constant value and I am done. */
628 if (top == 1) {
629 verinum::V out = obj->type()==NetLogic::XNOR
630 ? verinum::V1
631 : verinum::V0;
632 NetConst*tmp = new NetConst(scope, obj->name(), out);
634 tmp->rise_time(obj->rise_time());
635 tmp->fall_time(obj->fall_time());
636 tmp->decay_time(obj->decay_time());
638 des->add_node(tmp);
639 tmp->pin(0).drive0(obj->pin(0).drive0());
640 tmp->pin(0).drive1(obj->pin(0).drive1());
641 connect(obj->pin(0), tmp->pin(0));
643 delete obj;
644 count += 1;
645 return;
648 /* If there is a stray V1 input and only one other
649 input, then replace the gate with an inverter and
650 we are done. */
652 if ((top == 3) && (ones == 1)) {
653 unsigned save;
654 if (! obj->pin(1).nexus()->drivers_constant())
655 save = 1;
656 else if (obj->pin(1).nexus()->driven_value() != verinum::V1)
657 save = 1;
658 else
659 save = 2;
661 NetLogic*tmp;
663 if (obj->type() == NetLogic::XOR)
664 tmp = new NetLogic(scope,
665 obj->name(), 2,
666 NetLogic::NOT, 1);
667 else
668 tmp = new NetLogic(scope,
669 obj->name(), 2,
670 NetLogic::BUF, 1);
672 tmp->rise_time(obj->rise_time());
673 tmp->fall_time(obj->fall_time());
674 tmp->decay_time(obj->decay_time());
676 des->add_node(tmp);
677 tmp->pin(0).drive0(obj->pin(0).drive0());
678 tmp->pin(0).drive1(obj->pin(0).drive1());
679 connect(obj->pin(0), tmp->pin(0));
680 connect(obj->pin(save), tmp->pin(1));
682 delete obj;
683 count += 1;
684 return;
687 /* If we are down to only one input, then replace
688 the XOR with a BUF and exit now. */
689 if (top == 2) {
690 NetLogic*tmp;
692 if (obj->type() == NetLogic::XOR)
693 tmp = new NetLogic(scope,
694 obj->name(), 2,
695 NetLogic::BUF, 1);
696 else
697 tmp = new NetLogic(scope,
698 obj->name(), 2,
699 NetLogic::NOT, 1);
701 tmp->rise_time(obj->rise_time());
702 tmp->fall_time(obj->fall_time());
703 tmp->decay_time(obj->decay_time());
705 des->add_node(tmp);
706 tmp->pin(0).drive0(obj->pin(0).drive0());
707 tmp->pin(0).drive1(obj->pin(0).drive1());
708 connect(obj->pin(0), tmp->pin(0));
709 connect(obj->pin(1), tmp->pin(1));
710 delete obj;
711 count += 1;
712 return;
715 /* Finally, this cleans up the gate by creating a
716 new XOR gate that has the right number of
717 inputs, connected in the right place. */
718 if (top < obj->pin_count()) {
719 NetLogic*tmp = new NetLogic(scope,
720 obj->name(), top,
721 obj->type(), 1);
722 des->add_node(tmp);
723 tmp->pin(0).drive0(obj->pin(0).drive0());
724 tmp->pin(0).drive1(obj->pin(0).drive1());
725 for (unsigned idx = 0 ; idx < top ; idx += 1)
726 connect(tmp->pin(idx), obj->pin(idx));
728 delete obj;
729 count += 1;
730 return;
732 break;
734 #endif
735 default:
736 break;
740 static void replace_with_bufif(Design*des, NetMux*obj, NetLogic::TYPE type)
742 NetScope*scope = obj->scope();
743 NetLogic*tmp = new NetLogic(obj->scope(),
744 scope->local_symbol(),
745 3, type, obj->width());
747 des->add_node(tmp);
749 connect(obj->pin_Result(), tmp->pin(0));
750 connect(obj->pin_Data(type==NetLogic::BUFIF0? 0 : 1), tmp->pin(1));
752 if (obj->width() == 1) {
753 /* Special case that the expression is 1 bit
754 wide. Connect the select directly to the enable. */
755 connect(obj->pin_Sel(), tmp->pin(2));
757 } else {
758 /* General case that the expression is arbitrarily
759 wide. Replicate the enable signal (which we
760 assume is 1 bit wide) to match the expression,
761 and connect the enable vector to the enable
762 input of the gate. */
763 NetReplicate*rtmp = new NetReplicate(scope,
764 scope->local_symbol(),
765 obj->width(),
766 obj->width());
767 des->add_node(rtmp);
769 connect(obj->pin_Sel(), rtmp->pin(1));
770 connect(tmp->pin(2), rtmp->pin(0));
772 NetNet*rsig = new NetNet(scope, scope->local_symbol(),
773 NetNet::WIRE, obj->width());
774 rsig->local_flag(true);
775 rsig->data_type(IVL_VT_LOGIC);
776 connect(tmp->pin(2), rsig->pin(0));
779 delete obj;
783 * This detects the case where the mux selects between a value and
784 * Vz. In this case, replace the device with a bufif with the sel
785 * input used to enable the output.
787 void cprop_functor::lpm_mux(Design*des, NetMux*obj)
789 if (obj->size() != 2)
790 return;
791 if (obj->sel_width() != 1)
792 return;
794 /* If the first input is all constant Vz, then replace the
795 NetMux with an array of BUFIF1 devices, with the enable
796 connected to the select input. */
797 bool flag = true;
799 if (! obj->pin_Data(0).nexus()->drivers_constant()) {
800 flag = false;
803 if (flag && obj->pin_Data(0).nexus()->driven_value() != verinum::Vz) {
804 flag = false;
807 if (flag) {
808 replace_with_bufif(des, obj, NetLogic::BUFIF1);
809 count += 1;
810 return;
814 /* If instead the second input is all constant Vz, replace the
815 NetMux with an array of BUFIF0 devices. */
816 flag = true;
817 if (! obj->pin_Data(1).nexus()->drivers_constant()) {
818 flag = false;
821 if (flag && obj->pin_Data(1).nexus()->driven_value() != verinum::Vz) {
822 flag = false;
825 if (flag) {
826 replace_with_bufif(des, obj, NetLogic::BUFIF0);
827 count += 1;
828 return;
833 * This functor looks to see if the constant is connected to nothing
834 * but signals. If that is the case, delete the dangling constant and
835 * the now useless signals. This functor is applied after the regular
836 * functor to clean up dangling constants that might be left behind.
838 struct cprop_dc_functor : public functor_t {
840 virtual void lpm_const(Design*des, NetConst*obj);
843 void cprop_dc_functor::lpm_const(Design*des, NetConst*obj)
845 // 'bz constant values drive high impedance to whatever is
846 // connected to it. In other words, it is a noop. But that is
847 // only true if *all* the bits of the vectors.
848 { unsigned tmp = 0;
849 ivl_assert(*obj, obj->pin_count()==1);
850 for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
851 if (obj->value(idx) == verinum::Vz) {
852 tmp += 1;
856 if (tmp == obj->width()) {
857 delete obj;
858 return;
862 // For each bit, if this is the only driver, then set the
863 // initial value of all the signals to this value.
864 for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
865 if (count_outputs(obj->pin(idx)) > 1)
866 continue;
868 Nexus*nex = obj->pin(idx).nexus();
869 for (Link*clnk = nex->first_nlink()
870 ; clnk ; clnk = clnk->next_nlink()) {
872 NetObj*cur;
873 unsigned pin;
874 clnk->cur_link(cur, pin);
876 NetNet*tmp = dynamic_cast<NetNet*>(cur);
877 if (tmp == 0)
878 continue;
880 tmp->pin(pin).set_init(obj->value(idx));
884 // If there are any links that take input, the constant is
885 // used structurally somewhere.
886 for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
887 if (count_inputs(obj->pin(idx)) > 0)
888 return;
890 // Look for signals that have NetESignal nodes attached to
891 // them. If I find any, then this constant is used by a
892 // behavioral expression somewhere.
893 for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
894 Nexus*nex = obj->pin(idx).nexus();
895 for (Link*clnk = nex->first_nlink()
896 ; clnk ; clnk = clnk->next_nlink()) {
898 NetObj*cur;
899 unsigned pin;
900 clnk->cur_link(cur, pin);
902 NetNet*tmp = dynamic_cast<NetNet*>(cur);
903 if (tmp == 0)
904 continue;
906 assert(tmp->scope());
908 // If the net is a signal name from the source,
909 // then users will probably want to see it in the
910 // waveform dump, so unhooking the constant will
911 // make it look wrong.
912 if (! tmp->local_flag())
913 return;
915 // If the net has an eref, then there is an
916 // expression somewhere that reads this signal. So
917 // the constant does get read.
918 if (tmp->peek_eref() > 0)
919 return;
921 // If the net is a port of the root module, then
922 // the constant may be driving something outside
923 // the design, so do not eliminate it.
924 if ((tmp->port_type() != NetNet::NOT_A_PORT)
925 && (tmp->scope()->parent() == 0))
926 return;
931 // Done. Delete me.
932 delete obj;
936 void cprop(Design*des)
938 // Continually propagate constants until a scan finds nothing
939 // to do.
940 cprop_functor prop;
941 do {
942 prop.count = 0;
943 des->functor(&prop);
944 } while (prop.count > 0);
946 cprop_dc_functor dc;
947 des->functor(&dc);