
import byucc.jhdl.base.CellInterface;
import byucc.jhdl.base.Node;
import byucc.jhdl.base.Wire;
import byucc.jhdl.Logic.Logic;
import byucc.jhdl.Xilinx.Virtex.Modules.Equals;
import byucc.jhdl.Xilinx.Virtex.Modules.upcnt;

/** This parameterizable module keeps track of the number of hits to a
 * specified value on its input line.
 * @author Anthony L. Slade */
public class HitCounter extends Logic {

  public static CellInterface[] cell_interface = {
    in( "value", "INPUTWIDTH" ),
    in( "restartCount", 1 ),
    out( "count", "OUTPUTWIDTH" ),
    out( "hit", 1 ),
    param( "INPUTWIDTH", INTEGER ),
    param( "OUTPUTWIDTH", INTEGER ),
  };

  /**
   * @param parent the parent node of this cell
   * @param hitValue the value to watch for
   * @param value the value to check for hits
   * @param restartCount sets the count to zero on next cycle if
   * asserted
   * @param count the number of hits so far
   * @param hit indicates if the current value is a hit; the count
   * output will be incremented on the next cycle. */
  public HitCounter( Node parent, int hitValue,
		     Wire value, Wire restartCount,
		     Wire count, Wire hit ) {
    this( parent, hitValue, value,
	  restartCount, count, hit, null );
  }

  /**
   * @param parent the parent node of this cell
   * @param hitValue the value to watch for
   * @param value the value to check for hits
   * @param restartCount sets the count to zero on next cycle if
   * asserted
   * @param count the number of hits so far
   * @param hit indicates if the current value is a hit; the count
   * output will be incremented on the next cycle.
   * @param name the name of this HitCounter */
  public HitCounter( Node parent, int hitValue,
		     Wire value, Wire restartCount,
		     Wire count, Wire hit, String name) {
    super( parent, name );
    bind( "INPUTWIDTH", value.getWidth() );
    bind( "OUTPUTWIDTH", count.getWidth() );
    Wire toCompare = connect( "value", value );
    Wire reset = connect( "restartCount", restartCount );
    Wire output = connect( "count", count );
    Wire match = connect( "hit", hit );

    Equals eq = new Equals( this, toCompare, hitValue,
			    match, "HitCountEq" );
    eq.enableBehavioralModel();
    new upcnt( this, or(match,reset,"enable"), reset,
	       constant(count.getWidth(),0), count, "HitCountOut" );
  }
  
} // end class HitCounter

