--=========================================================================== -- This file was written by Arpad Muranyi, Intel Corporation. It does not -- contain any confidential or proprietary information, and it is made -- available to the public with the intent of promoting the usage of the -- Multi-Lingual Extensions of the IBIS specification and to help pave the -- way for more accurate behavioral I/O buffer models and simulations. This -- file may be used, modified, and distributed without any limitations; -- however, this file is provided "as is" with no warranties whatsoever, -- including any warranty of merchantability, noninfringement, fitness for -- any particular purpose, or any warranty otherwise arising out of any -- proposal, specification or sample. Intel and the author disclaim all -- liability, including liability or infringement of any proprietary rights, -- including rights to use the information in this file. No license, -- express or implied, by estoppel or otherwise, to any intellectual -- property rights is granted herein. --=========================================================================== -- Base model v2.0 -- -- This version uses an improved digital logic to find the state of the -- buffer. Process "Catch" was changed, processes "****_event_time" -- were added, and the "simultaneous analog equations" section was also -- modified to accomodate the above changes. This model is more compact -- compared with the older version. A.M. 4/5/2004 -- -- Features: -- -- 1) This model is an open source (no pulldown IV tables) differential -- pre/de-emphasis version of the VHDL-AMS base model suitable for -- modeling SATA buffers. It uses a 1 equation 1 unknown algorithm -- to process the IV and Vt tables of IBIS v2.1 files with support -- for a differential IV surface (or resistor) and a differential -- capacitance. -- -- 2) This model uses 3 IV curves, 2 Vt curves (OS buffer model) and -- 6 coefficients to describe a non-linear differential IV surface -- or a single resistance value. -- -- Vt tables do not have to be the same length, -- Vt tables do not have to start and/or end at the same time, -- Vt tables do not have to have the same time points -- -- Note that the data provided in this model is not realistic and -- must be replaced before any meaningful simulation can be done. -- -- 3) Model has common time axis generator for the Vt curves (executes -- once during initialization of constants) -- -- 5) Model has time axis interpolator for improved resolution with Vt -- curves having a few points, or large dt between points (executes -- once during initialization of constants) -- -- 6) Includes Vt curve to scaling coefficient converter (executes once -- during initialization of constants) -- -- 7) This model has a 4-way split constant C_comp -- -- 8) This model has a clocked Input and an asynchronous Enable logic -- with generics to define which edge of the clock is used, and to -- define the initial condition of the outputs before the first -- triggering clock edge is received. -- -- To be done: -- -- 1) C_comp compensation algorithm needs to be modified to account -- for the mutual loading between the two halves of the buffer -- 2) Add receiver model (threshold sensing, etc...) -- 3) Add support for the Ramp keyword -- 4) Provisions for switching into unfinished edges -- 5) Data dependent switching and strength characteristics support -- 6) File I/O to read IV, Vt, etc. data from external files --=========================================================================== library IEEE; use IEEE.math_real.all; use IEEE.std_logic_1164.all; use IEEE.electrical_systems.all; use IEEE.energy_systems.all; --=========================================================================== entity IBIS_DIFF_OS_CLK_2TAP is generic (Edge : integer := 2; -- "0" = Falling edge triggered -- "1" = Rising edge triggered -- "2" = Triggers on both edges Out_ini : std_logic := 'Z'; -- Initial condition for output C_comp : real := 1.00e-12; -- Default C_comp value and k_C_comp_pc : real := 0.25; -- splitting coefficients k_C_comp_pu : real := 0.25; k_C_comp_pd : real := 0.25; k_C_comp_gc : real := 0.25; C_diff : real := 50.0e-15; -- Default C_diff value (50.0fF) ------------------------------------------------------------------ -- [Pullup Reference] and [Pulldown Reference] values ------------------------------------------------------------------ V_pu_ref : real := 1.8; V_pd_ref : real := 0.0; ------------------------------------------------------------------ -- Coefficients of Idiff surface (from Matlab surface fitting) ------------------------------------------------------------------ k0 : real := -6.503179353194756e-006; k1 : real := 2.541816815085296e-003; k2 : real := -2.541334083148360e-003; k3 : real := 2.809854297776799e-005; k4 : real := -4.580644144607367e-004; k5 : real := 4.354430013260378e-004; R_diff : real := 700.0; -- In case a linear resistor does the job ----------------------------------------------------------------------------- -- Vectors of the IV curve tables ----------------------------------------------------------------------------- V_pc : real_vector := ( -1.80000000E+00, 3.60000000E+00); I_pc : real_vector := ( 0.00000000E+00, 0.00000000E+00); ----------------------------------------------------------------------------- V_pu : real_vector := ( -1.80000000E+0, 0.00000000E+0, 3.60000000E+0); I_pu : real_vector := ( 14.49811000E-3, 57.64466100E-6, -21.11750000E-3); ----------------------------------------------------------------------------- V_gc : real_vector := ( -1.80000000E+00, 3.60000000E+00); I_gc : real_vector := ( -3.60000000E-02, 7.20000000E-02); ----------------------------------------------------------------------------- -- Vectors of the Vt curve tables ----------------------------------------------------------------------------- T_pu_on : real_vector := ( 0.00000000E+0, 0.20000000E-9, 0.80000000E-9, 2.00000000E-9); V_pu_on : real_vector := ( 881.54343788E-3, 881.54343788E-3, 1.28339102E+0, 1.28339102E+0); ----------------------------------------------------------------------------- T_pu_off : real_vector := ( 0.00000000E+0, 0.20000000E-9, 0.80000000E-9, 2.00000000E-9); V_pu_off : real_vector := ( 1.28339102E+0, 1.28339102E+0, 881.54343788E-3, 881.54343788E-3); ----------------------------------------------------------------------------- -- V_fixture and R_fixture values ----------------------------------------------------------------------------- Vfx_pu_on : real := 1.0; Vfx_pu_off : real := 1.0; Rfx_pu_on : real := 50.0; Rfx_pu_off : real := 50.0; ------------------------------------------------------------------ Delta_t : real := 1.0e-12); -- This parameter -- determines what the maximum time delta will be between the -- points of the Vt curves and scaling coefficient curves -- after preprocessing the input data. ------------------------------------------------------------------------ port (signal In_D : in std_logic; signal En_D : in std_logic; signal Rcv_D : out std_logic; signal Clk : in std_logic; terminal IO_p : electrical; terminal IO_n : electrical; terminal PC_ref : electrical; terminal PU_ref : electrical; terminal PD_ref : electrical; terminal GC_ref : electrical); end entity IBIS_DIFF_OS_CLK_2TAP; --=========================================================================== architecture DIFF_OS_CLK_2TAP_1EQ of IBIS_DIFF_OS_CLK_2TAP is --------------------------------------------------------------------------- -- Common mode components for IV curves --------------------------------------------------------------------------- quantity Vpc_p_0 across Ipc_p_0 through PC_ref to IO_p; quantity Vpu_p_0 across Ipu_p_0 through PU_ref to IO_p; quantity Vgc_p_0 across Igc_p_0 through IO_p to GC_ref; quantity Vpc_n_0 across Ipc_n_0 through PC_ref to IO_n; quantity Vpu_n_0 across Ipu_n_0 through PU_ref to IO_n; quantity Vgc_n_0 across Igc_n_0 through IO_n to GC_ref; quantity Vpc_p_1 across Ipc_p_1 through PC_ref to IO_p; quantity Vpu_p_1 across Ipu_p_1 through PU_ref to IO_p; quantity Vgc_p_1 across Igc_p_1 through IO_p to GC_ref; quantity Vpc_n_1 across Ipc_n_1 through PC_ref to IO_n; quantity Vpu_n_1 across Ipu_n_1 through PU_ref to IO_n; quantity Vgc_n_1 across Igc_n_1 through IO_n to GC_ref; --------------------------------------------------------------------------- -- Common mode components for C_comp --------------------------------------------------------------------------- quantity Vc_pc_p across Ic_pc_p through PC_ref to IO_p; quantity Vc_pu_p across Ic_pu_p through PU_ref to IO_p; quantity Vc_pd_p across Ic_pd_p through IO_p to PD_ref; quantity Vc_gc_p across Ic_gc_p through IO_p to GC_ref; quantity Vc_pc_n across Ic_pc_n through PC_ref to IO_n; quantity Vc_pu_n across Ic_pu_n through PU_ref to IO_n; quantity Vc_pd_n across Ic_pd_n through IO_n to PD_ref; quantity Vc_gc_n across Ic_gc_n through IO_n to GC_ref; --------------------------------------------------------------------------- -- Differential IV surface and C_comp --------------------------------------------------------------------------- quantity V_pn across I_pn through IO_p to IO_n; quantity Vc_diff across Ic_diff through IO_p to IO_n; --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- Various signals and quantities (for internal calculations) --------------------------------------------------------------------------- signal Data_D : std_logic := Out_ini; signal Data_InvDel_D : std_logic := Out_ini; signal pu_p_on_0 : std_logic := '0'; signal pu_p_off_0 : std_logic := '0'; signal pu_n_on_0 : std_logic := '0'; signal pu_n_off_0 : std_logic := '0'; signal pu_p_on_1 : std_logic := '0'; signal pu_p_off_1 : std_logic := '0'; signal pu_n_on_1 : std_logic := '0'; signal pu_n_off_1 : std_logic := '0'; signal Tpu_p_on_event_0 : real := 0.0; signal Tpu_p_off_event_0 : real := 0.0; signal Tpu_n_on_event_0 : real := 0.0; signal Tpu_n_off_event_0 : real := 0.0; signal Tpu_p_on_event_1 : real := 0.0; signal Tpu_p_off_event_1 : real := 0.0; signal Tpu_n_on_event_1 : real := 0.0; signal Tpu_n_off_event_1 : real := 0.0; quantity k_pu_p_0 : real := 0.0; quantity k_pu_n_0 : real := 0.0; quantity k_pu_p_1 : real := 0.0; quantity k_pu_n_1 : real := 0.0; --=========================================================================== function Lookup (Extrapolation : in string := "IV"; X : in real; Ydata : in real_vector; Xdata : in real_vector) return real is --------------------------------------------------------------------------- -- This function is basically the equivalent of a PWL function in SPICE. -- It returns "Y" that corresponds to "X" in the "Ydata" "Xdata" input pair -- using linear interpolation. -- -- If the "X" input value lies outside the range of "Xdata", the returned -- "Y" value will either be equal to the first or last point in "Ydata", -- or it will be calculated using the slope between the first or last two -- points of "Ydata". The extrapolation method is determined by the string -- in "Extrapolation". "Vt" selects the repeated points method, "IV" -- selects the last slopes method. -- -- (The original code of this function was received from Mentor Graphics, -- modifications written by Arpad Muranyi, Intel Corporation). --------------------------------------------------------------------------- variable xvalue, yvalue, m : real; variable start, fin, mid : integer; --------------------------------------------------------------------------- begin ------------------------------------------------------------------------- -- Handle cases when "X" is outside the range of "Xdata" ------------------------------------------------------------------------- if (Extrapolation = "IV") and (X <= Xdata(0)) then m := (Ydata(1) - Ydata(0)) / (Xdata(1) - Xdata(0)); yvalue := Ydata(0) + m * (X - Xdata(0)); return yvalue; elsif (Extrapolation = "Vt") and (X <= Xdata(0)) then yvalue := Ydata(0); return yvalue; elsif (Extrapolation = "IV") and (X >= Xdata(Xdata'right)) then m := (Ydata(Ydata'right) - Ydata(Ydata'right - 1)) / (Xdata(Xdata'right) - Xdata(Xdata'right - 1)); yvalue := Ydata(Ydata'right) + m * (X - Xdata(Xdata'right)); return yvalue; elsif (Extrapolation = "Vt") and (X >= Xdata(Xdata'right)) then yvalue := Ydata(Ydata'right); return yvalue; ------------------------------------------------------------------------- -- Handle cases when "X" is in the range of "Xdata" ------------------------------------------------------------------------- else start:= 0; fin := Xdata'right; while start <= fin loop mid := (start + fin) / 2; if Xdata(mid) < X then start := mid + 1; else fin := mid - 1; end if; end loop; if Xdata(mid) > X then mid := mid - 1; end if; ----------------------------------------------------------------------- -- Find "Y" by linear interpolation ----------------------------------------------------------------------- yvalue := Ydata(mid) + (X - Xdata(mid)) * (Ydata(mid+1) - Ydata(mid)) / (Xdata(mid+1) - Xdata(mid)); return yvalue; ------------------------------------------------------------------------- end if; ------------------------------------------------------------------------- end function Lookup; --=========================================================================== function Find_common_length (Max_dt : real := 1.0e-12; Twfm_1 : in real_vector; Twfm_2 : in real_vector) return integer is --------------------------------------------------------------------------- -- This function finds the total number of points needed for having a -- common time axis for all Vt curves, such that the maximum delta time -- between each time point doesn't exceed the value provided in "Max_dt". --------------------------------------------------------------------------- variable Common_length : integer := 0; variable Return_val : integer := 0; variable index_1 : integer := Twfm_1'left; variable index_2 : integer := Twfm_2'left; variable new_index_1 : integer := Twfm_1'left; variable new_index_2 : integer := Twfm_2'left; variable old_t : real := 0.0; variable new_t : real := 0.0; variable remainder : real := 0.0; variable min_dt : real := 1.0e-3; -- This sets the size of the -- roundoff error relative to -- "Max_dt" --------------------------------------------------------------------------- begin --------------------------------------------------------------------------- -- Put the earliest time value of all given time vectors into "old_t" --------------------------------------------------------------------------- old_t := Twfm_1(Twfm_1'left); if (Twfm_2(Twfm_2'left) < old_t) then old_t := Twfm_2(Twfm_2'left); end if; --------------------------------------------------------------------------- -- Put the latest time value of all given time vectors into "new_t" --------------------------------------------------------------------------- new_t := Twfm_1(Twfm_1'right); if (Twfm_2(Twfm_2'right) > new_t) then new_t := Twfm_2(Twfm_2'right); end if; new_t := new_t; --------------------------------------------------------------------------- -- Loop until latest time value is reached in each given time vector --------------------------------------------------------------------------- while (old_t < new_t) loop ------------------------------------------------------------------------- -- Find which given time vector(s) have the lowest time value and -- advance their temporary indexes ------------------------------------------------------------------------- if (Twfm_1(index_1) <= old_t) then new_index_1 := index_1 + 1; end if; if (Twfm_2(index_2) <= old_t) then new_index_2 := index_2 + 1; end if; ------------------------------------------------------------------------- -- Find the lowest value at the new indexes in the given vector(s) and -- update indexes for next iteration ------------------------------------------------------------------------- if (new_index_1 <= Twfm_1'right) then if (Twfm_1(new_index_1) < new_t) then new_t := Twfm_1(new_index_1); end if; index_1 := new_index_1; end if; if (new_index_2 <= Twfm_2'right) then if (Twfm_2(new_index_2) < new_t) then new_t := Twfm_2(new_index_2); end if; index_2 := new_index_2; end if; ------------------------------------------------------------------------- -- Calculate how many additional points are needed between the given -- points to satisfy the "Max_dt" separation criteria. Note: the extra -- logic is needed due to floating point inaccuracies. ------------------------------------------------------------------------- Common_length := Common_length + integer(ceil((new_t-old_t)/Max_dt)); remainder := "mod"((new_t-old_t),Max_dt); if (remainder < (min_dt * Max_dt)) and (remainder > 0.0) then Common_length := Common_length - 1; end if; ------------------------------------------------------------------------- -- Update variables for next iteration ------------------------------------------------------------------------- old_t := new_t; new_t := Twfm_1(Twfm_1'right); if (Twfm_2(Twfm_2'right) > new_t) then new_t := Twfm_2(Twfm_2'right); end if; new_t := new_t; --------------------------------------------------------------------------- end loop; --------------------------------------------------------------------------- return Common_length; end function Find_common_length; --=========================================================================== function Common_time (Max_dt : real := 1.0e-12; Twfm_1 : in real_vector; Twfm_2 : in real_vector) return real_vector is --------------------------------------------------------------------------- -- This function generates a vector that serves as a common time axis for -- all Vt curves, such that the maximum delta time between each time point -- doesn't exceed the value provided in "Max_dt". --------------------------------------------------------------------------- variable New_time : real_vector(0 to Find_common_length(Max_dt, Twfm_1, Twfm_2)) := (others => 0.0); variable index : integer := 0; variable extra_start : integer := 0; variable extra_points : integer := 0; variable index_1 : integer := Twfm_1'left; variable index_2 : integer := Twfm_2'left; variable new_index_1 : integer := Twfm_1'left; variable new_index_2 : integer := Twfm_2'left; variable old_t : real := 0.0; variable new_t : real := 0.0; variable remainder : real := 0.0; variable min_dt : real := 1.0e-3; -- This sets the size of the -- roundoff error relative to -- "Max_dt" --------------------------------------------------------------------------- begin --------------------------------------------------------------------------- -- Put the earliest time value of all given time vectors into "old_t" --------------------------------------------------------------------------- old_t := Twfm_1(Twfm_1'left); if (Twfm_2(Twfm_2'left) < old_t) then old_t := Twfm_2(Twfm_2'left); end if; --------------------------------------------------------------------------- -- Put the latest time value of all given time vectors into "new_t" --------------------------------------------------------------------------- new_t := Twfm_1(Twfm_1'right); if (Twfm_2(Twfm_2'right) > new_t) then new_t := Twfm_2(Twfm_2'right); end if; new_t := new_t; --------------------------------------------------------------------------- -- Loop until last index is reached in each given time vector --------------------------------------------------------------------------- index := New_time'left; while (old_t < new_t) loop ------------------------------------------------------------------------- -- Find which given time vector(s) have the lowest time value and -- advance their temporary indexes ------------------------------------------------------------------------- if (Twfm_1(index_1) <= old_t) then new_index_1 := index_1 + 1; end if; if (Twfm_2(index_2) <= old_t) then new_index_2 := index_2 + 1; end if; ------------------------------------------------------------------------- -- Find the lowest value at the new indexes in the given vector(s) and -- update indexes for next iteration ------------------------------------------------------------------------- if (new_index_1 <= Twfm_1'right) then if (Twfm_1(new_index_1) < new_t) then new_t := Twfm_1(new_index_1); end if; index_1 := new_index_1; end if; if (new_index_2 <= Twfm_2'right) then if (Twfm_2(new_index_2) < new_t) then new_t := Twfm_2(new_index_2); end if; index_2 := new_index_2; end if; ------------------------------------------------------------------------- -- Calculate how many additional points are needed between the given -- points to satisfy the "Max_dt" separation criteria. Note: the extra -- logic is needed due to floating point inaccuracies. ------------------------------------------------------------------------- extra_points := integer(ceil((new_t-old_t)/Max_dt)); remainder := "mod"((new_t-old_t),Max_dt); if remainder < (min_dt * Max_dt) and remainder > 0.0 then extra_points := extra_points - 1; end if; ------------------------------------------------------------------------- -- Calculate and write the values of points into the "New_time" vector ------------------------------------------------------------------------- for x_index in 0 to (extra_points - 1) loop New_time(index) := old_t + (real(x_index) * (new_t-old_t)) / real(extra_points); index := index + 1; end loop; ------------------------------------------------------------------------- -- Update variables for next iteration ------------------------------------------------------------------------- old_t := new_t; new_t := Twfm_1(Twfm_1'right); if (Twfm_2(Twfm_2'right) > new_t) then new_t := Twfm_2(Twfm_2'right); end if; new_t := new_t; --------------------------------------------------------------------------- end loop; --------------------------------------------------------------------------- -- Insert the largest value at the end of the given vector(s) into the -- last position of "New_time". (The loop above stops at the next to -- the last point). --------------------------------------------------------------------------- -- This may look better than the -- next line, but doesn't seem to -- New_time(New_time'right) := new_t; -- work due to a possible bug. New_time(index) := new_t; --------------------------------------------------------------------------- return New_time; end function Common_time; --=========================================================================== function Common_wfm (New_t : in real_vector; Vwfm : in real_vector; Twfm : in real_vector) return real_vector is --------------------------------------------------------------------------- -- This function generates an interpolated vector based on the input vector -- "New_t" using the input vector pair "Vwfm" and "Twfm". --------------------------------------------------------------------------- variable New_v : real_vector(New_t'range) := (others => 1.0); --------------------------------------------------------------------------- begin -- This is the better notation -- but it doesn't work due to -- for index in New_v'range loop -- a possible bug. for index in New_v'left to New_v'right loop New_v(index) := Lookup("Vt", New_t(index), Vwfm, Twfm); end loop; return New_v; end function Common_wfm; --=========================================================================== constant T_common : real_vector := Common_time(Delta_t, T_pu_on, T_pu_off); constant V_pu_on_common : real_vector := Common_wfm(T_common, V_pu_on, T_pu_on); constant V_pu_off_common : real_vector := Common_wfm(T_common, V_pu_off, T_pu_off); --=========================================================================== function Coeff (Edge : in string; Vwfm : in real_vector; Twfm : in real_vector; Rfx : in real; Vfx : in real; Iiv : in real_vector; Viv : in real_vector; Vref : in real) return real_vector is --------------------------------------------------------------------------- -- This function converts the Vt curve to a corresponding scaling -- coefficient curve that is used to scale the IV curve with respect -- to time. The effects of C_comp on the waveforms are included in the -- scaling coefficient, so that the presence of C_comp in the output -- stage will not "load" the driver, i.e. C_comp in the output stage -- will not derate the original waveforms in the Vt curves. --------------------------------------------------------------------------- -- variable Kout : real_vector(Vwfm'range); -- This is the better notation -- variable dVwfm : real_vector(Vwfm'range); -- but it doesn't work due to -- a possible bug. variable Kout : real_vector(Vwfm'left to Vwfm'right); variable dVwfm : real_vector(Vwfm'left to Vwfm'right); variable I1 : real := 1.0; variable Ifx1 : real := 0.0; --------------------------------------------------------------------------- begin for index in Vwfm'range loop ------------------------------------------------------------------------- -- Generate the derivative of the waveform -- Force the derivatives of the first and last points to zero ------------------------------------------------------------------------- if (index = Vwfm'left) then dVwfm(index) := 0.0; dVwfm(index) := 0.0; elsif (index = Vwfm'right) then dVwfm(index) := 0.0; dVwfm(index) := 0.0; ----------------------------------------------------------------------- -- Calculate the derivative of a point using both of its neighbors ----------------------------------------------------------------------- else dVwfm(index) := ((Vwfm(index) - Vwfm(index-1))/(Twfm(index) - Twfm(index-1)) + (Vwfm(index+1) - Vwfm(index))/(Twfm(index+1) - Twfm(index)))/2.0; end if; ----------------------------------------------------------------------- -- Calculate intermediate currents ----------------------------------------------------------------------- if (Edge = "K_pu_on") or (Edge = "K_pu_off") then I1 := Lookup("IV", Vref - Vwfm(index), Iiv, Viv); Ifx1 := realmin(((Vfx - Vwfm(index)) / Rfx), 0.0) - C_comp * dVwfm(index); elsif (Edge = "K_pd_on") or (Edge = "K_pd_off") then I1 := Lookup("IV", Vwfm(index) - Vref, Iiv, Viv); Ifx1 := realmax(((Vfx - Vwfm(index)) / Rfx), 0.0) - C_comp * dVwfm(index); else I1 := 1.0; Ifx1 := 0.0; end if; Kout(index) := Ifx1 / I1; ------------------------------------------------------------------------- end loop; ------------------------------------------------------------------------- return Kout; end function Coeff; --=========================================================================== constant K_pu_on : real_vector := Coeff("K_pu_on", V_pu_on_common, T_common, Rfx_pu_on, Vfx_pu_on, I_pu, V_pu, V_pu_ref); constant K_pu_off : real_vector := Coeff("K_pu_off", V_pu_off_common, T_common, Rfx_pu_off, Vfx_pu_off, I_pu, V_pu, V_pu_ref); --=========================================================================== begin --=========================================================================== Clock: process (Clk) is --------------------------------------------------------------------------- begin --------------------------------------------------------------------------- if (Clk = '1') and (Clk'LAST_VALUE = '0') then -- Rising edge if (Edge = 1) or (Edge = 2) then Data_InvDel_D <= not Data_D; -- One clock delayed inverted Data_D Data_D <= In_D; -- Clocked input end if; elsif (Clk = '0') and (Clk'LAST_VALUE = '1') then -- Falling edge if (Edge = 0) or (Edge = 2) then Data_InvDel_D <= not Data_D; -- One clock delayed inverted Data_D Data_D <= In_D; -- Clocked input end if; end if; --------------------------------------------------------------------------- end process Clock; --=========================================================================== Catch_0: process (Data_D, En_D) is --------------------------------------------------------------------------- begin Rcv_D <= Data_D; -- Dummy receiver logic --------------------------------------------------------------------------- if (En_D = '1') and (Data_D = '1') then -- Find logic state pu_p_on_0 <= '1'; pu_n_off_0 <= '1'; pu_n_on_0 <= '0'; pu_p_off_0 <= '0'; elsif (En_D = '1') and (Data_D = '0') then pu_p_on_0 <= '0'; pu_n_off_0 <= '0'; pu_n_on_0 <= '1'; pu_p_off_0 <= '1'; else pu_p_on_0 <= '0'; pu_n_off_0 <= '1'; pu_n_on_0 <= '0'; pu_p_off_0 <= '1'; end if; --------------------------------------------------------------------------- end process Catch_0; --=========================================================================== Catch_1: process (Data_InvDel_D, En_D) is --------------------------------------------------------------------------- begin --------------------------------------------------------------------------- if (En_D = '1') and (Data_InvDel_D = '1') then -- Find logic state pu_p_on_1 <= '1'; pu_n_off_1 <= '1'; pu_n_on_1 <= '0'; pu_p_off_1 <= '0'; elsif (En_D = '1') and (Data_InvDel_D = '0') then pu_p_on_1 <= '0'; pu_n_off_1 <= '0'; pu_n_on_1 <= '1'; pu_p_off_1 <= '1'; else pu_p_on_1 <= '0'; pu_n_off_1 <= '1'; pu_n_on_1 <= '0'; pu_p_off_1 <= '1'; end if; --------------------------------------------------------------------------- end process Catch_1; --=========================================================================== pu_p_on_event_time_0: process (pu_p_on_0) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_p_on_event_0 <= now; --------------------------------------------------------------------------- end process pu_p_on_event_time_0; --=========================================================================== pu_p_off_event_time_0: process (pu_p_off_0) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_p_off_event_0 <= now; --------------------------------------------------------------------------- end process pu_p_off_event_time_0; --=========================================================================== pu_n_on_event_time_0: process (pu_n_on_0) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_n_on_event_0 <= now; --------------------------------------------------------------------------- end process pu_n_on_event_time_0; --=========================================================================== pu_n_off_event_time_0: process (pu_n_off_0) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_n_off_event_0 <= now; --------------------------------------------------------------------------- end process pu_n_off_event_time_0; --=========================================================================== pu_p_on_event_time_1: process (pu_p_on_1) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_p_on_event_1 <= now; --------------------------------------------------------------------------- end process pu_p_on_event_time_1; --=========================================================================== pu_p_off_event_time_1: process (pu_p_off_1) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_p_off_event_1 <= now; --------------------------------------------------------------------------- end process pu_p_off_event_time_1; --=========================================================================== pu_n_on_event_time_1: process (pu_n_on_1) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_n_on_event_1 <= now; --------------------------------------------------------------------------- end process pu_n_on_event_time_1; --=========================================================================== pu_n_off_event_time_1: process (pu_n_off_1) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_n_off_event_1 <= now; --------------------------------------------------------------------------- end process pu_n_off_event_time_1; --=========================================================================== break on pu_p_on_0; break on pu_p_off_0; break on pu_n_on_0; break on pu_n_off_0; break on pu_p_on_1; break on pu_p_off_1; break on pu_n_on_1; break on pu_n_off_1; --=========================================================================== -- This section contains the simultaneous analog equations to find the -- appropriate scaling coefficients according to the state the buffer. --------------------------------------------------------------------------- if (Tpu_p_on_event_0 = 0.0 and Tpu_p_off_event_0 = 0.0 and Tpu_n_on_event_0 = 0.0 and Tpu_n_off_event_0 = 0.0) use -- Initialization if (pu_p_on_0 = '1') use -- Start with the end of the k_pu_p_0 == K_pu_on(K_pu_on'right); -- Vt curves for those which elsif (pu_p_off_0 = '1') use -- are fully on initially k_pu_p_0 == K_pu_off(K_pu_off'right); else k_pu_p_0 == 0.0; end use; if (pu_n_on_0 = '1') use k_pu_n_0 == K_pu_on(K_pu_on'right); elsif (pu_n_off_0 = '1') use k_pu_n_0 == K_pu_off(K_pu_off'right); else k_pu_n_0 == 0.0; end use; else -- Look up coefficients in normal operation if (pu_p_on_0 = '1') use k_pu_p_0 == Lookup("Vt", now - Tpu_p_on_event_0, K_pu_on, T_common); elsif (pu_p_off_0 = '1') use k_pu_p_0 == Lookup("Vt", now - Tpu_p_off_event_0, K_pu_off, T_common); else k_pu_p_0 == K_pu_on(K_pu_on'left); end use; if (pu_n_on_0 = '1') use k_pu_n_0 == Lookup("Vt", now - Tpu_n_on_event_0, K_pu_on, T_common); elsif (pu_n_off_0 = '1') use k_pu_n_0 == Lookup("Vt", now - Tpu_n_off_event_0, K_pu_off, T_common); else k_pu_n_0 == K_pu_on(K_pu_on'left); end use; end use; --=========================================================================== -- This section contains the simultaneous analog equations to find the -- appropriate scaling coefficients according to the state the buffer. --------------------------------------------------------------------------- if (Tpu_p_on_event_1 = 0.0 and Tpu_p_off_event_1 = 0.0 and Tpu_n_on_event_1 = 0.0 and Tpu_n_off_event_1 = 0.0) use -- Initialization if (pu_p_on_1 = '1') use -- Start with the end of the k_pu_p_1 == K_pu_on(K_pu_on'right); -- Vt curves for those which elsif (pu_p_off_1 = '1') use -- are fully on initially k_pu_p_1 == K_pu_off(K_pu_off'right); else k_pu_p_1 == 0.0; end use; if (pu_n_on_1 = '1') use k_pu_n_1 == K_pu_on(K_pu_on'right); elsif (pu_n_off_1 = '1') use k_pu_n_1 == K_pu_off(K_pu_off'right); else k_pu_n_1 == 0.0; end use; else -- Look up coefficients in normal operation if (pu_p_on_1 = '1') use k_pu_p_1 == Lookup("Vt", now - Tpu_p_on_event_1, K_pu_on, T_common); elsif (pu_p_off_1 = '1') use k_pu_p_1 == Lookup("Vt", now - Tpu_p_off_event_1, K_pu_off, T_common); else k_pu_p_1 == K_pu_on(K_pu_on'left); end use; if (pu_n_on_1 = '1') use k_pu_n_1 == Lookup("Vt", now - Tpu_n_on_event_1, K_pu_on, T_common); elsif (pu_n_off_1 = '1') use k_pu_n_1 == Lookup("Vt", now - Tpu_n_off_event_1, K_pu_off, T_common); else k_pu_n_1 == K_pu_on(K_pu_on'left); end use; end use; --=========================================================================== -- This section contains the simultaneous analog equations which calculate -- the output currents of the IV curves and C_comp capacitors. --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- Common mode components for IV curves --------------------------------------------------------------------------- Ipc_p_0 == -1.0 * Lookup("IV", Vpc_p_0, I_pc, V_pc); Ipu_p_0 == -1.0 * k_pu_p_0 * Lookup("IV", Vpu_p_0, I_pu, V_pu); Igc_p_0 == Lookup("IV", Vgc_p_0, I_gc, V_gc); Ipc_n_0 == -1.0 * Lookup("IV", Vpc_n_0, I_pc, V_pc); Ipu_n_0 == -1.0 * k_pu_n_0 * Lookup("IV", Vpu_n_0, I_pu, V_pu); Igc_n_0 == Lookup("IV", Vgc_n_0, I_gc, V_gc); Ipc_p_1 == -0.2 * Lookup("IV", Vpc_p_1, I_pc, V_pc); Ipu_p_1 == -0.2 * k_pu_p_1 * Lookup("IV", Vpu_p_1, I_pu, V_pu); Igc_p_1 == 0.2 * Lookup("IV", Vgc_p_1, I_gc, V_gc); Ipc_n_1 == -0.2 * Lookup("IV", Vpc_n_1, I_pc, V_pc); Ipu_n_1 == -0.2 * k_pu_n_1 * Lookup("IV", Vpu_n_1, I_pu, V_pu); Igc_n_1 == 0.2 * Lookup("IV", Vgc_n_1, I_gc, V_gc); --------------------------------------------------------------------------- -- Common mode components for C_comp --------------------------------------------------------------------------- Ic_pc_p == k_C_comp_pc * C_comp * Vc_pc_p'dot; Ic_pu_p == k_C_comp_pu * C_comp * Vc_pu_p'dot; Ic_pd_p == k_C_comp_pd * C_comp * Vc_pd_p'dot; Ic_gc_p == k_C_comp_gc * C_comp * Vc_gc_p'dot; Ic_pc_n == k_C_comp_pc * C_comp * Vc_pc_n'dot; Ic_pu_n == k_C_comp_pu * C_comp * Vc_pu_n'dot; Ic_pd_n == k_C_comp_pd * C_comp * Vc_pd_n'dot; Ic_gc_n == k_C_comp_gc * C_comp * Vc_gc_n'dot; --------------------------------------------------------------------------- -- Differential IV surface and C_comp --------------------------------------------------------------------------- I_pn == k0 + k1*V_pn + k2*V_pn + k3*V_pn*V_pn + k4*(V_pn**2) + k5*(V_pn**2); -- I_pn == V_pn / R_diff; -- In case a linear resistor does the job -- I_pn == 0.0; -- In case we don't want differential currents Ic_diff == C_diff * Vc_diff'dot; --=========================================================================== end architecture DIFF_OS_CLK_2TAP_1EQ; --===========================================================================