diff --git a/cprop.cc b/cprop.cc index 0b705368b..c5a62f505 100644 --- a/cprop.cc +++ b/cprop.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -25,7 +25,7 @@ # include "functor.h" # include "compiler.h" # include "ivl_assert.h" - +# include /* @@ -72,127 +72,6 @@ void cprop_functor::lpm_compare(Design*des, NetCompare*obj) void cprop_functor::lpm_compare_eq_(Design*des, NetCompare*obj) { -#if 0 - /* XXXX Need to reimplement this code to account for vectors. */ - NetScope*scope = obj->scope(); - - unsigned const_count = 0; - bool unknown_flag = false; - - /* First, look for the case where constant bits on matching A - and B inputs are different. This this is so, the device can - be completely eliminated and replaced with a constant 0. */ - - for (unsigned idx = 0 ; idx < obj->width() ; idx += 1) { - if (! obj->pin_DataA(idx).nexus()->drivers_constant()) - continue; - if (! obj->pin_DataB(idx).nexus()->drivers_constant()) - continue; - - const_count += 1; - - verinum::V abit = obj->pin_DataA(idx).nexus()->driven_value(); - verinum::V bbit = obj->pin_DataB(idx).nexus()->driven_value(); - - if ((abit == verinum::V0) && (bbit == verinum::V0)) - continue; - if ((abit == verinum::V1) && (bbit == verinum::V1)) - continue; - - unknown_flag = true; - if ((abit == verinum::Vz) || (abit == verinum::Vx)) - continue; - if ((bbit == verinum::Vz) || (bbit == verinum::Vx)) - continue; - - NetConst*zero = new NetConst(scope, obj->name(), verinum::V0); - connect(zero->pin(0), obj->pin_AEB()); - delete obj; - des->add_node(zero); - count += 1; - return; - } - - /* If all the inputs are constant, then at this point the - result is either V1 or Vx. */ - if (const_count == obj->width()) { - - NetConst*val = new NetConst(scope, obj->name(), - unknown_flag - ? verinum::Vx - : verinum::V1); - connect(val->pin(0), obj->pin_AEB()); - delete obj; - des->add_node(val); - count += 1; - return; - } - - /* Still may need the gate. Run through the inputs again, and - look for pairs of constants. Those inputs can be removed. */ - - unsigned top = obj->width(); - for (unsigned idx = 0 ; idx < top ; ) { - if (! obj->pin_DataA(idx).nexus()->drivers_constant()) { - idx += 1; - continue; - } - if (! obj->pin_DataB(idx).nexus()->drivers_constant()) { - idx += 1; - continue; - } - - obj->pin_DataA(idx).unlink(); - obj->pin_DataB(idx).unlink(); - - top -= 1; - for (unsigned jj = idx ; jj < top ; jj += 1) { - connect(obj->pin_DataA(jj), obj->pin_DataA(jj+1)); - connect(obj->pin_DataB(jj), obj->pin_DataB(jj+1)); - obj->pin_DataA(jj+1).unlink(); - obj->pin_DataB(jj+1).unlink(); - } - } - - /* If we wound up disconnecting all the inputs, then remove - the device and replace it with a constant. */ - if (top == 0) { - NetConst*one = new NetConst(scope, obj->name(), verinum::V1); - connect(one->pin(0), obj->pin_AEB()); - delete obj; - des->add_node(one); - count += 1; - return; - } - - /* If there is only one bit left, then replace the comparator - with a simple XOR gate. */ - if (top == 1) { - NetLogic*tmp = new NetLogic(scope, obj->name(), 3, - NetLogic::XNOR, 1); - connect(tmp->pin(0), obj->pin_AEB()); - connect(tmp->pin(1), obj->pin_DataA(0)); - connect(tmp->pin(2), obj->pin_DataB(0)); - delete obj; - des->add_node(tmp); - count += 1; - return; - } - - - if (top == obj->width()) - return; - - NetCompare*tmp = new NetCompare(scope, obj->name(), top); - connect(tmp->pin_AEB(), obj->pin_AEB()); - for (unsigned idx = 0 ; idx < top ; idx += 1) { - connect(tmp->pin_DataA(idx), obj->pin_DataA(idx)); - connect(tmp->pin_DataB(idx), obj->pin_DataB(idx)); - } - delete obj; - des->add_node(tmp); - count += 1; -#endif } void cprop_functor::lpm_ff(Design*des, NetFF*obj) @@ -214,575 +93,8 @@ void cprop_functor::lpm_ff(Design*des, NetFF*obj) void cprop_functor::lpm_logic(Design*des, NetLogic*obj) { -#if 0 - NetScope*scope = obj->scope(); -#endif - - switch (obj->type()) { -#if 0 - /* XXXX This old code assumed that the individual bit - slices could be replaced with different gates. They - cannot when the device takes atomic vectors, so this - needs to be rewritten. XXXX */ - case NetLogic::NAND: - case NetLogic::AND: { - unsigned top = obj->pin_count(); - unsigned idx = 1; - unsigned xs = 0; - - /* Eliminate all the 1 inputs. They have no effect - on the output of an AND gate. */ - - while (idx < top) { - if (! obj->pin(idx).nexus()->drivers_constant()) { - idx += 1; - continue; - } - - if (obj->pin(idx).nexus()->driven_value()==verinum::V1) { - obj->pin(idx).unlink(); - top -= 1; - if (idx < top) { - connect(obj->pin(idx), obj->pin(top)); - obj->pin(top).unlink(); - } - - continue; - } - - if (obj->pin(idx).nexus()->driven_value() != verinum::V0) { - idx += 1; - xs += 1; - continue; - } - - /* Oops! We just stumbled on a driven-0 input - to the AND gate. That means we can replace - the whole bloody thing with a constant - driver and exit now. */ - NetConst*tmp; - switch (obj->type()) { - case NetLogic::AND: - tmp = new NetConst(scope, obj->name(), verinum::V0); - break; - case NetLogic::NAND: - tmp = new NetConst(scope, obj->name(), verinum::V1); - break; - default: - assert(0); - } - - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - - delete obj; - count += 1; - return; - } - - /* If all the inputs were eliminated, then replace - the gate with a constant 1 and I am done. */ - if (top == 1) { - NetConst*tmp; - switch (obj->type()) { - case NetLogic::AND: - tmp = new NetConst(scope, obj->name(), verinum::V1); - break; - case NetLogic::NAND: - tmp = new NetConst(scope, obj->name(), verinum::V0); - break; - default: - assert(0); - } - - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - - delete obj; - count += 1; - return; - } - - /* If all the inputs are unknowns, then replace the - gate with a Vx. */ - if (xs == (top-1)) { - NetConst*tmp; - tmp = new NetConst(scope, obj->name(), verinum::Vx); - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - - delete obj; - count += 1; - return; - } - - /* If we are down to only one input, then replace - the AND with a BUF and exit now. */ - if (top == 2) { - NetLogic*tmp; - switch (obj->type()) { - case NetLogic::AND: - tmp = new NetLogic(scope, - obj->name(), 2, - NetLogic::BUF, 1); - break; - case NetLogic::NAND: - tmp = new NetLogic(scope, - obj->name(), 2, - NetLogic::NOT, 1); - break; - default: - assert(0); - } - - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - connect(obj->pin(1), tmp->pin(1)); - delete obj; - count += 1; - return; - } - - /* Finally, this cleans up the gate by creating a - new [N]AND gate that has the right number of - inputs, connected in the right place. */ - if (top < obj->pin_count()) { - NetLogic*tmp = new NetLogic(scope, - obj->name(), top, - obj->type(), 1); - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - for (unsigned idx = 0 ; idx < top ; idx += 1) - connect(tmp->pin(idx), obj->pin(idx)); - - delete obj; - count += 1; - return; - } - break; - } -#endif -#if 0 - /* XXXX This old code assumed that the individual bit - slices could be replaced with different gates. They - cannot when the device takes atomic vectors, so this - needs to be rewritten. XXXX */ - - case NetLogic::NOR: - case NetLogic::OR: { - unsigned top = obj->pin_count(); - unsigned idx = 1; - - - /* Eliminate all the 0 inputs. They have no effect - on the output of an OR gate. */ - - while (idx < top) { - if (! obj->pin(idx).nexus()->drivers_constant()) { - idx += 1; - continue; - } - - if (obj->pin(idx).nexus()->driven_value() == verinum::V0) { - obj->pin(idx).unlink(); - top -= 1; - if (idx < top) { - connect(obj->pin(idx), obj->pin(top)); - obj->pin(top).unlink(); - } - - continue; - } - - if (obj->pin(idx).nexus()->driven_value() != verinum::V1) { - idx += 1; - continue; - } - - /* Oops! We just stumbled on a driven-1 input - to the OR gate. That means we can replace - the whole bloody thing with a constant - driver and exit now. */ - NetConst*tmp; - switch (obj->type()) { - case NetLogic::OR: - tmp = new NetConst(scope, obj->name(), verinum::V1); - break; - case NetLogic::NOR: - tmp = new NetConst(scope, obj->name(), verinum::V0); - break; - default: - assert(0); - } - - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - - delete obj; - count += 1; - return; - } - - /* If all the inputs were eliminated, then replace - the gate with a constant 0 and I am done. */ - if (top == 1) { - NetConst*tmp; - switch (obj->type()) { - case NetLogic::OR: - tmp = new NetConst(scope, obj->name(), verinum::V0); - break; - case NetLogic::NOR: - tmp = new NetConst(scope, obj->name(), verinum::V1); - break; - default: - assert(0); - } - - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - - delete obj; - count += 1; - return; - } - - /* If we are down to only one input, then replace - the OR with a BUF and exit now. */ - if (top == 2) { - NetLogic*tmp; - switch (obj->type()) { - case NetLogic::OR: - tmp = new NetLogic(scope, - obj->name(), 2, - NetLogic::BUF, 1); - break; - case NetLogic::NOR: - tmp = new NetLogic(scope, - obj->name(), 2, - NetLogic::NOT, 1); - break; - default: - assert(0); - } - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - connect(obj->pin(1), tmp->pin(1)); - delete obj; - count += 1; - return; -v } - - /* Finally, this cleans up the gate by creating a - new [N]OR gate that has the right number of - inputs, connected in the right place. */ - if (top < obj->pin_count()) { - NetLogic*tmp = new NetLogic(scope, - obj->name(), top, - obj->type(), 1); - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - for (unsigned idx = 0 ; idx < top ; idx += 1) - connect(tmp->pin(idx), obj->pin(idx)); - - delete obj; - count += 1; - return; - } - break; - } -#endif -#if 0 - /* XXXX This old code assumed that the individual bit - slices could be replaced with different gates. They - cannot when the device takes atomic vectors, so this - needs to be rewritten. XXXX */ - case NetLogic::XNOR: - case NetLogic::XOR: { - unsigned top = obj->pin_count(); - unsigned idx = 1; - - /* Eliminate all the 0 inputs. They have no effect - on the output of an XOR gate. The eliminate works - by unlinking the current input and relinking the - last input to this position. It's like bubbling - all the 0 inputs to the end. */ - while (idx < top) { - if (! obj->pin(idx).nexus()->drivers_constant()) { - idx += 1; - continue; - } - - if (obj->pin(idx).nexus()->driven_value() == verinum::V0) { - obj->pin(idx).unlink(); - top -= 1; - if (idx < top) { - connect(obj->pin(idx), obj->pin(top)); - obj->pin(top).unlink(); - } - - } else { - idx += 1; - } - } - - /* Look for pairs of constant 1 inputs. If I find a - pair, then eliminate both. Each iteration through - the loop, the `one' variable holds the index to - the previous V1, or 0 if there is none. - - The `ones' variable counts the number of V1 - inputs. After this loop completes, `ones' will be - 0 or 1. */ - - unsigned one = 0, ones = 0; - idx = 1; - while (idx < top) { - if (! obj->pin(idx).nexus()->drivers_constant()) { - idx += 1; - continue; - } - - if (obj->pin(idx).nexus()->driven_value() == verinum::V1) { - if (one == 0) { - one = idx; - ones += 1; - idx += 1; - continue; - } - - /* Here we found two constant V1 - inputs. Unlink both. */ - obj->pin(idx).unlink(); - top -= 1; - if (idx < top) { - connect(obj->pin(idx), obj->pin(top)); - obj->pin(top).unlink(); - } - - obj->pin(one).unlink(); - top -= 1; - if (one < top) { - connect(obj->pin(one), obj->pin(top)); - obj->pin(top).unlink(); - } - - /* Reset ones counter and one index, - start looking for the next pair. */ - assert(ones == 1); - ones = 0; - one = 0; - continue; - } - - idx += 1; - } - - /* If all the inputs were eliminated, then replace - the gate with a constant value and I am done. */ - if (top == 1) { - verinum::V out = obj->type()==NetLogic::XNOR - ? verinum::V1 - : verinum::V0; - NetConst*tmp = new NetConst(scope, obj->name(), out); - - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - - delete obj; - count += 1; - return; - } - - /* If there is a stray V1 input and only one other - input, then replace the gate with an inverter and - we are done. */ - - if ((top == 3) && (ones == 1)) { - unsigned save; - if (! obj->pin(1).nexus()->drivers_constant()) - save = 1; - else if (obj->pin(1).nexus()->driven_value() != verinum::V1) - save = 1; - else - save = 2; - - NetLogic*tmp; - - if (obj->type() == NetLogic::XOR) - tmp = new NetLogic(scope, - obj->name(), 2, - NetLogic::NOT, 1); - else - tmp = new NetLogic(scope, - obj->name(), 2, - NetLogic::BUF, 1); - - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - connect(obj->pin(save), tmp->pin(1)); - - delete obj; - count += 1; - return; - } - - /* If we are down to only one input, then replace - the XOR with a BUF and exit now. */ - if (top == 2) { - NetLogic*tmp; - - if (obj->type() == NetLogic::XOR) - tmp = new NetLogic(scope, - obj->name(), 2, - NetLogic::BUF, 1); - else - tmp = new NetLogic(scope, - obj->name(), 2, - NetLogic::NOT, 1); - - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); - - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - connect(obj->pin(0), tmp->pin(0)); - connect(obj->pin(1), tmp->pin(1)); - delete obj; - count += 1; - return; - } - - /* Finally, this cleans up the gate by creating a - new XOR gate that has the right number of - inputs, connected in the right place. */ - if (top < obj->pin_count()) { - NetLogic*tmp = new NetLogic(scope, - obj->name(), top, - obj->type(), 1); - des->add_node(tmp); - tmp->pin(0).drive0(obj->pin(0).drive0()); - tmp->pin(0).drive1(obj->pin(0).drive1()); - for (unsigned idx = 0 ; idx < top ; idx += 1) - connect(tmp->pin(idx), obj->pin(idx)); - - delete obj; - count += 1; - return; - } - break; - } -#endif - default: - break; - } } -#if 0 -static void replace_with_mos(Design*des, NetMux*obj, NetLogic::TYPE type) -{ - NetScope*scope = obj->scope(); - NetLogic*tmp = new NetLogic(obj->scope(), - scope->local_symbol(), - 3, type, obj->width()); - - des->add_node(tmp); - - connect(obj->pin_Result(), tmp->pin(0)); - connect(obj->pin_Data(type==NetLogic::PMOS? 0 : 1), tmp->pin(1)); - - if (obj->width() == 1) { - /* Special case that the expression is 1 bit - wide. Connect the select directly to the enable. */ - connect(obj->pin_Sel(), tmp->pin(2)); - - } else { - /* General case that the expression is arbitrarily - wide. Replicate the enable signal (which we - assume is 1 bit wide) to match the expression, - and connect the enable vector to the enable - input of the gate. */ - NetReplicate*rtmp = new NetReplicate(scope, - scope->local_symbol(), - obj->width(), - obj->width()); - des->add_node(rtmp); - - connect(obj->pin_Sel(), rtmp->pin(1)); - connect(tmp->pin(2), rtmp->pin(0)); - - NetNet*rsig = new NetNet(scope, scope->local_symbol(), - NetNet::WIRE, obj->width()); - rsig->local_flag(true); - rsig->data_type(IVL_VT_LOGIC); - connect(tmp->pin(2), rsig->pin(0)); - } - - delete obj; -} -#endif - /* * This detects the case where the mux selects between a value and * Vz. In this case, replace the device with a mos with the sel @@ -795,61 +107,47 @@ void cprop_functor::lpm_mux(Design*des, NetMux*obj) if (obj->sel_width() != 1) return; -#if 0 -/* - * This is slower than the actual MUXZ so we are skipping this for now. - * If we had a half mux functor this could be faster and more compact - * so I'm leaving the code for future reference. - */ - /* If the first input is all constant Vz, then replace the - NetMux with an array of NMOS devices, with the enable - connected to the select input. */ - if (obj->pin_Data(0).nexus()->drivers_constant() && - obj->pin_Data(0).nexus()->driven_value() == verinum::Vz) { - replace_with_mos(des, obj, NetLogic::NMOS); - count += 1; - return; - } - - /* If instead the second input is all constant Vz, replace the - NetMux with an array of PMOS devices. */ - if (obj->pin_Data(1).nexus()->drivers_constant() && - obj->pin_Data(1).nexus()->driven_value() == verinum::Vz) { - replace_with_mos(des, obj, NetLogic::PMOS); - count += 1; - return; - } -#endif + Nexus*sel_nex = obj->pin_Sel().nexus(); /* If the select input is constant, then replace with a BUFZ */ - bool flag = obj->pin_Sel().nexus()->drivers_constant(); - /* Note that this cannot be constant if there are assignments - to this nexus. (Assignments include "force" to nets.) */ - flag &= !obj->pin_Sel().nexus()->assign_lval(); - verinum::V sel_val = flag? obj->pin_Sel().nexus()->driven_value() : verinum::Vx; - if ((sel_val != verinum::Vz) && (sel_val != verinum::Vx)) { - NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width()); - tmp->set_line(*obj); + // If the select is not constant, there is nothing we can do. + if (! sel_nex->drivers_constant()) + return; - if (debug_optimizer) - cerr << obj->get_fileline() << ": debug: " - << "Replace binary MUX with constant select=" << sel_val - << " with a BUFZ to the selected input." << endl; + // If the select input is assigned or forced, then again there + // is nothing we can do here. + if (sel_nex->assign_lval()) + return; - tmp->rise_time(obj->rise_time()); - tmp->fall_time(obj->fall_time()); - tmp->decay_time(obj->decay_time()); + // If the constant select is 'bz or 'bx, then give up. + verinum::V sel_val = sel_nex->driven_value(); + if (sel_val == verinum::Vz || sel_val == verinum::Vx) + return; - connect(tmp->pin(0), obj->pin_Result()); - if (sel_val == verinum::V1) - connect(tmp->pin(1), obj->pin_Data(1)); - else - connect(tmp->pin(1), obj->pin_Data(0)); - delete obj; - des->add_node(tmp); - count += 1; - } + // The Select input must be a defined constant value, so we + // can replace the device with a BUFZ. + + NetBUFZ*tmp = new NetBUFZ(obj->scope(), obj->name(), obj->width()); + tmp->set_line(*obj); + + if (debug_optimizer) + cerr << obj->get_fileline() << ": debug: " + << "Replace binary MUX with constant select=" << sel_val + << " with a BUFZ to the selected input." << endl; + + tmp->rise_time(obj->rise_time()); + tmp->fall_time(obj->fall_time()); + tmp->decay_time(obj->decay_time()); + + connect(tmp->pin(0), obj->pin_Result()); + if (sel_val == verinum::V1) + connect(tmp->pin(1), obj->pin_Data(1)); + else + connect(tmp->pin(1), obj->pin_Data(0)); + delete obj; + des->add_node(tmp); + count += 1; } /* @@ -863,6 +161,12 @@ struct cprop_dc_functor : public functor_t { virtual void lpm_const(Design*des, NetConst*obj); }; +struct nexus_info_s { + Nexus*nex; + unsigned inp; + unsigned out; +}; + void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) { // 'bz constant values drive high impedance to whatever is @@ -882,14 +186,22 @@ void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) } } + std::vector nexus_info (obj->pin_count()); + for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) { + nexus_info[idx].nex = obj->pin(idx).nexus(); + unsigned inputs, outputs; + nexus_info[idx].nex -> count_io(inputs, outputs); + nexus_info[idx].inp = inputs; + nexus_info[idx].out = outputs; + } + // For each bit, if this is the only driver, then set the // initial value of all the signals to this value. for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) { - if (count_outputs(obj->pin(idx)) > 1) + if (nexus_info[idx].out > 1) continue; - Nexus*nex = obj->pin(idx).nexus(); - for (Link*clnk = nex->first_nlink() + for (Link*clnk = nexus_info[idx].nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { NetPins*cur; @@ -907,15 +219,15 @@ void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) // If there are any links that take input, the constant is // used structurally somewhere. for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) - if (count_inputs(obj->pin(idx)) > 0) + if (nexus_info[idx].inp > 0) return; // Look for signals that have NetESignal nodes attached to // them. If I find any, then this constant is used by a // behavioral expression somewhere. for (unsigned idx = 0 ; idx < obj->pin_count() ; idx += 1) { - Nexus*nex = obj->pin(idx).nexus(); - for (Link*clnk = nex->first_nlink() + + for (Link*clnk = nexus_info[idx].nex->first_nlink() ; clnk ; clnk = clnk->next_nlink()) { NetPins*cur; @@ -951,7 +263,7 @@ void cprop_dc_functor::lpm_const(Design*des, NetConst*obj) } } - // Done. Delete me. + // Done. Found no reason to keep this object, so delete it. delete obj; } @@ -964,8 +276,15 @@ void cprop(Design*des) do { prop.count = 0; des->functor(&prop); + if (verbose_flag) { + cout << " cprop: Iteration detected " + << prop.count << " optimizations." << endl << flush; + } } while (prop.count > 0); + if (verbose_flag) { + cout << " cprop: Look for dangling constants" << endl << flush; + } cprop_dc_functor dc; des->functor(&dc); } diff --git a/net_link.cc b/net_link.cc index 3cd433039..13d134138 100644 --- a/net_link.cc +++ b/net_link.cc @@ -249,48 +249,6 @@ bool Link::is_linked(const Link&that) const return false; } -/* - * If this link has a nexus_ pointer, then it is the last Link in the - * list. next_nlink() returns 0 for the last Link. - */ -Link* Link::next_nlink() -{ - if (nexus_) return 0; - else return next_; -} - -const Link* Link::next_nlink() const -{ - if (nexus_) return 0; - else return next_; -} - -const NetPins*Link::get_obj() const -{ - if (pin_zero_) - return node_; - const Link*tmp = this - pin_; - assert(tmp->pin_zero_); - return tmp->node_; -} - -NetPins*Link::get_obj() -{ - if (pin_zero_) - return node_; - Link*tmp = this - pin_; - assert(tmp->pin_zero_); - return tmp->node_; -} - -unsigned Link::get_pin() const -{ - if (pin_zero_) - return 0; - else - return pin_; -} - Nexus::Nexus(Link&that) { name_ = 0; @@ -355,6 +313,20 @@ bool Nexus::assign_lval() const return false; } +void Nexus::count_io(unsigned&inp, unsigned&out) const +{ + for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) { + switch (cur->get_dir()) { + case Link::INPUT: + inp += 1; + break; + case Link::OUTPUT: + out += 1; + break; + } + } +} + bool Nexus::drivers_present() const { for (const Link*cur = first_nlink() ; cur ; cur = cur->next_nlink()) { diff --git a/netlist.cc b/netlist.cc index ea6618db5..0798384cc 100644 --- a/netlist.cc +++ b/netlist.cc @@ -84,41 +84,6 @@ ostream& operator<< (ostream&o, NetNet::Type t) return o; } - -unsigned count_inputs(const Link&pin) -{ - unsigned count = 0; - - const Nexus*nex = pin.nexus(); - for (const Link*clnk = nex->first_nlink() - ; clnk ; clnk = clnk->next_nlink()) { - const NetPins*cur; - unsigned cpin; - clnk->cur_link(cur, cpin); - if (cur->pin(cpin).get_dir() == Link::INPUT) - count += 1; - } - - return count; -} - -unsigned count_outputs(const Link&pin) -{ - unsigned count = 0; - - const Nexus*nex = pin.nexus(); - for (const Link*clnk = nex->first_nlink() - ; clnk ; clnk = clnk->next_nlink()) { - const NetPins*cur; - unsigned cpin; - clnk->cur_link(cur, cpin); - if (cur->pin(cpin).get_dir() == Link::OUTPUT) - count += 1; - } - - return count; -} - unsigned count_signals(const Link&pin) { unsigned count = 0; @@ -858,11 +823,6 @@ void NetNet::decr_lref() lref_count_ -= 1; } -unsigned NetNet::peek_lref() const -{ - return lref_count_; -} - unsigned NetNet::get_refs() const { return lref_count_ + eref_count_; diff --git a/netlist.h b/netlist.h index 5bc381fb9..09795b1f0 100644 --- a/netlist.h +++ b/netlist.h @@ -358,6 +358,10 @@ class Nexus { NetNet* pick_any_net(); + /* This method counts the number of input and output links for + this nexus, and assigns the results to the output arguments. */ + void count_io(unsigned&inp, unsigned&out) const; + /* This method returns true if there are any assignments that use this nexus as an l-value. This can be true if the nexus is a variable, but also if this is a net with a force. */ @@ -653,7 +657,7 @@ class NetNet : public NetObj { /* Assignment statements count their lrefs here. */ void incr_lref(); void decr_lref(); - unsigned peek_lref() const; + unsigned peek_lref() const { return lref_count_; } unsigned get_refs() const; @@ -4033,10 +4037,7 @@ extern void connect(Link&, Link&); inline bool connected(const Link&l, const Link&r) { return l.is_linked(r); } -/* Return the number of links in the ring that are of the specified - type. */ -extern unsigned count_inputs(const Link&pin); -extern unsigned count_outputs(const Link&pin); +/* Return the number of signals in the nexus. */ extern unsigned count_signals(const Link&pin); /* Find the next link that is an output into the nexus. */ @@ -4065,4 +4066,46 @@ inline __ScopePathManip scope_path(const NetScope*scope) extern ostream& operator << (ostream&o, __ScopePathManip); +/* + * If this link has a nexus_ pointer, then it is the last Link in the + * list. next_nlink() returns 0 for the last Link. + */ +inline Link* Link::next_nlink() +{ + if (nexus_) return 0; + else return next_; +} + +inline const Link* Link::next_nlink() const +{ + if (nexus_) return 0; + else return next_; +} + +inline NetPins*Link::get_obj() +{ + if (pin_zero_) + return node_; + Link*tmp = this - pin_; + assert(tmp->pin_zero_); + return tmp->node_; +} + +inline const NetPins*Link::get_obj() const +{ + if (pin_zero_) + return node_; + const Link*tmp = this - pin_; + assert(tmp->pin_zero_); + return tmp->node_; +} + +inline unsigned Link::get_pin() const +{ + if (pin_zero_) + return 0; + else + return pin_; +} + #endif