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

// ------------------------------------------------------------------------
// Company           : ON Semiconductor
// ------------------------------------------------------------------------
// File              : $RCSfile: common.inc.sv,v $
// ------------------------------------------------------------------------
// Last Modified     : $Date: 2016/04/15 11:25:06 $
// Last Modified By  : $Author: fg7g4t $
// Revision          : $Revision: 1.2 $
// ------------------------------------------------------------------------
// Description       : Common model tasks & functions
// ------------------------------------------------------------------------
// Revision history  :
//
// $Log: common.inc.sv,v $
// Revision 1.2  2016/04/15 11:25:06  fg7g4t
// Testcase for mbist
//
// Revision 1.2  2016/03/04 14:40:55  fg7g4t
// Add oscillator to TB, parameters of memory
//
// Revision 1.1.1.1  2016/03/04 10:32:14  fg7g4t
// Initial commit
//

  /* ***************************************************************************
    set debug level for messages
  *************************************************************************** */
  function void f_dbg_msg (input int _dbg_level);
    `MSG(("Debug level set to %0d", _dbg_level), msg_indent)
    dbg_msg = _dbg_level;
  endfunction

  /* ***************************************************************************
    set mesagge indentation
  *************************************************************************** */
  function void f_set_msg_indent (input int _indent);
    msg_indent = _indent;
  endfunction

  /* ***************************************************************************
    set oscillator period
  *************************************************************************** */
  function void f_set_clk_per (input time  _per);
    $timeformat(-9, 2, "ns", 3);
    `MSG_INF(("Clock period set to %t", _per), msg_indent)
    clk_per   = _per;
  endfunction

  /* ***************************************************************************
    enable/disable checks
  *************************************************************************** */
  function void f_checks_ena (
    input int _checks_ena     = -1,
    input int _x_checks_ena   = -1
  );
    if (_checks_ena   != -1) begin
      if (_checks_ena == 1)   `MSG(("Checks enabled"))
      else                    `MSG_WRN(("Checks disabled"))
      checks_ena    = _checks_ena;
    end
    if (_x_checks_ena != -1) begin
      if (_x_checks_ena == 1) `MSG(("X checks enabled"))
      else                    `MSG_WRN(("X checks disabled"))
      x_checks_ena  = _x_checks_ena;
    end
  endfunction

  /* ***************************************************************************
  compares two integers/reals with given tolerance

  examples of message output:
    "Incorrect value of sig_name! Exp : exp, DUT : dut (@ 1000ns)"
    "Incorrect value of sig_name[arr_indx] (extra_info)! Exp : exp, DUT : dut (@ 1000ns)"
  *************************************************************************** */
  task tsk_compare (
    input integer dut,                // DUT value
    input integer exp,                // expected value
    input string  sig_name,           // signal name
    input int     tol         = 0,    // tolerance
    input string  extra_info  = "",   // extra info
    input int     arr_indx    = -1    // array index
  );
    int err;
    string str_main, str_indx, str_info, str_val;
    $swrite(str_indx, "");
    $swrite(str_info, "");

    err = 0;
    if (tol == 0) begin
      if (dut !== exp) err = 1;
    end else begin
      if (f_abs (dut - exp) > tol) err = 1;
    end

    if (err) begin
      $swrite(str_main, "Incorrect value of %0s", sig_name);
      if (arr_indx != -1)   $swrite(str_indx, "[%0d]", arr_indx);
      if (extra_info != "") $swrite(str_info, " (%0s)", extra_info);
      $swrite(str_val, "! DUT: %0d, exp: %0d", dut, exp);
      `MSG_ERR(({str_main, str_indx, str_info, str_val}))
    end
  endtask

  task tsk_compare_real (
    input real    dut,                // DUT value
    input real    exp,                // expected value
    input string  sig_name,           // signal name
    input real    tol         = 0.0,  // tolerance
    input string  extra_info  = "",   // extra info
    input int     arr_indx    = -1    // array index
  );
    string str_main, str_indx, str_info, str_val;
    $swrite(str_indx, "");
    $swrite(str_info, "");

    if ((dut < (exp - tol)) || (dut > (exp + tol))) begin
      $swrite(str_main, "Incorrect value of %0s", sig_name);
      if (arr_indx != -1)   $swrite(str_indx, "[%0d]", arr_indx);
      if (extra_info != "") $swrite(str_info, " (%0s)", extra_info);
      $swrite(str_val, "! DUT: %0d, exp: %0d", dut, exp);
      `MSG_ERR(({str_main, str_indx, str_info, str_val}))
    end
  endtask

  task tsk_compare_time (
    input time    dut,                // DUT value
    input time    exp_min,            //
    input time    exp_max,            //
    input string  name                // name
  );
    if ((dut < exp_min) || (dut > exp_max))
      `MSG_ERR(("Incorrect %s! DUT: %0dns, min: %0dns, max: %0dns",
                name, dut/1ns, exp_min/1ns, exp_max/1ns))
  endtask

  /* ***************************************************************************
    X-checker tasks
  *************************************************************************** */
  task automatic tsk_x_checker (
    ref   logic   _ena,
    ref   integer _sig,
    input string  _name,
    input bit     _glitch_filt  = 0     // filter out glitches
  );
    forever begin
      if (_ena && $isunknown(_sig)) `MSG_WRN(("X detected on '%0s'", _name))
      @(_ena, _sig);
      if (_glitch_filt == 1) #(c_DELS);
    end
  endtask

  task automatic tsk_x_checker_logic (
    ref   logic   _ena,
    ref   logic   _sig,
    input string  _name,
    input bit     _glitch_filt  = 0     // filter out glitches
  );
    forever begin
      if (_ena && $isunknown(_sig)) `MSG_WRN(("X detected on '%0s'", _name))
      @(_ena, _sig);
      if (_glitch_filt == 1) #(c_DELS);
    end
  endtask

  /* ***************************************************************************
    logic checker tasks
  *************************************************************************** */
  task automatic tsk_checker (
    ref   logic     ena,
    ref   integer   dut,
    ref   int       exp,
    input string    sig_name,
    input time      delay       = c_DELS,
    input int       tol         = 0
  );
    forever begin
      #(delay);
      if (ena) tsk_compare (dut, exp, sig_name, tol);
      @(dut, exp, ena);
    end
  endtask

  task automatic tsk_checker_logic (
    ref   logic     ena,
    ref   logic     dut,
    ref   logic     exp,
    input string    sig_name,
    input time      delay       = c_DELS
  );
    forever begin
      #(delay);
      if (ena && !$isunknown(exp)) tsk_compare (dut, exp, sig_name);
      @(dut, exp, ena);
    end
  endtask

  /* ***************************************************************************
    simple timeout macro
      `TIMEOUT(@(posedge signal), 1us)
      `TIMEOUT(wait (rst_b), 1us)
  *************************************************************************** */
  `define TIMEOUT(__event, __time)  \
    fork                            \
      __event;                      \
      #(__time);                    \
    join_any; disable fork;         

  /* ***************************************************************************
    X-checker macro
    __ena         : X-check enabled
    __sig         : signal to be checked (logic)
    __glitch_filt : filter glitches
  *************************************************************************** */
  `define X_CHK(__ena, __sig, __glitch_filt = 0)                                \
    forever begin                                                               \
      if (__ena && $isunknown(__sig))                                           \
        `MSG_WRN(("X detected on '%0s'", `"__sig`"))                            \
      @(__ena, __sig);                                                          \
      if (__glitch_filt == 1)                                                   \
        #(c_DELS);                                                              \
    end

  /* ***************************************************************************
    logic checker macro
    __ena         : logic check enabled
    __dut         : signal to be checked (logic)
    __exp         : expected value, could be 'X' to temporarily disable check (logic)
  *************************************************************************** */
  `define LOGIC_CHK(__ena, __dut, __exp)                                        \
    forever begin                                                               \
      #(c_DELS);                                                                \
      if (__ena && !$isunknown(__exp)) tsk_compare (__dut, __exp, `"__dut`");   \
      @(__ena, __dut, __exp);                                                   \
    end

  /* ***************************************************************************
    simple macro for DEBOUNCED signals
      `ASYM_DEBOUNCE(signal, signal_deb. pos_edge_time, neg_edge_time)
  *************************************************************************** */
  `define ASYM_DEBOUNCE(__signal, __signal_deb, __time_pos, __time_neg)  \
  always begin                                                           \
    @(__signal);                                                         \
    fork                                                                 \
      begin                                                              \
        if(__signal == 1'b1)                                             \
          #(__time_pos);                                                 \
        else                                                             \
          #(__time_neg);                                                 \
        __signal_deb <= __signal;                                        \
      end                                                                \
      @(__signal);                                                       \
    join_any; disable fork;                                              \
  end  
