Fix botched processing of MUX with constant select.
[sverilog.git] / cprop.cc
blob9345b9ea814c70e9d839b80b9a387188f42bd50f
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 <cstdlib>
23 # include "netlist.h"
24 # include "netmisc.h"
25 # include "functor.h"
26 # include "compiler.h"
27 # include "ivl_assert.h"
32 * The cprop function below invokes constant propagation where
33 * possible. The elaboration generates NetConst objects. I can remove
34 * these and replace the gates connected to it with simpler ones. I
35 * may even be able to replace nets with a new constant.
38 struct cprop_functor : public functor_t {
40 unsigned count;
42 virtual void signal(Design*des, NetNet*obj);
43 virtual void lpm_add_sub(Design*des, NetAddSub*obj);
44 virtual void lpm_compare(Design*des, NetCompare*obj);
45 virtual void lpm_compare_eq_(Design*des, NetCompare*obj);
46 virtual void lpm_ff(Design*des, NetFF*obj);
47 virtual void lpm_logic(Design*des, NetLogic*obj);
48 virtual void lpm_mux(Design*des, NetMux*obj);
51 void cprop_functor::signal(Design*des, NetNet*obj)
55 void cprop_functor::lpm_add_sub(Design*des, NetAddSub*obj)
59 void cprop_functor::lpm_compare(Design*des, NetCompare*obj)
61 if (obj->pin_AEB().is_linked()) {
62 assert( ! obj->pin_AGB().is_linked() );
63 assert( ! obj->pin_AGEB().is_linked() );
64 assert( ! obj->pin_ALB().is_linked() );
65 assert( ! obj->pin_ALEB().is_linked() );
66 assert( ! obj->pin_AGB().is_linked() );
67 assert( ! obj->pin_ANEB().is_linked() );
68 lpm_compare_eq_(des, obj);
69 return;
73 void cprop_functor::lpm_compare_eq_(Design*des, NetCompare*obj)
75 #if 0
76 /* XXXX Need to reimplement this code to account for vectors. */
77 NetScope*scope = obj->scope();
79 unsigned const_count = 0;
80 bool unknown_flag = false;
82 /* First, look for the case where constant bits on matching A
83 and B inputs are different. This this is so, the device can
84 be completely eliminated and replaced with a constant 0. */
86 for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
87 if (! obj->pin_DataA(idx).nexus()->drivers_constant())
88 continue;
89 if (! obj->pin_DataB(idx).nexus()->drivers_constant())
90 continue;
92 const_count += 1;
94 verinum::V abit = obj->pin_DataA(idx).nexus()->driven_value();
95 verinum::V bbit = obj->pin_DataB(idx).nexus()->driven_value();
97 if ((abit == verinum::V0) && (bbit == verinum::V0))
98 continue;
99 if ((abit == verinum::V1) && (bbit == verinum::V1))
100 continue;
102 unknown_flag = true;
103 if ((abit == verinum::Vz) || (abit == verinum::Vx))
104 continue;
105 if ((bbit == verinum::Vz) || (bbit == verinum::Vx))
106 continue;
108 NetConst*zero = new NetConst(scope, obj->name(), verinum::V0);
109 connect(zero->pin(0), obj->pin_AEB());
110 delete obj;
111 des->add_node(zero);
112 count += 1;
113 return;
116 /* If all the inputs are constant, then at this point the
117 result is either V1 or Vx. */
118 if (const_count == obj->width()) {
120 NetConst*val = new NetConst(scope, obj->name(),
121 unknown_flag
122 ? verinum::Vx
123 : verinum::V1);
124 connect(val->pin(0), obj->pin_AEB());
125 delete obj;
126 des->add_node(val);
127 count += 1;
128 return;
131 /* Still may need the gate. Run through the inputs again, and
132 look for pairs of constants. Those inputs can be removed. */
134 unsigned top = obj->width();
135 for (unsigned idx = 0 ; idx < top ; ) {
136 if (! obj->pin_DataA(idx).nexus()->drivers_constant()) {
137 idx += 1;
138 continue;
140 if (! obj->pin_DataB(idx).nexus()->drivers_constant()) {
141 idx += 1;
142 continue;
145 obj->pin_DataA(idx).unlink();
146 obj->pin_DataB(idx).unlink();
148 top -= 1;
149 for (unsigned jj = idx ; jj < top ; jj += 1) {
150 connect(obj->pin_DataA(jj), obj->pin_DataA(jj+1));
151 connect(obj->pin_DataB(jj), obj->pin_DataB(jj+1));
152 obj->pin_DataA(jj+1).unlink();
153 obj->pin_DataB(jj+1).unlink();
157 /* If we wound up disconnecting all the inputs, then remove
158 the device and replace it with a constant. */
159 if (top == 0) {
160 NetConst*one = new NetConst(scope, obj->name(), verinum::V1);
161 connect(one->pin(0), obj->pin_AEB());
162 delete obj;
163 des->add_node(one);
164 count += 1;
165 return;
168 /* If there is only one bit left, then replace the comparator
169 with a simple XOR gate. */
170 if (top == 1) {
171 NetLogic*tmp = new NetLogic(scope, obj->name(), 3,
172 NetLogic::XNOR, 1);
173 connect(tmp->pin(0), obj->pin_AEB());
174 connect(tmp->pin(1), obj->pin_DataA(0));
175 connect(tmp->pin(2), obj->pin_DataB(0));
176 delete obj;
177 des->add_node(tmp);
178 count += 1;
179 return;
183 if (top == obj->width())
184 return;
186 NetCompare*tmp = new NetCompare(scope, obj->name(), top);
187 connect(tmp->pin_AEB(), obj->pin_AEB());
188 for (unsigned idx = 0 ; idx < top ; idx += 1) {
189 connect(tmp->pin_DataA(idx), obj->pin_DataA(idx));
190 connect(tmp->pin_DataB(idx), obj->pin_DataB(idx));
192 delete obj;
193 des->add_node(tmp);
194 count += 1;
195 #endif
198 void cprop_functor::lpm_ff(Design*des, NetFF*obj)
200 // Look for and count unlinked FF outputs. Note that if the
201 // Data and Q pins are connected together, they can be removed
202 // from the circuit, since it doesn't do anything.
204 if (connected(obj->pin_Data(), obj->pin_Q())
205 && (! obj->pin_Sclr().is_linked())
206 && (! obj->pin_Sset().is_linked())
207 && (! obj->pin_Aclr().is_linked())
208 && (! obj->pin_Aset().is_linked())) {
209 obj->pin_Data().unlink();
210 obj->pin_Q().unlink();
211 delete obj;
215 void cprop_functor::lpm_logic(Design*des, NetLogic*obj)
217 #if 0
218 NetScope*scope = obj->scope();
219 #endif
221 switch (obj->type()) {
222 #if 0
223 /* XXXX This old code assumed that the individual bit
224 slices could be replaced with different gates. They
225 cannot when the device takes atomic vectors, so this
226 needs to be rewritten. XXXX */
227 case NetLogic::NAND:
228 case NetLogic::AND: {
229 unsigned top = obj->pin_count();
230 unsigned idx = 1;
231 unsigned xs = 0;
233 /* Eliminate all the 1 inputs. They have no effect
234 on the output of an AND gate. */
236 while (idx < top) {
237 if (! obj->pin(idx).nexus()->drivers_constant()) {
238 idx += 1;
239 continue;
242 if (obj->pin(idx).nexus()->driven_value()==verinum::V1) {
243 obj->pin(idx).unlink();
244 top -= 1;
245 if (idx < top) {
246 connect(obj->pin(idx), obj->pin(top));
247 obj->pin(top).unlink();
250 continue;
253 if (obj->pin(idx).nexus()->driven_value() != verinum::V0) {
254 idx += 1;
255 xs += 1;
256 continue;
259 /* Oops! We just stumbled on a driven-0 input
260 to the AND gate. That means we can replace
261 the whole bloody thing with a constant
262 driver and exit now. */
263 NetConst*tmp;
264 switch (obj->type()) {
265 case NetLogic::AND:
266 tmp = new NetConst(scope, obj->name(), verinum::V0);
267 break;
268 case NetLogic::NAND:
269 tmp = new NetConst(scope, obj->name(), verinum::V1);
270 break;
271 default:
272 assert(0);
275 tmp->rise_time(obj->rise_time());
276 tmp->fall_time(obj->fall_time());
277 tmp->decay_time(obj->decay_time());
279 des->add_node(tmp);
280 tmp->pin(0).drive0(obj->pin(0).drive0());
281 tmp->pin(0).drive1(obj->pin(0).drive1());
282 connect(obj->pin(0), tmp->pin(0));
284 delete obj;
285 count += 1;
286 return;
289 /* If all the inputs were eliminated, then replace
290 the gate with a constant 1 and I am done. */
291 if (top == 1) {
292 NetConst*tmp;
293 switch (obj->type()) {
294 case NetLogic::AND:
295 tmp = new NetConst(scope, obj->name(), verinum::V1);
296 break;
297 case NetLogic::NAND:
298 tmp = new NetConst(scope, obj->name(), verinum::V0);
299 break;
300 default:
301 assert(0);
304 tmp->rise_time(obj->rise_time());
305 tmp->fall_time(obj->fall_time());
306 tmp->decay_time(obj->decay_time());
308 des->add_node(tmp);
309 tmp->pin(0).drive0(obj->pin(0).drive0());
310 tmp->pin(0).drive1(obj->pin(0).drive1());
311 connect(obj->pin(0), tmp->pin(0));
313 delete obj;
314 count += 1;
315 return;
318 /* If all the inputs are unknowns, then replace the
319 gate with a Vx. */
320 if (xs == (top-1)) {
321 NetConst*tmp;
322 tmp = new NetConst(scope, obj->name(), verinum::Vx);
323 des->add_node(tmp);
324 tmp->pin(0).drive0(obj->pin(0).drive0());
325 tmp->pin(0).drive1(obj->pin(0).drive1());
326 connect(obj->pin(0), tmp->pin(0));
328 delete obj;
329 count += 1;
330 return;
333 /* If we are down to only one input, then replace
334 the AND with a BUF and exit now. */
335 if (top == 2) {
336 NetLogic*tmp;
337 switch (obj->type()) {
338 case NetLogic::AND:
339 tmp = new NetLogic(scope,
340 obj->name(), 2,
341 NetLogic::BUF, 1);
342 break;
343 case NetLogic::NAND:
344 tmp = new NetLogic(scope,
345 obj->name(), 2,
346 NetLogic::NOT, 1);
347 break;
348 default:
349 assert(0);
352 tmp->rise_time(obj->rise_time());
353 tmp->fall_time(obj->fall_time());
354 tmp->decay_time(obj->decay_time());
356 des->add_node(tmp);
357 tmp->pin(0).drive0(obj->pin(0).drive0());
358 tmp->pin(0).drive1(obj->pin(0).drive1());
359 connect(obj->pin(0), tmp->pin(0));
360 connect(obj->pin(1), tmp->pin(1));
361 delete obj;
362 count += 1;
363 return;
366 /* Finally, this cleans up the gate by creating a
367 new [N]AND gate that has the right number of
368 inputs, connected in the right place. */
369 if (top < obj->pin_count()) {
370 NetLogic*tmp = new NetLogic(scope,
371 obj->name(), top,
372 obj->type(), 1);
373 tmp->rise_time(obj->rise_time());
374 tmp->fall_time(obj->fall_time());
375 tmp->decay_time(obj->decay_time());
377 des->add_node(tmp);
378 tmp->pin(0).drive0(obj->pin(0).drive0());
379 tmp->pin(0).drive1(obj->pin(0).drive1());
380 for (unsigned idx = 0 ; idx < top ; idx += 1)
381 connect(tmp->pin(idx), obj->pin(idx));
383 delete obj;
384 count += 1;
385 return;
387 break;
389 #endif
390 #if 0
391 /* XXXX This old code assumed that the individual bit
392 slices could be replaced with different gates. They
393 cannot when the device takes atomic vectors, so this
394 needs to be rewritten. XXXX */
396 case NetLogic::NOR:
397 case NetLogic::OR: {
398 unsigned top = obj->pin_count();
399 unsigned idx = 1;
402 /* Eliminate all the 0 inputs. They have no effect
403 on the output of an OR gate. */
405 while (idx < top) {
406 if (! obj->pin(idx).nexus()->drivers_constant()) {
407 idx += 1;
408 continue;
411 if (obj->pin(idx).nexus()->driven_value() == verinum::V0) {
412 obj->pin(idx).unlink();
413 top -= 1;
414 if (idx < top) {
415 connect(obj->pin(idx), obj->pin(top));
416 obj->pin(top).unlink();
419 continue;
422 if (obj->pin(idx).nexus()->driven_value() != verinum::V1) {
423 idx += 1;
424 continue;
427 /* Oops! We just stumbled on a driven-1 input
428 to the OR gate. That means we can replace
429 the whole bloody thing with a constant
430 driver and exit now. */
431 NetConst*tmp;
432 switch (obj->type()) {
433 case NetLogic::OR:
434 tmp = new NetConst(scope, obj->name(), verinum::V1);
435 break;
436 case NetLogic::NOR:
437 tmp = new NetConst(scope, obj->name(), verinum::V0);
438 break;
439 default:
440 assert(0);
443 tmp->rise_time(obj->rise_time());
444 tmp->fall_time(obj->fall_time());
445 tmp->decay_time(obj->decay_time());
447 des->add_node(tmp);
448 tmp->pin(0).drive0(obj->pin(0).drive0());
449 tmp->pin(0).drive1(obj->pin(0).drive1());
450 connect(obj->pin(0), tmp->pin(0));
452 delete obj;
453 count += 1;
454 return;
457 /* If all the inputs were eliminated, then replace
458 the gate with a constant 0 and I am done. */
459 if (top == 1) {
460 NetConst*tmp;
461 switch (obj->type()) {
462 case NetLogic::OR:
463 tmp = new NetConst(scope, obj->name(), verinum::V0);
464 break;
465 case NetLogic::NOR:
466 tmp = new NetConst(scope, obj->name(), verinum::V1);
467 break;
468 default:
469 assert(0);
472 tmp->rise_time(obj->rise_time());
473 tmp->fall_time(obj->fall_time());
474 tmp->decay_time(obj->decay_time());
476 des->add_node(tmp);
477 tmp->pin(0).drive0(obj->pin(0).drive0());
478 tmp->pin(0).drive1(obj->pin(0).drive1());
479 connect(obj->pin(0), tmp->pin(0));
481 delete obj;
482 count += 1;
483 return;
486 /* If we are down to only one input, then replace
487 the OR with a BUF and exit now. */
488 if (top == 2) {
489 NetLogic*tmp;
490 switch (obj->type()) {
491 case NetLogic::OR:
492 tmp = new NetLogic(scope,
493 obj->name(), 2,
494 NetLogic::BUF, 1);
495 break;
496 case NetLogic::NOR:
497 tmp = new NetLogic(scope,
498 obj->name(), 2,
499 NetLogic::NOT, 1);
500 break;
501 default:
502 assert(0);
504 tmp->rise_time(obj->rise_time());
505 tmp->fall_time(obj->fall_time());
506 tmp->decay_time(obj->decay_time());
508 des->add_node(tmp);
509 tmp->pin(0).drive0(obj->pin(0).drive0());
510 tmp->pin(0).drive1(obj->pin(0).drive1());
511 connect(obj->pin(0), tmp->pin(0));
512 connect(obj->pin(1), tmp->pin(1));
513 delete obj;
514 count += 1;
515 return;
518 /* Finally, this cleans up the gate by creating a
519 new [N]OR gate that has the right number of
520 inputs, connected in the right place. */
521 if (top < obj->pin_count()) {
522 NetLogic*tmp = new NetLogic(scope,
523 obj->name(), top,
524 obj->type(), 1);
525 tmp->rise_time(obj->rise_time());
526 tmp->fall_time(obj->fall_time());
527 tmp->decay_time(obj->decay_time());
529 des->add_node(tmp);
530 tmp->pin(0).drive0(obj->pin(0).drive0());
531 tmp->pin(0).drive1(obj->pin(0).drive1());
532 for (unsigned idx = 0 ; idx < top ; idx += 1)
533 connect(tmp->pin(idx), obj->pin(idx));
535 delete obj;
536 count += 1;
537 return;
539 break;
541 #endif
542 #if 0
543 /* XXXX This old code assumed that the individual bit
544 slices could be replaced with different gates. They
545 cannot when the device takes atomic vectors, so this
546 needs to be rewritten. XXXX */
547 case NetLogic::XNOR:
548 case NetLogic::XOR: {
549 unsigned top = obj->pin_count();
550 unsigned idx = 1;
552 /* Eliminate all the 0 inputs. They have no effect
553 on the output of an XOR gate. The eliminate works
554 by unlinking the current input and relinking the
555 last input to this position. It's like bubbling
556 all the 0 inputs to the end. */
557 while (idx < top) {
558 if (! obj->pin(idx).nexus()->drivers_constant()) {
559 idx += 1;
560 continue;
563 if (obj->pin(idx).nexus()->driven_value() == verinum::V0) {
564 obj->pin(idx).unlink();
565 top -= 1;
566 if (idx < top) {
567 connect(obj->pin(idx), obj->pin(top));
568 obj->pin(top).unlink();
571 } else {
572 idx += 1;
576 /* Look for pairs of constant 1 inputs. If I find a
577 pair, then eliminate both. Each iteration through
578 the loop, the `one' variable holds the index to
579 the previous V1, or 0 if there is none.
581 The `ones' variable counts the number of V1
582 inputs. After this loop completes, `ones' will be
583 0 or 1. */
585 unsigned one = 0, ones = 0;
586 idx = 1;
587 while (idx < top) {
588 if (! obj->pin(idx).nexus()->drivers_constant()) {
589 idx += 1;
590 continue;
593 if (obj->pin(idx).nexus()->driven_value() == verinum::V1) {
594 if (one == 0) {
595 one = idx;
596 ones += 1;
597 idx += 1;
598 continue;
601 /* Here we found two constant V1
602 inputs. Unlink both. */
603 obj->pin(idx).unlink();
604 top -= 1;
605 if (idx < top) {
606 connect(obj->pin(idx), obj->pin(top));
607 obj->pin(top).unlink();
610 obj->pin(one).unlink();
611 top -= 1;
612 if (one < top) {
613 connect(obj->pin(one), obj->pin(top));
614 obj->pin(top).unlink();
617 /* Reset ones counter and one index,
618 start looking for the next pair. */
619 assert(ones == 1);
620 ones = 0;
621 one = 0;
622 continue;
625 idx += 1;
628 /* If all the inputs were eliminated, then replace
629 the gate with a constant value and I am done. */
630 if (top == 1) {
631 verinum::V out = obj->type()==NetLogic::XNOR
632 ? verinum::V1
633 : verinum::V0;
634 NetConst*tmp = new NetConst(scope, obj->name(), out);
636 tmp->rise_time(obj->rise_time());
637 tmp->fall_time(obj->fall_time());
638 tmp->decay_time(obj->decay_time());
640 des->add_node(tmp);
641 tmp->pin(0).drive0(obj->pin(0).drive0());
642 tmp->pin(0).drive1(obj->pin(0).drive1());
643 connect(obj->pin(0), tmp->pin(0));
645 delete obj;
646 count += 1;
647 return;
650 /* If there is a stray V1 input and only one other
651 input, then replace the gate with an inverter and
652 we are done. */
654 if ((top == 3) && (ones == 1)) {
655 unsigned save;
656 if (! obj->pin(1).nexus()->drivers_constant())
657 save = 1;
658 else if (obj->pin(1).nexus()->driven_value() != verinum::V1)
659 save = 1;
660 else
661 save = 2;
663 NetLogic*tmp;
665 if (obj->type() == NetLogic::XOR)
666 tmp = new NetLogic(scope,
667 obj->name(), 2,
668 NetLogic::NOT, 1);
669 else
670 tmp = new NetLogic(scope,
671 obj->name(), 2,
672 NetLogic::BUF, 1);
674 tmp->rise_time(obj->rise_time());
675 tmp->fall_time(obj->fall_time());
676 tmp->decay_time(obj->decay_time());
678 des->add_node(tmp);
679 tmp->pin(0).drive0(obj->pin(0).drive0());
680 tmp->pin(0).drive1(obj->pin(0).drive1());
681 connect(obj->pin(0), tmp->pin(0));
682 connect(obj->pin(save), tmp->pin(1));
684 delete obj;
685 count += 1;
686 return;
689 /* If we are down to only one input, then replace
690 the XOR with a BUF and exit now. */
691 if (top == 2) {
692 NetLogic*tmp;
694 if (obj->type() == NetLogic::XOR)
695 tmp = new NetLogic(scope,
696 obj->name(), 2,
697 NetLogic::BUF, 1);
698 else
699 tmp = new NetLogic(scope,
700 obj->name(), 2,
701 NetLogic::NOT, 1);
703 tmp->rise_time(obj->rise_time());
704 tmp->fall_time(obj->fall_time());
705 tmp->decay_time(obj->decay_time());
707 des->add_node(tmp);
708 tmp->pin(0).drive0(obj->pin(0).drive0());
709 tmp->pin(0).drive1(obj->pin(0).drive1());
710 connect(obj->pin(0), tmp->pin(0));
711 connect(obj->pin(1), tmp->pin(1));
712 delete obj;
713 count += 1;
714 return;
717 /* Finally, this cleans up the gate by creating a
718 new XOR gate that has the right number of
719 inputs, connected in the right place. */
720 if (top < obj->pin_count()) {
721 NetLogic*tmp = new NetLogic(scope,
722 obj->name(), top,
723 obj->type(), 1);
724 des->add_node(tmp);
725 tmp->pin(0).drive0(obj->pin(0).drive0());
726 tmp->pin(0).drive1(obj->pin(0).drive1());
727 for (unsigned idx = 0 ; idx < top ; idx += 1)
728 connect(tmp->pin(idx), obj->pin(idx));
730 delete obj;
731 count += 1;
732 return;
734 break;
736 #endif
737 default:
738 break;
742 static void replace_with_bufif(Design*des, NetMux*obj, NetLogic::TYPE type)
744 NetScope*scope = obj->scope();
745 NetLogic*tmp = new NetLogic(obj->scope(),
746 scope->local_symbol(),
747 3, type, obj->width());
749 des->add_node(tmp);
751 connect(obj->pin_Result(), tmp->pin(0));
752 connect(obj->pin_Data(type==NetLogic::BUFIF0? 0 : 1), tmp->pin(1));
754 if (obj->width() == 1) {
755 /* Special case that the expression is 1 bit
756 wide. Connect the select directly to the enable. */
757 connect(obj->pin_Sel(), tmp->pin(2));
759 } else {
760 /* General case that the expression is arbitrarily
761 wide. Replicate the enable signal (which we
762 assume is 1 bit wide) to match the expression,
763 and connect the enable vector to the enable
764 input of the gate. */
765 NetReplicate*rtmp = new NetReplicate(scope,
766 scope->local_symbol(),
767 obj->width(),
768 obj->width());
769 des->add_node(rtmp);
771 connect(obj->pin_Sel(), rtmp->pin(1));
772 connect(tmp->pin(2), rtmp->pin(0));
774 NetNet*rsig = new NetNet(scope, scope->local_symbol(),
775 NetNet::WIRE, obj->width());
776 rsig->local_flag(true);
777 rsig->data_type(IVL_VT_LOGIC);
778 connect(tmp->pin(2), rsig->pin(0));
781 delete obj;
785 * This detects the case where the mux selects between a value and
786 * Vz. In this case, replace the device with a bufif with the sel
787 * input used to enable the output.
789 void cprop_functor::lpm_mux(Design*des, NetMux*obj)
791 if (obj->size() != 2)
792 return;
793 if (obj->sel_width() != 1)
794 return;
796 /* If the first input is all constant Vz, then replace the
797 NetMux with an array of BUFIF1 devices, with the enable
798 connected to the select input. */
799 bool flag = true;
801 if (! obj->pin_Data(0).nexus()->drivers_constant()) {
802 flag = false;
805 if (flag && obj->pin_Data(0).nexus()->driven_value() != verinum::Vz) {
806 flag = false;
809 if (flag) {
810 replace_with_bufif(des, obj, NetLogic::BUFIF1);
811 count += 1;
812 return;
816 /* If instead the second input is all constant Vz, replace the
817 NetMux with an array of BUFIF0 devices. */
818 flag = true;
819 if (! obj->pin_Data(1).nexus()->drivers_constant()) {
820 flag = false;
823 if (flag && obj->pin_Data(1).nexus()->driven_value() != verinum::Vz) {
824 flag = false;
827 if (flag) {
828 replace_with_bufif(des, obj, NetLogic::BUFIF0);
829 count += 1;
830 return;
833 /* If the select input is constant, then replace with a BUFZ */
834 flag = obj->pin_Sel().nexus()->drivers_constant();
835 verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx;
836 if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) {
837 NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width());
838 tmp->set_line(*obj);
840 if (debug_optimizer)
841 cerr << obj->get_fileline() << ": debug: "
842 << "Replace binary MUX with constant select=" << sel_val
843 << " with a BUFZ to the selected input." << endl;
845 tmp->rise_time(obj->rise_time());
846 tmp->fall_time(obj->fall_time());
847 tmp->decay_time(obj->decay_time());
849 connect(tmp->pin(0), obj->pin_Result());
850 if (sel_val == verinum::V1)
851 connect(tmp->pin(1), obj->pin_Data(1));
852 else
853 connect(tmp->pin(1), obj->pin_Data(0));
854 delete obj;
855 des->add_node(tmp);
856 count += 1;
861 * This functor looks to see if the constant is connected to nothing
862 * but signals. If that is the case, delete the dangling constant and
863 * the now useless signals. This functor is applied after the regular
864 * functor to clean up dangling constants that might be left behind.
866 struct cprop_dc_functor : public functor_t {
868 virtual void lpm_const(Design*des, NetConst*obj);
871 void cprop_dc_functor::lpm_const(Design*des, NetConst*obj)
873 // 'bz constant values drive high impedance to whatever is
874 // connected to it. In other words, it is a noop. But that is
875 // only true if *all* the bits of the vectors.
876 { unsigned tmp = 0;
877 ivl_assert(*obj, obj->pin_count()==1);
878 for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) {
879 if (obj->value(idx) == verinum::Vz) {
880 tmp += 1;
884 if (tmp == obj->width()) {
885 delete obj;
886 return;
890 // For each bit, if this is the only driver, then set the
891 // initial value of all the signals to this value.
892 for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
893 if (count_outputs(obj->pin(idx)) > 1)
894 continue;
896 Nexus*nex = obj->pin(idx).nexus();
897 for (Link*clnk = nex->first_nlink()
898 ; clnk ; clnk = clnk->next_nlink()) {
900 NetObj*cur;
901 unsigned pin;
902 clnk->cur_link(cur, pin);
904 NetNet*tmp = dynamic_cast<NetNet*>(cur);
905 if (tmp == 0)
906 continue;
908 tmp->pin(pin).set_init(obj->value(idx));
912 // If there are any links that take input, the constant is
913 // used structurally somewhere.
914 for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1)
915 if (count_inputs(obj->pin(idx)) > 0)
916 return;
918 // Look for signals that have NetESignal nodes attached to
919 // them. If I find any, then this constant is used by a
920 // behavioral expression somewhere.
921 for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) {
922 Nexus*nex = obj->pin(idx).nexus();
923 for (Link*clnk = nex->first_nlink()
924 ; clnk ; clnk = clnk->next_nlink()) {
926 NetObj*cur;
927 unsigned pin;
928 clnk->cur_link(cur, pin);
930 NetNet*tmp = dynamic_cast<NetNet*>(cur);
931 if (tmp == 0)
932 continue;
934 assert(tmp->scope());
936 // If the net is a signal name from the source,
937 // then users will probably want to see it in the
938 // waveform dump, so unhooking the constant will
939 // make it look wrong.
940 if (! tmp->local_flag())
941 return;
943 // If the net has an eref, then there is an
944 // expression somewhere that reads this signal. So
945 // the constant does get read.
946 if (tmp->peek_eref() > 0)
947 return;
949 // If the net is a port of the root module, then
950 // the constant may be driving something outside
951 // the design, so do not eliminate it.
952 if ((tmp->port_type() != NetNet::NOT_A_PORT)
953 && (tmp->scope()->parent() == 0))
954 return;
959 // Done. Delete me.
960 delete obj;
964 void cprop(Design*des)
966 // Continually propagate constants until a scan finds nothing
967 // to do.
968 cprop_functor prop;
969 do {
970 prop.count = 0;
971 des->functor(&prop);
972 } while (prop.count > 0);
974 cprop_dc_functor dc;
975 des->functor(&dc);