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

// ------------------------------------------------------------------------
// Company           : ON Semiconductor
// ------------------------------------------------------------------------
// File              : $RCSfile
// ------------------------------------------------------------------------
// Last Modified     : $Date: 2016/07/26 10:53:25 $
// Last Modified By  : $Author: fg7g4t $
// Revision          : $Revision: 1.3 $
// ------------------------------------------------------------------------
// Description       : Testcase - TB must have only MBIST_ADR_CNT entity
// ------------------------------------------------------------------------
// Revision history  :
//
//   $Log: tc_mbist.sv,v $
//   Revision 1.3  2016/07/26 10:53:25  fg7g4t
//   Extended for SMARCH algo
//
//   Revision 1.2  2016/06/15 10:47:18  fg7g4t
//   Start of MBIST testcases and testbench
//
//   Revision 1.1  2016/04/15 11:25:10  fg7g4t
//   Testcase for mbist
//
//   Revision 1.3  2016/03/11 08:55:04  fg7g4t
//   Start of BIST with one pin
//
//   Revision 1.2  2016/03/04 14:41:36  fg7g4t
//   RC_OSC + start of BIST
//
//   Revision 1.1  2016/03/04 11:31:20  fg7g4t
//   Test harness for BIST generation - 1st steps
//
//

module tc_mbist;
  import tb_pkg::*;                     // testbench specific stuff

  `include "messages.inc.sv"            // messag macros
  `include "paths.inc.sv"               // model/design paths
  `include "transaction.inc.sv"         // transaction macros
  `include "macros.inc.sv"              // macros

  // ######################################################################## //
  //                          PARAMETER DEFINITIONS                           //
  // ######################################################################## //
  parameter         c_MODULE = "TC_MBIST";


  // ######################################################################## //
  //                           TESTCASE VARIABLES                             //
  // ######################################################################## //
  // -- wave transactions ------------------------------------------------------
  integer           stream_tc, tr_tc;
  int               tr_active;

  // -- global variables -------------------------------------------------------

  time              clk_per;

  // ######################################################################## //
  //                            TASKS & FUNCTIONS                             //
  // ######################################################################## //



  /* ***************************************************************************
  coverpoint version: 0

  1.1 Example testcase
    1. ...
    2. ...

  *************************************************************************** */
  task tsk_test_mbist;
    // -- local parameters -----------------------------------------------------
    localparam string c_TEST_NAME = "MBIST";

    // -- local variables ------------------------------------------------------
    time start_time;
    time test_time;

    // == stimuli ==============================================================
    `TEST_HEADER(c_TEST_NAME)
    `MBIST.tsk_enable( ._biste(1'b0), ._sen(1'b0));
    tb.tsk_gen_reset();

    // -------------------------------------------------------------------------

    `PHASE(" Run of MBIST controller", "run_mbist")
    test_time = 0ns;

    for (int i = 0; i < 5; i++)
    begin
      if (i == 2)
        `MSG(("%1d. Run of MBIST with faulty memory", i+1))
      else if (i == 3)
        `MSG(("%1d. Run of MBIST and interrupt in middle", i+1))
      else
        `MSG(("%1d. Run of MBIST", i+1))

      `MSG((" a) Start of MBIST"));
      fork
        `MBIST.tsk_enable( ._biste(1'b1), ._sen(1'b0));
      join_none;

      // Check fail pulse after start of test
//      `MBIST.tsk_wait_fail( .edg(e_POSEDGE), .timeout(`MBIST.c_START_TO));
//      `MBIST.tsk_read_fail( .exp_fail('b1));
//      #(4*clk_per);
//      `MBIST.tsk_read_fail( .exp_fail('b1));
//      `MBIST.tsk_wait_fail( .edg(e_NEGEDGE), .timeout(7*clk_per));
//      `MBIST.tsk_read_fail( .exp_fail('b0));
      start_time = $time;
      `MSG((" b) Start Fail pulse detected"));

      if (i == 2) begin

        // In half of run simulate error on memory
        #(clk_per * (2**`MBIST.c_ADR_WIDTH) * `MBIST.c_MC_LENGTH/4);

        // Test shall be still running
        `MBIST.tsk_read_fail(1'b0);
        `MBIST.tsk_read_done(1'b0);

        // Simulate error
        `MBIST.tsk_corrupt_memory(2**(`MBIST.c_ADR_WIDTH-1),1'b1);

        //Wait for end by FAIL signal
        fork
          begin
            `MBIST.tsk_wait_done( .edg(e_POSEDGE), .timeout(test_time/2));
            #(clk_per); // Take chance to execute next block of code in case
                        //   Done and Fail come in same time
            `MSG_ERR(("No fail on fault memory !! "))
          end
          `MBIST.tsk_wait_fail( .edg(e_POSEDGE), .timeout(test_time/2));
        join_any; disable fork;

        // Simulate error
        `MBIST.tsk_corrupt_memory(2**(`MBIST.c_ADR_WIDTH-1),1'b0);

        #(clk_per);
      end
      else if (i == 3) begin

        #(test_time/4); // Interrupt test
        `MBIST.tsk_enable( ._biste('b0), ._sen('b0));
        #(5*clk_per);
        continue;

      end
      else begin

        // Wait for end when no error detected
        fork
          begin
            `MBIST.tsk_wait_fail( .edg(e_POSEDGE), .timeout(`MBIST.c_TEST_TO+1us)); // We want TO to occure on DONE signal
            `MSG_ERR(("Fail on fault-free memory !! "))
          end
          begin
            `MBIST.tsk_wait_done( .edg(e_POSEDGE), .timeout(`MBIST.c_TEST_TO));

            `MBIST.tsk_read_fail(1'b0);
          end
        join_any; disable fork;

      end

      `MSG((" c) Test done. (T = %dus)", ($time - start_time)/1us))

      if (i < 2)
        test_time += ($time - start_time);
      if (i == 4)
      begin
        automatic real expected_clks = test_time/2/clk_per;
        automatic real actual_clks   = ($time - start_time)/clk_per;
        automatic real difference    = f_abs(actual_clks - expected_clks);
        if ( difference > 4.0)
          `MSG_ERR(("Test take unusal amount of time! Expected %d clk's measured %d clk's, difference %d clk's",
                     actual_clks, expected_clks, difference ))

      end
      `MBIST.tsk_read_done( .exp_done('b1));
      `MSG((" d) End of test"));

      #(2*clk_per);

      // Disable BIST test
      `MBIST.tsk_enable( ._biste('b0), ._sen('b0));
      `MBIST.tsk_wait_done( .edg(e_NEGEDGE), .timeout(`MBIST.c_START_TO));

      // Wait before reactivating
      #(5*clk_per);
    end

    // =========================================================================
    `TC_TASK_END
    #(clk_per * 100.0);

    `MSG((""))
    `LOG_DELIMITER("*")
    if (tb.err_detected !== 1) begin
      // -- list of testplan coverpoints
      //`SCB.cp_rst_gen_0     <= 1;
      //`SCB.tsk_cg_testplan_sample;

      `MSG(("Section '%s' PASSED", c_TEST_NAME))
    end else begin
      `MSG_ERR(("Section '%s' FAILED", c_TEST_NAME))
    end
    `MSG((""))              // intentionally empty
//    `MSG(("  F_UPAL_CLKGEN_0010"))
//    `MSG(("  F_UPAL_CLKGEN_0020"))
//    `MSG(("  F_UPAL_RSTGEN_0010"))
    `MSG((""))              // intentionally empty
    `LOG_DELIMITER("*")
  endtask



  // ######################################################################## //
  //                               MAIN STIMULI                               //
  // ######################################################################## //
  initial begin
    stream_tc = `TR_CREATE("tc")
  end

  initial begin : p_main_stimuli
    #0;
    @(tb.tb_init_done);                     // wait for testbench initialization

    // -- get current clock period & start osc ---------------------------------
    clk_per = `RC_OSC.clk_per;

    // -- testcase -------------------------------------------------------------
    tsk_test_mbist;

    // -- end of simulation ----------------------------------------------------
    `MSG(("Simulation of %s finished", c_MODULE))
    #(clk_per * 100);
//    `RST_CTRL.tsk_drive (e_POR_VDD_B, 0, e_NEGEDGE);   // reset to break assertions
    `RC_OSC.f_osc_ctrl (0);                             // stop osc

    if(tb.err_detected == 1)
      $finish(2);
    else
      $finish(0);
  end

endmodule


