--=============================================================================
-- Description: IBIS macro library implemented in VHDL-A(MS)
-- Created: January 2006 by Arpad Muranyi (Intel Corporation)
--
-- Revision history:
--
-- 2006/01/19  VHDL-A(MS) rev0.0 completed
--
--=============================================================================
-- List of building blocks contained in this library:
--
-- IBIS_R             (p, n);
-- IBIS_VCR           (p, n, ps, ns);
-- IBIS_CCR           (p, n, ps, ns);
--
-- IBIS_C             (p, n);
-- IBIS_VCC           (p, n, ps, ns);
-- IBIS_CCC           (p, n, ps, ns);
--
-- IBIS_L             (p, n);
-- IBIS_VCL           (p, n, ps, ns);
-- IBIS_CCL           (p, n, ps, ns);
-- IBIS_K             (p1, n1, p2, n2);
--
-- IBIS_V             (p, n);
-- IBIS_VCVS          (p, n, ps, ns);
-- IBIS_CCVS          (p, n, ps, ns);
-- IBIS_VCVS_DELAY    (p, n, ps, ns);
-- IBIS_CCVS_DELAY    (p, n, ps, ns);
-- IBIS_VCVS_MIN      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCVS_MIN      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCVS_MAX      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCVS_MAX      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCVS_ABS      (p, n, ps, ns);
-- IBIS_CCVS_ABS      (p, n, ps, ns);
-- IBIS_VCVS_SUM      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCVS_SUM      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCVS_MULT     (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCVS_MULT     (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCVS_DIV      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCVS_DIV      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCVS_PWL      (p, n, ps, ns);
-- IBIS_CCVS_PWL      (p, n, ps, ns);
-- IBIS_TCVS_PWL      (p, n);
-- IBIS_VECVS_PWL     (p, n, ps, ns);
-- IBIS_CECVS_PWL     (p, n, ps, ns);
--
-- IBIS_I             (p, n);
-- IBIS_VCCS          (p, n, ps, ns);
-- IBIS_CCCS          (p, n, ps, ns);
-- IBIS_VCCS_DELAY    (p, n, ps, ns);
-- IBIS_CCCS_DELAY    (p, n, ps, ns);
-- IBIS_VCCS_MIN      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCCS_MIN      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCCS_MAX      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCCS_MAX      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCCS_ABS      (p, n, ps, ns);
-- IBIS_CCCS_ABS      (p, n, ps, ns);
-- IBIS_VCCS_SUM      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCCS_SUM      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCCS_MULT     (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCCS_MULT     (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCCS_DIV      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_CCCS_DIV      (p, n, ps1, ns1, ps2, ns2);
-- IBIS_VCCS_PWL      (p, n, ps, ns);
-- IBIS_CCCS_PWL      (p, n, ps, ns);
-- IBIS_TCCS_PWL      (p, n);
-- IBIS_VECCS_PWL     (p, n, ps, ns);
-- IBIS_CECCS_PWL     (p, n, ps, ns);
--
-- IBIS_T             (n1, ref1, n2, ref2);
--
-- IBIS_INPUT         (PC_ref, GC_ref, Input, Rcv_D);
-- IBIS_OUTPUT        (PU_ref, PD_ref, Output, In_D, PC_ref, GC_ref);
-- IBIS_IO            (PU_ref, PD_ref, IO, In_D, En_D, Rcv_D, PC_ref, GC_ref);
-- IBIS_3STATE        (PU_ref, PD_ref, IO, In_D, En_D, PC_ref, GC_ref);
-- IBIS_OPENSINK      (PU_ref, PD_ref, IO, In_D, PC_ref, GC_ref);
-- IBIS_IO_OPENSINK   (PU_ref, PD_ref, IO, In_D, En_D, Rcv_D, PC_ref, GC_ref);
-- IBIS_OPENSOURCE    (PU_ref, PD_ref, IO, In_D, PC_ref, GC_ref);
-- IBIS_IO_OPENSOURCE (PU_ref, PD_ref, IO, In_D, En_D, Rcv_D, PC_ref, GC_ref);
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_R is

    generic (Rval  : real := 1.0;
             Scale : real := 1.0);

    port (terminal p, n : electrical);

  end entity IBIS_R;
  --===========================================================================
  architecture ideal of IBIS_R is

  quantity Vout across Iout through p to n;

  begin

    Vout == Scale * Rval * Iout;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCR is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCR;
  --===========================================================================
  architecture ideal of IBIS_VCR is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;

  begin

    Vout == Scale * Vin * Iout;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCR is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCR;
  --===========================================================================
  architecture ideal of IBIS_CCR is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;

  begin

    Vin  == 0.0;
    Vout == Scale * Iin * Iout;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_C is

    generic (Cval  : real := 1.0;
             V0    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n : electrical);

  end entity IBIS_C;
  --===========================================================================
  architecture ideal of IBIS_C is

  quantity Vout across Iout through p to n;

  begin

    if domain = quiescent_domain use
      Vout == V0;
    else
      Iout == Scale * Cval * Vout'dot;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCC is

    generic (V0    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCC;
  --===========================================================================
  architecture ideal of IBIS_VCC is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;

  begin

    if domain = quiescent_domain use
      Vout == V0;
    else
      Iout == Vout * Scale * Vin'dot + Scale * Vin * Vout'dot;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCC is

    generic (V0    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCC;
  --===========================================================================
  architecture ideal of IBIS_CCC is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;

  begin

    Vin  == 0.0;
    if domain = quiescent_domain use
      Vout == V0;
    else
      Iout == Vout * Scale * Iin'dot + Scale * Iin * Vout'dot;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_L is

    generic (Lval  : real := 1.0;
             I0    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n : electrical);

  end entity IBIS_L;
  --===========================================================================
  architecture ideal of IBIS_L is

  quantity Vout across Iout through p to n;

  begin

    if domain = quiescent_domain use
      Iout == I0;
    else
      Vout == Scale * Lval * Iout'dot;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCL is

    generic (I0    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCL;
  --===========================================================================
  architecture ideal of IBIS_VCL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;

  begin

    if domain = quiescent_domain use
      Iout == I0;
    else
      Vout == Iout * Scale * Vin'dot + Scale * Vin * Iout'dot;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCL is

    generic (I0    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCL;
  --===========================================================================
  architecture ideal of IBIS_CCL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;

  begin

    Vin  == 0.0;
    if domain = quiescent_domain use
      Iout == I0;
    else
      Vout == Iout * Scale * Iin'dot + Scale * Iin * Iout'dot;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
  entity IBIS_K is

    generic (Lval_1 : real := 1.0;
             Lval_2 : real := 1.0;
             Kval   : real := 0.0;
             I0_1   : real := 0.0;
             I0_2   : real := 0.0;
             Scale  : real := 1.0);

    port (terminal p1, n1, p2, n2 : electrical);

  end entity IBIS_K;
  --===========================================================================
  architecture ideal of IBIS_K is

  quantity Vout1 across Iout1 through p1 to n1;
  quantity Vout2 across Iout2 through p2 to n2;
  constant M : real := Scale * Kval * sqrt(Lval_1 * Lval_2);

  begin

    if domain = quiescent_domain use
      Iout1 == I0_1;
      Iout2 == I0_2;
    else
      Vout1 == Scale * Lval_1 * Iout1'dot + M * Iout2'dot;
      Vout2 == Scale * Lval_2 * Iout2'dot + M * Iout1'dot;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_V is

    generic (Vdc   : real := 1.0;
             Scale : real := 1.0);

    port (terminal p, n : electrical);

  end entity IBIS_V;
  --===========================================================================
  architecture ideal of IBIS_V is

  quantity Vout across Iout through p to n;

  begin

    Vout == Scale * Vdc;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCVS is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCVS;
  --===========================================================================
  architecture ideal of IBIS_VCVS is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;

  begin

    Vout == Scale * Vin;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCVS is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCVS;
  --===========================================================================
  architecture ideal of IBIS_CCVS is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;

  begin

    Vin  == 0.0;
    Vout == Scale * Iin;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCVS_DELAY is

    generic (TD    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCVS_DELAY;
  --===========================================================================
  architecture ideal of IBIS_VCVS_DELAY is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;

  begin

    Vout == Scale * Vin'delayed(TD);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCVS_DELAY is

    generic (TD    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCVS_DELAY;
  --===========================================================================
  architecture ideal of IBIS_CCVS_DELAY is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;

  begin

    Vin  == 0.0;
    Vout == Scale * Iin'delayed(TD);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
  entity IBIS_VCVS_MIN is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCVS_MIN;
  --===========================================================================
  architecture ideal of IBIS_VCVS_MIN is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    Vout == Scale * realmin(Vin1, Vin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
  entity IBIS_CCVS_MIN is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCVS_MIN;
  --===========================================================================
  architecture ideal of IBIS_CCVS_MIN is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    Vout == Scale * realmin(Iin1, Iin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
  entity IBIS_VCVS_MAX is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCVS_MAX;
  --===========================================================================
  architecture ideal of IBIS_VCVS_MAX is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    Vout == Scale * realmax(Vin1, Vin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
  entity IBIS_CCVS_MAX is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCVS_MAX;
  --===========================================================================
  architecture ideal of IBIS_CCVS_MAX is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    Vout == Scale * realmax(Iin1, Iin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCVS_ABS is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCVS_ABS;
  --===========================================================================
  architecture ideal of IBIS_VCVS_ABS is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;

  begin

    Vout == Scale * abs(Vin);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCVS_ABS is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCVS_ABS;
  --===========================================================================
  architecture ideal of IBIS_CCVS_ABS is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;

  begin

    Vin  == 0.0;
    Vout == Scale * abs(Iin);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCVS_SUM is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCVS_SUM;
  --===========================================================================
  architecture ideal of IBIS_VCVS_SUM is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    Vout == Scale * (Vin1 + Vin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCVS_SUM is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCVS_SUM;
  --===========================================================================
  architecture ideal of IBIS_CCVS_SUM is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    Vout == Scale * (Iin1 + Iin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCVS_MULT is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCVS_MULT;
  --===========================================================================
  architecture ideal of IBIS_VCVS_MULT is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    Vout == Scale * Vin1 * Vin2;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCVS_MULT is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCVS_MULT;
  --===========================================================================
  architecture ideal of IBIS_CCVS_MULT is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    Vout == Scale * Iin1 * Iin2;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCVS_DIV is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCVS_DIV;
  --===========================================================================
  architecture ideal of IBIS_VCVS_DIV is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    if Vin2 /= 0.0 use
      Vout == Scale * Vin1 / Vin2;
    else
--    Vout == real'high;   -- instead of inf.  This doesn't work in some tools.
      Vout == 1.0e+15;     -- instead of inf.
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCVS_DIV is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCVS_DIV;
  --===========================================================================
  architecture ideal of IBIS_CCVS_DIV is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    if Iin2 /= 0.0 use
      Vout == Scale * Iin1 / Iin2;
    else
--    Vout == real'high;   -- instead of inf.  This doesn't work in some tools.
      Vout == 1.0e+15;     -- instead of inf.
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCVS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X : real_vector := (-5.00,  0.00,  5.00, 10.00);
             Y : real_vector := (-0.10,  0.00,  0.10,  0.10));
    ---------------------------------------------------------------------------
    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCVS_PWL;
  --===========================================================================
  architecture ideal of IBIS_VCVS_PWL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    Vout == Scale * Lookup(Vin, X, Y, "SE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCVS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X : real_vector := (-5.00,  0.00,  5.00, 10.00);
             Y : real_vector := (-0.10,  0.00,  0.10,  0.10));
    ---------------------------------------------------------------------------
    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCVS_PWL;
  --===========================================================================
  architecture ideal of IBIS_CCVS_PWL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    Vin  == 0.0;
    Vout == Scale * Lookup(Iin, X, Y, "SE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_TCVS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             Y : real_vector := (0.00,     0.10,     0.90,     1.00));
    ---------------------------------------------------------------------------
    port (terminal p, n : electrical);

  end entity IBIS_TCVS_PWL;
  --===========================================================================
  architecture ideal of IBIS_TCVS_PWL is

  quantity Vout across Iout through p to n;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    Vout == Scale * Lookup(now, X, Y, "HE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VECVS_PWL is

    generic (Vth_R : real := 0.0;
             Vth_F : real := 0.0;
             Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             XR : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YR : real_vector := (0.00,     0.10,     0.90,     1.00);
             XF : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YF : real_vector := (1.00,     0.90,     0.10,     0.00));
    ---------------------------------------------------------------------------
    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VECVS_PWL;
  --===========================================================================
  architecture ideal of IBIS_VECVS_PWL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;
  signal   T_event    : real    := 0.0;
  signal   EventState : integer := 0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    ---------------------------------------------------------------------------
    Threshold_crossing : process is
    begin
      if domain = quiescent_domain then
        wait until domain /= quiescent_domain;
        if Vin > Vth_R then            -- high state
          EventState <= 1;
        elsif Vin < Vth_F then         -- low state
          EventState <= -1;
        end if;
      else
        wait on Vin'above(Vth_R), Vin'above(Vth_F);
        if Vin > Vth_R then            -- rising edge
          EventState <= 2;
          T_event    <= now;
        elsif Vin < Vth_F then         -- falling edge
          EventState <= -2;
          T_event    <= now;
        end if;
      end if;
    end process Threshold_crossing;
    ---------------------------------------------------------------------------

    case EventState use
      when -2 =>        -- Executes after falling edge events
        Vout == Scale * Lookup(now-T_event, XF, YF, "HE");
      when -1 =>        -- Executes between t=0 and first threshold crossing
        Vout == Scale * Lookup(0.0, XR, YR, "HE");    -- when input is LOW
      when 1 =>         -- Executes between t=0 and first threshold crossing
        Vout == Scale * Lookup(0.0, XF, YF, "HE");    -- when input is HIGH
      when 2 =>         -- Executes after rising edge events
        Vout == Scale * Lookup(now-T_event, XR, YR, "HE");
      when others =>    -- Executes during DC operating point analysis
        if Vin > Vth_R use
          Vout == Scale * Lookup(0.0, XF, YF, "HE");
        elsif Vin < Vth_F use
          Vout == Scale * Lookup(0.0, XR, YR, "HE");
        else
          Vout == Scale * (Lookup(0.0, XR, YR, "HE") + Lookup(0.0, XF, YF, "HE")) / 2.0;
        end use;
    end case;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CECVS_PWL is

    generic (Ith_R : real := 0.0;
             Ith_F : real := 0.0;
             Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             XR : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YR : real_vector := (0.00,     0.10,     0.90,     1.00);
             XF : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YF : real_vector := (1.00,     0.90,     0.10,     0.00));
    ---------------------------------------------------------------------------
    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CECVS_PWL;
  --===========================================================================
  architecture ideal of IBIS_CECVS_PWL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;
  signal   T_event    : real    := 0.0;
  signal   EventState : integer := 0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    ---------------------------------------------------------------------------
    Threshold_crossing : process is
    begin
      if domain = quiescent_domain then
        wait until domain /= quiescent_domain;
        if Iin > Ith_R then            -- high state
          EventState <= 1;
        elsif Iin < Ith_F then         -- low state
          EventState <= -1;
        end if;
      else
        wait on Iin'above(Ith_R), Iin'above(Ith_F);
        if Iin > Ith_R then            -- rising edge
          EventState <= 2;
          T_event    <= now;
        elsif Iin < Ith_F then         -- falling edge
          EventState <= -2;
          T_event    <= now;
        end if;
      end if;
    end process Threshold_crossing;
    ---------------------------------------------------------------------------

    Vin == 0.0;
    case EventState use
      when -2 =>        -- Executes after falling edge events
        Vout == Scale * Lookup(now-T_event, XF, YF, "HE");
      when -1 =>        -- Executes between t=0 and first threshold crossing
        Vout == Scale * Lookup(0.0, XR, YR, "HE");    -- when input is LOW
      when 1 =>         -- Executes between t=0 and first threshold crossing
        Vout == Scale * Lookup(0.0, XF, YF, "HE");    -- when input is HIGH
      when 2 =>         -- Executes after rising edge events
        Vout == Scale * Lookup(now-T_event, XR, YR, "HE");
      when others =>    -- Executes during DC operating point analysis
        if Iin > Ith_R use
          Vout == Scale * Lookup(0.0, XF, YF, "HE");
        elsif Iin < Ith_F use
          Vout == Scale * Lookup(0.0, XR, YR, "HE");
        else
          Vout == Scale * (Lookup(0.0, XR, YR, "HE") + Lookup(0.0, XF, YF, "HE")) / 2.0;
        end use;
    end case;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_I is

    generic (Idc   : real := 1.0;
             Scale : real := 1.0);

    port (terminal p, n : electrical);

  end entity IBIS_I;
  --===========================================================================
  architecture ideal of IBIS_I is

  quantity Vout across Iout through p to n;

  begin

    Iout == Scale * Idc;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCCS is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCCS;
  --===========================================================================
  architecture ideal of IBIS_VCCS is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;

  begin

    Iout == Scale * Vin;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCCS is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCCS;
  --===========================================================================
  architecture ideal of IBIS_CCCS is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;

  begin

    Vin  == 0.0;
    Iout == Scale * Iin;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCCS_DELAY is

    generic (TD    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCCS_DELAY;
  --===========================================================================
  architecture ideal of IBIS_VCCS_DELAY is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;

  begin

    Iout == Scale * Vin'delayed(TD);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCCS_DELAY is

    generic (TD    : real := 0.0;
             Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCCS_DELAY;
  --===========================================================================
  architecture ideal of IBIS_CCCS_DELAY is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;

  begin

    Vin  == 0.0;
    Iout == Scale * Iin'delayed(TD);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
  entity IBIS_VCCS_MIN is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCCS_MIN;
  --===========================================================================
  architecture ideal of IBIS_VCCS_MIN is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    Iout == Scale * realmin(Vin1, Vin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
  entity IBIS_CCCS_MIN is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCCS_MIN;
  --===========================================================================
  architecture ideal of IBIS_CCCS_MIN is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    Iout == Scale * realmin(Iin1, Iin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
  entity IBIS_VCCS_MAX is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCCS_MAX;
  --===========================================================================
  architecture ideal of IBIS_VCCS_MAX is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    Iout == Scale * realmax(Vin1, Vin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
  entity IBIS_CCCS_MAX is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCCS_MAX;
  --===========================================================================
  architecture ideal of IBIS_CCCS_MAX is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    Iout == Scale * realmax(Iin1, Iin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCCS_ABS is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCCS_ABS;
  --===========================================================================
  architecture ideal of IBIS_VCCS_ABS is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;

  begin

    Iout == Scale * abs(Vin);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCCS_ABS is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCCS_ABS;
  --===========================================================================
  architecture ideal of IBIS_CCCS_ABS is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;

  begin

    Vin  == 0.0;
    Iout == Scale * abs(Iin);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCCS_SUM is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCCS_SUM;
  --===========================================================================
  architecture ideal of IBIS_VCCS_SUM is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    Iout == Scale * (Vin1 + Vin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCCS_SUM is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCCS_SUM;
  --===========================================================================
  architecture ideal of IBIS_CCCS_SUM is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    Iout == Scale * (Iin1 + Iin2);

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCCS_MULT is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCCS_MULT;
  --===========================================================================
  architecture ideal of IBIS_VCCS_MULT is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    Iout == Scale * Vin1 * Vin2;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCCS_MULT is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCCS_MULT;
  --===========================================================================
  architecture ideal of IBIS_CCCS_MULT is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    Iout == Scale * Iin1 * Iin2;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCCS_DIV is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_VCCS_DIV;
  --===========================================================================
  architecture ideal of IBIS_VCCS_DIV is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across              ps1 to ns1;
  quantity Vin2 across              ps2 to ns2;

  begin

    if Vin2 /= 0.0 use
      Iout == Scale * Vin1 / Vin2;
    else
--    Iout == real'high;   -- instead of inf.  This doesn't work in some tools.
      Iout == 1.0e+12;     -- instead of inf.
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCCS_DIV is

    generic (Scale : real := 1.0);

    port (terminal p, n, ps1, ns1, ps2, ns2 : electrical);

  end entity IBIS_CCCS_DIV;
  --===========================================================================
  architecture ideal of IBIS_CCCS_DIV is

  quantity Vout across Iout through p   to n;
  quantity Vin1 across Iin1 through ps1 to ns1;
  quantity Vin2 across Iin2 through ps2 to ns2;

  begin

    Vin1 == 0.0;
    Vin2 == 0.0;
    if Iin2 /= 0.0 use
      Iout == Scale * Iin1 / Iin2;
    else
--    Iout == real'high;   -- instead of inf.  This doesn't work in some tools.
      Iout == 1.0e+12;     -- instead of inf.
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VCCS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X : real_vector := (-5.00,  0.00,  5.00, 10.00);
             Y : real_vector := (-0.10,  0.00,  0.10,  0.10));
    ---------------------------------------------------------------------------
    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VCCS_PWL;
  --===========================================================================
  architecture ideal of IBIS_VCCS_PWL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    Iout == Scale * Lookup(Vin, X, Y, "SE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCCS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X : real_vector := (-5.00,  0.00,  5.00, 10.00);
             Y : real_vector := (-0.10,  0.00,  0.10,  0.10));
    ---------------------------------------------------------------------------
    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CCCS_PWL;
  --===========================================================================
  architecture ideal of IBIS_CCCS_PWL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    Vin  == 0.0;
    Iout == Scale * Lookup(Iin, X, Y, "SE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_TCCS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             Y : real_vector := (0.00,     0.10,     0.90,     1.00));
    ---------------------------------------------------------------------------
    port (terminal p, n : electrical);

  end entity IBIS_TCCS_PWL;
  --===========================================================================
  architecture ideal of IBIS_TCCS_PWL is

  quantity Vout across Iout through p to n;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    Iout == Scale * Lookup(now, X, Y, "HE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_VECCS_PWL is

    generic (Vth_R : real := 0.0;
             Vth_F : real := 0.0;
             Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             XR : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YR : real_vector := (0.00,     0.10,     0.90,     1.00);
             XF : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YF : real_vector := (1.00,     0.90,     0.10,     0.00));
    ---------------------------------------------------------------------------
    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_VECCS_PWL;
  --===========================================================================
  architecture ideal of IBIS_VECCS_PWL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across              ps to ns;
  signal   T_event    : real    := 0.0;
  signal   EventState : integer := 0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    ---------------------------------------------------------------------------
    Threshold_crossing : process is
    begin
      if domain = quiescent_domain then
        wait until domain /= quiescent_domain;
        if Vin > Vth_R then            -- high state
          EventState <= 1;
        elsif Vin < Vth_F then         -- low state
          EventState <= -1;
        end if;
      else
        wait on Vin'above(Vth_R), Vin'above(Vth_F);
        if Vin > Vth_R then            -- rising edge
          EventState <= 2;
          T_event    <= now;
        elsif Vin < Vth_F then         -- falling edge
          EventState <= -2;
          T_event    <= now;
        end if;
      end if;
    end process Threshold_crossing;
    ---------------------------------------------------------------------------

    case EventState use
      when -2 =>        -- Executes after falling edge events
        Iout == Scale * Lookup(now-T_event, XF, YF, "HE");
      when -1 =>        -- Executes between t=0 and first threshold crossing
        Iout == Scale * Lookup(0.0, XR, YR, "HE");    -- when input is LOW
      when 1 =>         -- Executes between t=0 and first threshold crossing
        Iout == Scale * Lookup(0.0, XF, YF, "HE");    -- when input is HIGH
      when 2 =>         -- Executes after rising edge events
        Iout == Scale * Lookup(now-T_event, XR, YR, "HE");
      when others =>    -- Executes during DC operating point analysis
        if Vin > Vth_R use
          Iout == Scale * Lookup(0.0, XF, YF, "HE");
        elsif Vin < Vth_F use
          Iout == Scale * Lookup(0.0, XR, YR, "HE");
        else
          Iout == Scale * (Lookup(0.0, XR, YR, "HE") + Lookup(0.0, XF, YF, "HE")) / 2.0;
        end use;
    end case;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CECCS_PWL is

    generic (Ith_R : real := 0.0;
             Ith_F : real := 0.0;
             Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             XR : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YR : real_vector := (0.00,     0.10,     0.90,     1.00);
             XF : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YF : real_vector := (1.00,     0.90,     0.10,     0.00));
    ---------------------------------------------------------------------------

    port (terminal p, n, ps, ns : electrical);

  end entity IBIS_CECCS_PWL;
  --===========================================================================
  architecture ideal of IBIS_CECCS_PWL is

  quantity Vout across Iout through p  to n;
  quantity Vin  across Iin  through ps to ns;
  signal   T_event    : real    := 0.0;
  signal   EventState : integer := 0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
  begin

    ---------------------------------------------------------------------------
    Threshold_crossing : process is
    begin
      if domain = quiescent_domain then
        wait until domain /= quiescent_domain;
        if Iin > Ith_R then            -- high state
          EventState <= 1;
        elsif Iin < Ith_F then         -- low state
          EventState <= -1;
        end if;
      else
        wait on Iin'above(Ith_R), Iin'above(Ith_F);
        if Iin > Ith_R then            -- rising edge
          EventState <= 2;
          T_event    <= now;
        elsif Iin < Ith_F then         -- falling edge
          EventState <= -2;
          T_event    <= now;
        end if;
      end if;
    end process Threshold_crossing;
    ---------------------------------------------------------------------------

    Vin == 0.0;
    case EventState use
      when -2 =>        -- Executes after falling edge events
        Iout == Scale * Lookup(now-T_event, XF, YF, "HE");
      when -1 =>        -- Executes between t=0 and first threshold crossing
        Iout == Scale * Lookup(0.0, XR, YR, "HE");    -- when input is LOW
      when 1 =>         -- Executes between t=0 and first threshold crossing
        Iout == Scale * Lookup(0.0, XF, YF, "HE");    -- when input is HIGH
      when 2 =>         -- Executes after rising edge events
        Iout == Scale * Lookup(now-T_event, XR, YR, "HE");
      when others =>    -- Executes during DC operating point analysis
        if Iin > Ith_R use
          Iout == Scale * Lookup(0.0, XF, YF, "HE");
        elsif Iin < Ith_F use
          Iout == Scale * Lookup(0.0, XR, YR, "HE");
        else
          Iout == Scale * (Lookup(0.0, XR, YR, "HE") + Lookup(0.0, XF, YF, "HE")) / 2.0;
        end use;
    end case;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_T is

    generic (Z0 : real := 50.0;
             TD : real := 1.0e-9);

    port (terminal n1, ref1, n2, ref2 : electrical);

  end entity IBIS_T;
  --===========================================================================
  architecture Ideal of IBIS_T is

  quantity Vend1 across Iend1 through n1 to ref1;
  quantity Vend2 across Iend2 through n2 to ref2;

  quantity i12 : real;  -- Current wave traveling from end1 to end2
  quantity i21 : real;  -- Current wave traveling from end2 to end1

  begin

    Iend1 == i12 - i21'delayed(TD);
    Iend2 == i21 - i12'delayed(TD);
    Vend1 == Z0 * (2.0 * i12 - Iend1);
    Vend2 == Z0 * (2.0 * i21 - Iend2);

  end architecture Ideal;
--=============================================================================
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
entity IBIS_INPUT is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.50;       -- splitting coefficients
           kC_comp_gc : real := 0.50;
           --------------------------------------------------------------------
           -- Receiver thresholds
           --------------------------------------------------------------------
           Vinh : real := 2.00;
           Vinl : real := 0.80;
           --------------------------------------------------------------------
           -- Vectors of the IV curve tables
           --------------------------------------------------------------------
           Ipc_data : real_vector := ( 0.08,  0.00,  0.00,  0.00);
           Vpc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           Igc_data : real_vector := (-0.08,  0.00,  0.00,  0.00);
           Vgc_data : real_vector := (-5.00, -1.00,  5.00, 10.00));
     --------------------------------------------------------------------------
     port (terminal PC_ref : electrical;
           terminal GC_ref : electrical;

           terminal Pad    : electrical;
           terminal Rcv_D  : electrical);

end entity IBIS_INPUT;
--=============================================================================
architecture SIMPLE_RECEIVER of IBIS_INPUT is

  quantity  Vpc   across  Ipc   through  PC_ref  to  Pad;
  quantity  Vgc   across  Igc   through  Pad     to  GC_ref;
  quantity  Vrcv  across  Ircv  through  Rcv_D   to  ELECTRICAL_REF;

  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
--=============================================================================
begin
  --===========================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc   == -1.0*Lookup(Vpc, Vpc_data, Ipc_data, "SE") + kC_comp_pc*C_comp*Vpc'dot; 
  Igc   ==      Lookup(Vgc, Vgc_data, Igc_data, "SE") + kC_comp_gc*C_comp*Vgc'dot;
  -----------------------------------------------------------------------------
  -- A simple receiver logic
  -----------------------------------------------------------------------------
  if    (Vgc > Vinh) use Vrcv == 1.0;
  elsif (Vgc < Vinl) use Vrcv == 0.0;
  else                   Vrcv == 0.5;
  end use;
--=============================================================================
end architecture SIMPLE_RECEIVER;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
entity IBIS_OUTPUT is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.00;       -- splitting coefficients
           kC_comp_pu : real := 0.50;
           kC_comp_pd : real := 0.50;
           kC_comp_gc : real := 0.00;
           --------------------------------------------------------------------
           -- [Pullup Reference] and [Pulldown Reference] values
           --------------------------------------------------------------------
           Vpc_ref : real := 5.0;
           Vpu_ref : real := 5.0;
           Vpd_ref : real := 0.0;
           Vgc_ref : real := 0.0;
           --------------------------------------------------------------------
           -- Vectors of the IV curve tables
           --------------------------------------------------------------------
           Ipc_data : real_vector := ( 0.08,  0.00,  0.00,  0.00);
           Vpc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           Ipu_data : real_vector := ( 0.10,  0.00, -0.10, -0.20);
           Vpu_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Ipd_data : real_vector := (-0.10,  0.00,  0.10,  0.20);
           Vpd_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Igc_data : real_vector := (-0.08,  0.00,  0.00,  0.00);
           Vgc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           --------------------------------------------------------------------
           -- Vectors of the Vt curve tables
           --------------------------------------------------------------------
           Vr1_data : real_vector := (0.00,  0.00,     2.50,     2.50);
           Tr1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           Vr2_data : real_vector := (2.50,  2.50,     5.00,     5.00);
           Tr2_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           Vf1_data : real_vector := (5.00,  5.00,     2.50,     2.50);
           Tf1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           Vf2_data : real_vector := (2.50,  2.50,     0.00,     0.00);
           Tf2_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           --------------------------------------------------------------------
           -- V_fixture and R_fixture values
           --------------------------------------------------------------------
           Vfx_r1 : real := 0.0;
           Vfx_r2 : real := 5.0;
           Vfx_f1 : real := 5.0;
           Vfx_f2 : real := 0.0;

           Rfx_r1 : real := 50.0;
           Rfx_r2 : real := 50.0;
           Rfx_f1 : real := 50.0;
           Rfx_f2 : real := 50.0;
           --------------------------------------------------------------------
           -- Non IBIS parameters
           --------------------------------------------------------------------
           Max_dt : real := 1.0e-12;   -- Maximum dt between time points
           Vth_R  : real := 0.8;       -- Input threshold for rising edges
           Vth_F  : real := 0.2);      -- Input threshold for falling edges
     --------------------------------------------------------------------------
     port (terminal PU_ref : electrical;
           terminal PD_ref : electrical;

           terminal Pad    : electrical;
           terminal In_D   : electrical;

           terminal PC_ref : electrical;
           terminal GC_ref : electrical);

end entity IBIS_OUTPUT;
--=============================================================================
architecture IBIS_2EQ2UK of IBIS_OUTPUT is

  quantity  Vpc   across  Ipc   through  PC_ref  to  Pad;
  quantity  Vpu   across  Ipu   through  PU_ref  to  Pad;
  quantity  Vpd   across  Ipd   through  Pad     to  PD_ref;
  quantity  Vgc   across  Igc   through  Pad     to  GC_ref;

  quantity  Vin   across                 In_D    to  ELECTRICAL_REF;

  signal    pu_on         : integer := 0;
  signal    pu_off        : integer := 0;
  signal    pd_on         : integer := 0;
  signal    pd_off        : integer := 0;
  signal    EventState    : integer := 0;

  signal    Tpu_on_event  : real := 0.0;
  signal    Tpd_off_event : real := 0.0;
  signal    Tpd_on_event  : real := 0.0;
  signal    Tpu_off_event : real := 0.0;

  quantity  kpu           : real := 0.0;
  quantity  kpd           : real := 0.0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
  --===========================================================================
  function FindCommonLength (Max_dt : real;
                             T_r1   : real_vector;
                             T_r2   : real_vector;
                             T_f1   : real_vector;
                             T_f2   : real_vector) return integer is
  -----------------------------------------------------------------------------
  -- This function finds the total number of points needed for having a
  -- common time axis for all Vt curves, such that the maximum delta time
  -- between each time point doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_index      : integer := 1;

    variable Index_r1     : integer := T_r1'left;
    variable Index_r2     : integer := T_r2'left;
    variable Index_f1     : integer := T_f1'left;
    variable Index_f2     : integer := T_f2'left;

    variable New_index_r1 : integer := T_r1'left;
    variable New_index_r2 : integer := T_r2'left;
    variable New_index_f1 : integer := T_f1'left;
    variable New_index_f2 : integer := T_f2'left;

    variable Old_t        : real    := 0.0;
    variable Last_t       : real    := 0.0;
    variable New_t        : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_r2(T_r2'left));
    Old_t := realmin(Old_t, T_f1(T_f1'left));
    Old_t := realmin(Old_t, T_f2(T_f2'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_r2(T_r2'right));
    Last_t := realmax(New_t, T_f1(T_f1'right));
    Last_t := realmax(New_t, T_f2(T_f2'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_r2(Index_r2) <= Old_t) then New_index_r2 := Index_r2 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      if (T_f2(Index_f2) <= Old_t) then New_index_f2 := Index_f2 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_r2 <= T_r2'right) then
        if (T_r2(New_index_r2) < New_t) then New_t := T_r2(New_index_r2);
        end if;
        Index_r2 := New_index_r2;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      if (New_index_f2 <= T_f2'right) then
        if (T_f2(New_index_f2) < New_t) then New_t := T_f2(New_index_f2);
        end if;
        Index_f2 := New_index_f2;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        T_index := T_index + integer(ceil((New_t-Old_t)/Max_dt)) - 1;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
    end loop; 
    ---------------------------------------------------------------------------
    --report "Common length: " & integer'image(T_index);
    return T_index;
  end function FindCommonLength;
--=============================================================================
  function CommonTime (Common_length : integer;
                       Max_dt        : real;
                       T_r1          : real_vector;
                       T_r2          : real_vector;
                       T_f1          : real_vector;
                       T_f2          : real_vector) return real_vector is
  -----------------------------------------------------------------------------
  -- This function generates a vector that serves as a common time axis for
  -- all Vt curves, such that the maximum delta time between each time point
  -- doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_common       : real_vector(1 to Common_length) := (others => 0.0);
    variable T_index        : integer := 1;

    variable Index_r1       : integer := T_r1'left;
    variable Index_r2       : integer := T_r2'left;
    variable Index_f1       : integer := T_f1'left;
    variable Index_f2       : integer := T_f2'left;

    variable New_index_r1   : integer := T_r1'left;
    variable New_index_r2   : integer := T_r2'left;
    variable New_index_f1   : integer := T_f1'left;
    variable New_index_f2   : integer := T_f2'left;

    variable Old_t          : real    := 0.0;
    variable Last_t         : real    := 0.0;
    variable New_t          : real    := 0.0;

    variable Additional_pts : real    := 0.0;
    variable New_dt         : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_r2(T_r2'left));
    Old_t := realmin(Old_t, T_f1(T_f1'left));
    Old_t := realmin(Old_t, T_f2(T_f2'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_r2(T_r2'right));
    Last_t := realmax(New_t, T_f1(T_f1'right));
    Last_t := realmax(New_t, T_f2(T_f2'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      -------------------------------------------------------------------------
      -- Save the time value from Old_t in T_common
      -- and increment T_index counter
      -------------------------------------------------------------------------
      T_common(T_index) := Old_t;
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_r2(Index_r2) <= Old_t) then New_index_r2 := Index_r2 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      if (T_f2(Index_f2) <= Old_t) then New_index_f2 := Index_f2 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_r2 <= T_r2'right) then
        if (T_r2(New_index_r2) < New_t) then New_t := T_r2(New_index_r2);
        end if;
        Index_r2 := New_index_r2;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      if (New_index_f2 <= T_f2'right) then
        if (T_f2(New_index_f2) < New_t) then New_t := T_f2(New_index_f2);
        end if;
        Index_f2 := New_index_f2;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        Additional_pts := ceil((New_t-Old_t)/Max_dt);
        New_dt := (New_t-Old_t) / Additional_pts;
        for i in 1 to integer(Additional_pts)-1 loop
          T_common(T_index) := T_common(T_index-1) + New_dt;
          T_index := T_index + 1;
        end loop;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
      --report "T_common: " & real'image(T_common(T_index-1));
    end loop; 
    T_common(T_index) := Last_t;
    --report "T_common: " & real'image(T_common(T_index));
    ---------------------------------------------------------------------------
    --report "Length of T_common: " & integer'image(T_index);
    return T_common;
  end function CommonTime;
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_data, Tr2_data, Tf1_data, Tf2_data);

  type k_elements    is (Tcm, Kr1, Kr2, Kf1, Kf2);
  type k_tables_type is array(k_elements) of real_vector(1 to CommonLength);
--=============================================================================
  function Coeff (Common_length : integer;
                  Max_dt : real;
                  I_pc   : real_vector;
                  V_pc   : real_vector;
                  I_pu   : real_vector;
                  V_pu   : real_vector;
                  I_pd   : real_vector;
                  V_pd   : real_vector;
                  I_gc   : real_vector;
                  V_gc   : real_vector;

                  V_r1   : real_vector;
                  T_r1   : real_vector;
                  V_r2   : real_vector;
                  T_r2   : real_vector;
                  V_f1   : real_vector;
                  T_f1   : real_vector;
                  V_f2   : real_vector;
                  T_f2   : real_vector;

                  V_pc_ref : real;
                  V_pu_ref : real;
                  V_pd_ref : real;
                  V_gc_ref : real;

                  V_fx_r1  : real;
                  V_fx_r2  : real;
                  V_fx_f1  : real;
                  V_fx_f2  : real;

                  R_fx_r1  : real;
                  R_fx_r2  : real;
                  R_fx_f1  : real;
                  R_fx_f2  : real;

                  C_comp_total : real) return k_tables_type is
  -----------------------------------------------------------------------------
  -- This function converts each Vt table to a corresponding scaling
  -- coefficient table that is used to scale the IV curves with respect
  -- to time.  The C_comp effects in the waveforms are eliminated from the
  -- scaling coefficients, so that the output waveforms will match the Vt
  -- table regardless of the presence of C_comp under identical loading
  -- conditions, i.e. C_comp in the output stage will not derate the
  -- original Vt curves.
  -----------------------------------------------------------------------------
    variable K_tables : k_tables_type;

    variable Vr1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vr2cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf2cm : real_vector(1 to 3) := (others => 0.0);

    variable dVwfm_r1 : real := 0.0;
    variable dVwfm_r2 : real := 0.0;
    variable dVwfm_f1 : real := 0.0;
    variable dVwfm_f2 : real := 0.0;

    variable Iout1 : real := 0.0;
    variable Iout2 : real := 0.0;
    variable Ipc1  : real := 0.0;
    variable Ipc2  : real := 0.0;
    variable Ipu1  : real := 0.0;
    variable Ipu2  : real := 0.0;
    variable Ipd1  : real := 0.0;
    variable Ipd2  : real := 0.0;
    variable Igc1  : real := 0.0;
    variable Igc2  : real := 0.0;

    variable Term1 : real := 0.0;
    variable Term2 : real := 0.0;
    variable Den   : real := 1.0;
  -----------------------------------------------------------------------------
  begin
    K_tables(Tcm) := CommonTime(Common_length, Max_dt, T_r1, T_r2, T_f1, T_f2);
    --=========================================================================
    -- Calculate the scaling coefficients for each time point along Tcm
    ---------------------------------------------------------------------------
    -- Store the first voltage point in the common waveform variables
    ---------------------------------------------------------------------------
    Vr1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r1, V_r1, "HE");
    Vr2cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r2, V_r2, "HE");
    Vf1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f1, V_f1, "HE");
    Vf2cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f2, V_f2, "HE");

    for i in K_tables(Tcm)'range loop
    --report "Tcm: " & real'image(K_tables(Tcm)(i));  -- For debugging
    ---------------------------------------------------------------------------
    -- Store the next point (for the derivative calculations)
    ---------------------------------------------------------------------------
      if (i < K_tables(Tcm)'right) then
        Vr1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r1, V_r1, "HE");
        Vr2cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r2, V_r2, "HE");
        Vf1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f1, V_f1, "HE");
        Vf2cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f2, V_f2, "HE");
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: " & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " R1: " & real'image(Vr1cm(2)) &
      --       " R2: " & real'image(Vr2cm(2)) &
      --       " F1: " & real'image(Vf1cm(2)) &
      --       " F2: " & real'image(Vf2cm(2));
      -------------------------------------------------------------------------
      -- Calculate the derivative of each waveform for C_comp compensation
      -------------------------------------------------------------------------
      if ((i <= K_tables(Tcm)'left) or (i >= K_tables(Tcm)'right)) then
        dVwfm_r1 := 0.0;          -- Force the end point derivatives to zero
        dVwfm_r2 := 0.0;
        dVwfm_f1 := 0.0;
        dVwfm_f2 := 0.0;
      else
        dVwfm_r1 := ((Vr1cm(2) - Vr1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr1cm(3) - Vr1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_r2 := ((Vr2cm(2) - Vr2cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr2cm(3) - Vr2cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f1 := ((Vf1cm(2) - Vf1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf1cm(3) - Vf1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f2 := ((Vf2cm(2) - Vf2cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf2cm(3) - Vf2cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " dR1: " & real'image(dVwfm_r1) &
      --       " dR2: " & real'image(dVwfm_r2) &
      --       " dF1: " & real'image(dVwfm_f1) &
      --       " dF2: " & real'image(dVwfm_f2);
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kr1 Kr2 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vr1cm(2) - V_fx_r1) / R_fx_r1) + C_comp_total * dVwfm_r1;
      Iout2 := ((Vr2cm(2) - V_fx_r2) / R_fx_r2) + C_comp_total * dVwfm_r2;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vr1cm(2), V_pc, I_pc, "HE");
      Ipc2  := -1.0 * Lookup(V_pc_ref - Vr2cm(2), V_pc, I_pc, "HE");
      Ipu1  := -1.0 * Lookup(V_pu_ref - Vr1cm(2), V_pu, I_pu, "HE");
      Ipu2  := -1.0 * Lookup(V_pu_ref - Vr2cm(2), V_pu, I_pu, "HE");
      Ipd1  :=        Lookup(Vr1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Ipd2  :=        Lookup(Vr2cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vr1cm(2) - V_gc_ref, V_gc, I_gc, "HE");
      Igc2  :=        Lookup(Vr2cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      Term1 := Iout1 + Igc1 - Ipc1;
      Term2 := Ipc2  - Igc2 - Iout2;
      Den   := (Ipu1 * Ipd2) - (Ipd1 * Ipu2);

      -- Since these are rising waveforms
      -- Kr1 == Kpu_on and Kr2 == Kpd_off
      K_tables(Kr1)(i) := (Ipd2*Term1 + Ipd1*Term2) / Den;
      K_tables(Kr2)(i) := (Ipu2*Term1 + Ipu1*Term2) / Den;
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kf1 Kf2 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vf1cm(2) - V_fx_f1) / R_fx_f1) + C_comp_total * dVwfm_f1;
      Iout2 := ((Vf2cm(2) - V_fx_f2) / R_fx_f2) + C_comp_total * dVwfm_f2;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vf1cm(2), V_pc, I_pc, "HE");
      Ipc2  := -1.0 * Lookup(V_pc_ref - Vf2cm(2), V_pc, I_pc, "HE");
      Ipu1  := -1.0 * Lookup(V_pu_ref - Vf1cm(2), V_pu, I_pu, "HE");
      Ipu2  := -1.0 * Lookup(V_pu_ref - Vf2cm(2), V_pu, I_pu, "HE");
      Ipd1  :=        Lookup(Vf1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Ipd2  :=        Lookup(Vf2cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vf1cm(2) - V_gc_ref, V_gc, I_gc, "HE");
      Igc2  :=        Lookup(Vf2cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      Term1 := Iout1 + Igc1 - Ipc1;
      Term2 := Ipc2  - Igc2 - Iout2;
      Den   := (Ipu1 * Ipd2) - (Ipd1 * Ipu2);

      -- Since these are falling waveforms
      -- Kf1 == Kpd_on and Kf2 == Kpu_off
      K_tables(Kf1)(i) := (Ipu2*Term1 + Ipu1*Term2) / Den;
      K_tables(Kf2)(i) := (Ipd2*Term1 + Ipd1*Term2) / Den;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " Kr1: " & real'image(K_tables(Kr1)(i)) &
      --       " Kr2: " & real'image(K_tables(Kr2)(i)) &
      --       " Kf1: " & real'image(K_tables(Kf1)(i)) &
      --       " Kf2: " & real'image(K_tables(Kf2)(i));
      -------------------------------------------------------------------------
      -- Shift points by one index for next iteration (for C_comp compensation)
      -------------------------------------------------------------------------
      Vr1cm(1) := Vr1cm(2);
      Vr2cm(1) := Vr2cm(2);
      Vf1cm(1) := Vf1cm(2);
      Vf2cm(1) := Vf2cm(2);

      Vr1cm(2) := Vr1cm(3);
      Vr2cm(2) := Vr2cm(3);
      Vf1cm(2) := Vf1cm(3);
      Vf2cm(2) := Vf2cm(3);

    end loop; -- for loop
    ---------------------------------------------------------------------------
    return K_tables;
  end function Coeff;
--=============================================================================
  constant Ktables : k_tables_type := Coeff(CommonLength, Max_dt,
                                            Ipc_data, Vpc_data,
                                            Ipu_data, Vpu_data,
                                            Ipd_data, Vpd_data,
                                            Igc_data, Vgc_data,
                                            Vr1_data, Tr1_data,
                                            Vr2_data, Tr2_data,
                                            Vf1_data, Tf1_data,
                                            Vf2_data, Tf2_data,
                                            Vpc_ref,
                                            Vpu_ref,
                                            Vpd_ref,
                                            Vgc_ref,
                                            Vfx_r1,
                                            Vfx_r2,
                                            Vfx_f1,
                                            Vfx_f2,
                                            Rfx_r1,
                                            Rfx_r2,
                                            Rfx_f1,
                                            Rfx_f2,
                                            C_comp);
--=============================================================================
begin

  Catch: process is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if domain = quiescent_domain then

      wait until domain /= quiescent_domain;
      EventState <= 1;

    else

      wait on Vin'above(Vth_R), Vin'above(Vth_F);

      if ((Vin > Vth_R) or (Vin < Vth_F)) then

        if   EventState < 3 then  EventState <= EventState+1;
        else                      EventState <= EventState-1;
        end if;

      end if;
    end if;
  -----------------------------------------------------------------------------
  end process Catch;
  --===========================================================================
  FindState: process (EventState) is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if (Vin > Vth_R) then                             -- high state
      pu_on  <= 1;
      pd_off <= 1;
      pd_on  <= 0;
      pu_off <= 0;
    elsif (Vin < Vth_F) then                          -- low state
      pu_on  <= 0;
      pd_off <= 0;
      pd_on  <= 1;
      pu_off <= 1;
    else                                              -- unknown state
      pu_on  <= 1;
      pd_off <= 0;
      pd_on  <= 1;
      pu_off <= 0;
    end if;
  -----------------------------------------------------------------------------
  end process FindState;
--=============================================================================
  break on pu_on;
  break on pu_off;
  break on pd_on;
  break on pd_off;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-- This entire section could be made more efficient with nested IF statements
-- if the simulator wouldn't have a problem with simultaneous statements in
-- nested case statements.
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Vin > Vth_R) use                  -- high state
    kpu == Ktables(Kr1)(CommonLength);
  elsif (EventState = 0) and (Vin < Vth_F) use                  -- low state
    kpu == Ktables(Kf2)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pu_off = 1) use
    kpu == Ktables(Kf2)(CommonLength);      -- Last point from pu_off table
  elsif (EventState = 1) and (pu_off /= 1)use
    kpu == Ktables(Kr1)(CommonLength);      -- Last point from pu_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pu_on  = 1) use    -- Pullup turning on
    kpu == Lookup(pu_on'last_event,  Ktables(Tcm), Ktables(Kr1), "HE");
  elsif (EventState > 1) and (pu_off = 1) use    -- Pullup turning off
    kpu == Lookup(pu_off'last_event, Ktables(Tcm), Ktables(Kf2), "HE");

  -- Just in case
  else
    kpu == Ktables(Kr1)(Ktables(Kr1)'left); -- 1st point of pullup on table
  end use;


  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Vin > Vth_R) use                  -- high state
    kpd == Ktables(Kr2)(CommonLength);
  elsif (EventState = 0) and (Vin < Vth_F) use                  -- low state
    kpd == Ktables(Kf1)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pd_off = 1) use
    kpd == Ktables(Kr2)(CommonLength);      -- Last point from pd_off table
  elsif (EventState = 1) and (pd_off /= 1)use
    kpd == Ktables(Kf1)(CommonLength);      -- Last point from pd_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pd_on  = 1) use    -- Pulldown turning on
    kpd == Lookup(pd_on'last_event,  Ktables(Tcm), Ktables(Kf1), "HE");
  elsif (EventState > 1) and (pd_off = 1) use    -- Pulldown turning off
    kpd == Lookup(pd_off'last_event, Ktables(Tcm), Ktables(Kr2), "HE");

  -- Just in case
  else
    kpd == Ktables(Kf1)(Ktables(Kf1)'left); -- 1st point of pulldown on table
  end use;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc   == -1.0    *Lookup(Vpc, Vpc_data, Ipc_data, "SE");-- + kC_comp_pc*C_comp*Vpc'dot; 
  Ipu   == -1.0*kpu*Lookup(Vpu, Vpu_data, Ipu_data, "SE");-- + kC_comp_pu*C_comp*Vpu'dot; 
  Ipd   ==      kpd*Lookup(Vpd, Vpd_data, Ipd_data, "SE");-- + kC_comp_pd*C_comp*Vpd'dot;
  Igc   ==          Lookup(Vgc, Vgc_data, Igc_data, "SE");-- + kC_comp_gc*C_comp*Vgc'dot;
--=============================================================================
end architecture IBIS_2EQ2UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
entity IBIS_IO is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.00;       -- splitting coefficients
           kC_comp_pu : real := 0.50;
           kC_comp_pd : real := 0.50;
           kC_comp_gc : real := 0.00;
           --------------------------------------------------------------------
           -- Receiver thresholds
           --------------------------------------------------------------------
           Vinh : real := 2.00;
           Vinl : real := 0.80;
           --------------------------------------------------------------------
           -- [Pullup Reference] and [Pulldown Reference] values
           --------------------------------------------------------------------
           Vpc_ref : real := 5.0;
           Vpu_ref : real := 5.0;
           Vpd_ref : real := 0.0;
           Vgc_ref : real := 0.0;
           --------------------------------------------------------------------
           -- Vectors of the IV curve tables
           --------------------------------------------------------------------
           Ipc_data : real_vector := ( 0.08,  0.00,  0.00,  0.00);
           Vpc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           Ipu_data : real_vector := ( 0.10,  0.00, -0.10, -0.20);
           Vpu_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Ipd_data : real_vector := (-0.10,  0.00,  0.10,  0.20);
           Vpd_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Igc_data : real_vector := (-0.08,  0.00,  0.00,  0.00);
           Vgc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           --------------------------------------------------------------------
           -- Vectors of the Vt curve tables
           --------------------------------------------------------------------
           Vr1_data : real_vector := (0.00,  0.00,     2.50,     2.50);
           Tr1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           Vr2_data : real_vector := (2.50,  2.50,     5.00,     5.00);
           Tr2_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           Vf1_data : real_vector := (5.00,  5.00,     2.50,     2.50);
           Tf1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           Vf2_data : real_vector := (2.50,  2.50,     0.00,     0.00);
           Tf2_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           --------------------------------------------------------------------
           -- V_fixture and R_fixture values
           --------------------------------------------------------------------
           Vfx_r1 : real := 0.0;
           Vfx_r2 : real := 5.0;
           Vfx_f1 : real := 5.0;
           Vfx_f2 : real := 0.0;

           Rfx_r1 : real := 50.0;
           Rfx_r2 : real := 50.0;
           Rfx_f1 : real := 50.0;
           Rfx_f2 : real := 50.0;
           --------------------------------------------------------------------
           -- Non IBIS parameters
           --------------------------------------------------------------------
           Max_dt : real := 1.0e-12;   -- Maximum dt between time points
           Vth_R  : real := 0.8;       -- Input threshold for rising edges
           Vth_F  : real := 0.2);      -- Input threshold for falling edges
     --------------------------------------------------------------------------
     port (terminal PU_ref : electrical;
           terminal PD_ref : electrical;

           terminal Pad    : electrical;
           terminal In_D   : electrical;
           terminal En_D   : electrical;
--           terminal Rcv_D  : electrical;

           terminal PC_ref : electrical;
           terminal GC_ref : electrical);

end entity IBIS_IO;
--=============================================================================
architecture IBIS_2EQ2UK of IBIS_IO is

  quantity  Vpc   across  Ipc   through  PC_ref  to  Pad;
  quantity  Vpu   across  Ipu   through  PU_ref  to  Pad;
  quantity  Vpd   across  Ipd   through  Pad     to  PD_ref;
  quantity  Vgc   across  Igc   through  Pad     to  GC_ref;

  quantity  Vin   across                 In_D    to  ELECTRICAL_REF;
  quantity  Ven   across                 En_D    to  ELECTRICAL_REF;
--  quantity  Vrcv  across  Ircv  through  Rcv_D   to  ELECTRICAL_REF;

  signal    pu_on         : integer := 0;
  signal    pu_off        : integer := 0;
  signal    pd_on         : integer := 0;
  signal    pd_off        : integer := 0;
  signal    EventState    : integer := 0;

  signal    Tpu_on_event  : real := 0.0;
  signal    Tpd_off_event : real := 0.0;
  signal    Tpd_on_event  : real := 0.0;
  signal    Tpu_off_event : real := 0.0;

  quantity  kpu           : real := 0.0;
  quantity  kpd           : real := 0.0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
  --===========================================================================
  function FindCommonLength (Max_dt : real;
                             T_r1   : real_vector;
                             T_r2   : real_vector;
                             T_f1   : real_vector;
                             T_f2   : real_vector) return integer is
  -----------------------------------------------------------------------------
  -- This function finds the total number of points needed for having a
  -- common time axis for all Vt curves, such that the maximum delta time
  -- between each time point doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_index      : integer := 1;

    variable Index_r1     : integer := T_r1'left;
    variable Index_r2     : integer := T_r2'left;
    variable Index_f1     : integer := T_f1'left;
    variable Index_f2     : integer := T_f2'left;

    variable New_index_r1 : integer := T_r1'left;
    variable New_index_r2 : integer := T_r2'left;
    variable New_index_f1 : integer := T_f1'left;
    variable New_index_f2 : integer := T_f2'left;

    variable Old_t        : real    := 0.0;
    variable Last_t       : real    := 0.0;
    variable New_t        : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_r2(T_r2'left));
    Old_t := realmin(Old_t, T_f1(T_f1'left));
    Old_t := realmin(Old_t, T_f2(T_f2'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_r2(T_r2'right));
    Last_t := realmax(New_t, T_f1(T_f1'right));
    Last_t := realmax(New_t, T_f2(T_f2'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_r2(Index_r2) <= Old_t) then New_index_r2 := Index_r2 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      if (T_f2(Index_f2) <= Old_t) then New_index_f2 := Index_f2 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_r2 <= T_r2'right) then
        if (T_r2(New_index_r2) < New_t) then New_t := T_r2(New_index_r2);
        end if;
        Index_r2 := New_index_r2;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      if (New_index_f2 <= T_f2'right) then
        if (T_f2(New_index_f2) < New_t) then New_t := T_f2(New_index_f2);
        end if;
        Index_f2 := New_index_f2;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        T_index := T_index + integer(ceil((New_t-Old_t)/Max_dt)) - 1;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
    end loop; 
    ---------------------------------------------------------------------------
    --report "Common length: " & integer'image(T_index);
    return T_index;
  end function FindCommonLength;
--=============================================================================
  function CommonTime (Common_length : integer;
                       Max_dt        : real;
                       T_r1          : real_vector;
                       T_r2          : real_vector;
                       T_f1          : real_vector;
                       T_f2          : real_vector) return real_vector is
  -----------------------------------------------------------------------------
  -- This function generates a vector that serves as a common time axis for
  -- all Vt curves, such that the maximum delta time between each time point
  -- doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_common       : real_vector(1 to Common_length) := (others => 0.0);
    variable T_index        : integer := 1;

    variable Index_r1       : integer := T_r1'left;
    variable Index_r2       : integer := T_r2'left;
    variable Index_f1       : integer := T_f1'left;
    variable Index_f2       : integer := T_f2'left;

    variable New_index_r1   : integer := T_r1'left;
    variable New_index_r2   : integer := T_r2'left;
    variable New_index_f1   : integer := T_f1'left;
    variable New_index_f2   : integer := T_f2'left;

    variable Old_t          : real    := 0.0;
    variable Last_t         : real    := 0.0;
    variable New_t          : real    := 0.0;

    variable Additional_pts : real    := 0.0;
    variable New_dt         : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_r2(T_r2'left));
    Old_t := realmin(Old_t, T_f1(T_f1'left));
    Old_t := realmin(Old_t, T_f2(T_f2'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_r2(T_r2'right));
    Last_t := realmax(New_t, T_f1(T_f1'right));
    Last_t := realmax(New_t, T_f2(T_f2'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      -------------------------------------------------------------------------
      -- Save the time value from Old_t in T_common
      -- and increment T_index counter
      -------------------------------------------------------------------------
      T_common(T_index) := Old_t;
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_r2(Index_r2) <= Old_t) then New_index_r2 := Index_r2 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      if (T_f2(Index_f2) <= Old_t) then New_index_f2 := Index_f2 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_r2 <= T_r2'right) then
        if (T_r2(New_index_r2) < New_t) then New_t := T_r2(New_index_r2);
        end if;
        Index_r2 := New_index_r2;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      if (New_index_f2 <= T_f2'right) then
        if (T_f2(New_index_f2) < New_t) then New_t := T_f2(New_index_f2);
        end if;
        Index_f2 := New_index_f2;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        Additional_pts := ceil((New_t-Old_t)/Max_dt);
        New_dt := (New_t-Old_t) / Additional_pts;
        for i in 1 to integer(Additional_pts)-1 loop
          T_common(T_index) := T_common(T_index-1) + New_dt;
          T_index := T_index + 1;
        end loop;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
      --report "T_common: " & real'image(T_common(T_index-1));
    end loop; 
    T_common(T_index) := Last_t;
    --report "T_common: " & real'image(T_common(T_index));
    ---------------------------------------------------------------------------
    --report "Length of T_common: " & integer'image(T_index);
    return T_common;
  end function CommonTime;
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_data, Tr2_data, Tf1_data, Tf2_data);

  type k_elements    is (Tcm, Kr1, Kr2, Kf1, Kf2);
  type k_tables_type is array(k_elements) of real_vector(1 to CommonLength);
--=============================================================================
  function Coeff (Common_length : integer;
                  Max_dt : real;
                  I_pc   : real_vector;
                  V_pc   : real_vector;
                  I_pu   : real_vector;
                  V_pu   : real_vector;
                  I_pd   : real_vector;
                  V_pd   : real_vector;
                  I_gc   : real_vector;
                  V_gc   : real_vector;

                  V_r1   : real_vector;
                  T_r1   : real_vector;
                  V_r2   : real_vector;
                  T_r2   : real_vector;
                  V_f1   : real_vector;
                  T_f1   : real_vector;
                  V_f2   : real_vector;
                  T_f2   : real_vector;

                  V_pc_ref : real;
                  V_pu_ref : real;
                  V_pd_ref : real;
                  V_gc_ref : real;

                  V_fx_r1  : real;
                  V_fx_r2  : real;
                  V_fx_f1  : real;
                  V_fx_f2  : real;

                  R_fx_r1  : real;
                  R_fx_r2  : real;
                  R_fx_f1  : real;
                  R_fx_f2  : real;

                  C_comp_total : real) return k_tables_type is
  -----------------------------------------------------------------------------
  -- This function converts each Vt table to a corresponding scaling
  -- coefficient table that is used to scale the IV curves with respect
  -- to time.  The C_comp effects in the waveforms are eliminated from the
  -- scaling coefficients, so that the output waveforms will match the Vt
  -- table regardless of the presence of C_comp under identical loading
  -- conditions, i.e. C_comp in the output stage will not derate the
  -- original Vt curves.
  -----------------------------------------------------------------------------
    variable K_tables : k_tables_type;

    variable Vr1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vr2cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf2cm : real_vector(1 to 3) := (others => 0.0);

    variable dVwfm_r1 : real := 0.0;
    variable dVwfm_r2 : real := 0.0;
    variable dVwfm_f1 : real := 0.0;
    variable dVwfm_f2 : real := 0.0;

    variable Iout1 : real := 0.0;
    variable Iout2 : real := 0.0;
    variable Ipc1  : real := 0.0;
    variable Ipc2  : real := 0.0;
    variable Ipu1  : real := 0.0;
    variable Ipu2  : real := 0.0;
    variable Ipd1  : real := 0.0;
    variable Ipd2  : real := 0.0;
    variable Igc1  : real := 0.0;
    variable Igc2  : real := 0.0;

    variable Term1 : real := 0.0;
    variable Term2 : real := 0.0;
    variable Den   : real := 1.0;
  -----------------------------------------------------------------------------
  begin
    K_tables(Tcm) := CommonTime(Common_length, Max_dt, T_r1, T_r2, T_f1, T_f2);
    --=========================================================================
    -- Calculate the scaling coefficients for each time point along Tcm
    ---------------------------------------------------------------------------
    -- Store the first voltage point in the common waveform variables
    ---------------------------------------------------------------------------
    Vr1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r1, V_r1, "HE");
    Vr2cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r2, V_r2, "HE");
    Vf1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f1, V_f1, "HE");
    Vf2cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f2, V_f2, "HE");

    for i in K_tables(Tcm)'range loop
    --report "Tcm: " & real'image(K_tables(Tcm)(i));  -- For debugging
    ---------------------------------------------------------------------------
    -- Store the next point (for the derivative calculations)
    ---------------------------------------------------------------------------
      if (i < K_tables(Tcm)'right) then
        Vr1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r1, V_r1, "HE");
        Vr2cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r2, V_r2, "HE");
        Vf1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f1, V_f1, "HE");
        Vf2cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f2, V_f2, "HE");
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: " & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " R1: " & real'image(Vr1cm(2)) &
      --       " R2: " & real'image(Vr2cm(2)) &
      --       " F1: " & real'image(Vf1cm(2)) &
      --       " F2: " & real'image(Vf2cm(2));
      -------------------------------------------------------------------------
      -- Calculate the derivative of each waveform for C_comp compensation
      -------------------------------------------------------------------------
      if ((i <= K_tables(Tcm)'left) or (i >= K_tables(Tcm)'right)) then
        dVwfm_r1 := 0.0;          -- Force the end point derivatives to zero
        dVwfm_r2 := 0.0;
        dVwfm_f1 := 0.0;
        dVwfm_f2 := 0.0;
      else
        dVwfm_r1 := ((Vr1cm(2) - Vr1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr1cm(3) - Vr1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_r2 := ((Vr2cm(2) - Vr2cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr2cm(3) - Vr2cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f1 := ((Vf1cm(2) - Vf1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf1cm(3) - Vf1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f2 := ((Vf2cm(2) - Vf2cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf2cm(3) - Vf2cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " dR1: " & real'image(dVwfm_r1) &
      --       " dR2: " & real'image(dVwfm_r2) &
      --       " dF1: " & real'image(dVwfm_f1) &
      --       " dF2: " & real'image(dVwfm_f2);
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kr1 Kr2 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vr1cm(2) - V_fx_r1) / R_fx_r1) + C_comp_total * dVwfm_r1;
      Iout2 := ((Vr2cm(2) - V_fx_r2) / R_fx_r2) + C_comp_total * dVwfm_r2;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vr1cm(2), V_pc, I_pc, "HE");
      Ipc2  := -1.0 * Lookup(V_pc_ref - Vr2cm(2), V_pc, I_pc, "HE");
      Ipu1  := -1.0 * Lookup(V_pu_ref - Vr1cm(2), V_pu, I_pu, "HE");
      Ipu2  := -1.0 * Lookup(V_pu_ref - Vr2cm(2), V_pu, I_pu, "HE");
      Ipd1  :=        Lookup(Vr1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Ipd2  :=        Lookup(Vr2cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vr1cm(2) - V_gc_ref, V_gc, I_gc, "HE");
      Igc2  :=        Lookup(Vr2cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      Term1 := Iout1 + Igc1 - Ipc1;
      Term2 := Ipc2  - Igc2 - Iout2;
      Den   := (Ipu1 * Ipd2) - (Ipd1 * Ipu2);

      -- Since these are rising waveforms
      -- Kr1 == Kpu_on and Kr2 == Kpd_off
      K_tables(Kr1)(i) := (Ipd2*Term1 + Ipd1*Term2) / Den;
      K_tables(Kr2)(i) := (Ipu2*Term1 + Ipu1*Term2) / Den;
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kf1 Kf2 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vf1cm(2) - V_fx_f1) / R_fx_f1) + C_comp_total * dVwfm_f1;
      Iout2 := ((Vf2cm(2) - V_fx_f2) / R_fx_f2) + C_comp_total * dVwfm_f2;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vf1cm(2), V_pc, I_pc, "HE");
      Ipc2  := -1.0 * Lookup(V_pc_ref - Vf2cm(2), V_pc, I_pc, "HE");
      Ipu1  := -1.0 * Lookup(V_pu_ref - Vf1cm(2), V_pu, I_pu, "HE");
      Ipu2  := -1.0 * Lookup(V_pu_ref - Vf2cm(2), V_pu, I_pu, "HE");
      Ipd1  :=        Lookup(Vf1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Ipd2  :=        Lookup(Vf2cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vf1cm(2) - V_gc_ref, V_gc, I_gc, "HE");
      Igc2  :=        Lookup(Vf2cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      Term1 := Iout1 + Igc1 - Ipc1;
      Term2 := Ipc2  - Igc2 - Iout2;
      Den   := (Ipu1 * Ipd2) - (Ipd1 * Ipu2);

      -- Since these are falling waveforms
      -- Kf1 == Kpd_on and Kf2 == Kpu_off
      K_tables(Kf1)(i) := (Ipu2*Term1 + Ipu1*Term2) / Den;
      K_tables(Kf2)(i) := (Ipd2*Term1 + Ipd1*Term2) / Den;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " Kr1: " & real'image(K_tables(Kr1)(i)) &
      --       " Kr2: " & real'image(K_tables(Kr2)(i)) &
      --       " Kf1: " & real'image(K_tables(Kf1)(i)) &
      --       " Kf2: " & real'image(K_tables(Kf2)(i));
      -------------------------------------------------------------------------
      -- Shift points by one index for next iteration (for C_comp compensation)
      -------------------------------------------------------------------------
      Vr1cm(1) := Vr1cm(2);
      Vr2cm(1) := Vr2cm(2);
      Vf1cm(1) := Vf1cm(2);
      Vf2cm(1) := Vf2cm(2);

      Vr1cm(2) := Vr1cm(3);
      Vr2cm(2) := Vr2cm(3);
      Vf1cm(2) := Vf1cm(3);
      Vf2cm(2) := Vf2cm(3);

    end loop; -- for loop
    ---------------------------------------------------------------------------
    return K_tables;
  end function Coeff;
--=============================================================================
  constant Ktables : k_tables_type := Coeff(CommonLength, Max_dt,
                                            Ipc_data, Vpc_data,
                                            Ipu_data, Vpu_data,
                                            Ipd_data, Vpd_data,
                                            Igc_data, Vgc_data,
                                            Vr1_data, Tr1_data,
                                            Vr2_data, Tr2_data,
                                            Vf1_data, Tf1_data,
                                            Vf2_data, Tf2_data,
                                            Vpc_ref,
                                            Vpu_ref,
                                            Vpd_ref,
                                            Vgc_ref,
                                            Vfx_r1,
                                            Vfx_r2,
                                            Vfx_f1,
                                            Vfx_f2,
                                            Rfx_r1,
                                            Rfx_r2,
                                            Rfx_f1,
                                            Rfx_f2,
                                            C_comp);
--=============================================================================
begin

  Catch: process is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if domain = quiescent_domain then

      wait until domain /= quiescent_domain;
      EventState <= 1;

    else

      wait on Vin'above(Vth_R), Vin'above(Vth_F),
              Ven'above(Vth_R), Ven'above(Vth_F);

      if ((Vin > Vth_R) or (Vin < Vth_F)) and
         ((Ven > Vth_R) or (Ven < Vth_F)) then

        if   EventState < 3 then  EventState <= EventState+1;
        else                      EventState <= EventState-1;
        end if;

      end if;
    end if;
  -----------------------------------------------------------------------------
  end process Catch;
  --===========================================================================
  FindState: process (EventState) is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if (Ven > Vth_R) and (Vin > Vth_R) then           -- high state
      pu_on  <= 1;
      pd_off <= 1;
      pd_on  <= 0;
      pu_off <= 0;
    elsif (Ven > Vth_R) and (Vin < Vth_F) then        -- low state
      pu_on  <= 0;
      pd_off <= 0;
      pd_on  <= 1;
      pu_off <= 1;
    elsif (Ven < Vth_F) then                          -- 3-state
      pu_on  <= 0;
      pd_off <= 1;
      pd_on  <= 0;
      pu_off <= 1;
    else                                              -- unknown state
      pu_on  <= 1;
      pd_off <= 0;
      pd_on  <= 1;
      pu_off <= 0;
    end if;
  -----------------------------------------------------------------------------
  end process FindState;
--=============================================================================
  break on pu_on;
  break on pu_off;
  break on pd_on;
  break on pd_off;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-- This entire section could be made more efficient with nested IF statements
-- if the simulator wouldn't have a problem with simultaneous statements in
-- nested case statements.
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Ven > Vth_R) and (Vin > Vth_R) use   -- high state
    kpu == Ktables(Kr1)(CommonLength);
  elsif (EventState = 0) and (Ven > Vth_R) and (Vin < Vth_F) use   -- low state
    kpu == Ktables(Kf2)(CommonLength);
  elsif (EventState = 0) and (Ven < Vth_F) use                     -- 3-state
    kpu == Ktables(Kf2)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pu_off = 1) use
    kpu == Ktables(Kf2)(CommonLength);      -- Last point from pu_off table
  elsif (EventState = 1) and (pu_off /= 1)use
    kpu == Ktables(Kr1)(CommonLength);      -- Last point from pu_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pu_on  = 1) use    -- Pullup turning on
    kpu == Lookup(pu_on'last_event,  Ktables(Tcm), Ktables(Kr1), "HE");
  elsif (EventState > 1) and (pu_off = 1) use    -- Pullup turning off
    kpu == Lookup(pu_off'last_event, Ktables(Tcm), Ktables(Kf2), "HE");

  -- Just in case
  else
    kpu == Ktables(Kr1)(Ktables(Kr1)'left); -- 1st point of pullup on table
  end use;


  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Ven > Vth_R) and (Vin > Vth_R) use   -- high state
    kpd == Ktables(Kr2)(CommonLength);
  elsif (EventState = 0) and (Ven > Vth_R) and (Vin < Vth_F) use   -- low state
    kpd == Ktables(Kf1)(CommonLength);
  elsif (EventState = 0) and (Ven < Vth_F) use                     -- 3-state
    kpd == Ktables(Kr2)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pd_off = 1) use
    kpd == Ktables(Kr2)(CommonLength);      -- Last point from pd_off table
  elsif (EventState = 1) and (pd_off /= 1)use
    kpd == Ktables(Kf1)(CommonLength);      -- Last point from pd_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pd_on  = 1) use    -- Pulldown turning on
    kpd == Lookup(pd_on'last_event,  Ktables(Tcm), Ktables(Kf1), "HE");
  elsif (EventState > 1) and (pd_off = 1) use    -- Pulldown turning off
    kpd == Lookup(pd_off'last_event, Ktables(Tcm), Ktables(Kr2), "HE");

  -- Just in case
  else
    kpd == Ktables(Kf1)(Ktables(Kf1)'left); -- 1st point of pulldown on table
  end use;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc   == -1.0    *Lookup(Vpc, Vpc_data, Ipc_data, "SE");-- + kC_comp_pc*C_comp*Vpc'dot; 
  Ipu   == -1.0*kpu*Lookup(Vpu, Vpu_data, Ipu_data, "SE");-- + kC_comp_pu*C_comp*Vpu'dot; 
  Ipd   ==      kpd*Lookup(Vpd, Vpd_data, Ipd_data, "SE");-- + kC_comp_pd*C_comp*Vpd'dot;
  Igc   ==          Lookup(Vgc, Vgc_data, Igc_data, "SE");-- + kC_comp_gc*C_comp*Vgc'dot;
  -----------------------------------------------------------------------------
  -- A simple receiver logic
  -----------------------------------------------------------------------------
--  if    (Vpd > Vinh) use Vrcv == 1.0;
--  elsif (Vpd < Vinl) use Vrcv == 0.0;
--  else                   Vrcv == 0.5;
--  end use;
--=============================================================================
end architecture IBIS_2EQ2UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
entity IBIS_3STATE is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.00;       -- splitting coefficients
           kC_comp_pu : real := 0.50;
           kC_comp_pd : real := 0.50;
           kC_comp_gc : real := 0.00;
           --------------------------------------------------------------------
           -- [Pullup Reference] and [Pulldown Reference] values
           --------------------------------------------------------------------
           Vpc_ref : real := 5.0;
           Vpu_ref : real := 5.0;
           Vpd_ref : real := 0.0;
           Vgc_ref : real := 0.0;
           --------------------------------------------------------------------
           -- Vectors of the IV curve tables
           --------------------------------------------------------------------
           Ipc_data : real_vector := ( 0.08,  0.00,  0.00,  0.00);
           Vpc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           Ipu_data : real_vector := ( 0.10,  0.00, -0.10, -0.20);
           Vpu_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Ipd_data : real_vector := (-0.10,  0.00,  0.10,  0.20);
           Vpd_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Igc_data : real_vector := (-0.08,  0.00,  0.00,  0.00);
           Vgc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           --------------------------------------------------------------------
           -- Vectors of the Vt curve tables
           --------------------------------------------------------------------
           Vr1_data : real_vector := (0.00,  0.00,     2.50,     2.50);
           Tr1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           Vr2_data : real_vector := (2.50,  2.50,     5.00,     5.00);
           Tr2_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           Vf1_data : real_vector := (5.00,  5.00,     2.50,     2.50);
           Tf1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           Vf2_data : real_vector := (2.50,  2.50,     0.00,     0.00);
           Tf2_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           --------------------------------------------------------------------
           -- V_fixture and R_fixture values
           --------------------------------------------------------------------
           Vfx_r1 : real := 0.0;
           Vfx_r2 : real := 5.0;
           Vfx_f1 : real := 5.0;
           Vfx_f2 : real := 0.0;

           Rfx_r1 : real := 50.0;
           Rfx_r2 : real := 50.0;
           Rfx_f1 : real := 50.0;
           Rfx_f2 : real := 50.0;
           --------------------------------------------------------------------
           -- Non IBIS parameters
           --------------------------------------------------------------------
           Max_dt : real := 1.0e-12;   -- Maximum dt between time points
           Vth_R  : real := 0.8;       -- Input threshold for rising edges
           Vth_F  : real := 0.2);      -- Input threshold for falling edges
     --------------------------------------------------------------------------
     port (terminal PU_ref : electrical;
           terminal PD_ref : electrical;

           terminal Pad    : electrical;
           terminal In_D   : electrical;
           terminal En_D   : electrical;

           terminal PC_ref : electrical;
           terminal GC_ref : electrical);

end entity IBIS_3STATE;
--=============================================================================
architecture IBIS_2EQ2UK of IBIS_3STATE is

  quantity  Vpc   across  Ipc   through  PC_ref  to  Pad;
  quantity  Vpu   across  Ipu   through  PU_ref  to  Pad;
  quantity  Vpd   across  Ipd   through  Pad     to  PD_ref;
  quantity  Vgc   across  Igc   through  Pad     to  GC_ref;

  quantity  Vin   across                 In_D    to  ELECTRICAL_REF;
  quantity  Ven   across                 En_D    to  ELECTRICAL_REF;

  signal    pu_on         : integer := 0;
  signal    pu_off        : integer := 0;
  signal    pd_on         : integer := 0;
  signal    pd_off        : integer := 0;
  signal    EventState    : integer := 0;

  signal    Tpu_on_event  : real := 0.0;
  signal    Tpd_off_event : real := 0.0;
  signal    Tpd_on_event  : real := 0.0;
  signal    Tpu_off_event : real := 0.0;

  quantity  kpu           : real := 0.0;
  quantity  kpd           : real := 0.0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
  --===========================================================================
  function FindCommonLength (Max_dt : real;
                             T_r1   : real_vector;
                             T_r2   : real_vector;
                             T_f1   : real_vector;
                             T_f2   : real_vector) return integer is
  -----------------------------------------------------------------------------
  -- This function finds the total number of points needed for having a
  -- common time axis for all Vt curves, such that the maximum delta time
  -- between each time point doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_index      : integer := 1;

    variable Index_r1     : integer := T_r1'left;
    variable Index_r2     : integer := T_r2'left;
    variable Index_f1     : integer := T_f1'left;
    variable Index_f2     : integer := T_f2'left;

    variable New_index_r1 : integer := T_r1'left;
    variable New_index_r2 : integer := T_r2'left;
    variable New_index_f1 : integer := T_f1'left;
    variable New_index_f2 : integer := T_f2'left;

    variable Old_t        : real    := 0.0;
    variable Last_t       : real    := 0.0;
    variable New_t        : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_r2(T_r2'left));
    Old_t := realmin(Old_t, T_f1(T_f1'left));
    Old_t := realmin(Old_t, T_f2(T_f2'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_r2(T_r2'right));
    Last_t := realmax(New_t, T_f1(T_f1'right));
    Last_t := realmax(New_t, T_f2(T_f2'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_r2(Index_r2) <= Old_t) then New_index_r2 := Index_r2 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      if (T_f2(Index_f2) <= Old_t) then New_index_f2 := Index_f2 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_r2 <= T_r2'right) then
        if (T_r2(New_index_r2) < New_t) then New_t := T_r2(New_index_r2);
        end if;
        Index_r2 := New_index_r2;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      if (New_index_f2 <= T_f2'right) then
        if (T_f2(New_index_f2) < New_t) then New_t := T_f2(New_index_f2);
        end if;
        Index_f2 := New_index_f2;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        T_index := T_index + integer(ceil((New_t-Old_t)/Max_dt)) - 1;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
    end loop; 
    ---------------------------------------------------------------------------
    --report "Common length: " & integer'image(T_index);
    return T_index;
  end function FindCommonLength;
--=============================================================================
  function CommonTime (Common_length : integer;
                       Max_dt        : real;
                       T_r1          : real_vector;
                       T_r2          : real_vector;
                       T_f1          : real_vector;
                       T_f2          : real_vector) return real_vector is
  -----------------------------------------------------------------------------
  -- This function generates a vector that serves as a common time axis for
  -- all Vt curves, such that the maximum delta time between each time point
  -- doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_common       : real_vector(1 to Common_length) := (others => 0.0);
    variable T_index        : integer := 1;

    variable Index_r1       : integer := T_r1'left;
    variable Index_r2       : integer := T_r2'left;
    variable Index_f1       : integer := T_f1'left;
    variable Index_f2       : integer := T_f2'left;

    variable New_index_r1   : integer := T_r1'left;
    variable New_index_r2   : integer := T_r2'left;
    variable New_index_f1   : integer := T_f1'left;
    variable New_index_f2   : integer := T_f2'left;

    variable Old_t          : real    := 0.0;
    variable Last_t         : real    := 0.0;
    variable New_t          : real    := 0.0;

    variable Additional_pts : real    := 0.0;
    variable New_dt         : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_r2(T_r2'left));
    Old_t := realmin(Old_t, T_f1(T_f1'left));
    Old_t := realmin(Old_t, T_f2(T_f2'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_r2(T_r2'right));
    Last_t := realmax(New_t, T_f1(T_f1'right));
    Last_t := realmax(New_t, T_f2(T_f2'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      -------------------------------------------------------------------------
      -- Save the time value from Old_t in T_common
      -- and increment T_index counter
      -------------------------------------------------------------------------
      T_common(T_index) := Old_t;
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_r2(Index_r2) <= Old_t) then New_index_r2 := Index_r2 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      if (T_f2(Index_f2) <= Old_t) then New_index_f2 := Index_f2 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_r2 <= T_r2'right) then
        if (T_r2(New_index_r2) < New_t) then New_t := T_r2(New_index_r2);
        end if;
        Index_r2 := New_index_r2;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      if (New_index_f2 <= T_f2'right) then
        if (T_f2(New_index_f2) < New_t) then New_t := T_f2(New_index_f2);
        end if;
        Index_f2 := New_index_f2;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        Additional_pts := ceil((New_t-Old_t)/Max_dt);
        New_dt := (New_t-Old_t) / Additional_pts;
        for i in 1 to integer(Additional_pts)-1 loop
          T_common(T_index) := T_common(T_index-1) + New_dt;
          T_index := T_index + 1;
        end loop;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
      --report "T_common: " & real'image(T_common(T_index-1));
    end loop; 
    T_common(T_index) := Last_t;
    --report "T_common: " & real'image(T_common(T_index));
    ---------------------------------------------------------------------------
    --report "Length of T_common: " & integer'image(T_index);
    return T_common;
  end function CommonTime;
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_data, Tr2_data, Tf1_data, Tf2_data);

  type k_elements    is (Tcm, Kr1, Kr2, Kf1, Kf2);
  type k_tables_type is array(k_elements) of real_vector(1 to CommonLength);
--=============================================================================
  function Coeff (Common_length : integer;
                  Max_dt : real;
                  I_pc   : real_vector;
                  V_pc   : real_vector;
                  I_pu   : real_vector;
                  V_pu   : real_vector;
                  I_pd   : real_vector;
                  V_pd   : real_vector;
                  I_gc   : real_vector;
                  V_gc   : real_vector;

                  V_r1   : real_vector;
                  T_r1   : real_vector;
                  V_r2   : real_vector;
                  T_r2   : real_vector;
                  V_f1   : real_vector;
                  T_f1   : real_vector;
                  V_f2   : real_vector;
                  T_f2   : real_vector;

                  V_pc_ref : real;
                  V_pu_ref : real;
                  V_pd_ref : real;
                  V_gc_ref : real;

                  V_fx_r1  : real;
                  V_fx_r2  : real;
                  V_fx_f1  : real;
                  V_fx_f2  : real;

                  R_fx_r1  : real;
                  R_fx_r2  : real;
                  R_fx_f1  : real;
                  R_fx_f2  : real;

                  C_comp_total : real) return k_tables_type is
  -----------------------------------------------------------------------------
  -- This function converts each Vt table to a corresponding scaling
  -- coefficient table that is used to scale the IV curves with respect
  -- to time.  The C_comp effects in the waveforms are eliminated from the
  -- scaling coefficients, so that the output waveforms will match the Vt
  -- table regardless of the presence of C_comp under identical loading
  -- conditions, i.e. C_comp in the output stage will not derate the
  -- original Vt curves.
  -----------------------------------------------------------------------------
    variable K_tables : k_tables_type;

    variable Vr1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vr2cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf2cm : real_vector(1 to 3) := (others => 0.0);

    variable dVwfm_r1 : real := 0.0;
    variable dVwfm_r2 : real := 0.0;
    variable dVwfm_f1 : real := 0.0;
    variable dVwfm_f2 : real := 0.0;

    variable Iout1 : real := 0.0;
    variable Iout2 : real := 0.0;
    variable Ipc1  : real := 0.0;
    variable Ipc2  : real := 0.0;
    variable Ipu1  : real := 0.0;
    variable Ipu2  : real := 0.0;
    variable Ipd1  : real := 0.0;
    variable Ipd2  : real := 0.0;
    variable Igc1  : real := 0.0;
    variable Igc2  : real := 0.0;

    variable Term1 : real := 0.0;
    variable Term2 : real := 0.0;
    variable Den   : real := 1.0;
  -----------------------------------------------------------------------------
  begin
    K_tables(Tcm) := CommonTime(Common_length, Max_dt, T_r1, T_r2, T_f1, T_f2);
    --=========================================================================
    -- Calculate the scaling coefficients for each time point along Tcm
    ---------------------------------------------------------------------------
    -- Store the first voltage point in the common waveform variables
    ---------------------------------------------------------------------------
    Vr1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r1, V_r1, "HE");
    Vr2cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r2, V_r2, "HE");
    Vf1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f1, V_f1, "HE");
    Vf2cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f2, V_f2, "HE");

    for i in K_tables(Tcm)'range loop
    --report "Tcm: " & real'image(K_tables(Tcm)(i));  -- For debugging
    ---------------------------------------------------------------------------
    -- Store the next point (for the derivative calculations)
    ---------------------------------------------------------------------------
      if (i < K_tables(Tcm)'right) then
        Vr1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r1, V_r1, "HE");
        Vr2cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r2, V_r2, "HE");
        Vf1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f1, V_f1, "HE");
        Vf2cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f2, V_f2, "HE");
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: " & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " R1: " & real'image(Vr1cm(2)) &
      --       " R2: " & real'image(Vr2cm(2)) &
      --       " F1: " & real'image(Vf1cm(2)) &
      --       " F2: " & real'image(Vf2cm(2));
      -------------------------------------------------------------------------
      -- Calculate the derivative of each waveform for C_comp compensation
      -------------------------------------------------------------------------
      if ((i <= K_tables(Tcm)'left) or (i >= K_tables(Tcm)'right)) then
        dVwfm_r1 := 0.0;          -- Force the end point derivatives to zero
        dVwfm_r2 := 0.0;
        dVwfm_f1 := 0.0;
        dVwfm_f2 := 0.0;
      else
        dVwfm_r1 := ((Vr1cm(2) - Vr1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr1cm(3) - Vr1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_r2 := ((Vr2cm(2) - Vr2cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr2cm(3) - Vr2cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f1 := ((Vf1cm(2) - Vf1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf1cm(3) - Vf1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f2 := ((Vf2cm(2) - Vf2cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf2cm(3) - Vf2cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " dR1: " & real'image(dVwfm_r1) &
      --       " dR2: " & real'image(dVwfm_r2) &
      --       " dF1: " & real'image(dVwfm_f1) &
      --       " dF2: " & real'image(dVwfm_f2);
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kr1 Kr2 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vr1cm(2) - V_fx_r1) / R_fx_r1) + C_comp_total * dVwfm_r1;
      Iout2 := ((Vr2cm(2) - V_fx_r2) / R_fx_r2) + C_comp_total * dVwfm_r2;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vr1cm(2), V_pc, I_pc, "HE");
      Ipc2  := -1.0 * Lookup(V_pc_ref - Vr2cm(2), V_pc, I_pc, "HE");
      Ipu1  := -1.0 * Lookup(V_pu_ref - Vr1cm(2), V_pu, I_pu, "HE");
      Ipu2  := -1.0 * Lookup(V_pu_ref - Vr2cm(2), V_pu, I_pu, "HE");
      Ipd1  :=        Lookup(Vr1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Ipd2  :=        Lookup(Vr2cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vr1cm(2) - V_gc_ref, V_gc, I_gc, "HE");
      Igc2  :=        Lookup(Vr2cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      Term1 := Iout1 + Igc1 - Ipc1;
      Term2 := Ipc2  - Igc2 - Iout2;
      Den   := (Ipu1 * Ipd2) - (Ipd1 * Ipu2);

      -- Since these are rising waveforms
      -- Kr1 == Kpu_on and Kr2 == Kpd_off
      K_tables(Kr1)(i) := (Ipd2*Term1 + Ipd1*Term2) / Den;
      K_tables(Kr2)(i) := (Ipu2*Term1 + Ipu1*Term2) / Den;
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kf1 Kf2 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vf1cm(2) - V_fx_f1) / R_fx_f1) + C_comp_total * dVwfm_f1;
      Iout2 := ((Vf2cm(2) - V_fx_f2) / R_fx_f2) + C_comp_total * dVwfm_f2;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vf1cm(2), V_pc, I_pc, "HE");
      Ipc2  := -1.0 * Lookup(V_pc_ref - Vf2cm(2), V_pc, I_pc, "HE");
      Ipu1  := -1.0 * Lookup(V_pu_ref - Vf1cm(2), V_pu, I_pu, "HE");
      Ipu2  := -1.0 * Lookup(V_pu_ref - Vf2cm(2), V_pu, I_pu, "HE");
      Ipd1  :=        Lookup(Vf1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Ipd2  :=        Lookup(Vf2cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vf1cm(2) - V_gc_ref, V_gc, I_gc, "HE");
      Igc2  :=        Lookup(Vf2cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      Term1 := Iout1 + Igc1 - Ipc1;
      Term2 := Ipc2  - Igc2 - Iout2;
      Den   := (Ipu1 * Ipd2) - (Ipd1 * Ipu2);

      -- Since these are falling waveforms
      -- Kf1 == Kpd_on and Kf2 == Kpu_off
      K_tables(Kf1)(i) := (Ipu2*Term1 + Ipu1*Term2) / Den;
      K_tables(Kf2)(i) := (Ipd2*Term1 + Ipd1*Term2) / Den;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " Kr1: " & real'image(K_tables(Kr1)(i)) &
      --       " Kr2: " & real'image(K_tables(Kr2)(i)) &
      --       " Kf1: " & real'image(K_tables(Kf1)(i)) &
      --       " Kf2: " & real'image(K_tables(Kf2)(i));
      -------------------------------------------------------------------------
      -- Shift points by one index for next iteration (for C_comp compensation)
      -------------------------------------------------------------------------
      Vr1cm(1) := Vr1cm(2);
      Vr2cm(1) := Vr2cm(2);
      Vf1cm(1) := Vf1cm(2);
      Vf2cm(1) := Vf2cm(2);

      Vr1cm(2) := Vr1cm(3);
      Vr2cm(2) := Vr2cm(3);
      Vf1cm(2) := Vf1cm(3);
      Vf2cm(2) := Vf2cm(3);

    end loop; -- for loop
    ---------------------------------------------------------------------------
    return K_tables;
  end function Coeff;
--=============================================================================
  constant Ktables : k_tables_type := Coeff(CommonLength, Max_dt,
                                            Ipc_data, Vpc_data,
                                            Ipu_data, Vpu_data,
                                            Ipd_data, Vpd_data,
                                            Igc_data, Vgc_data,
                                            Vr1_data, Tr1_data,
                                            Vr2_data, Tr2_data,
                                            Vf1_data, Tf1_data,
                                            Vf2_data, Tf2_data,
                                            Vpc_ref,
                                            Vpu_ref,
                                            Vpd_ref,
                                            Vgc_ref,
                                            Vfx_r1,
                                            Vfx_r2,
                                            Vfx_f1,
                                            Vfx_f2,
                                            Rfx_r1,
                                            Rfx_r2,
                                            Rfx_f1,
                                            Rfx_f2,
                                            C_comp);
--=============================================================================
begin

  Catch: process is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if domain = quiescent_domain then

      wait until domain /= quiescent_domain;
      EventState <= 1;

    else

      wait on Vin'above(Vth_R), Vin'above(Vth_F),
              Ven'above(Vth_R), Ven'above(Vth_F);

      if ((Vin > Vth_R) or (Vin < Vth_F)) and
         ((Ven > Vth_R) or (Ven < Vth_F)) then

        if   EventState < 3 then  EventState <= EventState+1;
        else                      EventState <= EventState-1;
        end if;

      end if;
    end if;
  -----------------------------------------------------------------------------
  end process Catch;
  --===========================================================================
  FindState: process (EventState) is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if (Ven > Vth_R) and (Vin > Vth_R) then           -- high state
      pu_on  <= 1;
      pd_off <= 1;
      pd_on  <= 0;
      pu_off <= 0;
    elsif (Ven > Vth_R) and (Vin < Vth_F) then        -- low state
      pu_on  <= 0;
      pd_off <= 0;
      pd_on  <= 1;
      pu_off <= 1;
    elsif (Ven < Vth_F) then                          -- 3-state
      pu_on  <= 0;
      pd_off <= 1;
      pd_on  <= 0;
      pu_off <= 1;
    else                                              -- unknown state
      pu_on  <= 1;
      pd_off <= 0;
      pd_on  <= 1;
      pu_off <= 0;
    end if;
  -----------------------------------------------------------------------------
  end process FindState;
--=============================================================================
  break on pu_on;
  break on pu_off;
  break on pd_on;
  break on pd_off;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-- This entire section could be made more efficient with nested IF statements
-- if the simulator wouldn't have a problem with simultaneous statements in
-- nested case statements.
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Ven > Vth_R) and (Vin > Vth_R) use   -- high state
    kpu == Ktables(Kr1)(CommonLength);
  elsif (EventState = 0) and (Ven > Vth_R) and (Vin < Vth_F) use   -- low state
    kpu == Ktables(Kf2)(CommonLength);
  elsif (EventState = 0) and (Ven < Vth_F) use                     -- 3-state
    kpu == Ktables(Kf2)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pu_off = 1) use
    kpu == Ktables(Kf2)(CommonLength);      -- Last point from pu_off table
  elsif (EventState = 1) and (pu_off /= 1)use
    kpu == Ktables(Kr1)(CommonLength);      -- Last point from pu_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pu_on  = 1) use    -- Pullup turning on
    kpu == Lookup(pu_on'last_event,  Ktables(Tcm), Ktables(Kr1), "HE");
  elsif (EventState > 1) and (pu_off = 1) use    -- Pullup turning off
    kpu == Lookup(pu_off'last_event, Ktables(Tcm), Ktables(Kf2), "HE");

  -- Just in case
  else
    kpu == Ktables(Kr1)(Ktables(Kr1)'left); -- 1st point of pullup on table
  end use;


  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Ven > Vth_R) and (Vin > Vth_R) use   -- high state
    kpd == Ktables(Kr2)(CommonLength);
  elsif (EventState = 0) and (Ven > Vth_R) and (Vin < Vth_F) use   -- low state
    kpd == Ktables(Kf1)(CommonLength);
  elsif (EventState = 0) and (Ven < Vth_F) use                     -- 3-state
    kpd == Ktables(Kr2)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pd_off = 1) use
    kpd == Ktables(Kr2)(CommonLength);      -- Last point from pd_off table
  elsif (EventState = 1) and (pd_off /= 1)use
    kpd == Ktables(Kf1)(CommonLength);      -- Last point from pd_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pd_on  = 1) use    -- Pulldown turning on
    kpd == Lookup(pd_on'last_event,  Ktables(Tcm), Ktables(Kf1), "HE");
  elsif (EventState > 1) and (pd_off = 1) use    -- Pulldown turning off
    kpd == Lookup(pd_off'last_event, Ktables(Tcm), Ktables(Kr2), "HE");

  -- Just in case
  else
    kpd == Ktables(Kf1)(Ktables(Kf1)'left); -- 1st point of pulldown on table
  end use;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc   == -1.0    *Lookup(Vpc, Vpc_data, Ipc_data, "SE");-- + kC_comp_pc*C_comp*Vpc'dot; 
  Ipu   == -1.0*kpu*Lookup(Vpu, Vpu_data, Ipu_data, "SE");-- + kC_comp_pu*C_comp*Vpu'dot; 
  Ipd   ==      kpd*Lookup(Vpd, Vpd_data, Ipd_data, "SE");-- + kC_comp_pd*C_comp*Vpd'dot;
  Igc   ==          Lookup(Vgc, Vgc_data, Igc_data, "SE");-- + kC_comp_gc*C_comp*Vgc'dot;
--=============================================================================
end architecture IBIS_2EQ2UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
entity IBIS_OPENSINK is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.00;       -- splitting coefficients
           kC_comp_pu : real := 0.50;
           kC_comp_pd : real := 0.50;
           kC_comp_gc : real := 0.00;
           --------------------------------------------------------------------
           -- [Pullup Reference] and [Pulldown Reference] values
           --------------------------------------------------------------------
           Vpc_ref : real := 5.0;
           Vpd_ref : real := 0.0;
           Vgc_ref : real := 0.0;
           --------------------------------------------------------------------
           -- Vectors of the IV curve tables
           --------------------------------------------------------------------
           Ipc_data : real_vector := ( 0.08,  0.00,  0.00,  0.00);
           Vpc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           Ipd_data : real_vector := (-0.10,  0.00,  0.10,  0.20);
           Vpd_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Igc_data : real_vector := (-0.08,  0.00,  0.00,  0.00);
           Vgc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           --------------------------------------------------------------------
           -- Vectors of the Vt curve tables
           --------------------------------------------------------------------
           Vr1_data : real_vector := (2.50,  2.50,     5.00,     5.00);
           Tr1_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           Vf1_data : real_vector := (5.00,  5.00,     2.50,     2.50);
           Tf1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           --------------------------------------------------------------------
           -- V_fixture and R_fixture values
           --------------------------------------------------------------------
           Vfx_r1 : real := 5.0;
           Vfx_f1 : real := 5.0;

           Rfx_r1 : real := 50.0;
           Rfx_f1 : real := 50.0;
           --------------------------------------------------------------------
           -- Non IBIS parameters
           --------------------------------------------------------------------
           Max_dt : real := 1.0e-12;   -- Maximum dt between time points
           Vth_R  : real := 0.8;       -- Input threshold for rising edges
           Vth_F  : real := 0.2);      -- Input threshold for falling edges
     --------------------------------------------------------------------------
     port (terminal PU_ref : electrical;
           terminal PD_ref : electrical;

           terminal Pad    : electrical;
           terminal In_D   : electrical;

           terminal PC_ref : electrical;
           terminal GC_ref : electrical);

end entity IBIS_OPENSINK;
--=============================================================================
architecture IBIS_1EQ1UK of IBIS_OPENSINK is

  quantity  Vpc   across  Ipc   through  PC_ref  to  Pad;
  quantity  Vpd   across  Ipd   through  Pad     to  PD_ref;
  quantity  Vgc   across  Igc   through  Pad     to  GC_ref;

  quantity  Vin   across                 In_D    to  ELECTRICAL_REF;

  signal    pd_on         : integer := 0;
  signal    pd_off        : integer := 0;
  signal    EventState    : integer := 0;

  signal    Tpd_off_event : real := 0.0;
  signal    Tpd_on_event  : real := 0.0;

  quantity  kpd           : real := 0.0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
  --===========================================================================
  function FindCommonLength (Max_dt : real;
                             T_r1   : real_vector;
                             T_f1   : real_vector) return integer is
  -----------------------------------------------------------------------------
  -- This function finds the total number of points needed for having a
  -- common time axis for all Vt curves, such that the maximum delta time
  -- between each time point doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_index      : integer := 1;

    variable Index_r1     : integer := T_r1'left;
    variable Index_f1     : integer := T_f1'left;

    variable New_index_r1 : integer := T_r1'left;
    variable New_index_f1 : integer := T_f1'left;

    variable Old_t        : real    := 0.0;
    variable Last_t       : real    := 0.0;
    variable New_t        : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_f1(T_f1'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_f1(T_f1'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        T_index := T_index + integer(ceil((New_t-Old_t)/Max_dt)) - 1;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
    end loop; 
    ---------------------------------------------------------------------------
    --report "Common length: " & integer'image(T_index);
    return T_index;
  end function FindCommonLength;
--=============================================================================
  function CommonTime (Common_length : integer;
                       Max_dt        : real;
                       T_r1          : real_vector;
                       T_f1          : real_vector) return real_vector is
  -----------------------------------------------------------------------------
  -- This function generates a vector that serves as a common time axis for
  -- all Vt curves, such that the maximum delta time between each time point
  -- doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_common       : real_vector(1 to Common_length) := (others => 0.0);
    variable T_index        : integer := 1;

    variable Index_r1       : integer := T_r1'left;
    variable Index_f1       : integer := T_f1'left;

    variable New_index_r1   : integer := T_r1'left;
    variable New_index_f1   : integer := T_f1'left;

    variable Old_t          : real    := 0.0;
    variable Last_t         : real    := 0.0;
    variable New_t          : real    := 0.0;

    variable Additional_pts : real    := 0.0;
    variable New_dt         : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_f1(T_f1'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_f1(T_f1'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      -------------------------------------------------------------------------
      -- Save the time value from Old_t in T_common
      -- and increment T_index counter
      -------------------------------------------------------------------------
      T_common(T_index) := Old_t;
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        Additional_pts := ceil((New_t-Old_t)/Max_dt);
        New_dt := (New_t-Old_t) / Additional_pts;
        for i in 1 to integer(Additional_pts)-1 loop
          T_common(T_index) := T_common(T_index-1) + New_dt;
          T_index := T_index + 1;
        end loop;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
      --report "T_common: " & real'image(T_common(T_index-1));
    end loop; 
    T_common(T_index) := Last_t;
    --report "T_common: " & real'image(T_common(T_index));
    ---------------------------------------------------------------------------
    --report "Length of T_common: " & integer'image(T_index);
    return T_common;
  end function CommonTime;
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_data, Tf1_data);

  type k_elements    is (Tcm, Kr1, Kf1);
  type k_tables_type is array(k_elements) of real_vector(1 to CommonLength);
--=============================================================================
  function Coeff (Common_length : integer;
                  Max_dt : real;
                  I_pc   : real_vector;
                  V_pc   : real_vector;
                  I_pd   : real_vector;
                  V_pd   : real_vector;
                  I_gc   : real_vector;
                  V_gc   : real_vector;

                  V_r1   : real_vector;
                  T_r1   : real_vector;
                  V_f1   : real_vector;
                  T_f1   : real_vector;

                  V_pc_ref : real;
                  V_pd_ref : real;
                  V_gc_ref : real;

                  V_fx_r1  : real;
                  V_fx_f1  : real;

                  R_fx_r1  : real;
                  R_fx_f1  : real;

                  C_comp_total : real) return k_tables_type is
  -----------------------------------------------------------------------------
  -- This function converts each Vt table to a corresponding scaling
  -- coefficient table that is used to scale the IV curves with respect
  -- to time.  The C_comp effects in the waveforms are eliminated from the
  -- scaling coefficients, so that the output waveforms will match the Vt
  -- table regardless of the presence of C_comp under identical loading
  -- conditions, i.e. C_comp in the output stage will not derate the
  -- original Vt curves.
  -----------------------------------------------------------------------------
    variable K_tables : k_tables_type;

    variable Vr1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf1cm : real_vector(1 to 3) := (others => 0.0);

    variable dVwfm_r1 : real := 0.0;
    variable dVwfm_f1 : real := 0.0;

    variable Iout1 : real := 0.0;
    variable Ipc1  : real := 0.0;
    variable Ipd1  : real := 0.0;
    variable Igc1  : real := 0.0;
  -----------------------------------------------------------------------------
  begin
    K_tables(Tcm) := CommonTime(Common_length, Max_dt, T_r1, T_f1);
    --=========================================================================
    -- Calculate the scaling coefficients for each time point along Tcm
    ---------------------------------------------------------------------------
    -- Store the first voltage point in the common waveform variables
    ---------------------------------------------------------------------------
    Vr1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r1, V_r1, "HE");
    Vf1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f1, V_f1, "HE");

    for i in K_tables(Tcm)'range loop
    --report "Tcm: " & real'image(K_tables(Tcm)(i));  -- For debugging
    ---------------------------------------------------------------------------
    -- Store the next point (for the derivative calculations)
    ---------------------------------------------------------------------------
      if (i < K_tables(Tcm)'right) then
        Vr1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r1, V_r1, "HE");
        Vf1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f1, V_f1, "HE");
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: " & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " R1: " & real'image(Vr1cm(2)) &
      --       " F1: " & real'image(Vf1cm(2));
      -------------------------------------------------------------------------
      -- Calculate the derivative of each waveform for C_comp compensation
      -------------------------------------------------------------------------
      if ((i <= K_tables(Tcm)'left) or (i >= K_tables(Tcm)'right)) then
        dVwfm_r1 := 0.0;          -- Force the end point derivatives to zero
        dVwfm_f1 := 0.0;
      else
        dVwfm_r1 := ((Vr1cm(2) - Vr1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr1cm(3) - Vr1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f1 := ((Vf1cm(2) - Vf1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf1cm(3) - Vf1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " dR1: " & real'image(dVwfm_r1) &
      --       " dF1: " & real'image(dVwfm_f1);
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kr1 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vr1cm(2) - V_fx_r1) / R_fx_r1) + C_comp_total * dVwfm_r1;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vr1cm(2), V_pc, I_pc, "HE");
      Ipd1  :=        Lookup(Vr1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vr1cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      -- Since these are rising waveforms
      -- Kr1 == Kpd_off
      if (Ipd1 = 0.0) then K_tables(Kr1)(i) := 0.0;
      else                 K_tables(Kr1)(i) := (Ipc1 - Igc1 - Iout1) / Ipd1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kf1 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vf1cm(2) - V_fx_f1) / R_fx_f1) + C_comp_total * dVwfm_f1;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vf1cm(2), V_pc, I_pc, "HE");
      Ipd1  :=        Lookup(Vf1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vf1cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      -- Since these are falling waveforms
      -- Kf1 == Kpd_on
      if (Ipd1 = 0.0) then K_tables(Kf1)(i) := 0.0;
      else                 K_tables(Kf1)(i) := (Ipc1 - Igc1 - Iout1) / Ipd1;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " Kr1: " & real'image(K_tables(Kr1)(i)) &
      --       " Kf1: " & real'image(K_tables(Kf1)(i));
      -------------------------------------------------------------------------
      -- Shift points by one index for next iteration (for C_comp compensation)
      -------------------------------------------------------------------------
      Vr1cm(1) := Vr1cm(2);
      Vf1cm(1) := Vf1cm(2);

      Vr1cm(2) := Vr1cm(3);
      Vf1cm(2) := Vf1cm(3);

    end loop; -- for loop
    ---------------------------------------------------------------------------
    return K_tables;
  end function Coeff;
--=============================================================================
  constant Ktables : k_tables_type := Coeff(CommonLength, Max_dt,
                                            Ipc_data, Vpc_data,
                                            Ipd_data, Vpd_data,
                                            Igc_data, Vgc_data,
                                            Vr1_data, Tr1_data,
                                            Vf1_data, Tf1_data,
                                            Vpc_ref,
                                            Vpd_ref,
                                            Vgc_ref,
                                            Vfx_r1,
                                            Vfx_f1,
                                            Rfx_r1,
                                            Rfx_f1,
                                            C_comp);
--=============================================================================
begin

  Catch: process is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if domain = quiescent_domain then

      wait until domain /= quiescent_domain;
      EventState <= 1;

    else

      wait on Vin'above(Vth_R), Vin'above(Vth_F);

      if ((Vin > Vth_R) or (Vin < Vth_F)) then

        if   EventState < 3 then  EventState <= EventState+1;
        else                      EventState <= EventState-1;
        end if;

      end if;
    end if;
  -----------------------------------------------------------------------------
  end process Catch;
  --===========================================================================
  FindState: process (EventState) is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if (Vin > Vth_R) then                             -- high state
      pd_off <= 1;
      pd_on  <= 0;
    elsif (Vin < Vth_F) then                          -- low state
      pd_off <= 0;
      pd_on  <= 1;
    else                                              -- unknown state
      pd_off <= 0;
      pd_on  <= 1;
    end if;
  -----------------------------------------------------------------------------
  end process FindState;
--=============================================================================
  break on pd_on;
  break on pd_off;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-- This entire section could be made more efficient with nested IF statements
-- if the simulator wouldn't have a problem with simultaneous statements in
-- nested case statements.
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Vin > Vth_R) use                     -- high state
    kpd == Ktables(Kr1)(CommonLength);
  elsif (EventState = 0) and (Vin < Vth_F) use                     -- low state
    kpd == Ktables(Kf1)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pd_off = 1) use
    kpd == Ktables(Kr1)(CommonLength);      -- Last point from pd_off table
  elsif (EventState = 1) and (pd_off /= 1)use
    kpd == Ktables(Kf1)(CommonLength);      -- Last point from pd_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pd_on  = 1) use    -- Pulldown turning on
    kpd == Lookup(pd_on'last_event,  Ktables(Tcm), Ktables(Kf1), "HE");
  elsif (EventState > 1) and (pd_off = 1) use    -- Pulldown turning off
    kpd == Lookup(pd_off'last_event, Ktables(Tcm), Ktables(Kr1), "HE");

  -- Just in case
  else
    kpd == Ktables(Kf1)(Ktables(Kf1)'left); -- 1st point of pulldown on table
  end use;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc   == -1.0    *Lookup(Vpc, Vpc_data, Ipc_data, "SE");-- + kC_comp_pc*C_comp*Vpc'dot; 
  Ipd   ==      kpd*Lookup(Vpd, Vpd_data, Ipd_data, "SE");-- + kC_comp_pd*C_comp*Vpd'dot;
  Igc   ==          Lookup(Vgc, Vgc_data, Igc_data, "SE");-- + kC_comp_gc*C_comp*Vgc'dot;
--=============================================================================
end architecture IBIS_1EQ1UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
entity IBIS_IO_OPENSINK is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.00;       -- splitting coefficients
           kC_comp_pu : real := 0.50;
           kC_comp_pd : real := 0.50;
           kC_comp_gc : real := 0.00;
           --------------------------------------------------------------------
           -- Receiver thresholds
           --------------------------------------------------------------------
           Vinh : real := 2.00;
           Vinl : real := 0.80;
           --------------------------------------------------------------------
           -- [Pullup Reference] and [Pulldown Reference] values
           --------------------------------------------------------------------
           Vpc_ref : real := 5.0;
           Vpd_ref : real := 0.0;
           Vgc_ref : real := 0.0;
           --------------------------------------------------------------------
           -- Vectors of the IV curve tables
           --------------------------------------------------------------------
           Ipc_data : real_vector := ( 0.08,  0.00,  0.00,  0.00);
           Vpc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           Ipd_data : real_vector := (-0.10,  0.00,  0.10,  0.20);
           Vpd_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Igc_data : real_vector := (-0.08,  0.00,  0.00,  0.00);
           Vgc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           --------------------------------------------------------------------
           -- Vectors of the Vt curve tables
           --------------------------------------------------------------------
           Vr1_data : real_vector := (2.50,  2.50,     5.00,     5.00);
           Tr1_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           Vf1_data : real_vector := (5.00,  5.00,     2.50,     2.50);
           Tf1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           --------------------------------------------------------------------
           -- V_fixture and R_fixture values
           --------------------------------------------------------------------
           Vfx_r1 : real := 5.0;
           Vfx_f1 : real := 5.0;

           Rfx_r1 : real := 50.0;
           Rfx_f1 : real := 50.0;
           --------------------------------------------------------------------
           -- Non IBIS parameters
           --------------------------------------------------------------------
           Max_dt : real := 1.0e-12;   -- Maximum dt between time points
           Vth_R  : real := 0.8;       -- Input threshold for rising edges
           Vth_F  : real := 0.2);      -- Input threshold for falling edges
     --------------------------------------------------------------------------
     port (terminal PU_ref : electrical;
           terminal PD_ref : electrical;

           terminal Pad    : electrical;
           terminal In_D   : electrical;
           terminal En_D   : electrical;
--           terminal Rcv_D  : electrical;

           terminal PC_ref : electrical;
           terminal GC_ref : electrical);

end entity IBIS_IO_OPENSINK;
--=============================================================================
architecture IBIS_1EQ1UK of IBIS_IO_OPENSINK is

  quantity  Vpc   across  Ipc   through  PC_ref  to  Pad;
  quantity  Vpd   across  Ipd   through  Pad     to  PD_ref;
  quantity  Vgc   across  Igc   through  Pad     to  GC_ref;

  quantity  Vin   across                 In_D    to  ELECTRICAL_REF;
  quantity  Ven   across                 En_D    to  ELECTRICAL_REF;
--  quantity  Vrcv  across  Ircv  through  Rcv_D   to  ELECTRICAL_REF;

  signal    pd_on         : integer := 0;
  signal    pd_off        : integer := 0;
  signal    EventState    : integer := 0;

  signal    Tpd_off_event : real := 0.0;
  signal    Tpd_on_event  : real := 0.0;

  quantity  kpd           : real := 0.0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
  --===========================================================================
  function FindCommonLength (Max_dt : real;
                             T_r1   : real_vector;
                             T_f1   : real_vector) return integer is
  -----------------------------------------------------------------------------
  -- This function finds the total number of points needed for having a
  -- common time axis for all Vt curves, such that the maximum delta time
  -- between each time point doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_index      : integer := 1;

    variable Index_r1     : integer := T_r1'left;
    variable Index_f1     : integer := T_f1'left;

    variable New_index_r1 : integer := T_r1'left;
    variable New_index_f1 : integer := T_f1'left;

    variable Old_t        : real    := 0.0;
    variable Last_t       : real    := 0.0;
    variable New_t        : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_f1(T_f1'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_f1(T_f1'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        T_index := T_index + integer(ceil((New_t-Old_t)/Max_dt)) - 1;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
    end loop; 
    ---------------------------------------------------------------------------
    --report "Common length: " & integer'image(T_index);
    return T_index;
  end function FindCommonLength;
--=============================================================================
  function CommonTime (Common_length : integer;
                       Max_dt        : real;
                       T_r1          : real_vector;
                       T_f1          : real_vector) return real_vector is
  -----------------------------------------------------------------------------
  -- This function generates a vector that serves as a common time axis for
  -- all Vt curves, such that the maximum delta time between each time point
  -- doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_common       : real_vector(1 to Common_length) := (others => 0.0);
    variable T_index        : integer := 1;

    variable Index_r1       : integer := T_r1'left;
    variable Index_f1       : integer := T_f1'left;

    variable New_index_r1   : integer := T_r1'left;
    variable New_index_f1   : integer := T_f1'left;

    variable Old_t          : real    := 0.0;
    variable Last_t         : real    := 0.0;
    variable New_t          : real    := 0.0;

    variable Additional_pts : real    := 0.0;
    variable New_dt         : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_f1(T_f1'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_f1(T_f1'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      -------------------------------------------------------------------------
      -- Save the time value from Old_t in T_common
      -- and increment T_index counter
      -------------------------------------------------------------------------
      T_common(T_index) := Old_t;
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        Additional_pts := ceil((New_t-Old_t)/Max_dt);
        New_dt := (New_t-Old_t) / Additional_pts;
        for i in 1 to integer(Additional_pts)-1 loop
          T_common(T_index) := T_common(T_index-1) + New_dt;
          T_index := T_index + 1;
        end loop;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
      --report "T_common: " & real'image(T_common(T_index-1));
    end loop; 
    T_common(T_index) := Last_t;
    --report "T_common: " & real'image(T_common(T_index));
    ---------------------------------------------------------------------------
    --report "Length of T_common: " & integer'image(T_index);
    return T_common;
  end function CommonTime;
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_data, Tf1_data);

  type k_elements    is (Tcm, Kr1, Kf1);
  type k_tables_type is array(k_elements) of real_vector(1 to CommonLength);
--=============================================================================
  function Coeff (Common_length : integer;
                  Max_dt : real;
                  I_pc   : real_vector;
                  V_pc   : real_vector;
                  I_pd   : real_vector;
                  V_pd   : real_vector;
                  I_gc   : real_vector;
                  V_gc   : real_vector;

                  V_r1   : real_vector;
                  T_r1   : real_vector;
                  V_f1   : real_vector;
                  T_f1   : real_vector;

                  V_pc_ref : real;
                  V_pd_ref : real;
                  V_gc_ref : real;

                  V_fx_r1  : real;
                  V_fx_f1  : real;

                  R_fx_r1  : real;
                  R_fx_f1  : real;

                  C_comp_total : real) return k_tables_type is
  -----------------------------------------------------------------------------
  -- This function converts each Vt table to a corresponding scaling
  -- coefficient table that is used to scale the IV curves with respect
  -- to time.  The C_comp effects in the waveforms are eliminated from the
  -- scaling coefficients, so that the output waveforms will match the Vt
  -- table regardless of the presence of C_comp under identical loading
  -- conditions, i.e. C_comp in the output stage will not derate the
  -- original Vt curves.
  -----------------------------------------------------------------------------
    variable K_tables : k_tables_type;

    variable Vr1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf1cm : real_vector(1 to 3) := (others => 0.0);

    variable dVwfm_r1 : real := 0.0;
    variable dVwfm_f1 : real := 0.0;

    variable Iout1 : real := 0.0;
    variable Ipc1  : real := 0.0;
    variable Ipd1  : real := 0.0;
    variable Igc1  : real := 0.0;
  -----------------------------------------------------------------------------
  begin
    K_tables(Tcm) := CommonTime(Common_length, Max_dt, T_r1, T_f1);
    --=========================================================================
    -- Calculate the scaling coefficients for each time point along Tcm
    ---------------------------------------------------------------------------
    -- Store the first voltage point in the common waveform variables
    ---------------------------------------------------------------------------
    Vr1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r1, V_r1, "HE");
    Vf1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f1, V_f1, "HE");

    for i in K_tables(Tcm)'range loop
    --report "Tcm: " & real'image(K_tables(Tcm)(i));  -- For debugging
    ---------------------------------------------------------------------------
    -- Store the next point (for the derivative calculations)
    ---------------------------------------------------------------------------
      if (i < K_tables(Tcm)'right) then
        Vr1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r1, V_r1, "HE");
        Vf1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f1, V_f1, "HE");
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: " & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " R1: " & real'image(Vr1cm(2)) &
      --       " F1: " & real'image(Vf1cm(2));
      -------------------------------------------------------------------------
      -- Calculate the derivative of each waveform for C_comp compensation
      -------------------------------------------------------------------------
      if ((i <= K_tables(Tcm)'left) or (i >= K_tables(Tcm)'right)) then
        dVwfm_r1 := 0.0;          -- Force the end point derivatives to zero
        dVwfm_f1 := 0.0;
      else
        dVwfm_r1 := ((Vr1cm(2) - Vr1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr1cm(3) - Vr1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f1 := ((Vf1cm(2) - Vf1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf1cm(3) - Vf1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " dR1: " & real'image(dVwfm_r1) &
      --       " dF1: " & real'image(dVwfm_f1);
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kr1 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vr1cm(2) - V_fx_r1) / R_fx_r1) + C_comp_total * dVwfm_r1;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vr1cm(2), V_pc, I_pc, "HE");
      Ipd1  :=        Lookup(Vr1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vr1cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      -- Since these are rising waveforms
      -- Kr1 == Kpd_off
      if (Ipd1 = 0.0) then K_tables(Kr1)(i) := 0.0;
      else                 K_tables(Kr1)(i) := (Ipc1 - Igc1 - Iout1) / Ipd1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kf1 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vf1cm(2) - V_fx_f1) / R_fx_f1) + C_comp_total * dVwfm_f1;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vf1cm(2), V_pc, I_pc, "HE");
      Ipd1  :=        Lookup(Vf1cm(2) - V_pd_ref, V_pd, I_pd, "HE");
      Igc1  :=        Lookup(Vf1cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      -- Since these are falling waveforms
      -- Kf1 == Kpd_on
      if (Ipd1 = 0.0) then K_tables(Kf1)(i) := 0.0;
      else                 K_tables(Kf1)(i) := (Ipc1 - Igc1 - Iout1) / Ipd1;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " Kr1: " & real'image(K_tables(Kr1)(i)) &
      --       " Kf1: " & real'image(K_tables(Kf1)(i));
      -------------------------------------------------------------------------
      -- Shift points by one index for next iteration (for C_comp compensation)
      -------------------------------------------------------------------------
      Vr1cm(1) := Vr1cm(2);
      Vf1cm(1) := Vf1cm(2);

      Vr1cm(2) := Vr1cm(3);
      Vf1cm(2) := Vf1cm(3);

    end loop; -- for loop
    ---------------------------------------------------------------------------
    return K_tables;
  end function Coeff;
--=============================================================================
  constant Ktables : k_tables_type := Coeff(CommonLength, Max_dt,
                                            Ipc_data, Vpc_data,
                                            Ipd_data, Vpd_data,
                                            Igc_data, Vgc_data,
                                            Vr1_data, Tr1_data,
                                            Vf1_data, Tf1_data,
                                            Vpc_ref,
                                            Vpd_ref,
                                            Vgc_ref,
                                            Vfx_r1,
                                            Vfx_f1,
                                            Rfx_r1,
                                            Rfx_f1,
                                            C_comp);
--=============================================================================
begin

  Catch: process is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if domain = quiescent_domain then

      wait until domain /= quiescent_domain;
      EventState <= 1;

    else

      wait on Vin'above(Vth_R), Vin'above(Vth_F),
              Ven'above(Vth_R), Ven'above(Vth_F);

      if ((Vin > Vth_R) or (Vin < Vth_F)) and
         ((Ven > Vth_R) or (Ven < Vth_F)) then

        if   EventState < 3 then  EventState <= EventState+1;
        else                      EventState <= EventState-1;
        end if;

      end if;
    end if;
  -----------------------------------------------------------------------------
  end process Catch;
  --===========================================================================
  FindState: process (EventState) is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if (Ven > Vth_R) and (Vin > Vth_R) then           -- high state
      pd_off <= 1;
      pd_on  <= 0;
    elsif (Ven > Vth_R) and (Vin < Vth_F) then        -- low state
      pd_off <= 0;
      pd_on  <= 1;
    elsif (Ven < Vth_F) then                          -- 3-state
      pd_off <= 1;
      pd_on  <= 0;
    else                                              -- unknown state
      pd_off <= 0;
      pd_on  <= 1;
    end if;
  -----------------------------------------------------------------------------
  end process FindState;
--=============================================================================
  break on pd_on;
  break on pd_off;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-- This entire section could be made more efficient with nested IF statements
-- if the simulator wouldn't have a problem with simultaneous statements in
-- nested case statements.
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Ven > Vth_R) and (Vin > Vth_R) use   -- high state
    kpd == Ktables(Kr1)(CommonLength);
  elsif (EventState = 0) and (Ven > Vth_R) and (Vin < Vth_F) use   -- low state
    kpd == Ktables(Kf1)(CommonLength);
  elsif (EventState = 0) and (Ven < Vth_F) use                     -- 3-state
    kpd == Ktables(Kr1)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pd_off = 1) use
    kpd == Ktables(Kr1)(CommonLength);      -- Last point from pd_off table
  elsif (EventState = 1) and (pd_off /= 1)use
    kpd == Ktables(Kf1)(CommonLength);      -- Last point from pd_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pd_on  = 1) use    -- Pulldown turning on
    kpd == Lookup(pd_on'last_event,  Ktables(Tcm), Ktables(Kf1), "HE");
  elsif (EventState > 1) and (pd_off = 1) use    -- Pulldown turning off
    kpd == Lookup(pd_off'last_event, Ktables(Tcm), Ktables(Kr1), "HE");

  -- Just in case
  else
    kpd == Ktables(Kf1)(Ktables(Kf1)'left); -- 1st point of pulldown on table
  end use;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc   == -1.0    *Lookup(Vpc, Vpc_data, Ipc_data, "SE");-- + kC_comp_pc*C_comp*Vpc'dot; 
  Ipd   ==      kpd*Lookup(Vpd, Vpd_data, Ipd_data, "SE");-- + kC_comp_pd*C_comp*Vpd'dot;
  Igc   ==          Lookup(Vgc, Vgc_data, Igc_data, "SE");-- + kC_comp_gc*C_comp*Vgc'dot;
  -----------------------------------------------------------------------------
  -- A simple receiver logic
  -----------------------------------------------------------------------------
--  if    (Vpd > Vinh) use Vrcv == 1.0;
--  elsif (Vpd < Vinl) use Vrcv == 0.0;
--  else                   Vrcv == 0.5;
--  end use;
--=============================================================================
end architecture IBIS_1EQ1UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
entity IBIS_OPENSOURCE is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.00;       -- splitting coefficients
           kC_comp_pu : real := 0.50;
           kC_comp_pd : real := 0.50;
           kC_comp_gc : real := 0.00;
           --------------------------------------------------------------------
           -- [Pullup Reference] and [Pulldown Reference] values
           --------------------------------------------------------------------
           Vpc_ref : real := 5.0;
           Vpu_ref : real := 5.0;
           Vgc_ref : real := 0.0;
           --------------------------------------------------------------------
           -- Vectors of the IV curve tables
           --------------------------------------------------------------------
           Ipc_data : real_vector := ( 0.08,  0.00,  0.00,  0.00);
           Vpc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           Ipu_data : real_vector := ( 0.10,  0.00, -0.10, -0.20);
           Vpu_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Igc_data : real_vector := (-0.08,  0.00,  0.00,  0.00);
           Vgc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           --------------------------------------------------------------------
           -- Vectors of the Vt curve tables
           --------------------------------------------------------------------
           Vr1_data : real_vector := (0.00,  0.00,     2.50,     2.50);
           Tr1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           Vf1_data : real_vector := (2.50,  2.50,     0.00,     0.00);
           Tf1_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           --------------------------------------------------------------------
           -- V_fixture and R_fixture values
           --------------------------------------------------------------------
           Vfx_r1 : real := 0.0;
           Vfx_f1 : real := 0.0;

           Rfx_r1 : real := 50.0;
           Rfx_f1 : real := 50.0;
           --------------------------------------------------------------------
           -- Non IBIS parameters
           --------------------------------------------------------------------
           Max_dt : real := 1.0e-12;   -- Maximum dt between time points
           Vth_R  : real := 0.8;       -- Input threshold for rising edges
           Vth_F  : real := 0.2);      -- Input threshold for falling edges
     --------------------------------------------------------------------------
     port (terminal PU_ref : electrical;
           terminal PD_ref : electrical;

           terminal Pad    : electrical;
           terminal In_D   : electrical;

           terminal PC_ref : electrical;
           terminal GC_ref : electrical);

end entity IBIS_OPENSOURCE;
--=============================================================================
architecture IBIS_1EQ1UK of IBIS_OPENSOURCE is

  quantity  Vpc   across  Ipc   through  PC_ref  to  Pad;
  quantity  Vpu   across  Ipu   through  PU_ref  to  Pad;
  quantity  Vgc   across  Igc   through  Pad     to  GC_ref;

  quantity  Vin   across                 In_D    to  ELECTRICAL_REF;

  signal    pu_on         : integer := 0;
  signal    pu_off        : integer := 0;
  signal    EventState    : integer := 0;

  signal    Tpu_on_event  : real := 0.0;
  signal    Tpu_off_event : real := 0.0;

  quantity  kpu           : real := 0.0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
  --===========================================================================
  function FindCommonLength (Max_dt : real;
                             T_r1   : real_vector;
                             T_f1   : real_vector) return integer is
  -----------------------------------------------------------------------------
  -- This function finds the total number of points needed for having a
  -- common time axis for all Vt curves, such that the maximum delta time
  -- between each time point doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_index      : integer := 1;

    variable Index_r1     : integer := T_r1'left;
    variable Index_f1     : integer := T_f1'left;

    variable New_index_r1 : integer := T_r1'left;
    variable New_index_f1 : integer := T_f1'left;

    variable Old_t        : real    := 0.0;
    variable Last_t       : real    := 0.0;
    variable New_t        : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_f1(T_f1'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_f1(T_f1'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        T_index := T_index + integer(ceil((New_t-Old_t)/Max_dt)) - 1;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
    end loop; 
    ---------------------------------------------------------------------------
    --report "Common length: " & integer'image(T_index);
    return T_index;
  end function FindCommonLength;
--=============================================================================
  function CommonTime (Common_length : integer;
                       Max_dt        : real;
                       T_r1          : real_vector;
                       T_f1          : real_vector) return real_vector is
  -----------------------------------------------------------------------------
  -- This function generates a vector that serves as a common time axis for
  -- all Vt curves, such that the maximum delta time between each time point
  -- doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_common       : real_vector(1 to Common_length) := (others => 0.0);
    variable T_index        : integer := 1;

    variable Index_r1       : integer := T_r1'left;
    variable Index_f1       : integer := T_f1'left;

    variable New_index_r1   : integer := T_r1'left;
    variable New_index_f1   : integer := T_f1'left;

    variable Old_t          : real    := 0.0;
    variable Last_t         : real    := 0.0;
    variable New_t          : real    := 0.0;

    variable Additional_pts : real    := 0.0;
    variable New_dt         : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_f1(T_f1'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_f1(T_f1'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      -------------------------------------------------------------------------
      -- Save the time value from Old_t in T_common
      -- and increment T_index counter
      -------------------------------------------------------------------------
      T_common(T_index) := Old_t;
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        Additional_pts := ceil((New_t-Old_t)/Max_dt);
        New_dt := (New_t-Old_t) / Additional_pts;
        for i in 1 to integer(Additional_pts)-1 loop
          T_common(T_index) := T_common(T_index-1) + New_dt;
          T_index := T_index + 1;
        end loop;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
      --report "T_common: " & real'image(T_common(T_index-1));
    end loop; 
    T_common(T_index) := Last_t;
    --report "T_common: " & real'image(T_common(T_index));
    ---------------------------------------------------------------------------
    --report "Length of T_common: " & integer'image(T_index);
    return T_common;
  end function CommonTime;
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_data, Tf1_data);

  type k_elements    is (Tcm, Kr1, Kf1);
  type k_tables_type is array(k_elements) of real_vector(1 to CommonLength);
--=============================================================================
  function Coeff (Common_length : integer;
                  Max_dt : real;
                  I_pc   : real_vector;
                  V_pc   : real_vector;
                  I_pu   : real_vector;
                  V_pu   : real_vector;
                  I_gc   : real_vector;
                  V_gc   : real_vector;

                  V_r1   : real_vector;
                  T_r1   : real_vector;
                  V_f1   : real_vector;
                  T_f1   : real_vector;

                  V_pc_ref : real;
                  V_pu_ref : real;
                  V_gc_ref : real;

                  V_fx_r1  : real;
                  V_fx_f1  : real;

                  R_fx_r1  : real;
                  R_fx_f1  : real;

                  C_comp_total : real) return k_tables_type is
  -----------------------------------------------------------------------------
  -- This function converts each Vt table to a corresponding scaling
  -- coefficient table that is used to scale the IV curves with respect
  -- to time.  The C_comp effects in the waveforms are eliminated from the
  -- scaling coefficients, so that the output waveforms will match the Vt
  -- table regardless of the presence of C_comp under identical loading
  -- conditions, i.e. C_comp in the output stage will not derate the
  -- original Vt curves.
  -----------------------------------------------------------------------------
    variable K_tables : k_tables_type;

    variable Vr1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf1cm : real_vector(1 to 3) := (others => 0.0);

    variable dVwfm_r1 : real := 0.0;
    variable dVwfm_f1 : real := 0.0;

    variable Iout1 : real := 0.0;
    variable Ipc1  : real := 0.0;
    variable Ipu1  : real := 0.0;
    variable Ipd1  : real := 0.0;
    variable Igc1  : real := 0.0;
  -----------------------------------------------------------------------------
  begin
    K_tables(Tcm) := CommonTime(Common_length, Max_dt, T_r1, T_f1);
    --=========================================================================
    -- Calculate the scaling coefficients for each time point along Tcm
    ---------------------------------------------------------------------------
    -- Store the first voltage point in the common waveform variables
    ---------------------------------------------------------------------------
    Vr1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r1, V_r1, "HE");
    Vf1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f1, V_f1, "HE");

    for i in K_tables(Tcm)'range loop
    --report "Tcm: " & real'image(K_tables(Tcm)(i));  -- For debugging
    ---------------------------------------------------------------------------
    -- Store the next point (for the derivative calculations)
    ---------------------------------------------------------------------------
      if (i < K_tables(Tcm)'right) then
        Vr1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r1, V_r1, "HE");
        Vf1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f1, V_f1, "HE");
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: " & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " R1: " & real'image(Vr1cm(2)) &
      --       " F1: " & real'image(Vf1cm(2));
      -------------------------------------------------------------------------
      -- Calculate the derivative of each waveform for C_comp compensation
      -------------------------------------------------------------------------
      if ((i <= K_tables(Tcm)'left) or (i >= K_tables(Tcm)'right)) then
        dVwfm_r1 := 0.0;          -- Force the end point derivatives to zero
        dVwfm_f1 := 0.0;
      else
        dVwfm_r1 := ((Vr1cm(2) - Vr1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr1cm(3) - Vr1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f1 := ((Vf1cm(2) - Vf1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf1cm(3) - Vf1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " dR1: " & real'image(dVwfm_r1) &
      --       " dF1: " & real'image(dVwfm_f1);
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kr1 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vr1cm(2) - V_fx_r1) / R_fx_r1) + C_comp_total * dVwfm_r1;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vr1cm(2), V_pc, I_pc, "HE");
      Ipu1  :=        Lookup(V_pu_ref - Vr1cm(2), V_pu, I_pu, "HE");
      Igc1  :=        Lookup(Vr1cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      -- Since these are rising waveforms
      -- Kr1 == Kpu_on
      if (Ipu1 = 0.0) then K_tables(Kr1)(i) := 0.0;
      else                 K_tables(Kr1)(i) := (Ipc1 - Igc1 - Iout1) / Ipu1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kf1 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vf1cm(2) - V_fx_f1) / R_fx_f1) + C_comp_total * dVwfm_f1;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vf1cm(2), V_pc, I_pc, "HE");
      Ipu1  :=        Lookup(V_pu_ref - Vf1cm(2), V_pu, I_pu, "HE");
      Igc1  :=        Lookup(Vf1cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      -- Since these are falling waveforms
      -- Kf1 == Kpu_off
      if (Ipu1 = 0.0) then K_tables(Kf1)(i) := 0.0;
      else                 K_tables(Kf1)(i) := (Ipc1 - Igc1 - Iout1) / Ipu1;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " Kr1: " & real'image(K_tables(Kr1)(i)) &
      --       " Kf1: " & real'image(K_tables(Kf1)(i));
      -------------------------------------------------------------------------
      -- Shift points by one index for next iteration (for C_comp compensation)
      -------------------------------------------------------------------------
      Vr1cm(1) := Vr1cm(2);
      Vf1cm(1) := Vf1cm(2);

      Vr1cm(2) := Vr1cm(3);
      Vf1cm(2) := Vf1cm(3);

    end loop; -- for loop
    ---------------------------------------------------------------------------
    return K_tables;
  end function Coeff;
--=============================================================================
  constant Ktables : k_tables_type := Coeff(CommonLength, Max_dt,
                                            Ipc_data, Vpc_data,
                                            Ipu_data, Vpu_data,
                                            Igc_data, Vgc_data,
                                            Vr1_data, Tr1_data,
                                            Vf1_data, Tf1_data,
                                            Vpc_ref,
                                            Vpu_ref,
                                            Vgc_ref,
                                            Vfx_r1,
                                            Vfx_f1,
                                            Rfx_r1,
                                            Rfx_f1,
                                            C_comp);
--=============================================================================
begin

  Catch: process is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if domain = quiescent_domain then

      wait until domain /= quiescent_domain;
      EventState <= 1;

    else

      wait on Vin'above(Vth_R), Vin'above(Vth_F);

      if ((Vin > Vth_R) or (Vin < Vth_F)) then

        if   EventState < 3 then  EventState <= EventState+1;
        else                      EventState <= EventState-1;
        end if;

      end if;
    end if;
  -----------------------------------------------------------------------------
  end process Catch;
  --===========================================================================
  FindState: process (EventState) is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if (Vin > Vth_R) then                             -- high state
      pu_on  <= 1;
      pu_off <= 0;
    elsif (Vin < Vth_F) then                          -- low state
      pu_on  <= 0;
      pu_off <= 1;
    else                                              -- unknown state
      pu_on  <= 1;
      pu_off <= 0;
    end if;
  -----------------------------------------------------------------------------
  end process FindState;
--=============================================================================
  break on pu_on;
  break on pu_off;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-- This entire section could be made more efficient with nested IF statements
-- if the simulator wouldn't have a problem with simultaneous statements in
-- nested case statements.
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Vin > Vth_R) use                     -- high state
    kpu == Ktables(Kr1)(CommonLength);
  elsif (EventState = 0) and (Vin < Vth_F) use                     -- low state
    kpu == Ktables(Kf1)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pu_off = 1) use
    kpu == Ktables(Kf1)(CommonLength);      -- Last point from pu_off table
  elsif (EventState = 1) and (pu_off /= 1)use
    kpu == Ktables(Kr1)(CommonLength);      -- Last point from pu_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pu_on  = 1) use    -- Pullup turning on
    kpu == Lookup(pu_on'last_event,  Ktables(Tcm), Ktables(Kr1), "HE");
  elsif (EventState > 1) and (pu_off = 1) use    -- Pullup turning off
    kpu == Lookup(pu_off'last_event, Ktables(Tcm), Ktables(Kf1), "HE");

  -- Just in case
  else
    kpu == Ktables(Kr1)(Ktables(Kr1)'left); -- 1st point of pullup on table
  end use;

--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc   == -1.0    *Lookup(Vpc, Vpc_data, Ipc_data, "SE");-- + kC_comp_pc*C_comp*Vpc'dot; 
  Ipu   == -1.0*kpu*Lookup(Vpu, Vpu_data, Ipu_data, "SE");-- + kC_comp_pu*C_comp*Vpu'dot; 
  Igc   ==          Lookup(Vgc, Vgc_data, Igc_data, "SE");-- + kC_comp_gc*C_comp*Vgc'dot;
--=============================================================================
end architecture IBIS_1EQ1UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;
--=============================================================================
entity IBIS_IO_OPENSOURCE is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.00;       -- splitting coefficients
           kC_comp_pu : real := 0.50;
           kC_comp_pd : real := 0.50;
           kC_comp_gc : real := 0.00;
           --------------------------------------------------------------------
           -- Receiver thresholds
           --------------------------------------------------------------------
           Vinh : real := 2.00;
           Vinl : real := 0.80;
           --------------------------------------------------------------------
           -- [Pullup Reference] and [Pulldown Reference] values
           --------------------------------------------------------------------
           Vpc_ref : real := 5.0;
           Vpu_ref : real := 5.0;
           Vgc_ref : real := 0.0;
           --------------------------------------------------------------------
           -- Vectors of the IV curve tables
           --------------------------------------------------------------------
           Ipc_data : real_vector := ( 0.08,  0.00,  0.00,  0.00);
           Vpc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           Ipu_data : real_vector := ( 0.10,  0.00, -0.10, -0.20);
           Vpu_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
           Igc_data : real_vector := (-0.08,  0.00,  0.00,  0.00);
           Vgc_data : real_vector := (-5.00, -1.00,  5.00, 10.00);
           --------------------------------------------------------------------
           -- Vectors of the Vt curve tables
           --------------------------------------------------------------------
           Vr1_data : real_vector := (0.00,  0.00,     2.50,     2.50);
           Tr1_data : real_vector := (0.00,  1.00e-9,  2.00e-9,  3.00e-9);
           Vf1_data : real_vector := (2.50,  2.50,     0.00,     0.00);
           Tf1_data : real_vector := (0.00,  0.50e-9,  0.80e-9,  3.00e-9);
           --------------------------------------------------------------------
           -- V_fixture and R_fixture values
           --------------------------------------------------------------------
           Vfx_r1 : real := 0.0;
           Vfx_f1 : real := 0.0;

           Rfx_r1 : real := 50.0;
           Rfx_f1 : real := 50.0;
           --------------------------------------------------------------------
           -- Non IBIS parameters
           --------------------------------------------------------------------
           Max_dt : real := 1.0e-12;   -- Maximum dt between time points
           Vth_R  : real := 0.8;       -- Input threshold for rising edges
           Vth_F  : real := 0.2);      -- Input threshold for falling edges
     --------------------------------------------------------------------------
     port (terminal PU_ref : electrical;
           terminal PD_ref : electrical;

           terminal Pad    : electrical;
           terminal In_D   : electrical;
           terminal En_D   : electrical;
--           terminal Rcv_D  : electrical;

           terminal PC_ref : electrical;
           terminal GC_ref : electrical);

end entity IBIS_IO_OPENSOURCE;
--=============================================================================
architecture IBIS_1EQ1UK of IBIS_IO_OPENSOURCE is

  quantity  Vpc   across  Ipc   through  PC_ref  to  Pad;
  quantity  Vpu   across  Ipu   through  PU_ref  to  Pad;
  quantity  Vgc   across  Igc   through  Pad     to  GC_ref;

  quantity  Vin   across                 In_D    to  ELECTRICAL_REF;
  quantity  Ven   across                 En_D    to  ELECTRICAL_REF;
--  quantity  Vrcv  across  Ircv  through  Rcv_D   to  ELECTRICAL_REF;

  signal    pu_on         : integer := 0;
  signal    pu_off        : integer := 0;
  signal    EventState    : integer := 0;

  signal    Tpu_on_event  : real := 0.0;
  signal    Tpu_off_event : real := 0.0;

  quantity  kpu           : real := 0.0;
  --===========================================================================
  function Lookup (X             : real;
                   Xdata         : real_vector;
                   Ydata         : real_vector;
                   Extrapolation : string := "SE") return real is 
  -----------------------------------------------------------------------------
  -- This function returns "Y" that corresponds to "X" in the "Ydata" "Xdata"
  -- input pair using linear interpolation.
  --
  -- If the "X" input value lies outside the range of "Xdata", the returned
  -- "Y" value will either be equal to the first or last point in "Ydata",
  -- or it will be calculated using the slope between the first or last two
  -- points of "Ydata".  The extrapolation method is determined by the string
  -- in "Extrapolation".  "HE" stands for "Horizontal Extrapolation" which
  -- selects the former method, and "SE" stands for "Slope Extrapolation" which
  -- selects the latter method.
  --
  -- Acknowledgements:  The original version of this function was developed by
  -- Mentor Graphics Corporation.  Modifications added by Intel Corporation.
  -----------------------------------------------------------------------------
    variable xvalue, yvalue, m : real;
    variable start, fin, mid   : integer; 
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is outside the range of "Xdata"
    ---------------------------------------------------------------------------
    if (Extrapolation = "SE") and (X <= Xdata(Xdata'left)) then
      m := (Ydata(Ydata'left+1) - Ydata(Ydata'left)) / (Xdata(Xdata'left+1) - Xdata(Xdata'left));
      yvalue := Ydata(Ydata'left) + m * (X - Xdata(Xdata'left));
      return yvalue;

    elsif (Extrapolation = "HE") and (X <= Xdata(Xdata'left)) then
      yvalue := Ydata(Ydata'left);
      return yvalue;

    elsif (Extrapolation = "SE") and (X >= Xdata(Xdata'right)) then
      m := (Ydata(Ydata'right) - Ydata(Ydata'right-1)) / (Xdata(Xdata'right) - Xdata(Xdata'right-1));
      yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right));
      return yvalue;

    elsif (Extrapolation = "HE") and (X >= Xdata(Xdata'right)) then
      yvalue := Ydata(Ydata'right);
      return yvalue;
    ---------------------------------------------------------------------------
    -- Handle cases when "X" is in the range of "Xdata"
    ---------------------------------------------------------------------------
    else
      start:= Xdata'left;
      fin := Xdata'right;

      while  start <= fin  loop
        mid := (start + fin) / 2; 

        if Xdata(mid) < X then
          start := mid + 1;
        else fin := mid - 1;
        end if;  

      end loop; 
                       
      if Xdata(mid) > X then
        mid := mid - 1; 
      end if;
      -------------------------------------------------------------------------
      -- Find "Y" by linear interpolation
      -------------------------------------------------------------------------
      yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid));
      return yvalue;
    ---------------------------------------------------------------------------
    end if;
    ---------------------------------------------------------------------------
  end function Lookup;
  --===========================================================================
  function FindCommonLength (Max_dt : real;
                             T_r1   : real_vector;
                             T_f1   : real_vector) return integer is
  -----------------------------------------------------------------------------
  -- This function finds the total number of points needed for having a
  -- common time axis for all Vt curves, such that the maximum delta time
  -- between each time point doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_index      : integer := 1;

    variable Index_r1     : integer := T_r1'left;
    variable Index_f1     : integer := T_f1'left;

    variable New_index_r1 : integer := T_r1'left;
    variable New_index_f1 : integer := T_f1'left;

    variable Old_t        : real    := 0.0;
    variable Last_t       : real    := 0.0;
    variable New_t        : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_f1(T_f1'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_f1(T_f1'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        T_index := T_index + integer(ceil((New_t-Old_t)/Max_dt)) - 1;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
    end loop; 
    ---------------------------------------------------------------------------
    --report "Common length: " & integer'image(T_index);
    return T_index;
  end function FindCommonLength;
--=============================================================================
  function CommonTime (Common_length : integer;
                       Max_dt        : real;
                       T_r1          : real_vector;
                       T_f1          : real_vector) return real_vector is
  -----------------------------------------------------------------------------
  -- This function generates a vector that serves as a common time axis for
  -- all Vt curves, such that the maximum delta time between each time point
  -- doesn't exceed the value provided in "Max_dt".
  -----------------------------------------------------------------------------
    variable T_common       : real_vector(1 to Common_length) := (others => 0.0);
    variable T_index        : integer := 1;

    variable Index_r1       : integer := T_r1'left;
    variable Index_f1       : integer := T_f1'left;

    variable New_index_r1   : integer := T_r1'left;
    variable New_index_f1   : integer := T_f1'left;

    variable Old_t          : real    := 0.0;
    variable Last_t         : real    := 0.0;
    variable New_t          : real    := 0.0;

    variable Additional_pts : real    := 0.0;
    variable New_dt         : real    := 0.0;
  -----------------------------------------------------------------------------
  begin
    ---------------------------------------------------------------------------
    -- Put the earliest time value of all given time vectors into "Old_t"
    ---------------------------------------------------------------------------
    Old_t := realmin(T_r1(T_r1'left), T_f1(T_f1'left));
    ---------------------------------------------------------------------------
    -- Put the latest time value of all given time vectors into "New_t"
    ---------------------------------------------------------------------------
    Last_t := realmax(T_r1(T_r1'right), T_f1(T_f1'right));
    New_t  := Last_t;
    ---------------------------------------------------------------------------
    -- Loop until latest time value is reached in each given time vector
    ---------------------------------------------------------------------------
    while (Old_t < New_t) loop
      -------------------------------------------------------------------------
      -- Save the time value from Old_t in T_common
      -- and increment T_index counter
      -------------------------------------------------------------------------
      T_common(T_index) := Old_t;
      T_index := T_index + 1;
      -------------------------------------------------------------------------
      -- Find which given time vector(s) have the lowest time value and
      -- advance their temporary indexes
      -------------------------------------------------------------------------
      if (T_r1(Index_r1) <= Old_t) then New_index_r1 := Index_r1 + 1;
      end if;
      if (T_f1(Index_f1) <= Old_t) then New_index_f1 := Index_f1 + 1;
      end if;
      -------------------------------------------------------------------------
      -- Find the lowest value at the new indexes in the given vector(s) and
      -- update indexes for next iteration
      -------------------------------------------------------------------------
      if (New_index_r1 <= T_r1'right) then
        if (T_r1(New_index_r1) < New_t) then New_t := T_r1(New_index_r1);
        end if;
        Index_r1 := New_index_r1;
      end if;
      if (New_index_f1 <= T_f1'right) then
        if (T_f1(New_index_f1) < New_t) then New_t := T_f1(New_index_f1);
        end if;
        Index_f1 := New_index_f1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate how many additional points are needed between the given
      -- points to satisfy the "Max_dt" separation criteria.
      -------------------------------------------------------------------------
      if ((New_t-Old_t) > Max_dt) then
        Additional_pts := ceil((New_t-Old_t)/Max_dt);
        New_dt := (New_t-Old_t) / Additional_pts;
        for i in 1 to integer(Additional_pts)-1 loop
          T_common(T_index) := T_common(T_index-1) + New_dt;
          T_index := T_index + 1;
        end loop;
      end if;
      -------------------------------------------------------------------------
      -- Update variables for next iteration
      -------------------------------------------------------------------------
      Old_t := New_t;
      New_t := Last_t;
    ---------------------------------------------------------------------------
      --report "T_common: " & real'image(T_common(T_index-1));
    end loop; 
    T_common(T_index) := Last_t;
    --report "T_common: " & real'image(T_common(T_index));
    ---------------------------------------------------------------------------
    --report "Length of T_common: " & integer'image(T_index);
    return T_common;
  end function CommonTime;
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_data, Tf1_data);

  type k_elements    is (Tcm, Kr1, Kf1);
  type k_tables_type is array(k_elements) of real_vector(1 to CommonLength);
--=============================================================================
  function Coeff (Common_length : integer;
                  Max_dt : real;
                  I_pc   : real_vector;
                  V_pc   : real_vector;
                  I_pu   : real_vector;
                  V_pu   : real_vector;
                  I_gc   : real_vector;
                  V_gc   : real_vector;

                  V_r1   : real_vector;
                  T_r1   : real_vector;
                  V_f1   : real_vector;
                  T_f1   : real_vector;

                  V_pc_ref : real;
                  V_pu_ref : real;
                  V_gc_ref : real;

                  V_fx_r1  : real;
                  V_fx_f1  : real;

                  R_fx_r1  : real;
                  R_fx_f1  : real;

                  C_comp_total : real) return k_tables_type is
  -----------------------------------------------------------------------------
  -- This function converts each Vt table to a corresponding scaling
  -- coefficient table that is used to scale the IV curves with respect
  -- to time.  The C_comp effects in the waveforms are eliminated from the
  -- scaling coefficients, so that the output waveforms will match the Vt
  -- table regardless of the presence of C_comp under identical loading
  -- conditions, i.e. C_comp in the output stage will not derate the
  -- original Vt curves.
  -----------------------------------------------------------------------------
    variable K_tables : k_tables_type;

    variable Vr1cm : real_vector(1 to 3) := (others => 0.0);
    variable Vf1cm : real_vector(1 to 3) := (others => 0.0);

    variable dVwfm_r1 : real := 0.0;
    variable dVwfm_f1 : real := 0.0;

    variable Iout1 : real := 0.0;
    variable Ipc1  : real := 0.0;
    variable Ipu1  : real := 0.0;
    variable Ipd1  : real := 0.0;
    variable Igc1  : real := 0.0;
  -----------------------------------------------------------------------------
  begin
    K_tables(Tcm) := CommonTime(Common_length, Max_dt, T_r1, T_f1);
    --=========================================================================
    -- Calculate the scaling coefficients for each time point along Tcm
    ---------------------------------------------------------------------------
    -- Store the first voltage point in the common waveform variables
    ---------------------------------------------------------------------------
    Vr1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_r1, V_r1, "HE");
    Vf1cm(2) := Lookup(K_tables(Tcm)(K_tables(Tcm)'left), T_f1, V_f1, "HE");

    for i in K_tables(Tcm)'range loop
    --report "Tcm: " & real'image(K_tables(Tcm)(i));  -- For debugging
    ---------------------------------------------------------------------------
    -- Store the next point (for the derivative calculations)
    ---------------------------------------------------------------------------
      if (i < K_tables(Tcm)'right) then
        Vr1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_r1, V_r1, "HE");
        Vf1cm(3) := Lookup(K_tables(Tcm)(i+K_tables(Tcm)'left), T_f1, V_f1, "HE");
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: " & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " R1: " & real'image(Vr1cm(2)) &
      --       " F1: " & real'image(Vf1cm(2));
      -------------------------------------------------------------------------
      -- Calculate the derivative of each waveform for C_comp compensation
      -------------------------------------------------------------------------
      if ((i <= K_tables(Tcm)'left) or (i >= K_tables(Tcm)'right)) then
        dVwfm_r1 := 0.0;          -- Force the end point derivatives to zero
        dVwfm_f1 := 0.0;
      else
        dVwfm_r1 := ((Vr1cm(2) - Vr1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vr1cm(3) - Vr1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
        dVwfm_f1 := ((Vf1cm(2) - Vf1cm(1)) / (K_tables(Tcm)(i)   - K_tables(Tcm)(i-1)) +
                     (Vf1cm(3) - Vf1cm(2)) / (K_tables(Tcm)(i+1) - K_tables(Tcm)(i)))  / 2.0;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " dR1: " & real'image(dVwfm_r1) &
      --       " dF1: " & real'image(dVwfm_f1);
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kr1 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vr1cm(2) - V_fx_r1) / R_fx_r1) + C_comp_total * dVwfm_r1;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vr1cm(2), V_pc, I_pc, "HE");
      Ipu1  :=        Lookup(V_pu_ref - Vr1cm(2), V_pu, I_pu, "HE");
      Igc1  :=        Lookup(Vr1cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      -- Since these are rising waveforms
      -- Kr1 == Kpu_on
      if (Ipu1 = 0.0) then K_tables(Kr1)(i) := 0.0;
      else                 K_tables(Kr1)(i) := (Ipc1 - Igc1 - Iout1) / Ipu1;
      end if;
      -------------------------------------------------------------------------
      -- Calculate intermediate variables and the Kf1 coefficients
      -------------------------------------------------------------------------
      Iout1 := ((Vf1cm(2) - V_fx_f1) / R_fx_f1) + C_comp_total * dVwfm_f1;

      Ipc1  := -1.0 * Lookup(V_pc_ref - Vf1cm(2), V_pc, I_pc, "HE");
      Ipu1  :=        Lookup(V_pu_ref - Vf1cm(2), V_pu, I_pu, "HE");
      Igc1  :=        Lookup(Vf1cm(2) - V_gc_ref, V_gc, I_gc, "HE");

      -- Since these are falling waveforms
      -- Kf1 == Kpu_off
      if (Ipu1 = 0.0) then K_tables(Kf1)(i) := 0.0;
      else                 K_tables(Kf1)(i) := (Ipc1 - Igc1 - Iout1) / Ipu1;
      end if;
      -------------------------------------------------------------------------
      --report "Tcm: "  & real'image(K_tables(Tcm)(i)) & -- For Debugging
      --       " Kr1: " & real'image(K_tables(Kr1)(i)) &
      --       " Kf1: " & real'image(K_tables(Kf1)(i));
      -------------------------------------------------------------------------
      -- Shift points by one index for next iteration (for C_comp compensation)
      -------------------------------------------------------------------------
      Vr1cm(1) := Vr1cm(2);
      Vf1cm(1) := Vf1cm(2);

      Vr1cm(2) := Vr1cm(3);
      Vf1cm(2) := Vf1cm(3);

    end loop; -- for loop
    ---------------------------------------------------------------------------
    return K_tables;
  end function Coeff;
--=============================================================================
  constant Ktables : k_tables_type := Coeff(CommonLength, Max_dt,
                                            Ipc_data, Vpc_data,
                                            Ipu_data, Vpu_data,
                                            Igc_data, Vgc_data,
                                            Vr1_data, Tr1_data,
                                            Vf1_data, Tf1_data,
                                            Vpc_ref,
                                            Vpu_ref,
                                            Vgc_ref,
                                            Vfx_r1,
                                            Vfx_f1,
                                            Rfx_r1,
                                            Rfx_f1,
                                            C_comp);
--=============================================================================
begin

  Catch: process is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if domain = quiescent_domain then

      wait until domain /= quiescent_domain;
      EventState <= 1;

    else

      wait on Vin'above(Vth_R), Vin'above(Vth_F),
              Ven'above(Vth_R), Ven'above(Vth_F);

      if ((Vin > Vth_R) or (Vin < Vth_F)) and
         ((Ven > Vth_R) or (Ven < Vth_F)) then

        if   EventState < 3 then  EventState <= EventState+1;
        else                      EventState <= EventState-1;
        end if;

      end if;
    end if;
  -----------------------------------------------------------------------------
  end process Catch;
  --===========================================================================
  FindState: process (EventState) is
  -----------------------------------------------------------------------------
  begin
  -----------------------------------------------------------------------------
    if (Ven > Vth_R) and (Vin > Vth_R) then           -- high state
      pu_on  <= 1;
      pu_off <= 0;
    elsif (Ven > Vth_R) and (Vin < Vth_F) then        -- low state
      pu_on  <= 0;
      pu_off <= 1;
    elsif (Ven < Vth_F) then                          -- 3-state
      pu_on  <= 0;
      pu_off <= 1;
    else                                              -- unknown state
      pu_on  <= 1;
      pu_off <= 0;
    end if;
  -----------------------------------------------------------------------------
  end process FindState;
--=============================================================================
  break on pu_on;
  break on pu_off;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-- This entire section could be made more efficient with nested IF statements
-- if the simulator wouldn't have a problem with simultaneous statements in
-- nested case statements.
--XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

  -- Executes during DC operating point calculation
  if    (EventState = 0) and (Ven > Vth_R) and (Vin > Vth_R) use   -- high state
    kpu == Ktables(Kr1)(CommonLength);
  elsif (EventState = 0) and (Ven > Vth_R) and (Vin < Vth_F) use   -- low state
    kpu == Ktables(Kf1)(CommonLength);
  elsif (EventState = 0) and (Ven < Vth_F) use                     -- 3-state
    kpu == Ktables(Kf1)(CommonLength);

  -- Executes after DC operating point calculation before first event
  elsif (EventState = 1) and (pu_off = 1) use
    kpu == Ktables(Kf1)(CommonLength);      -- Last point from pu_off table
  elsif (EventState = 1) and (pu_off /= 1)use
    kpu == Ktables(Kr1)(CommonLength);      -- Last point from pu_on table

  -- Executes after first event (normal operation)
  elsif (EventState > 1) and (pu_on  = 1) use    -- Pullup turning on
    kpu == Lookup(pu_on'last_event,  Ktables(Tcm), Ktables(Kr1), "HE");
  elsif (EventState > 1) and (pu_off = 1) use    -- Pullup turning off
    kpu == Lookup(pu_off'last_event, Ktables(Tcm), Ktables(Kf1), "HE");

  -- Just in case
  else
    kpu == Ktables(Kr1)(Ktables(Kr1)'left); -- 1st point of pullup on table
  end use;

--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc   == -1.0    *Lookup(Vpc, Vpc_data, Ipc_data, "SE");-- + kC_comp_pc*C_comp*Vpc'dot; 
  Ipu   == -1.0*kpu*Lookup(Vpu, Vpu_data, Ipu_data, "SE");-- + kC_comp_pu*C_comp*Vpu'dot; 
  Igc   ==          Lookup(Vgc, Vgc_data, Igc_data, "SE");-- + kC_comp_gc*C_comp*Vgc'dot;
  -----------------------------------------------------------------------------
  -- A simple receiver logic
  -----------------------------------------------------------------------------
--  if    (Vgc > Vinh) use Vrcv == 1.0;
--  elsif (Vgc < Vinl) use Vrcv == 0.0;
--  else                   Vrcv == 0.5;
--  end use;
--=============================================================================
end architecture IBIS_1EQ1UK;
--=============================================================================
