--=============================================================================
-- 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.
-- 2006/02/01  - Added file reader routine to read parameters from a file.
--             - Separated functions into package file.
--             - Changed the type of "i12" and "i21" from real to current to
--               eliminate some warning messages.
-- 2006/02/06  - Fixed a bug in the IBIS buffer models.  "FindCommonLength"
--               function was given the wrong vectors.
--             - Changed the algorithm of "DIV" controlled sources to handle
--               div/0 situation more gently.
--             - Changed the type of "kpd" and "kpu" from real to current to
--               eliminate all warning messages.
--             - Added three more data files to test the IBIS buffer models.
--               These files were extracted with the new Perl script from a
--               real IBIS file, and contain full length IV and Vt tables.
-- 2006/02/27  - Fixed a bug in the "FindCommonLength" and "CommonTime"
--               functions of IBIS buffer models.
--             - Added IV and Vt curve scaling capability to IBIS buffers.
--             - Corrected kC_comp_** initial values and analog equations 
--               for missing C_comp components in Open_*** models.
--             - Removed four unused signals (variables) from IBIS buffers.
-- 2006/06/28  - Fixed "DIV" controlled sources to eliminate div/0 error 
--               due to execution order during first few simulation cycles.
--             - Fixed the input thresholds for buffers and event triggered
--               PWL sources to be more compatible with HSPICE's B-element
--               threshold levels.
--             - Fixed buffers and event controlled PWL sources to initialize
--               properly for all possible combinations of input values. 
--               Also, eliminated possible glitches due to execution order of
--               various simulation cycles.
--             - Added BREAK statements to "DIV" and event controlled PWL
--               sources.
--             - Fixed V-t tables in data files for Open_*** models.
--             - Added a warning to the IBIS_***_DIV elements.
-- 2006/07/05  - Replaced the relational operators in the three IBIS_IO_***
--               models with 'above, and added corresponding break statements.
--=============================================================================
--=============================== Module list =================================
--=============================================================================
--=============================================================================
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;
             ZeroLimit : real := 1.0e-3);

    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;

  quantity AbsVin2  : voltage;
  signal   NearZero : boolean := true;

  begin

    ---------------------------------------------------------------------------
    Selector : process (AbsVin2'above(ZeroLimit)) is
    begin
      if AbsVin2 > ZeroLimit then
        NearZero <= false;
      else
        NearZero <= true;
      end if;
    end process Selector;
    ---------------------------------------------------------------------------
    Message : process is
    begin
      wait on domain, NearZero;
      if AbsVin2 <= ZeroLimit then
        report "  The divisor in module 'IBIS_VCVS_DIV' is less than or equal to the " &
               "value defined in its parameter 'ZeroLimit = " & real'image(ZeroLimit) &
               "' at time = " & real'image(now) & "." severity WARNING;
      end if;
    end process Message;
    ---------------------------------------------------------------------------
    break on NearZero;
    ---------------------------------------------------------------------------

    AbsVin2 == abs(Vin2);
    if NearZero use
      Vout == Scale * Vin1 * Vin2 / ZeroLimit**2;
    else
      Vout == Scale * Vin1 / Vin2;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCVS_DIV is

    generic (Scale     : real := 1.0;
             ZeroLimit : real := 1.0e-3);

    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;

  quantity AbsIin2  : current;
  signal   NearZero : boolean := true;

  begin

    ---------------------------------------------------------------------------
    Selector : process (AbsIin2'above(ZeroLimit)) is
    begin
      if AbsIin2 > ZeroLimit then
        NearZero <= false;
      else
        NearZero <= true;
      end if;
    end process Selector;
    ---------------------------------------------------------------------------
    Message : process is
    begin
      wait on domain, NearZero;
      if AbsIin2 <= ZeroLimit then
        report "  The divisor in module 'IBIS_CCVS_DIV' is less than or equal to the " &
               "value defined in its parameter 'ZeroLimit = " & real'image(ZeroLimit) &
               "' at time = " & real'image(now) & "." severity WARNING;
      end if;
    end process Message;
    ---------------------------------------------------------------------------
    break on NearZero;
    ---------------------------------------------------------------------------

    AbsIin2 == abs(Iin2);
    Vin1    == 0.0;
    Vin2    == 0.0;
    if NearZero use
      Vout == Scale * Iin1 * Iin2 / ZeroLimit**2;
    else
      Vout == Scale * Iin1 / Iin2;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
  entity IBIS_VCVS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
             Y_data : real_vector := (-0.10,  0.00,  0.10,  0.10);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------
    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;
  --===========================================================================
  constant  X_vec : real_vector := FileRead(DataFile, "X_data", X_data, Max_length);
  constant  Y_vec : real_vector := FileRead(DataFile, "Y_data", Y_data, Max_length);
--=============================================================================
  begin

    Vout == Scale * Lookup(Vin, X_vec, Y_vec, "SE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
  entity IBIS_CCVS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
             Y_data : real_vector := (-0.10,  0.00,  0.10,  0.10);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------
    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;
  --===========================================================================
  constant  X_vec : real_vector := FileRead(DataFile, "X_data", X_data, Max_length);
  constant  Y_vec : real_vector := FileRead(DataFile, "Y_data", Y_data, Max_length);
--=============================================================================
  begin

    Vin  == 0.0;
    Vout == Scale * Lookup(Iin, X_vec, Y_vec, "SE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
  entity IBIS_TCVS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             Y_data : real_vector := (0.00,     0.10,     0.90,     1.00);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------
    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;
  --===========================================================================
  constant  X_vec : real_vector := FileRead(DataFile, "X_data", X_data, Max_length);
  constant  Y_vec : real_vector := FileRead(DataFile, "Y_data", Y_data, Max_length);
--=============================================================================
  begin

    Vout == Scale * Lookup(now, X_vec, Y_vec, "HE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.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_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YR_data : real_vector := (0.00,     0.10,     0.90,     1.00);
             XF_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YF_data : real_vector := (1.00,     0.90,     0.10,     0.00);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------
    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   EventState : integer := 0;
  --===========================================================================
  constant  XR_vec : real_vector := FileRead(DataFile, "XR_data", XR_data, Max_length);
  constant  YR_vec : real_vector := FileRead(DataFile, "YR_data", YR_data, Max_length);
  constant  XF_vec : real_vector := FileRead(DataFile, "XF_data", XF_data, Max_length);
  constant  YF_vec : real_vector := FileRead(DataFile, "YF_data", YF_data, Max_length);
--=============================================================================
  constant  DC_threshold : real := (Vth_R + Vth_F) / 2.0;
--=============================================================================
  begin

    ---------------------------------------------------------------------------
    Threshold_crossing : process (Vin'above(DC_threshold),
                                  Vin'above(Vth_R), Vin'above(Vth_F)) is
    ---------------------------------------------------------------------------
    begin

      if domain = quiescent_domain then     -- during DC analysis
        if Vin > DC_threshold then          -- high state
          EventState <= 1;
        else                                -- low state
          EventState <= -1;
        end if;
      else
        if Vin > Vth_R then                 -- rising edge ****************
          if EventState < 0 then            -- low to high state transition
            EventState <= 2;
          end if;
        elsif Vin <= Vth_F then             -- falling edge ***************
          if EventState > 0 then            -- high to low state transition
            EventState <= -2;
          end if;
        end if;
      end if;

    end process Threshold_crossing;
    ---------------------------------------------------------------------------
    break on EventState;
    ---------------------------------------------------------------------------

    case EventState use
      when -2 =>        -- Executes after falling edge events (normal operation)
        Vout == Scale * Lookup(EventState'last_event, XF_vec, YF_vec, "HE");
      when -1 =>        -- Executes before first good threshold crossing
        Vout == Scale * YR_vec(YR_vec'left);        -- when input is LOW
      when 1 =>         -- Executes before first good threshold crossing
        Vout == Scale * YF_vec(YF_vec'left);        -- when input is HIGH
      when 2 =>         -- Executes after rising edge events (normal operation)
        Vout == Scale * Lookup(EventState'last_event, XR_vec, YR_vec, "HE");
      when others =>    -- This should really never execute
        Vout == 0.0;
    end case;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.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_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YR_data : real_vector := (0.00,     0.10,     0.90,     1.00);
             XF_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YF_data : real_vector := (1.00,     0.90,     0.10,     0.00);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------
    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   EventState : integer := 0;
  --===========================================================================
  constant  XR_vec : real_vector := FileRead(DataFile, "XR_data", XR_data, Max_length);
  constant  YR_vec : real_vector := FileRead(DataFile, "YR_data", YR_data, Max_length);
  constant  XF_vec : real_vector := FileRead(DataFile, "XF_data", XF_data, Max_length);
  constant  YF_vec : real_vector := FileRead(DataFile, "YF_data", YF_data, Max_length);
--=============================================================================
  constant  DC_threshold : real := (Ith_R + Ith_F) / 2.0;
--=============================================================================
  begin

    ---------------------------------------------------------------------------
    Threshold_crossing : process (Iin'above(DC_threshold),
                                  Iin'above(Ith_R), Iin'above(Ith_F)) is
    ---------------------------------------------------------------------------
    begin

      if domain = quiescent_domain then     -- during DC analysis
        if Iin > DC_threshold then          -- high state
          EventState <= 1;
        else                                -- low state
          EventState <= -1;
        end if;
      else
        if Iin > Ith_R then                 -- rising edge ****************
          if EventState < 0 then            -- low to high state transition
            EventState <= 2;
          end if;
        elsif Iin <= Ith_F then             -- falling edge ***************
          if EventState > 0 then            -- high to low state transition
            EventState <= -2;
          end if;
        end if;
      end if;

    end process Threshold_crossing;
    ---------------------------------------------------------------------------
    break on EventState;
    ---------------------------------------------------------------------------

    Vin == 0.0;
    case EventState use
      when -2 =>        -- Executes after falling edge events (normal operation)
        Vout == Scale * Lookup(EventState'last_event, XF_vec, YF_vec, "HE");
      when -1 =>        -- Executes before first good threshold crossing
        Vout == Scale * YR_vec(YR_vec'left);        -- when input is LOW
      when 1 =>         -- Executes before first good threshold crossing
        Vout == Scale * YF_vec(YF_vec'left);        -- when input is HIGH
      when 2 =>         -- Executes after rising edge events (normal operation)
        Vout == Scale * Lookup(EventState'last_event, XR_vec, YR_vec, "HE");
      when others =>    -- This should really never execute
        Vout == 0.0;
    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;
             ZeroLimit : real := 1.0e-3);

    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;

  quantity AbsVin2  : voltage;
  signal   NearZero : boolean := true;

  begin

    ---------------------------------------------------------------------------
    Selector : process (AbsVin2'above(ZeroLimit)) is
    begin
      if AbsVin2 > ZeroLimit then
        NearZero <= false;
      else
        NearZero <= true;
      end if;
    end process Selector;
    ---------------------------------------------------------------------------
    Message : process is
    begin
      wait on domain, NearZero;
      if AbsVin2 <= ZeroLimit then
        report "  The divisor in module 'IBIS_VCCS_DIV' is less than or equal to the " &
               "value defined in its parameter 'ZeroLimit = " & real'image(ZeroLimit) &
               "' at time = " & real'image(now) & "." severity WARNING;
      end if;
    end process Message;
    ---------------------------------------------------------------------------
    break on NearZero;
    ---------------------------------------------------------------------------

    AbsVin2 == abs(Vin2);
    if NearZero use
      Iout == Scale * Vin1 * Vin2 / ZeroLimit**2;
    else
      Iout == Scale * Vin1 / Vin2;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
--=============================================================================
  entity IBIS_CCCS_DIV is

    generic (Scale     : real := 1.0;
             ZeroLimit : real := 1.0e-3);

    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;

  quantity AbsIin2  : current;
  signal   NearZero : boolean := true;

  begin

    ---------------------------------------------------------------------------
    Selector : process (AbsIin2'above(ZeroLimit)) is
    begin
      if AbsIin2 > ZeroLimit then
        NearZero <= false;
      else
        NearZero <= true;
      end if;
    end process Selector;
    ---------------------------------------------------------------------------
    Message : process is
    begin
      wait on domain, NearZero;
      if AbsIin2 <= ZeroLimit then
        report "  The divisor in module 'IBIS_CCCS_DIV' is less than or equal to the " &
               "value defined in its parameter 'ZeroLimit = " & real'image(ZeroLimit) &
               "' at time = " & real'image(now) & "." severity WARNING;
      end if;
    end process Message;
    ---------------------------------------------------------------------------
    break on NearZero;
    ---------------------------------------------------------------------------

    AbsIin2 == abs(Iin2);
    Vin1    == 0.0;
    Vin2    == 0.0;
    if NearZero use
      Iout == Scale * Iin1 * Iin2 / ZeroLimit**2;
    else
      Iout == Scale * Iin1 / Iin2;
    end use;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
  entity IBIS_VCCS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
             Y_data : real_vector := (-0.10,  0.00,  0.10,  0.10);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------
    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;
  --===========================================================================
  constant  X_vec : real_vector := FileRead(DataFile, "X_data", X_data, Max_length);
  constant  Y_vec : real_vector := FileRead(DataFile, "Y_data", Y_data, Max_length);
--=============================================================================
  begin

    Iout == Scale * Lookup(Vin, X_vec, Y_vec, "SE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
  entity IBIS_CCCS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X_data : real_vector := (-5.00,  0.00,  5.00, 10.00);
             Y_data : real_vector := (-0.10,  0.00,  0.10,  0.10);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------
    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;
  --===========================================================================
  constant  X_vec : real_vector := FileRead(DataFile, "X_data", X_data, Max_length);
  constant  Y_vec : real_vector := FileRead(DataFile, "Y_data", Y_data, Max_length);
--=============================================================================
  begin

    Vin  == 0.0;
    Iout == Scale * Lookup(Iin, X_vec, Y_vec, "SE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
  entity IBIS_TCCS_PWL is

    generic (Scale : real := 1.0;
             ------------------------------------------------------------------
             -- Vectors of the PWL table
             ------------------------------------------------------------------
             X_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             Y_data : real_vector := (0.00,     0.10,     0.90,     1.00);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------
    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;
  --===========================================================================
  constant  X_vec : real_vector := FileRead(DataFile, "X_data", X_data, Max_length);
  constant  Y_vec : real_vector := FileRead(DataFile, "Y_data", Y_data, Max_length);
--=============================================================================
  begin

    Iout == Scale * Lookup(now, X_vec, Y_vec, "HE");

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.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_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YR_data : real_vector := (0.00,     0.10,     0.90,     1.00);
             XF_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YF_data : real_vector := (1.00,     0.90,     0.10,     0.00);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------
    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   EventState : integer := 0;
  --===========================================================================
  constant  XR_vec : real_vector := FileRead(DataFile, "XR_data", XR_data, Max_length);
  constant  YR_vec : real_vector := FileRead(DataFile, "YR_data", YR_data, Max_length);
  constant  XF_vec : real_vector := FileRead(DataFile, "XF_data", XF_data, Max_length);
  constant  YF_vec : real_vector := FileRead(DataFile, "YF_data", YF_data, Max_length);
--=============================================================================
  constant  DC_threshold : real := (Vth_R + Vth_F) / 2.0;
--=============================================================================
  begin

    ---------------------------------------------------------------------------
    Threshold_crossing : process (Vin'above(DC_threshold),
                                  Vin'above(Vth_R), Vin'above(Vth_F)) is
    ---------------------------------------------------------------------------
    begin

      if domain = quiescent_domain then     -- during DC analysis
        if Vin > DC_threshold then          -- high state
          EventState <= 1;
        else                                -- low state
          EventState <= -1;
        end if;
      else
        if Vin > Vth_R then                 -- rising edge ****************
          if EventState < 0 then            -- low to high state transition
            EventState <= 2;
          end if;
        elsif Vin <= Vth_F then             -- falling edge ***************
          if EventState > 0 then            -- high to low state transition
            EventState <= -2;
          end if;
        end if;
      end if;

    end process Threshold_crossing;
    ---------------------------------------------------------------------------
    break on EventState;
    ---------------------------------------------------------------------------

    case EventState use
      when -2 =>        -- Executes after falling edge events (normal operation)
        Iout == Scale * Lookup(EventState'last_event, XF_vec, YF_vec, "HE");
      when -1 =>        -- Executes before first good threshold crossing
        Iout == Scale * YR_vec(YR_vec'left);        -- when input is LOW
      when 1 =>         -- Executes before first good threshold crossing
        Iout == Scale * YF_vec(YF_vec'left);        -- when input is HIGH
      when 2 =>         -- Executes after rising edge events (normal operation)
        Iout == Scale * Lookup(EventState'last_event, XR_vec, YR_vec, "HE");
      when others =>    -- This should really never execute
        Iout == 0.0;
    end case;

  end architecture ideal;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;

library MacroLib;
use MacroLib.MacroLib_functions.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_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YR_data : real_vector := (0.00,     0.10,     0.90,     1.00);
             XF_data : real_vector := (0.50e-9,  1.00e-9,  2.00e-9,  2.50e-9);
             YF_data : real_vector := (1.00,     0.90,     0.10,     0.00);
             ------------------------------------------------------------------
             DataFile   : string  := "";      -- Data file name
             Max_length : integer := 100);    -- Maximum possible table length
    ---------------------------------------------------------------------------

    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   EventState : integer := 0;
  --===========================================================================
  constant  XR_vec : real_vector := FileRead(DataFile, "XR_data", XR_data, Max_length);
  constant  YR_vec : real_vector := FileRead(DataFile, "YR_data", YR_data, Max_length);
  constant  XF_vec : real_vector := FileRead(DataFile, "XF_data", XF_data, Max_length);
  constant  YF_vec : real_vector := FileRead(DataFile, "YF_data", YF_data, Max_length);
--=============================================================================
  constant  DC_threshold : real := (Ith_R + Ith_F) / 2.0;
--=============================================================================
  begin

    ---------------------------------------------------------------------------
    Threshold_crossing : process (Iin'above(DC_threshold),
                                  Iin'above(Ith_R), Iin'above(Ith_F)) is
    ---------------------------------------------------------------------------
    begin

      if domain = quiescent_domain then     -- during DC analysis
        if Iin > DC_threshold then          -- high state
          EventState <= 1;
        else                                -- low state
          EventState <= -1;
        end if;
      else
        if Iin > Ith_R then                 -- rising edge ****************
          if EventState < 0 then            -- low to high state transition
            EventState <= 2;
          end if;
        elsif Iin <= Ith_F then             -- falling edge ***************
          if EventState > 0 then            -- high to low state transition
            EventState <= -2;
          end if;
        end if;
      end if;

    end process Threshold_crossing;
    ---------------------------------------------------------------------------
    break on EventState;
    ---------------------------------------------------------------------------

    Vin == 0.0;
    case EventState use
      when -2 =>        -- Executes after falling edge events (normal operation)
        Iout == Scale * Lookup(EventState'last_event, XF_vec, YF_vec, "HE");
      when -1 =>        -- Executes before first good threshold crossing
        Iout == Scale * YR_vec(YR_vec'left);        -- when input is LOW
      when 1 =>         -- Executes before first good threshold crossing
        Iout == Scale * YF_vec(YF_vec'left);        -- when input is HIGH
      when 2 =>         -- Executes after rising edge events (normal operation)
        Iout == Scale * Lookup(EventState'last_event, XR_vec, YR_vec, "HE");
      when others =>    -- This should really never execute
        Iout == 0.0;
    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 : current;    -- Current wave traveling from end1 to end2
  quantity i21 : current;    -- 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;

library MacroLib;
use MacroLib.MacroLib_functions.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);
           --------------------------------------------------------------------
           -- Non IBIS parameters
           --------------------------------------------------------------------
           kI_pc        : real    := 1.0;     -- PC current scaling
           kI_gc        : real    := 1.0;     -- GC current scaling
           --------------------------------------------------------------------
           DataFile     : string  := "";      -- IBIS parameter file name
           MaxIV_length : integer := 100);    -- Maximum possible length of IV tables
     --------------------------------------------------------------------------
     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;

  --===========================================================================
  constant  C_comp_val     : real := FileRead(DataFile, "C_comp",     C_comp);
  constant  kC_comp_pc_val : real := FileRead(DataFile, "kC_comp_pc", kC_comp_pc);
  constant  kC_comp_gc_val : real := FileRead(DataFile, "kC_comp_gc", kC_comp_gc);

  constant  Vinh_val    : real := FileRead(DataFile, "Vinh", Vinh);
  constant  Vinl_val    : real := FileRead(DataFile, "Vinl", Vinl);

  constant  Ipc_vec     : real_vector := FileRead(DataFile, "Ipc_data", Ipc_data, MaxIV_length);
  constant  Vpc_vec     : real_vector := FileRead(DataFile, "Vpc_data", Vpc_data, MaxIV_length);
  constant  Igc_vec     : real_vector := FileRead(DataFile, "Igc_data", Igc_data, MaxIV_length);
  constant  Vgc_vec     : real_vector := FileRead(DataFile, "Vgc_data", Vgc_data, MaxIV_length);
--=============================================================================
begin
  --===========================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc == -1.0*kI_pc*Lookup(Vpc, Vpc_vec, Ipc_vec, "SE") + kC_comp_pc_val*C_comp_val*Vpc'dot;
  Igc ==      kI_gc*Lookup(Vgc, Vgc_vec, Igc_vec, "SE") + kC_comp_gc_val*C_comp_val*Vgc'dot;
  -----------------------------------------------------------------------------
  -- A simple receiver logic
  -----------------------------------------------------------------------------
  if        Vgc'above(Vinh_val)  use Vrcv == 1.0;
  elsif not(Vgc'above(Vinl_val)) use Vrcv == 0.0;
  else                               Vrcv == 0.5;
  end use;
  break on Vgc'above(Vinh_val), Vgc'above(Vinl_val);
--=============================================================================
end architecture SIMPLE_RECEIVER;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
entity IBIS_OUTPUT is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.25;       -- splitting coefficients
           kC_comp_pu : real := 0.25;
           kC_comp_pd : real := 0.25;
           kC_comp_gc : real := 0.25;
           --------------------------------------------------------------------
           -- [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
           --------------------------------------------------------------------
           kI_pc        : real    := 1.0;     -- PC current scaling
           kI_pu        : real    := 1.0;     -- PU current scaling
           kI_pd        : real    := 1.0;     -- PD current scaling
           kI_gc        : real    := 1.0;     -- GC current scaling

           kt_rise      : real    := 1.0;     -- Rising waveform time scaling
           kt_fall      : real    := 1.0;     -- Falling waveform time scaling
           --------------------------------------------------------------------
           DataFile     : string  := "";      -- IBIS parameter file name
           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
           MaxIV_length : integer := 100;     -- Maximum possible length of IV tables
           MaxVt_length : integer := 1000);   -- Maximum possible length of Vt tables
     --------------------------------------------------------------------------
     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_State      : integer := 0;
  signal    PD_State      : integer := 0;
  quantity  kpu           : current := 0.0;
  quantity  kpd           : current := 0.0;
  --===========================================================================
  constant  C_comp_val     : real := FileRead(DataFile, "C_comp",     C_comp);
  constant  kC_comp_pc_val : real := FileRead(DataFile, "kC_comp_pc", kC_comp_pc);
  constant  kC_comp_pu_val : real := FileRead(DataFile, "kC_comp_pu", kC_comp_pu);
  constant  kC_comp_pd_val : real := FileRead(DataFile, "kC_comp_pd", kC_comp_pd);
  constant  kC_comp_gc_val : real := FileRead(DataFile, "kC_comp_gc", kC_comp_gc);

  constant  Vpc_ref_val : real := FileRead(DataFile, "Vpc_ref", Vpc_ref);
  constant  Vpu_ref_val : real := FileRead(DataFile, "Vpu_ref", Vpu_ref);
  constant  Vpd_ref_val : real := FileRead(DataFile, "Vpd_ref", Vpd_ref);
  constant  Vgc_ref_val : real := FileRead(DataFile, "Vgc_ref", Vgc_ref);

  constant  Ipc_vec     : real_vector := FileRead(DataFile, "Ipc_data", Ipc_data, MaxIV_length);
  constant  Vpc_vec     : real_vector := FileRead(DataFile, "Vpc_data", Vpc_data, MaxIV_length);
  constant  Ipu_vec     : real_vector := FileRead(DataFile, "Ipu_data", Ipu_data, MaxIV_length);
  constant  Vpu_vec     : real_vector := FileRead(DataFile, "Vpu_data", Vpu_data, MaxIV_length);
  constant  Ipd_vec     : real_vector := FileRead(DataFile, "Ipd_data", Ipd_data, MaxIV_length);
  constant  Vpd_vec     : real_vector := FileRead(DataFile, "Vpd_data", Vpd_data, MaxIV_length);
  constant  Igc_vec     : real_vector := FileRead(DataFile, "Igc_data", Igc_data, MaxIV_length);
  constant  Vgc_vec     : real_vector := FileRead(DataFile, "Vgc_data", Vgc_data, MaxIV_length);

  constant  Vr1_vec     : real_vector := FileRead(DataFile, "Vr1_data", Vr1_data, MaxVt_length);
  constant  Tr1_vec     : real_vector := FileRead(DataFile, "Tr1_data", Tr1_data, MaxVt_length, kt_rise);
  constant  Vr2_vec     : real_vector := FileRead(DataFile, "Vr2_data", Vr2_data, MaxVt_length);
  constant  Tr2_vec     : real_vector := FileRead(DataFile, "Tr2_data", Tr2_data, MaxVt_length, kt_rise);
  constant  Vf1_vec     : real_vector := FileRead(DataFile, "Vf1_data", Vf1_data, MaxVt_length);
  constant  Tf1_vec     : real_vector := FileRead(DataFile, "Tf1_data", Tf1_data, MaxVt_length, kt_fall);
  constant  Vf2_vec     : real_vector := FileRead(DataFile, "Vf2_data", Vf2_data, MaxVt_length);
  constant  Tf2_vec     : real_vector := FileRead(DataFile, "Tf2_data", Tf2_data, MaxVt_length, kt_fall);

  constant  Vfx_r1_val  : real := FileRead(DataFile, "Vfx_r1", Vfx_r1);
  constant  Vfx_r2_val  : real := FileRead(DataFile, "Vfx_r2", Vfx_r2);
  constant  Vfx_f1_val  : real := FileRead(DataFile, "Vfx_f1", Vfx_f1);
  constant  Vfx_f2_val  : real := FileRead(DataFile, "Vfx_f2", Vfx_f2);

  constant  Rfx_r1_val  : real := FileRead(DataFile, "Rfx_r1", Rfx_r1);
  constant  Rfx_r2_val  : real := FileRead(DataFile, "Rfx_r2", Rfx_r2);
  constant  Rfx_f1_val  : real := FileRead(DataFile, "Rfx_f1", Rfx_f1);
  constant  Rfx_f2_val  : real := FileRead(DataFile, "Rfx_f2", Rfx_f2);
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_vec, Tr2_vec, Tf1_vec, Tf2_vec);

  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_vec, Vpc_vec,
                                            Ipu_vec, Vpu_vec,
                                            Ipd_vec, Vpd_vec,
                                            Igc_vec, Vgc_vec,

                                            Vr1_vec, Tr1_vec,
                                            Vr2_vec, Tr2_vec,
                                            Vf1_vec, Tf1_vec,
                                            Vf2_vec, Tf2_vec,

                                            Vpc_ref_val,
                                            Vpu_ref_val,
                                            Vpd_ref_val,
                                            Vgc_ref_val,

                                            Vfx_r1_val,
                                            Vfx_r2_val,
                                            Vfx_f1_val,
                                            Vfx_f2_val,

                                            Rfx_r1_val,
                                            Rfx_r2_val,
                                            Rfx_f1_val,
                                            Rfx_f2_val,

                                            C_comp_val);
--=============================================================================
  constant  DC_threshold : real := (Vth_R + Vth_F) / 2.0;
--=============================================================================
begin

  -----------------------------------------------------------------------------
  Threshold_crossing : process (Vin'above(DC_threshold),
                                Vin'above(Vth_R), Vin'above(Vth_F)) is
  -----------------------------------------------------------------------------
  begin
    if domain = quiescent_domain then                           -- during DC analysis
      if (Vin > DC_threshold) then                              -- high state
        PU_State <=  1;
        PD_State <= -1;
      else                                                      -- low state
        PU_State <= -1;
        PD_State <=  1;
      end if;
    else
      if (PU_State > 0) and (PD_State < 0) then                 -- curent state is high
        if (Vin < Vth_F) then                                   -- go to low state
          PU_State <= -2;
          PD_State <=  2;
        end if;
      elsif (PU_State < 0) and (PD_State > 0) then              -- curent state is low
        if (Vin > Vth_R) then                                   -- go to high state
          PU_State <=  2;
          PD_State <= -2;
        end if;
      end if;
    end if;
  end process Threshold_crossing;
  -----------------------------------------------------------------------------
  break on PU_State;
  break on PD_State;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------

  case PU_State use
    when -2 =>                                      -- PU is turning off
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kf2), "HE");
    when -1 =>                                      -- PU is off
      kpu == Ktables(Kr1)(Ktables(Kr1)'left);       -- 1st point in PU_on table
    when 1 =>                                       -- PU is on
      kpu == Ktables(Kf2)(Ktables(Kf2)'left);       -- 1st point in PU_off table
    when 2 =>                                       -- PU is tuning on
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kr1), "HE");
    when others =>              -- before any process assignments are available
      kpu == 0.0;
  end case;

  case PD_State use
    when -2 =>                                      -- PD is turning off
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kr2), "HE");
    when -1 =>                                      -- PD is off
      kpd == Ktables(Kf1)(Ktables(Kf1)'left);       -- 1st point in PD_on table
    when 1 =>                                       -- PD is on
      kpd == Ktables(Kr2)(Ktables(Kr2)'left);       -- 1st point in PD_off table
    when 2 =>                                       -- PD is tuning on
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kf1), "HE");
    when others =>              -- before any process assignments are available
      kpd == 0.0;
  end case;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc == -1.0*kI_pc    *Lookup(Vpc, Vpc_vec, Ipc_vec, "SE") + kC_comp_pc_val*C_comp_val*Vpc'dot;
  Ipu == -1.0*kI_pu*kpu*Lookup(Vpu, Vpu_vec, Ipu_vec, "SE") + kC_comp_pu_val*C_comp_val*Vpu'dot;
  Ipd ==      kI_pd*kpd*Lookup(Vpd, Vpd_vec, Ipd_vec, "SE") + kC_comp_pd_val*C_comp_val*Vpd'dot;
  Igc ==      kI_gc    *Lookup(Vgc, Vgc_vec, Igc_vec, "SE") + kC_comp_gc_val*C_comp_val*Vgc'dot;
--=============================================================================
end architecture IBIS_2EQ2UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
entity IBIS_IO is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.25;       -- splitting coefficients
           kC_comp_pu : real := 0.25;
           kC_comp_pd : real := 0.25;
           kC_comp_gc : real := 0.25;
           --------------------------------------------------------------------
           -- 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
           --------------------------------------------------------------------
           kI_pc        : real    := 1.0;     -- PC current scaling
           kI_pu        : real    := 1.0;     -- PU current scaling
           kI_pd        : real    := 1.0;     -- PD current scaling
           kI_gc        : real    := 1.0;     -- GC current scaling

           kt_rise      : real    := 1.0;     -- Rising waveform time scaling
           kt_fall      : real    := 1.0;     -- Falling waveform time scaling
           --------------------------------------------------------------------
           DataFile     : string  := "";      -- IBIS parameter file name
           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
           MaxIV_length : integer := 100;     -- Maximum possible length of IV tables
           MaxVt_length : integer := 1000);   -- Maximum possible length of Vt tables
     --------------------------------------------------------------------------
     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_State      : integer := 0;
  signal    PD_State      : integer := 0;
  quantity  kpu           : current := 0.0;
  quantity  kpd           : current := 0.0;
  --===========================================================================
  constant  C_comp_val     : real := FileRead(DataFile, "C_comp",     C_comp);
  constant  kC_comp_pc_val : real := FileRead(DataFile, "kC_comp_pc", kC_comp_pc);
  constant  kC_comp_pu_val : real := FileRead(DataFile, "kC_comp_pu", kC_comp_pu);
  constant  kC_comp_pd_val : real := FileRead(DataFile, "kC_comp_pd", kC_comp_pd);
  constant  kC_comp_gc_val : real := FileRead(DataFile, "kC_comp_gc", kC_comp_gc);

  constant  Vinh_val    : real := FileRead(DataFile, "Vinh", Vinh);
  constant  Vinl_val    : real := FileRead(DataFile, "Vinl", Vinl);

  constant  Vpc_ref_val : real := FileRead(DataFile, "Vpc_ref", Vpc_ref);
  constant  Vpu_ref_val : real := FileRead(DataFile, "Vpu_ref", Vpu_ref);
  constant  Vpd_ref_val : real := FileRead(DataFile, "Vpd_ref", Vpd_ref);
  constant  Vgc_ref_val : real := FileRead(DataFile, "Vgc_ref", Vgc_ref);

  constant  Ipc_vec     : real_vector := FileRead(DataFile, "Ipc_data", Ipc_data, MaxIV_length);
  constant  Vpc_vec     : real_vector := FileRead(DataFile, "Vpc_data", Vpc_data, MaxIV_length);
  constant  Ipu_vec     : real_vector := FileRead(DataFile, "Ipu_data", Ipu_data, MaxIV_length);
  constant  Vpu_vec     : real_vector := FileRead(DataFile, "Vpu_data", Vpu_data, MaxIV_length);
  constant  Ipd_vec     : real_vector := FileRead(DataFile, "Ipd_data", Ipd_data, MaxIV_length);
  constant  Vpd_vec     : real_vector := FileRead(DataFile, "Vpd_data", Vpd_data, MaxIV_length);
  constant  Igc_vec     : real_vector := FileRead(DataFile, "Igc_data", Igc_data, MaxIV_length);
  constant  Vgc_vec     : real_vector := FileRead(DataFile, "Vgc_data", Vgc_data, MaxIV_length);

  constant  Vr1_vec     : real_vector := FileRead(DataFile, "Vr1_data", Vr1_data, MaxVt_length);
  constant  Tr1_vec     : real_vector := FileRead(DataFile, "Tr1_data", Tr1_data, MaxVt_length, kt_rise);
  constant  Vr2_vec     : real_vector := FileRead(DataFile, "Vr2_data", Vr2_data, MaxVt_length);
  constant  Tr2_vec     : real_vector := FileRead(DataFile, "Tr2_data", Tr2_data, MaxVt_length, kt_rise);
  constant  Vf1_vec     : real_vector := FileRead(DataFile, "Vf1_data", Vf1_data, MaxVt_length);
  constant  Tf1_vec     : real_vector := FileRead(DataFile, "Tf1_data", Tf1_data, MaxVt_length, kt_fall);
  constant  Vf2_vec     : real_vector := FileRead(DataFile, "Vf2_data", Vf2_data, MaxVt_length);
  constant  Tf2_vec     : real_vector := FileRead(DataFile, "Tf2_data", Tf2_data, MaxVt_length, kt_fall);

  constant  Vfx_r1_val  : real := FileRead(DataFile, "Vfx_r1", Vfx_r1);
  constant  Vfx_r2_val  : real := FileRead(DataFile, "Vfx_r2", Vfx_r2);
  constant  Vfx_f1_val  : real := FileRead(DataFile, "Vfx_f1", Vfx_f1);
  constant  Vfx_f2_val  : real := FileRead(DataFile, "Vfx_f2", Vfx_f2);

  constant  Rfx_r1_val  : real := FileRead(DataFile, "Rfx_r1", Rfx_r1);
  constant  Rfx_r2_val  : real := FileRead(DataFile, "Rfx_r2", Rfx_r2);
  constant  Rfx_f1_val  : real := FileRead(DataFile, "Rfx_f1", Rfx_f1);
  constant  Rfx_f2_val  : real := FileRead(DataFile, "Rfx_f2", Rfx_f2);
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_vec, Tr2_vec, Tf1_vec, Tf2_vec);

  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_vec, Vpc_vec,
                                            Ipu_vec, Vpu_vec,
                                            Ipd_vec, Vpd_vec,
                                            Igc_vec, Vgc_vec,

                                            Vr1_vec, Tr1_vec,
                                            Vr2_vec, Tr2_vec,
                                            Vf1_vec, Tf1_vec,
                                            Vf2_vec, Tf2_vec,

                                            Vpc_ref_val,
                                            Vpu_ref_val,
                                            Vpd_ref_val,
                                            Vgc_ref_val,

                                            Vfx_r1_val,
                                            Vfx_r2_val,
                                            Vfx_f1_val,
                                            Vfx_f2_val,

                                            Rfx_r1_val,
                                            Rfx_r2_val,
                                            Rfx_f1_val,
                                            Rfx_f2_val,

                                            C_comp_val);
--=============================================================================
  constant  DC_threshold : real := (Vth_R + Vth_F) / 2.0;
--=============================================================================
begin

  -----------------------------------------------------------------------------
  Threshold_crossing : process (Vin'above(DC_threshold),
                                Vin'above(Vth_R), Vin'above(Vth_F),
                                Ven'above(Vth_R), Ven'above(Vth_F)) is
  -----------------------------------------------------------------------------
  begin
    if domain = quiescent_domain then                           -- during DC analysis
      if (Ven > DC_threshold) and (Vin > DC_threshold) then     -- high state
        PU_State <=  1;
        PD_State <= -1;
      elsif (Ven > DC_threshold) and (Vin <= DC_threshold) then -- low state
        PU_State <= -1;
        PD_State <=  1;
      else                                                      -- 3-state
        PU_State <= -1;
        PD_State <= -1;
      end if;
    else
      if (PU_State < 0) and (PD_State < 0) then                 -- curent state is 3-state
        if (Ven > Vth_R) and (Vin > DC_threshold) then          -- go to high state
          PU_State <=  2;
          PD_State <= -1;
        elsif (Ven > Vth_R) and (Vin <= DC_threshold) then      -- go to low state
          PU_State <= -1;
          PD_State <=  2;
        end if;
      elsif (PU_State > 0) and (PD_State < 0) then              -- curent state is high
        if (Ven > Vth_R) and (Vin < Vth_F) then                 -- go to low state
          PU_State <= -2;
          PD_State <=  2;
        elsif (Ven < Vth_F) then                                -- go to 3-state
          PU_State <= -2;
          PD_State <= -1;
        end if;
      elsif (PU_State < 0) and (PD_State > 0) then              -- curent state is low
        if (Ven > Vth_R) and (Vin > Vth_R) then                 -- go to high state
          PU_State <=  2;
          PD_State <= -2;
        elsif (Ven < Vth_F) then                                -- go to 3-state
          PU_State <= -1;
          PD_State <= -2;
        end if;
      end if;
    end if;
  end process Threshold_crossing;
  -----------------------------------------------------------------------------
  break on PU_State;
  break on PD_State;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------

  case PU_State use
    when -2 =>                                      -- PU is turning off
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kf2), "HE");
    when -1 =>                                      -- PU is off
      kpu == Ktables(Kr1)(Ktables(Kr1)'left);       -- 1st point in PU_on table
    when 1 =>                                       -- PU is on
      kpu == Ktables(Kf2)(Ktables(Kf2)'left);       -- 1st point in PU_off table
    when 2 =>                                       -- PU is tuning on
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kr1), "HE");
    when others =>              -- before any process assignments are available
      kpu == 0.0;
  end case;

  case PD_State use
    when -2 =>                                      -- PD is turning off
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kr2), "HE");
    when -1 =>                                      -- PD is off
      kpd == Ktables(Kf1)(Ktables(Kf1)'left);       -- 1st point in PD_on table
    when 1 =>                                       -- PD is on
      kpd == Ktables(Kr2)(Ktables(Kr2)'left);       -- 1st point in PD_off table
    when 2 =>                                       -- PD is tuning on
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kf1), "HE");
    when others =>              -- before any process assignments are available
      kpd == 0.0;
  end case;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc   == -1.0*kI_pc    *Lookup(Vpc, Vpc_vec, Ipc_vec, "SE") + kC_comp_pc_val*C_comp_val*Vpc'dot;
  Ipu   == -1.0*kI_pu*kpu*Lookup(Vpu, Vpu_vec, Ipu_vec, "SE") + kC_comp_pu_val*C_comp_val*Vpu'dot;
  Ipd   ==      kI_pd*kpd*Lookup(Vpd, Vpd_vec, Ipd_vec, "SE") + kC_comp_pd_val*C_comp_val*Vpd'dot;
  Igc   ==      kI_gc    *Lookup(Vgc, Vgc_vec, Igc_vec, "SE") + kC_comp_gc_val*C_comp_val*Vgc'dot;
  -----------------------------------------------------------------------------
  -- A simple receiver logic
  -----------------------------------------------------------------------------
  if        Vgc'above(Vinh_val)  use Vrcv == 1.0;
  elsif not(Vgc'above(Vinl_val)) use Vrcv == 0.0;
  else                               Vrcv == 0.5;
  end use;
  break on Vgc'above(Vinh_val), Vgc'above(Vinl_val);
--=============================================================================
end architecture IBIS_2EQ2UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
entity IBIS_3STATE is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.25;       -- splitting coefficients
           kC_comp_pu : real := 0.25;
           kC_comp_pd : real := 0.25;
           kC_comp_gc : real := 0.25;
           --------------------------------------------------------------------
           -- [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
           --------------------------------------------------------------------
           kI_pc        : real    := 1.0;     -- PC current scaling
           kI_pu        : real    := 1.0;     -- PU current scaling
           kI_pd        : real    := 1.0;     -- PD current scaling
           kI_gc        : real    := 1.0;     -- GC current scaling

           kt_rise      : real    := 1.0;     -- Rising waveform time scaling
           kt_fall      : real    := 1.0;     -- Falling waveform time scaling
           --------------------------------------------------------------------
           DataFile     : string  := "";      -- IBIS parameter file name
           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
           MaxIV_length : integer := 100;     -- Maximum possible length of IV tables
           MaxVt_length : integer := 1000);   -- Maximum possible length of Vt tables
     --------------------------------------------------------------------------
     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_State      : integer := 0;
  signal    PD_State      : integer := 0;
  quantity  kpu           : current := 0.0;
  quantity  kpd           : current := 0.0;
  --===========================================================================
  constant  C_comp_val     : real := FileRead(DataFile, "C_comp",     C_comp);
  constant  kC_comp_pc_val : real := FileRead(DataFile, "kC_comp_pc", kC_comp_pc);
  constant  kC_comp_pu_val : real := FileRead(DataFile, "kC_comp_pu", kC_comp_pu);
  constant  kC_comp_pd_val : real := FileRead(DataFile, "kC_comp_pd", kC_comp_pd);
  constant  kC_comp_gc_val : real := FileRead(DataFile, "kC_comp_gc", kC_comp_gc);

  constant  Vpc_ref_val : real := FileRead(DataFile, "Vpc_ref", Vpc_ref);
  constant  Vpu_ref_val : real := FileRead(DataFile, "Vpu_ref", Vpu_ref);
  constant  Vpd_ref_val : real := FileRead(DataFile, "Vpd_ref", Vpd_ref);
  constant  Vgc_ref_val : real := FileRead(DataFile, "Vgc_ref", Vgc_ref);

  constant  Ipc_vec     : real_vector := FileRead(DataFile, "Ipc_data", Ipc_data, MaxIV_length);
  constant  Vpc_vec     : real_vector := FileRead(DataFile, "Vpc_data", Vpc_data, MaxIV_length);
  constant  Ipu_vec     : real_vector := FileRead(DataFile, "Ipu_data", Ipu_data, MaxIV_length);
  constant  Vpu_vec     : real_vector := FileRead(DataFile, "Vpu_data", Vpu_data, MaxIV_length);
  constant  Ipd_vec     : real_vector := FileRead(DataFile, "Ipd_data", Ipd_data, MaxIV_length);
  constant  Vpd_vec     : real_vector := FileRead(DataFile, "Vpd_data", Vpd_data, MaxIV_length);
  constant  Igc_vec     : real_vector := FileRead(DataFile, "Igc_data", Igc_data, MaxIV_length);
  constant  Vgc_vec     : real_vector := FileRead(DataFile, "Vgc_data", Vgc_data, MaxIV_length);

  constant  Vr1_vec     : real_vector := FileRead(DataFile, "Vr1_data", Vr1_data, MaxVt_length);
  constant  Tr1_vec     : real_vector := FileRead(DataFile, "Tr1_data", Tr1_data, MaxVt_length, kt_rise);
  constant  Vr2_vec     : real_vector := FileRead(DataFile, "Vr2_data", Vr2_data, MaxVt_length);
  constant  Tr2_vec     : real_vector := FileRead(DataFile, "Tr2_data", Tr2_data, MaxVt_length, kt_rise);
  constant  Vf1_vec     : real_vector := FileRead(DataFile, "Vf1_data", Vf1_data, MaxVt_length);
  constant  Tf1_vec     : real_vector := FileRead(DataFile, "Tf1_data", Tf1_data, MaxVt_length, kt_fall);
  constant  Vf2_vec     : real_vector := FileRead(DataFile, "Vf2_data", Vf2_data, MaxVt_length);
  constant  Tf2_vec     : real_vector := FileRead(DataFile, "Tf2_data", Tf2_data, MaxVt_length, kt_fall);

  constant  Vfx_r1_val  : real := FileRead(DataFile, "Vfx_r1", Vfx_r1);
  constant  Vfx_r2_val  : real := FileRead(DataFile, "Vfx_r2", Vfx_r2);
  constant  Vfx_f1_val  : real := FileRead(DataFile, "Vfx_f1", Vfx_f1);
  constant  Vfx_f2_val  : real := FileRead(DataFile, "Vfx_f2", Vfx_f2);

  constant  Rfx_r1_val  : real := FileRead(DataFile, "Rfx_r1", Rfx_r1);
  constant  Rfx_r2_val  : real := FileRead(DataFile, "Rfx_r2", Rfx_r2);
  constant  Rfx_f1_val  : real := FileRead(DataFile, "Rfx_f1", Rfx_f1);
  constant  Rfx_f2_val  : real := FileRead(DataFile, "Rfx_f2", Rfx_f2);
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_vec, Tr2_vec, Tf1_vec, Tf2_vec);

  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_vec, Vpc_vec,
                                            Ipu_vec, Vpu_vec,
                                            Ipd_vec, Vpd_vec,
                                            Igc_vec, Vgc_vec,

                                            Vr1_vec, Tr1_vec,
                                            Vr2_vec, Tr2_vec,
                                            Vf1_vec, Tf1_vec,
                                            Vf2_vec, Tf2_vec,

                                            Vpc_ref_val,
                                            Vpu_ref_val,
                                            Vpd_ref_val,
                                            Vgc_ref_val,

                                            Vfx_r1_val,
                                            Vfx_r2_val,
                                            Vfx_f1_val,
                                            Vfx_f2_val,

                                            Rfx_r1_val,
                                            Rfx_r2_val,
                                            Rfx_f1_val,
                                            Rfx_f2_val,

                                            C_comp_val);
--=============================================================================
  constant  DC_threshold : real := (Vth_R + Vth_F) / 2.0;
--=============================================================================
begin

  -----------------------------------------------------------------------------
  Threshold_crossing : process (Vin'above(DC_threshold),
                                Vin'above(Vth_R), Vin'above(Vth_F),
                                Ven'above(Vth_R), Ven'above(Vth_F)) is
  -----------------------------------------------------------------------------
  begin
    if domain = quiescent_domain then                           -- during DC analysis
      if (Ven > DC_threshold) and (Vin > DC_threshold) then     -- high state
        PU_State <=  1;
        PD_State <= -1;
      elsif (Ven > DC_threshold) and (Vin <= DC_threshold) then -- low state
        PU_State <= -1;
        PD_State <=  1;
      else                                                      -- 3-state
        PU_State <= -1;
        PD_State <= -1;
      end if;
    else
      if (PU_State < 0) and (PD_State < 0) then                 -- curent state is 3-state
        if (Ven > Vth_R) and (Vin > DC_threshold) then          -- go to high state
          PU_State <=  2;
          PD_State <= -1;
        elsif (Ven > Vth_R) and (Vin <= DC_threshold) then      -- go to low state
          PU_State <= -1;
          PD_State <=  2;
        end if;
      elsif (PU_State > 0) and (PD_State < 0) then              -- curent state is high
        if (Ven > Vth_R) and (Vin < Vth_F) then                 -- go to low state
          PU_State <= -2;
          PD_State <=  2;
        elsif (Ven < Vth_F) then                                -- go to 3-state
          PU_State <= -2;
          PD_State <= -1;
        end if;
      elsif (PU_State < 0) and (PD_State > 0) then              -- curent state is low
        if (Ven > Vth_R) and (Vin > Vth_R) then                 -- go to high state
          PU_State <=  2;
          PD_State <= -2;
        elsif (Ven < Vth_F) then                                -- go to 3-state
          PU_State <= -1;
          PD_State <= -2;
        end if;
      end if;
    end if;
  end process Threshold_crossing;
  -----------------------------------------------------------------------------
  break on PU_State;
  break on PD_State;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------

  case PU_State use
    when -2 =>                                      -- PU is turning off
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kf2), "HE");
    when -1 =>                                      -- PU is off
      kpu == Ktables(Kr1)(Ktables(Kr1)'left);       -- 1st point in PU_on table
    when 1 =>                                       -- PU is on
      kpu == Ktables(Kf2)(Ktables(Kf2)'left);       -- 1st point in PU_off table
    when 2 =>                                       -- PU is tuning on
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kr1), "HE");
    when others =>              -- before any process assignments are available
      kpu == 0.0;
  end case;

  case PD_State use
    when -2 =>                                      -- PD is turning off
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kr2), "HE");
    when -1 =>                                      -- PD is off
      kpd == Ktables(Kf1)(Ktables(Kf1)'left);       -- 1st point in PD_on table
    when 1 =>                                       -- PD is on
      kpd == Ktables(Kr2)(Ktables(Kr2)'left);       -- 1st point in PD_off table
    when 2 =>                                       -- PD is tuning on
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kf1), "HE");
    when others =>              -- before any process assignments are available
      kpd == 0.0;
  end case;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc == -1.0*kI_pc    *Lookup(Vpc, Vpc_vec, Ipc_vec, "SE") + kC_comp_pc_val*C_comp_val*Vpc'dot;
  Ipu == -1.0*kI_pu*kpu*Lookup(Vpu, Vpu_vec, Ipu_vec, "SE") + kC_comp_pu_val*C_comp_val*Vpu'dot;
  Ipd ==      kI_pd*kpd*Lookup(Vpd, Vpd_vec, Ipd_vec, "SE") + kC_comp_pd_val*C_comp_val*Vpd'dot;
  Igc ==      kI_gc    *Lookup(Vgc, Vgc_vec, Igc_vec, "SE") + kC_comp_gc_val*C_comp_val*Vgc'dot;
--=============================================================================
end architecture IBIS_2EQ2UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
entity IBIS_OPENSINK is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.25;       -- splitting coefficients
           kC_comp_pu : real := 0.25;
           kC_comp_pd : real := 0.25;
           kC_comp_gc : real := 0.25;
           --------------------------------------------------------------------
           -- [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
           --------------------------------------------------------------------
           kI_pc        : real    := 1.0;     -- PC current scaling
           kI_pd        : real    := 1.0;     -- PD current scaling
           kI_gc        : real    := 1.0;     -- GC current scaling

           kt_rise      : real    := 1.0;     -- Rising waveform time scaling
           kt_fall      : real    := 1.0;     -- Falling waveform time scaling
           --------------------------------------------------------------------
           DataFile     : string  := "";      -- IBIS parameter file name
           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
           MaxIV_length : integer := 100;     -- Maximum possible length of IV tables
           MaxVt_length : integer := 1000);   -- Maximum possible length of Vt tables
     --------------------------------------------------------------------------
     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  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    PD_State      : integer := 0;
  quantity  kpd           : current := 0.0;
  --===========================================================================
  constant  C_comp_val     : real := FileRead(DataFile, "C_comp",     C_comp);
  constant  kC_comp_pc_val : real := FileRead(DataFile, "kC_comp_pc", kC_comp_pc);
  constant  kC_comp_pu_val : real := FileRead(DataFile, "kC_comp_pu", kC_comp_pu);
  constant  kC_comp_pd_val : real := FileRead(DataFile, "kC_comp_pd", kC_comp_pd);
  constant  kC_comp_gc_val : real := FileRead(DataFile, "kC_comp_gc", kC_comp_gc);

  constant  Vpc_ref_val : real := FileRead(DataFile, "Vpc_ref", Vpc_ref);
  constant  Vpd_ref_val : real := FileRead(DataFile, "Vpd_ref", Vpd_ref);
  constant  Vgc_ref_val : real := FileRead(DataFile, "Vgc_ref", Vgc_ref);

  constant  Ipc_vec     : real_vector := FileRead(DataFile, "Ipc_data", Ipc_data, MaxIV_length);
  constant  Vpc_vec     : real_vector := FileRead(DataFile, "Vpc_data", Vpc_data, MaxIV_length);
  constant  Ipd_vec     : real_vector := FileRead(DataFile, "Ipd_data", Ipd_data, MaxIV_length);
  constant  Vpd_vec     : real_vector := FileRead(DataFile, "Vpd_data", Vpd_data, MaxIV_length);
  constant  Igc_vec     : real_vector := FileRead(DataFile, "Igc_data", Igc_data, MaxIV_length);
  constant  Vgc_vec     : real_vector := FileRead(DataFile, "Vgc_data", Vgc_data, MaxIV_length);

  constant  Vr1_vec     : real_vector := FileRead(DataFile, "Vr1_data", Vr1_data, MaxVt_length);
  constant  Tr1_vec     : real_vector := FileRead(DataFile, "Tr1_data", Tr1_data, MaxVt_length, kt_rise);
  constant  Vf1_vec     : real_vector := FileRead(DataFile, "Vf1_data", Vf1_data, MaxVt_length);
  constant  Tf1_vec     : real_vector := FileRead(DataFile, "Tf1_data", Tf1_data, MaxVt_length, kt_fall);

  constant  Vfx_r1_val  : real := FileRead(DataFile, "Vfx_r1", Vfx_r1);
  constant  Vfx_f1_val  : real := FileRead(DataFile, "Vfx_f1", Vfx_f1);

  constant  Rfx_r1_val  : real := FileRead(DataFile, "Rfx_r1", Rfx_r1);
  constant  Rfx_f1_val  : real := FileRead(DataFile, "Rfx_f1", Rfx_f1);
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_vec, Tf1_vec);

  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_vec, Vpc_vec,
                                            Ipd_vec, Vpd_vec,
                                            Igc_vec, Vgc_vec,

                                            Vr1_vec, Tr1_vec,
                                            Vf1_vec, Tf1_vec,

                                            Vpc_ref_val,
                                            Vpd_ref_val,
                                            Vgc_ref_val,

                                            Vfx_r1_val,
                                            Vfx_f1_val,

                                            Rfx_r1_val,
                                            Rfx_f1_val,

                                            C_comp_val);
--=============================================================================
  constant  DC_threshold : real := (Vth_R + Vth_F) / 2.0;
--=============================================================================
begin

  -----------------------------------------------------------------------------
  Threshold_crossing : process (Vin'above(DC_threshold),
                                Vin'above(Vth_R), Vin'above(Vth_F)) is
  -----------------------------------------------------------------------------
  begin
    if domain = quiescent_domain then                           -- during DC analysis
      if (Vin > DC_threshold) then                              -- high state
        PD_State <= -1;
      else                                                      -- low state
        PD_State <=  1;
      end if;
    else
      if (PD_State < 0) then                                    -- curent state is high
        if (Vin < Vth_F) then                                   -- go to low state
          PD_State <=  2;
        end if;
      elsif (PD_State > 0) then                                 -- curent state is low
        if (Vin > Vth_R) then                                   -- go to high state
          PD_State <= -2;
        end if;
      end if;
    end if;
  end process Threshold_crossing;
  -----------------------------------------------------------------------------
  break on PD_State;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------

  case PD_State use
    when -2 =>                                      -- PD is turning off
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kr1), "HE");
    when -1 =>                                      -- PD is off
      kpd == Ktables(Kf1)(Ktables(Kf1)'left);       -- 1st point in PD_on table
    when 1 =>                                       -- PD is on
      kpd == Ktables(Kr1)(Ktables(Kr1)'left);       -- 1st point in PD_off table
    when 2 =>                                       -- PD is tuning on
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kf1), "HE");
    when others =>              -- before any process assignments are available
      kpd == 0.0;
  end case;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc == -1.0*kI_pc    *Lookup(Vpc, Vpc_vec, Ipc_vec, "SE") + kC_comp_pc_val*C_comp_val*Vpc'dot;
  Ipu ==  0.0                                               + kC_comp_pu_val*C_comp_val*Vpu'dot;
  Ipd ==      kI_pd*kpd*Lookup(Vpd, Vpd_vec, Ipd_vec, "SE") + kC_comp_pd_val*C_comp_val*Vpd'dot;
  Igc ==      kI_gc    *Lookup(Vgc, Vgc_vec, Igc_vec, "SE") + kC_comp_gc_val*C_comp_val*Vgc'dot;
--=============================================================================
end architecture IBIS_1EQ1UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
entity IBIS_IO_OPENSINK is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.25;       -- splitting coefficients
           kC_comp_pu : real := 0.25;
           kC_comp_pd : real := 0.25;
           kC_comp_gc : real := 0.25;
           --------------------------------------------------------------------
           -- 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
           --------------------------------------------------------------------
           kI_pc        : real    := 1.0;     -- PC current scaling
           kI_pd        : real    := 1.0;     -- PD current scaling
           kI_gc        : real    := 1.0;     -- GC current scaling

           kt_rise      : real    := 1.0;     -- Rising waveform time scaling
           kt_fall      : real    := 1.0;     -- Falling waveform time scaling
           --------------------------------------------------------------------
           DataFile     : string  := "";      -- IBIS parameter file name
           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
           MaxIV_length : integer := 100;     -- Maximum possible length of IV tables
           MaxVt_length : integer := 1000);   -- Maximum possible length of Vt tables
     --------------------------------------------------------------------------
     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  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_State      : integer := 0;
  signal    PD_State      : integer := 0;
  quantity  kpd           : current := 0.0;
  --===========================================================================
  constant  C_comp_val     : real := FileRead(DataFile, "C_comp",     C_comp);
  constant  kC_comp_pc_val : real := FileRead(DataFile, "kC_comp_pc", kC_comp_pc);
  constant  kC_comp_pu_val : real := FileRead(DataFile, "kC_comp_pu", kC_comp_pu);
  constant  kC_comp_pd_val : real := FileRead(DataFile, "kC_comp_pd", kC_comp_pd);
  constant  kC_comp_gc_val : real := FileRead(DataFile, "kC_comp_gc", kC_comp_gc);

  constant  Vinh_val    : real := FileRead(DataFile, "Vinh", Vinh);
  constant  Vinl_val    : real := FileRead(DataFile, "Vinl", Vinl);

  constant  Vpc_ref_val : real := FileRead(DataFile, "Vpc_ref", Vpc_ref);
  constant  Vpd_ref_val : real := FileRead(DataFile, "Vpd_ref", Vpd_ref);
  constant  Vgc_ref_val : real := FileRead(DataFile, "Vgc_ref", Vgc_ref);

  constant  Ipc_vec     : real_vector := FileRead(DataFile, "Ipc_data", Ipc_data, MaxIV_length);
  constant  Vpc_vec     : real_vector := FileRead(DataFile, "Vpc_data", Vpc_data, MaxIV_length);
  constant  Ipd_vec     : real_vector := FileRead(DataFile, "Ipd_data", Ipd_data, MaxIV_length);
  constant  Vpd_vec     : real_vector := FileRead(DataFile, "Vpd_data", Vpd_data, MaxIV_length);
  constant  Igc_vec     : real_vector := FileRead(DataFile, "Igc_data", Igc_data, MaxIV_length);
  constant  Vgc_vec     : real_vector := FileRead(DataFile, "Vgc_data", Vgc_data, MaxIV_length);

  constant  Vr1_vec     : real_vector := FileRead(DataFile, "Vr1_data", Vr1_data, MaxVt_length);
  constant  Tr1_vec     : real_vector := FileRead(DataFile, "Tr1_data", Tr1_data, MaxVt_length, kt_rise);
  constant  Vf1_vec     : real_vector := FileRead(DataFile, "Vf1_data", Vf1_data, MaxVt_length);
  constant  Tf1_vec     : real_vector := FileRead(DataFile, "Tf1_data", Tf1_data, MaxVt_length, kt_fall);

  constant  Vfx_r1_val  : real := FileRead(DataFile, "Vfx_r1", Vfx_r1);
  constant  Vfx_f1_val  : real := FileRead(DataFile, "Vfx_f1", Vfx_f1);

  constant  Rfx_r1_val  : real := FileRead(DataFile, "Rfx_r1", Rfx_r1);
  constant  Rfx_f1_val  : real := FileRead(DataFile, "Rfx_f1", Rfx_f1);
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_vec, Tf1_vec);

  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_vec, Vpc_vec,
                                            Ipd_vec, Vpd_vec,
                                            Igc_vec, Vgc_vec,

                                            Vr1_vec, Tr1_vec,
                                            Vf1_vec, Tf1_vec,

                                            Vpc_ref_val,
                                            Vpd_ref_val,
                                            Vgc_ref_val,

                                            Vfx_r1_val,
                                            Vfx_f1_val,

                                            Rfx_r1_val,
                                            Rfx_f1_val,

                                            C_comp_val);
--=============================================================================
  constant  DC_threshold : real := (Vth_R + Vth_F) / 2.0;
--=============================================================================
begin

  -----------------------------------------------------------------------------
  Threshold_crossing : process (Vin'above(DC_threshold),
                                Vin'above(Vth_R), Vin'above(Vth_F),
                                Ven'above(Vth_R), Ven'above(Vth_F)) is
  -----------------------------------------------------------------------------
  begin
    if domain = quiescent_domain then                           -- during DC analysis
      if (Ven > DC_threshold) and (Vin > DC_threshold) then     -- high state
        PU_State <=  1;
        PD_State <= -1;
      elsif (Ven > DC_threshold) and (Vin <= DC_threshold) then -- low state
        PU_State <= -1;
        PD_State <=  1;
      else                                                      -- 3-state
        PU_State <= -1;
        PD_State <= -1;
      end if;
    else
      if (PU_State < 0) and (PD_State < 0) then                 -- curent state is 3-state
        if (Ven > Vth_R) and (Vin > DC_threshold) then          -- go to high state
          PU_State <=  2;
          PD_State <= -1;
        elsif (Ven > Vth_R) and (Vin <= DC_threshold) then      -- go to low state
          PU_State <= -1;
          PD_State <=  2;
        end if;
      elsif (PU_State > 0) and (PD_State < 0) then              -- curent state is high
        if (Ven > Vth_R) and (Vin < Vth_F) then                 -- go to low state
          PU_State <= -2;
          PD_State <=  2;
        elsif (Ven < Vth_F) then                                -- go to 3-state
          PU_State <= -2;
          PD_State <= -1;
        end if;
      elsif (PU_State < 0) and (PD_State > 0) then              -- curent state is low
        if (Ven > Vth_R) and (Vin > Vth_R) then                 -- go to high state
          PU_State <=  2;
          PD_State <= -2;
        elsif (Ven < Vth_F) then                                -- go to 3-state
          PU_State <= -1;
          PD_State <= -2;
        end if;
      end if;
    end if;
  end process Threshold_crossing;
  -----------------------------------------------------------------------------
  break on PD_State;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------

  case PD_State use
    when -2 =>                                      -- PD is turning off
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kr1), "HE");
    when -1 =>                                      -- PD is off
      kpd == Ktables(Kf1)(Ktables(Kf1)'left);       -- 1st point in PD_on table
    when 1 =>                                       -- PD is on
      kpd == Ktables(Kr1)(Ktables(Kr1)'left);       -- 1st point in PD_off table
    when 2 =>                                       -- PD is tuning on
      kpd == Lookup(PD_State'last_event, Ktables(Tcm), Ktables(Kf1), "HE");
    when others =>              -- before any process assignments are available
      kpd == 0.0;
  end case;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc == -1.0*kI_pc    *Lookup(Vpc, Vpc_vec, Ipc_vec, "SE") + kC_comp_pc_val*C_comp_val*Vpc'dot;
  Ipu ==  0.0                                               + kC_comp_pu_val*C_comp_val*Vpu'dot;
  Ipd ==      kI_pd*kpd*Lookup(Vpd, Vpd_vec, Ipd_vec, "SE") + kC_comp_pd_val*C_comp_val*Vpd'dot;
  Igc ==      kI_gc    *Lookup(Vgc, Vgc_vec, Igc_vec, "SE") + kC_comp_gc_val*C_comp_val*Vgc'dot;
  -----------------------------------------------------------------------------
  -- A simple receiver logic
  -----------------------------------------------------------------------------
  if        Vgc'above(Vinh_val)  use Vrcv == 1.0;
  elsif not(Vgc'above(Vinl_val)) use Vrcv == 0.0;
  else                               Vrcv == 0.5;
  end use;
  break on Vgc'above(Vinh_val), Vgc'above(Vinl_val);
--=============================================================================
end architecture IBIS_1EQ1UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
entity IBIS_OPENSOURCE is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.25;       -- splitting coefficients
           kC_comp_pu : real := 0.25;
           kC_comp_pd : real := 0.25;
           kC_comp_gc : real := 0.25;
           --------------------------------------------------------------------
           -- [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
           --------------------------------------------------------------------
           kI_pc        : real    := 1.0;     -- PC current scaling
           kI_pu        : real    := 1.0;     -- PU current scaling
           kI_gc        : real    := 1.0;     -- GC current scaling

           kt_rise      : real    := 1.0;     -- Rising waveform time scaling
           kt_fall      : real    := 1.0;     -- Falling waveform time scaling
           --------------------------------------------------------------------
           DataFile     : string  := "";      -- IBIS parameter file name
           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
           MaxIV_length : integer := 100;     -- Maximum possible length of IV tables
           MaxVt_length : integer := 1000);   -- Maximum possible length of Vt tables
     --------------------------------------------------------------------------
     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  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_State      : integer := 0;
  quantity  kpu           : current := 0.0;
  --===========================================================================
  constant  C_comp_val     : real := FileRead(DataFile, "C_comp",     C_comp);
  constant  kC_comp_pc_val : real := FileRead(DataFile, "kC_comp_pc", kC_comp_pc);
  constant  kC_comp_pu_val : real := FileRead(DataFile, "kC_comp_pu", kC_comp_pu);
  constant  kC_comp_pd_val : real := FileRead(DataFile, "kC_comp_pd", kC_comp_pd);
  constant  kC_comp_gc_val : real := FileRead(DataFile, "kC_comp_gc", kC_comp_gc);

  constant  Vpc_ref_val : real := FileRead(DataFile, "Vpc_ref", Vpc_ref);
  constant  Vpu_ref_val : real := FileRead(DataFile, "Vpu_ref", Vpu_ref);
  constant  Vgc_ref_val : real := FileRead(DataFile, "Vgc_ref", Vgc_ref);

  constant  Ipc_vec     : real_vector := FileRead(DataFile, "Ipc_data", Ipc_data, MaxIV_length);
  constant  Vpc_vec     : real_vector := FileRead(DataFile, "Vpc_data", Vpc_data, MaxIV_length);
  constant  Ipu_vec     : real_vector := FileRead(DataFile, "Ipu_data", Ipu_data, MaxIV_length);
  constant  Vpu_vec     : real_vector := FileRead(DataFile, "Vpu_data", Vpu_data, MaxIV_length);
  constant  Igc_vec     : real_vector := FileRead(DataFile, "Igc_data", Igc_data, MaxIV_length);
  constant  Vgc_vec     : real_vector := FileRead(DataFile, "Vgc_data", Vgc_data, MaxIV_length);

  constant  Vr1_vec     : real_vector := FileRead(DataFile, "Vr1_data", Vr1_data, MaxVt_length);
  constant  Tr1_vec     : real_vector := FileRead(DataFile, "Tr1_data", Tr1_data, MaxVt_length, kt_rise);
  constant  Vf1_vec     : real_vector := FileRead(DataFile, "Vf1_data", Vf1_data, MaxVt_length);
  constant  Tf1_vec     : real_vector := FileRead(DataFile, "Tf1_data", Tf1_data, MaxVt_length, kt_fall);

  constant  Vfx_r1_val  : real := FileRead(DataFile, "Vfx_r1", Vfx_r1);
  constant  Vfx_f1_val  : real := FileRead(DataFile, "Vfx_f1", Vfx_f1);

  constant  Rfx_r1_val  : real := FileRead(DataFile, "Rfx_r1", Rfx_r1);
  constant  Rfx_f1_val  : real := FileRead(DataFile, "Rfx_f1", Rfx_f1);
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_vec, Tf1_vec);

  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_vec, Vpc_vec,
                                            Ipu_vec, Vpu_vec,
                                            Igc_vec, Vgc_vec,

                                            Vr1_vec, Tr1_vec,
                                            Vf1_vec, Tf1_vec,

                                            Vpc_ref_val,
                                            Vpu_ref_val,
                                            Vgc_ref_val,

                                            Vfx_r1_val,
                                            Vfx_f1_val,

                                            Rfx_r1_val,
                                            Rfx_f1_val,

                                            C_comp_val);
--=============================================================================
  constant  DC_threshold : real := (Vth_R + Vth_F) / 2.0;
--=============================================================================
begin

  -----------------------------------------------------------------------------
  Threshold_crossing : process (Vin'above(DC_threshold),
                                Vin'above(Vth_R), Vin'above(Vth_F)) is
  -----------------------------------------------------------------------------
  begin
    if domain = quiescent_domain then                           -- during DC analysis
      if (Vin > DC_threshold) then                              -- high state
        PU_State <=  1;
      else                                                      -- low state
        PU_State <= -1;
      end if;
    else
      if (PU_State > 0) then                                    -- curent state is high
        if (Vin < Vth_F) then                                   -- go to low state
          PU_State <= -2;
        end if;
      elsif (PU_State < 0) then                                 -- curent state is low
        if (Vin > Vth_R) then                                   -- go to high state
          PU_State <=  2;
        end if;
      end if;
    end if;
  end process Threshold_crossing;
  -----------------------------------------------------------------------------
  break on PU_State;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------

  case PU_State use
    when -2 =>                                      -- PU is turning off
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kf1), "HE");
    when -1 =>                                      -- PU is off
      kpu == Ktables(Kr1)(Ktables(Kr1)'left);       -- 1st point in PU_on table
    when 1 =>                                       -- PU is on
      kpu == Ktables(Kf1)(Ktables(Kf1)'left);       -- 1st point in PU_off table
    when 2 =>                                       -- PU is tuning on
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kr1), "HE");
    when others =>              -- before any process assignments are available
      kpu == 0.0;
  end case;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc == -1.0*kI_pc    *Lookup(Vpc, Vpc_vec, Ipc_vec, "SE") + kC_comp_pc_val*C_comp_val*Vpc'dot;
  Ipu == -1.0*kI_pu*kpu*Lookup(Vpu, Vpu_vec, Ipu_vec, "SE") + kC_comp_pu_val*C_comp_val*Vpu'dot;
  Ipd ==  0.0                                               + kC_comp_pd_val*C_comp_val*Vpd'dot;
  Igc ==      kI_gc    *Lookup(Vgc, Vgc_vec, Igc_vec, "SE") + kC_comp_gc_val*C_comp_val*Vgc'dot;
--=============================================================================
end architecture IBIS_1EQ1UK;
--=============================================================================
--=============================================================================
library IEEE;
use IEEE.electrical_systems.all;
use IEEE.math_real.all;

library MacroLib;
use MacroLib.MacroLib_functions.all;
--=============================================================================
entity IBIS_IO_OPENSOURCE is

  generic (C_comp     : real := 5.00e-12;   -- Default C_comp value and
           kC_comp_pc : real := 0.25;       -- splitting coefficients
           kC_comp_pu : real := 0.25;
           kC_comp_pd : real := 0.25;
           kC_comp_gc : real := 0.25;
           --------------------------------------------------------------------
           -- 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
           --------------------------------------------------------------------
           kI_pc        : real    := 1.0;     -- PC current scaling
           kI_pu        : real    := 1.0;     -- PU current scaling
           kI_gc        : real    := 1.0;     -- GC current scaling

           kt_rise      : real    := 1.0;     -- Rising waveform time scaling
           kt_fall      : real    := 1.0;     -- Falling waveform time scaling
           --------------------------------------------------------------------
           DataFile     : string  := "";      -- IBIS parameter file name
           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
           MaxIV_length : integer := 100;     -- Maximum possible length of IV tables
           MaxVt_length : integer := 1000);   -- Maximum possible length of Vt tables
     --------------------------------------------------------------------------
     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  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_State      : integer := 0;
  signal    PD_State      : integer := 0;
  quantity  kpu           : current := 0.0;
  --===========================================================================
  constant  C_comp_val     : real := FileRead(DataFile, "C_comp",     C_comp);
  constant  kC_comp_pc_val : real := FileRead(DataFile, "kC_comp_pc", kC_comp_pc);
  constant  kC_comp_pu_val : real := FileRead(DataFile, "kC_comp_pu", kC_comp_pu);
  constant  kC_comp_pd_val : real := FileRead(DataFile, "kC_comp_pd", kC_comp_pd);
  constant  kC_comp_gc_val : real := FileRead(DataFile, "kC_comp_gc", kC_comp_gc);

  constant  Vinh_val    : real := FileRead(DataFile, "Vinh", Vinh);
  constant  Vinl_val    : real := FileRead(DataFile, "Vinl", Vinl);

  constant  Vpc_ref_val : real := FileRead(DataFile, "Vpc_ref", Vpc_ref);
  constant  Vpu_ref_val : real := FileRead(DataFile, "Vpu_ref", Vpu_ref);
  constant  Vgc_ref_val : real := FileRead(DataFile, "Vgc_ref", Vgc_ref);

  constant  Ipc_vec     : real_vector := FileRead(DataFile, "Ipc_data", Ipc_data, MaxIV_length);
  constant  Vpc_vec     : real_vector := FileRead(DataFile, "Vpc_data", Vpc_data, MaxIV_length);
  constant  Ipu_vec     : real_vector := FileRead(DataFile, "Ipu_data", Ipu_data, MaxIV_length);
  constant  Vpu_vec     : real_vector := FileRead(DataFile, "Vpu_data", Vpu_data, MaxIV_length);
  constant  Igc_vec     : real_vector := FileRead(DataFile, "Igc_data", Igc_data, MaxIV_length);
  constant  Vgc_vec     : real_vector := FileRead(DataFile, "Vgc_data", Vgc_data, MaxIV_length);

  constant  Vr1_vec     : real_vector := FileRead(DataFile, "Vr1_data", Vr1_data, MaxVt_length);
  constant  Tr1_vec     : real_vector := FileRead(DataFile, "Tr1_data", Tr1_data, MaxVt_length, kt_rise);
  constant  Vf1_vec     : real_vector := FileRead(DataFile, "Vf1_data", Vf1_data, MaxVt_length);
  constant  Tf1_vec     : real_vector := FileRead(DataFile, "Tf1_data", Tf1_data, MaxVt_length, kt_fall);

  constant  Vfx_r1_val  : real := FileRead(DataFile, "Vfx_r1", Vfx_r1);
  constant  Vfx_f1_val  : real := FileRead(DataFile, "Vfx_f1", Vfx_f1);

  constant  Rfx_r1_val  : real := FileRead(DataFile, "Rfx_r1", Rfx_r1);
  constant  Rfx_f1_val  : real := FileRead(DataFile, "Rfx_f1", Rfx_f1);
--=============================================================================
  constant CommonLength : integer := FindCommonLength(Max_dt, Tr1_vec, Tf1_vec);

  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_vec, Vpc_vec,
                                            Ipu_vec, Vpu_vec,
                                            Igc_vec, Vgc_vec,

                                            Vr1_vec, Tr1_vec,
                                            Vf1_vec, Tf1_vec,

                                            Vpc_ref_val,
                                            Vpu_ref_val,
                                            Vgc_ref_val,

                                            Vfx_r1_val,
                                            Vfx_f1_val,

                                            Rfx_r1_val,
                                            Rfx_f1_val,

                                            C_comp_val);
--=============================================================================
  constant  DC_threshold : real := (Vth_R + Vth_F) / 2.0;
--=============================================================================
begin

  -----------------------------------------------------------------------------
  Threshold_crossing : process (Vin'above(DC_threshold),
                                Vin'above(Vth_R), Vin'above(Vth_F),
                                Ven'above(Vth_R), Ven'above(Vth_F)) is
  -----------------------------------------------------------------------------
  begin
    if domain = quiescent_domain then                           -- during DC analysis
      if (Ven > DC_threshold) and (Vin > DC_threshold) then     -- high state
        PU_State <=  1;
        PD_State <= -1;
      elsif (Ven > DC_threshold) and (Vin <= DC_threshold) then -- low state
        PU_State <= -1;
        PD_State <=  1;
      else                                                      -- 3-state
        PU_State <= -1;
        PD_State <= -1;
      end if;
    else
      if (PU_State < 0) and (PD_State < 0) then                 -- curent state is 3-state
        if (Ven > Vth_R) and (Vin > DC_threshold) then          -- go to high state
          PU_State <=  2;
          PD_State <= -1;
        elsif (Ven > Vth_R) and (Vin <= DC_threshold) then      -- go to low state
          PU_State <= -1;
          PD_State <=  2;
        end if;
      elsif (PU_State > 0) and (PD_State < 0) then              -- curent state is high
        if (Ven > Vth_R) and (Vin < Vth_F) then                 -- go to low state
          PU_State <= -2;
          PD_State <=  2;
        elsif (Ven < Vth_F) then                                -- go to 3-state
          PU_State <= -2;
          PD_State <= -1;
        end if;
      elsif (PU_State < 0) and (PD_State > 0) then              -- curent state is low
        if (Ven > Vth_R) and (Vin > Vth_R) then                 -- go to high state
          PU_State <=  2;
          PD_State <= -2;
        elsif (Ven < Vth_F) then                                -- go to 3-state
          PU_State <= -1;
          PD_State <= -2;
        end if;
      end if;
    end if;
  end process Threshold_crossing;
  -----------------------------------------------------------------------------
  break on PU_State;
--=============================================================================
  -- This section contains the simultaneous analog equations to find the
  -- appropriate scaling coefficients according to the state the buffer.
  -----------------------------------------------------------------------------

  case PU_State use
    when -2 =>                                      -- PU is turning off
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kf1), "HE");
    when -1 =>                                      -- PU is off
      kpu == Ktables(Kr1)(Ktables(Kr1)'left);       -- 1st point in PU_on table
    when 1 =>                                       -- PU is on
      kpu == Ktables(Kf1)(Ktables(Kf1)'left);       -- 1st point in PU_off table
    when 2 =>                                       -- PU is tuning on
      kpu == Lookup(PU_State'last_event, Ktables(Tcm), Ktables(Kr1), "HE");
    when others =>              -- before any process assignments are available
      kpu == 0.0;
  end case;
--=============================================================================
  -- This section contains the simultaneous analog equations which calculate
  -- the output currents of the IV curves and C_comp capacitors.
  -----------------------------------------------------------------------------
  Ipc == -1.0*kI_pc    *Lookup(Vpc, Vpc_vec, Ipc_vec, "SE") + kC_comp_pc_val*C_comp_val*Vpc'dot;
  Ipu == -1.0*kI_pu*kpu*Lookup(Vpu, Vpu_vec, Ipu_vec, "SE") + kC_comp_pu_val*C_comp_val*Vpu'dot;
  Ipd ==  0.0                                               + kC_comp_pd_val*C_comp_val*Vpd'dot;
  Igc ==      kI_gc    *Lookup(Vgc, Vgc_vec, Igc_vec, "SE") + kC_comp_gc_val*C_comp_val*Vgc'dot;
  -----------------------------------------------------------------------------
  -- A simple receiver logic
  -----------------------------------------------------------------------------
  if        Vgc'above(Vinh_val)  use Vrcv == 1.0;
  elsif not(Vgc'above(Vinl_val)) use Vrcv == 0.0;
  else                               Vrcv == 0.5;
  end use;
  break on Vgc'above(Vinh_val), Vgc'above(Vinl_val);
--=============================================================================
end architecture IBIS_1EQ1UK;
--=============================================================================
