// ------------------------------------------------------------------------
// ON Semiconductor Proprietary and Confidential Information.
// ------------------------------------------------------------------------

// ------------------------------------------------------------------------
// Company           : ON Semiconductor
// ------------------------------------------------------------------------
// File              : $HeadURL: file:///proj/p516/digital/svn_repo_pas_lin/trunk/hdl/model/class_pkg.sv $
// ------------------------------------------------------------------------
// Last Modified     : $Date: 2016/06/15 10:47:16 $
// Last Modified By  : $Author: fg7g4t $
// Revision          : $Revision: 1.1 $
// ------------------------------------------------------------------------
// Description       : Package with classes
// ------------------------------------------------------------------------
// Revision history  :
//
//   $Log: class_pkg.sv,v $
//   Revision 1.1  2016/06/15 10:47:16  fg7g4t
//   Start of MBIST testcases and testbench
//
//

package class_pkg;
  localparam c_MODULE = "class_pkg";
  `include "messages.inc.sv"            // import messaging macros

  /* ***************************************************************************
  Base class for random number generators

  Public methods:
    new ([id, seed])      - creates instance with specified id and seed (default 12345)
    set_seed (seed)       - set random number generator seed
    name()                - returns cl_id strig
    print_randstate()     - prints objects randstate

  Usage:
    It's not possible to instantiate this class, it's meant to be extended

  *************************************************************************** */
  virtual class cl_rng_base;
    local string  cl_id;              // class id (name)
          bit     initialized = 0;    // initialized via set_seed()

    // == local functions ======================================================
    // -- display random number generator state --------------------------------
    protected function void msg_randstate ();
      `MSG(("Randstate of %s = '%s'", cl_id, this.get_randstate()))
    endfunction

    // -- display message if randomization failed ------------------------------
    protected function void msg_rand_failed (string f_id, string msg);
      `MSG_WRN(("%s (%s): %s", cl_id, f_id, msg))
    endfunction

    // == public methods =======================================================
    // -- constructor ----------------------------------------------------------
    function new (
      string  id    = "RNG_BASE",
      int     seed  = 12345
    );
      cl_id = id;

      void'(this.set_seed(seed));
      initialized   = 0;
      `ifdef MODELSIM
        `MSG(("Class instance id of %s: %s", cl_id, $get_id_from_handle(this)))
      `endif
    endfunction

    // -- set custom seed ------------------------------------------------------
    function void set_seed (int seed);
      `MSG(("Initializing %s with seed = %0d", cl_id, seed))
      this.srandom (seed);
      initialized   = 1;          // set_seed explicitly called
    endfunction

    // -- get id string --------------------------------------------------------
    function string name();
      return (cl_id);
    endfunction

    // -- prints randstate -----------------------------------------------------
    function void print_randstate();
      void'(msg_randstate());
    endfunction
  endclass: cl_rng_base

  /* ***************************************************************************
  Random number generator class

    This class inherits all methods from cl_rng_base.

    Parameters:
      vect_size             - size of randomized logic vector

    Public methods:
      gen_int  ([min, max]) - generates int in <min:max> range (default <-2**31 : 2**31-1>)
      gen_uint ([min, max]) - generates unsigned int in <min:max> range (default <0 : 2**32-1>)
      gen_real ([min, max]) - generates real in <min:max> range (default <0.0 : 1.0>)
      gen_vect ([one_cnt])  - generates vector, number of 1's can be specified

      read_int()            - last value of int
      read_uint()           - last value of uint
      read_real()           - last value of real
      read_vect()           - last value of vect

    Usage:
      cl_rng #(16) rng = new("RNG", 1);       // create instance

      rng.set_seed (123);                     // set new seed

      v_int   = rng.gen_int();                // get random int
      v_uint  = rng.gen_uint(0, 100);         // get random uint in range <0 : 100>
      v_real  = rng.gen_real(, 5.0));         // get random real in range <0.0 : 5.0>
      v_vect  = rng.gen_vect(3);              // random vector with 3 1's

      v_int   = rng.read_int;                 // get last value
      v_uint  = rng.read_uint;                // get last value
      v_real  = rng.read_real;                // get last value
      v_vect  = rng.read_vect;                // get last value

      rng.print_randstate();                  // $display("%s", rng.get_randstate());
      rng.set_randstate(rand_state);          // set randstate

      rng.dbg_en();                           // enable debug mode

  *************************************************************************** */
  class cl_rng #(int vect_size = 32) extends cl_rng_base;
    typedef bit [vect_size-1:0] t_vect;

    local rand int          rand_int;       // random int
    local rand int unsigned rand_uint;      // random unsigned int
    local rand t_vect       rand_vect;      // random vector
    local real              rand_real;      // random real (not randomized, calculated)
    local time              rand_time;      // random time (calculated)


    // == public methods =======================================================
    // -- constructor ----------------------------------------------------------
    function new (
      string  id    = "RNG",
      int     seed  = 12345
    );
      super.new (id, seed);
    endfunction

    // -- generate random int --------------------------------------------------
    function int gen_int (
      input int min = -2**31,               // lower limit
      input int max =  2**31-1              // upper limit
    );
      if (!this.randomize(rand_int) with {rand_int inside {[min:max]}; }) begin
        void'(msg_rand_failed("gen_int", "Failed to randomize 'int'!"));
        if (min > max) begin
          `MSG(("   min > max!"))
          `MSG(("     min: %0d", min))
          `MSG(("     max: %0d", max))
        end
      end

      return (rand_int);
    endfunction: gen_int

    // -- generate random unsigned int -----------------------------------------
    function int unsigned gen_uint (
      input int unsigned min = 0,           // lower limit
      input int unsigned max = 2**32-1      // upper limit
    );
      if (!this.randomize(rand_uint) with {rand_uint inside {[min:max]}; }) begin
        void'(msg_rand_failed("gen_uint", "Failed to randomize 'uint'!"));
        if (min > max) `MSG(("   min > max!"))
      end

      return (rand_uint);
    endfunction: gen_uint

    // -- generate random real -------------------------------------------------
    function real gen_real(
      input real min  = 0.0,            // lower limit
      input real max  = 1.0             // upper limit
    );
      const automatic real c_RAND_REAL = gen_uint()/(2.0**32-1);   // range 0.0-1.0

      rand_real = min + (max-min)*c_RAND_REAL;

      return (rand_real);
    endfunction: gen_real

    // -- generate random 32-bit vector ----------------------------------------
    function t_vect gen_vect (int one_cnt = -1);
`ifndef VCS
      if (!this.randomize(rand_vect) with {
            (one_cnt >= 0) -> $countones(rand_vect) == one_cnt;
         }) begin
        void'(msg_rand_failed("gen_vect", "Failed to randomize 'vect'!"));
        `MSG(("   vector size: %0d", $bits(rand_vect)))
        `MSG(("   1 count:     %0d", one_cnt))
      end
`else
      // not really equivalent but VCS does not yet support functions in constraints
      if (one_cnt >= 0) rand_vect = 2**one_cnt - 1;
      else this.randomize(rand_vect);
`endif
      return (rand_vect);
    endfunction: gen_vect

    // -- generate random dominant time ----------------------------------------
    function time gen_time (
      input time  min, max,          // min/max limits
      input time  resolution = 100ns // Time step between discrete values
    );
      const int c_TICKS_MIN = min / resolution;
      const int c_TICKS_MAX = max / resolution;

      rand_time = (this.gen_uint(c_TICKS_MIN, c_TICKS_MAX) * resolution);
      return rand_time;
    endfunction

    // -- read local random variables ------------------------------------------
    function int          read_int ();  return rand_int;  endfunction
    function int unsigned read_uint (); return rand_uint; endfunction
    function real         read_real (); return rand_real; endfunction
    function t_vect       read_vect (); return rand_vect; endfunction
    function time         read_time (); return rand_time; endfunction
  endclass: cl_rng

endpackage


