
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
 * number of specified values on its input line.  It is built up of an
 * array of HitCounter cells.
 * @author Anthony L. Slade */
public class HitCounterArray extends Logic {

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

  /**
   * @param parent the parent node of this cell
   * @param hitValues the values to watch for
   * @param valueInput the value to check for hits
   * @param restartCounts sets the counts to zero on next cycle if
   * asserted
   * @param countersWidth the width of the counters
   * @param hit indicates if the current value is a hit on at least
   * one of the HitCounters; the corresponding count output(s) will be
   * incremented on the next cycle. */
  public HitCounterArray( Node parent, int[] hitValues,
			  Wire valueInput, Wire restartCounts,
			  int countersWidth, Wire hit ) {
    this( parent, hitValues, valueInput, restartCounts,
	  countersWidth, hit, null );
  }

  /**
   * @param parent the parent node of this cell
   * @param hitValues the values to watch for
   * @param valueInput the value to check for hits
   * @param restartCounts sets the counts to zero on next cycle if
   * asserted
   * @param countersWidth the width of the counters
   * @param hit indicates if the current value is a hit on at least
   * one of the HitCounters; the corresponding count output(s) will be
   * incremented on the next cycle.
   * @param name the name of this instance
   */
  public HitCounterArray( Node parent, int[] hitValues,
			  Wire valueInput, Wire restartCounts,
			  int countersWidth, Wire hit, String name ) {
    super( parent, name );
    bind( "INPUTWIDTH", valueInput.getWidth() );
    bind( "OUTPUTWIDTH", countersWidth );
    Wire toCompare = connect( "valueInput", valueInput );
    Wire reset = connect( "restartCounts", restartCounts );
    Wire match = connect( "hit", hit );

    Wire hits = wire( hitValues.length, "internalHits" );
    or_o( hits, match, "hitdetect" );

    for ( int ind = 0; ind < hitValues.length; ++ind ) {
      new HitCounter( this, hitValues[ind],
		      toCompare, reset,
		      nc(countersWidth), hits.gw(ind), "Counter"+ind );
    }
  }
  
} // end class HitCounterArray
