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)
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
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
{
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
);
71 void cprop_functor::lpm_compare_eq_(Design
*des
, NetCompare
*obj
)
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())
87 if (! obj
->pin_DataB(idx
).nexus()->drivers_constant())
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
))
97 if ((abit
== verinum::V1
) && (bbit
== verinum::V1
))
101 if ((abit
== verinum::Vz
) || (abit
== verinum::Vx
))
103 if ((bbit
== verinum::Vz
) || (bbit
== verinum::Vx
))
106 NetConst
*zero
= new NetConst(scope
, obj
->name(), verinum::V0
);
107 connect(zero
->pin(0), obj
->pin_AEB());
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(),
122 connect(val
->pin(0), obj
->pin_AEB());
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()) {
138 if (! obj
->pin_DataB(idx
).nexus()->drivers_constant()) {
143 obj
->pin_DataA(idx
).unlink();
144 obj
->pin_DataB(idx
).unlink();
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. */
158 NetConst
*one
= new NetConst(scope
, obj
->name(), verinum::V1
);
159 connect(one
->pin(0), obj
->pin_AEB());
166 /* If there is only one bit left, then replace the comparator
167 with a simple XOR gate. */
169 NetLogic
*tmp
= new NetLogic(scope
, obj
->name(), 3,
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));
181 if (top
== obj
->width())
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
));
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();
213 void cprop_functor::lpm_logic(Design
*des
, NetLogic
*obj
)
216 NetScope
*scope
= obj
->scope();
219 switch (obj
->type()) {
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 */
226 case NetLogic::AND
: {
227 unsigned top
= obj
->pin_count();
231 /* Eliminate all the 1 inputs. They have no effect
232 on the output of an AND gate. */
235 if (! obj
->pin(idx
).nexus()->drivers_constant()) {
240 if (obj
->pin(idx
).nexus()->driven_value()==verinum::V1
) {
241 obj
->pin(idx
).unlink();
244 connect(obj
->pin(idx
), obj
->pin(top
));
245 obj
->pin(top
).unlink();
251 if (obj
->pin(idx
).nexus()->driven_value() != verinum::V0
) {
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. */
262 switch (obj
->type()) {
264 tmp
= new NetConst(scope
, obj
->name(), verinum::V0
);
267 tmp
= new NetConst(scope
, obj
->name(), verinum::V1
);
273 tmp
->rise_time(obj
->rise_time());
274 tmp
->fall_time(obj
->fall_time());
275 tmp
->decay_time(obj
->decay_time());
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));
287 /* If all the inputs were eliminated, then replace
288 the gate with a constant 1 and I am done. */
291 switch (obj
->type()) {
293 tmp
= new NetConst(scope
, obj
->name(), verinum::V1
);
296 tmp
= new NetConst(scope
, obj
->name(), verinum::V0
);
302 tmp
->rise_time(obj
->rise_time());
303 tmp
->fall_time(obj
->fall_time());
304 tmp
->decay_time(obj
->decay_time());
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));
316 /* If all the inputs are unknowns, then replace the
320 tmp
= new NetConst(scope
, obj
->name(), verinum::Vx
);
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));
331 /* If we are down to only one input, then replace
332 the AND with a BUF and exit now. */
335 switch (obj
->type()) {
337 tmp
= new NetLogic(scope
,
342 tmp
= new NetLogic(scope
,
350 tmp
->rise_time(obj
->rise_time());
351 tmp
->fall_time(obj
->fall_time());
352 tmp
->decay_time(obj
->decay_time());
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));
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
,
371 tmp
->rise_time(obj
->rise_time());
372 tmp
->fall_time(obj
->fall_time());
373 tmp
->decay_time(obj
->decay_time());
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
));
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 */
396 unsigned top
= obj
->pin_count();
400 /* Eliminate all the 0 inputs. They have no effect
401 on the output of an OR gate. */
404 if (! obj
->pin(idx
).nexus()->drivers_constant()) {
409 if (obj
->pin(idx
).nexus()->driven_value() == verinum::V0
) {
410 obj
->pin(idx
).unlink();
413 connect(obj
->pin(idx
), obj
->pin(top
));
414 obj
->pin(top
).unlink();
420 if (obj
->pin(idx
).nexus()->driven_value() != verinum::V1
) {
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. */
430 switch (obj
->type()) {
432 tmp
= new NetConst(scope
, obj
->name(), verinum::V1
);
435 tmp
= new NetConst(scope
, obj
->name(), verinum::V0
);
441 tmp
->rise_time(obj
->rise_time());
442 tmp
->fall_time(obj
->fall_time());
443 tmp
->decay_time(obj
->decay_time());
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));
455 /* If all the inputs were eliminated, then replace
456 the gate with a constant 0 and I am done. */
459 switch (obj
->type()) {
461 tmp
= new NetConst(scope
, obj
->name(), verinum::V0
);
464 tmp
= new NetConst(scope
, obj
->name(), verinum::V1
);
470 tmp
->rise_time(obj
->rise_time());
471 tmp
->fall_time(obj
->fall_time());
472 tmp
->decay_time(obj
->decay_time());
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));
484 /* If we are down to only one input, then replace
485 the OR with a BUF and exit now. */
488 switch (obj
->type()) {
490 tmp
= new NetLogic(scope
,
495 tmp
= new NetLogic(scope
,
502 tmp
->rise_time(obj
->rise_time());
503 tmp
->fall_time(obj
->fall_time());
504 tmp
->decay_time(obj
->decay_time());
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));
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
,
523 tmp
->rise_time(obj
->rise_time());
524 tmp
->fall_time(obj
->fall_time());
525 tmp
->decay_time(obj
->decay_time());
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
));
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 */
546 case NetLogic::XOR
: {
547 unsigned top
= obj
->pin_count();
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. */
556 if (! obj
->pin(idx
).nexus()->drivers_constant()) {
561 if (obj
->pin(idx
).nexus()->driven_value() == verinum::V0
) {
562 obj
->pin(idx
).unlink();
565 connect(obj
->pin(idx
), obj
->pin(top
));
566 obj
->pin(top
).unlink();
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
583 unsigned one
= 0, ones
= 0;
586 if (! obj
->pin(idx
).nexus()->drivers_constant()) {
591 if (obj
->pin(idx
).nexus()->driven_value() == verinum::V1
) {
599 /* Here we found two constant V1
600 inputs. Unlink both. */
601 obj
->pin(idx
).unlink();
604 connect(obj
->pin(idx
), obj
->pin(top
));
605 obj
->pin(top
).unlink();
608 obj
->pin(one
).unlink();
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. */
626 /* If all the inputs were eliminated, then replace
627 the gate with a constant value and I am done. */
629 verinum::V out
= obj
->type()==NetLogic::XNOR
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());
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));
648 /* If there is a stray V1 input and only one other
649 input, then replace the gate with an inverter and
652 if ((top
== 3) && (ones
== 1)) {
654 if (! obj
->pin(1).nexus()->drivers_constant())
656 else if (obj
->pin(1).nexus()->driven_value() != verinum::V1
)
663 if (obj
->type() == NetLogic::XOR
)
664 tmp
= new NetLogic(scope
,
668 tmp
= new NetLogic(scope
,
672 tmp
->rise_time(obj
->rise_time());
673 tmp
->fall_time(obj
->fall_time());
674 tmp
->decay_time(obj
->decay_time());
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));
687 /* If we are down to only one input, then replace
688 the XOR with a BUF and exit now. */
692 if (obj
->type() == NetLogic::XOR
)
693 tmp
= new NetLogic(scope
,
697 tmp
= new NetLogic(scope
,
701 tmp
->rise_time(obj
->rise_time());
702 tmp
->fall_time(obj
->fall_time());
703 tmp
->decay_time(obj
->decay_time());
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));
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
,
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
));
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());
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));
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(),
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));
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)
791 if (obj
->sel_width() != 1)
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. */
799 if (! obj
->pin_Data(0).nexus()->drivers_constant()) {
803 if (flag
&& obj
->pin_Data(0).nexus()->driven_value() != verinum::Vz
) {
808 replace_with_bufif(des
, obj
, NetLogic::BUFIF1
);
814 /* If instead the second input is all constant Vz, replace the
815 NetMux with an array of BUFIF0 devices. */
817 if (! obj
->pin_Data(1).nexus()->drivers_constant()) {
821 if (flag
&& obj
->pin_Data(1).nexus()->driven_value() != verinum::Vz
) {
826 replace_with_bufif(des
, obj
, NetLogic::BUFIF0
);
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.
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
) {
856 if (tmp
== obj
->width()) {
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)
868 Nexus
*nex
= obj
->pin(idx
).nexus();
869 for (Link
*clnk
= nex
->first_nlink()
870 ; clnk
; clnk
= clnk
->next_nlink()) {
874 clnk
->cur_link(cur
, pin
);
876 NetNet
*tmp
= dynamic_cast<NetNet
*>(cur
);
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)
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()) {
900 clnk
->cur_link(cur
, pin
);
902 NetNet
*tmp
= dynamic_cast<NetNet
*>(cur
);
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())
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)
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))
936 void cprop(Design
*des
)
938 // Continually propagate constants until a scan finds nothing
944 } while (prop
.count
> 0);