--=========================================================================== -- 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.1 -- -- This version combines the analog equations in order to reduce the -- number of quantities used. A.M. 4/5/2005 -- -- Base model v2.0 -- -- This version uses a different digital logic to find the state of the -- buffer. Process "Catch" was changed, processes "pu_on_event_time", -- "pu_off_event_time", "pd_on_event_time", "pd_off_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. 2/27/2004 -- -- Features: -- -- 1) This model is a differential version of the VHDL-AMS base model -- (using the 2 equations 2 unknowns IBIS 2.1 IV / Vt curve algorithm -- with support for a differential IV surface or resistor and a -- differential capacitance). -- -- 2) This model uses 4 IV curves (I/O buffer model) and 6 coefficients -- to describe a non-linear differential IV surface or a single -- resistance value -- -- 3) This model uses 4 Vt curves (I/O buffer model) -- 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 -- -- 4) 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) Includes complete logic for Input and Enable -- High-to-Low / Low-to-High while enable is on or off -- Enable / Disable while input is High or Low -- Enable / Disable while input goes High-to-Low or Low-to-High -- -- To be done: -- -- 1) Add receiver model (threshold sensing, etc...) -- 2) Add support for the Ramp keyword -- 3) Provisions for switching into unfinished edges -- 4) Test terminations using voltages other than V_fixture -- 5) Provide on-die terminations as used with Submodel, etc. -- 6) Data dependent switching and strength characteristics support -- 7) Covering other buffer types (input, output, open_***, etc...) -- 8) Receiver threshold modeling and logic -- 9) 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_IO is generic (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_dn : real := 0.50; 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, 1.50000000E+0, 3.60000000E+0); I_pu : real_vector := ( 14.49811000E-3, 0.00000000E+0, -14.19129000E-3, -21.11750000E-3); ----------------------------------------------------------------------------- V_pd : real_vector := ( -1.80000000E+0, 0.00000000E+0, 500.00000000E-3, 1.78000000E+0, 3.60000000E+0); I_pd : real_vector := ( -159.69000000E-6, -144.22200000E-6, 0.00000000E+0, 10.09110700E-3, 18.40129000E-3); ----------------------------------------------------------------------------- V_gc : real_vector := ( -1.80000000E+00, 3.60000000E+00); I_gc : real_vector := ( 0.00000000E+00, 0.00000000E+00); ----------------------------------------------------------------------------- -- Vectors of the Vt curve tables ----------------------------------------------------------------------------- T_pu_on : real_vector := ( 0.00000000E+0, 180.00000000E-12, 290.00000000E-12, 475.00000000E-12, 2.00000000E-9); V_pu_on : real_vector := ( 881.54343788E-3, 874.71279002E-3, 791.34996459E-3, 1.28339102E+0, 1.28339102E+0); ----------------------------------------------------------------------------- T_pu_off : real_vector := ( 0.00000000E+0, 180.00000000E-12, 290.00000000E-12, 475.00000000E-12, 2.00000000E-9); V_pu_off : real_vector := ( 1.28339102E+0, 1.28904845E+0, 1.30057694E+0, 881.54343788E-3, 881.54343788E-3); ----------------------------------------------------------------------------- T_pd_on : real_vector := ( 0.00000000E+0, 163.00000000E-12, 262.00000000E-12, 475.00000000E-12, 2.00000000E-9); V_pd_on : real_vector := ( 1.60591168E+0, 1.61677744E+0, 1.64478901E+0, 1.22749223E+0, 1.22749223E+0); ----------------------------------------------------------------------------- T_pd_off : real_vector := ( 0.00000000E+0, 163.00000000E-12, 262.00000000E-12, 475.00000000E-12, 2.00000000E-9); V_pd_off : real_vector := ( 1.22749223E+0, 1.23404657E+0, 1.16504453E+0, 1.60691168E+0, 1.60591168E+0); ----------------------------------------------------------------------------- -- V_fixture and R_fixture values ----------------------------------------------------------------------------- Vfx_pu_on : real := 1.0; Vfx_pu_off : real := 1.0; Vfx_pd_on : real := 1.5; Vfx_pd_off : real := 1.5; Rfx_pu_on : real := 50.0; Rfx_pu_off : real := 50.0; Rfx_pd_on : real := 50.0; Rfx_pd_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; terminal IO_p : electrical; terminal IO_n : electrical; terminal PC_ref : electrical; terminal PU_ref : electrical; terminal GND_ref : electrical); end entity IBIS_DIFF_IO; --=========================================================================== architecture DIFF_IO_2EQ of IBIS_DIFF_IO is --------------------------------------------------------------------------- -- Common mode components for IV curves and C_comp --------------------------------------------------------------------------- quantity Vpc_p across Ipc_p through PC_ref to IO_p; quantity Vpu_p across Ipu_p through PU_ref to IO_p; quantity Vdn_p across Idn_p through IO_p to GND_ref; quantity Vpc_n across Ipc_n through PC_ref to IO_n; quantity Vpu_n across Ipu_n through PU_ref to IO_n; quantity Vdn_n across Idn_n through IO_n to GND_ref; --------------------------------------------------------------------------- -- Differential IV surface and C_comp --------------------------------------------------------------------------- quantity V_pn across I_pn through IO_p to IO_n; --------------------------------------------------------------------------- --------------------------------------------------------------------------- -- Various signals and quantities (for internal calculations) --------------------------------------------------------------------------- signal pu_on : std_logic := '0'; signal pu_off : std_logic := '0'; signal pd_on : std_logic := '0'; signal pd_off : std_logic := '0'; signal Tpu_on_event : real := 0.0; signal Tpd_off_event : real := 0.0; signal Tpd_on_event : real := 0.0; signal Tpu_off_event : real := 0.0; quantity k_pu_p : real := 0.0; quantity k_pd_p : real := 0.0; quantity k_pu_n : real := 0.0; quantity k_pd_n : 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; Twfm_3 : in real_vector; Twfm_4 : 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 index_3 : integer := Twfm_3'left; variable index_4 : integer := Twfm_4'left; variable new_index_1 : integer := Twfm_1'left; variable new_index_2 : integer := Twfm_2'left; variable new_index_3 : integer := Twfm_3'left; variable new_index_4 : integer := Twfm_4'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; if (Twfm_3(Twfm_3'left) < old_t) then old_t := Twfm_3(Twfm_3'left); end if; if (Twfm_4(Twfm_4'left) < old_t) then old_t := Twfm_4(Twfm_4'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; if (Twfm_3(Twfm_3'right) > new_t) then new_t := Twfm_3(Twfm_3'right); end if; if (Twfm_4(Twfm_4'right) > new_t) then new_t := Twfm_4(Twfm_4'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; if (Twfm_3(index_3) <= old_t) then new_index_3 := index_3 + 1; end if; if (Twfm_4(index_4) <= old_t) then new_index_4 := index_4 + 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; if (new_index_3 <= Twfm_3'right) then if (Twfm_3(new_index_3) < new_t) then new_t := Twfm_3(new_index_3); end if; index_3 := new_index_3; end if; if (new_index_4 <= Twfm_4'right) then if (Twfm_4(new_index_4) < new_t) then new_t := Twfm_4(new_index_4); end if; index_4 := new_index_4; 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; if (Twfm_3(Twfm_3'right) > new_t) then new_t := Twfm_3(Twfm_3'right); end if; if (Twfm_4(Twfm_4'right) > new_t) then new_t := Twfm_4(Twfm_4'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; Twfm_3 : in real_vector; Twfm_4 : 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, Twfm_3, Twfm_4)-1) := (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 index_3 : integer := Twfm_3'left; variable index_4 : integer := Twfm_4'left; variable new_index_1 : integer := Twfm_1'left; variable new_index_2 : integer := Twfm_2'left; variable new_index_3 : integer := Twfm_3'left; variable new_index_4 : integer := Twfm_4'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; if (Twfm_3(Twfm_3'left) < old_t) then old_t := Twfm_3(Twfm_3'left); end if; if (Twfm_4(Twfm_4'left) < old_t) then old_t := Twfm_4(Twfm_4'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; if (Twfm_3(Twfm_3'right) > new_t) then new_t := Twfm_3(Twfm_3'right); end if; if (Twfm_4(Twfm_4'right) > new_t) then new_t := Twfm_4(Twfm_4'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; if (Twfm_3(index_3) <= old_t) then new_index_3 := index_3 + 1; end if; if (Twfm_4(index_4) <= old_t) then new_index_4 := index_4 + 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; if (new_index_3 <= Twfm_3'right) then if (Twfm_3(new_index_3) < new_t) then new_t := Twfm_3(new_index_3); end if; index_3 := new_index_3; end if; if (new_index_4 <= Twfm_4'right) then if (Twfm_4(new_index_4) < new_t) then new_t := Twfm_4(new_index_4); end if; index_4 := new_index_4; 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; if (Twfm_3(Twfm_3'right) > new_t) then new_t := Twfm_3(Twfm_3'right); end if; if (Twfm_4(Twfm_4'right) > new_t) then new_t := Twfm_4(Twfm_4'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). --------------------------------------------------------------------------- New_time(New_time'right) := 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 bug in SystemVision 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, T_pd_on, T_pd_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); constant V_pd_on_common : real_vector := Common_wfm(T_common, V_pd_on, T_pd_on); constant V_pd_off_common : real_vector := Common_wfm(T_common, V_pd_off, T_pd_off); --=========================================================================== function Coeff (Edge : in string; Vwfm_pu : in real_vector; Vwfm_pd : in real_vector; Twfm : in real_vector; Rfx_pu : in real; Rfx_pd : in real; Vfx_pu : in real; Vfx_pd : in real; Iiv_pu : in real_vector; Viv_pu : in real_vector; Iiv_pd : in real_vector; Viv_pd : in real_vector; V_pu_ref : in real; V_pd_ref : in real) return real_vector is --------------------------------------------------------------------------- -- This function converts each Vt curve to a corresponding scaling -- coefficient curve that is used to scale the IV curves with respect -- to time. The effects of C_comp on the waveforms are included in the -- scaling coefficients, 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_pu'left to Vwfm_pu'right); variable dVwfm_pu : real_vector(Vwfm_pu'left to Vwfm_pu'right); variable dVwfm_pd : real_vector(Vwfm_pd'left to Vwfm_pd'right); variable I1 : real := 0.0; variable I2 : real := 0.0; variable I3 : real := 0.0; variable I4 : real := 0.0; variable Ifx1 : real := 0.0; variable Ifx2 : real := 0.0; variable num : real := 0.0; variable den : real := 1.0; --------------------------------------------------------------------------- begin --------------------------------------------------------------------------- -- Generate the derivative of each waveform --------------------------------------------------------------------------- for index in Vwfm_pu'range loop ------------------------------------------------------------------------- -- Force the derivatives of the first and last points to zero ------------------------------------------------------------------------- if (index = Vwfm_pu'left) then dVwfm_pu(index) := 0.0; dVwfm_pd(index) := 0.0; elsif (index = Vwfm_pu'right) then dVwfm_pu(index) := 0.0; dVwfm_pd(index) := 0.0; ----------------------------------------------------------------------- -- Calculate the derivative of a point using both of its neighbors ----------------------------------------------------------------------- else dVwfm_pu(index) := ((Vwfm_pu(index) - Vwfm_pu(index-1))/(Twfm(index) - Twfm(index-1)) + (Vwfm_pu(index+1) - Vwfm_pu(index))/(Twfm(index+1) - Twfm(index)))/2.0; dVwfm_pd(index) := ((Vwfm_pd(index) - Vwfm_pd(index-1))/(Twfm(index) - Twfm(index-1)) + (Vwfm_pd(index+1) - Vwfm_pd(index))/(Twfm(index+1) - Twfm(index)))/2.0; end if; ----------------------------------------------------------------------- -- Calculate intermediate (current) variables ----------------------------------------------------------------------- I1 := Lookup("IV", Vwfm_pd(index) - V_pd_ref, Iiv_pd, Viv_pd); I2 := Lookup("IV", Vwfm_pu(index) - V_pd_ref, Iiv_pd, Viv_pd); I3 := -1.0 * Lookup("IV", V_pu_ref - Vwfm_pu(index), Iiv_pu, Viv_pu); I4 := -1.0 * Lookup("IV", V_pu_ref - Vwfm_pd(index), Iiv_pu, Viv_pu); ----------------------------------------------------------------------- -- Calculate intermediate (fixture) variables ----------------------------------------------------------------------- Ifx1 := ((Vwfm_pu(index) - Vfx_pu) / Rfx_pu) + C_comp * dVwfm_pu(index); Ifx2 := ((Vfx_pd - Vwfm_pd(index)) / Rfx_pd) - C_comp * dVwfm_pd(index); ----------------------------------------------------------------------- -- Set up the numerator of the equation depending on the direction of -- the transition, and set up denominator of the equation. ----------------------------------------------------------------------- if (Edge = "K_pu_on") or (Edge = "K_pu_off") then num := (Ifx1 * I1) + (Ifx2 * I2); elsif (Edge = "K_pd_on") or (Edge = "K_pd_off") then num := (Ifx1 * I4) + (Ifx2 * I3); else num := 0.0; end if; den := (I1 * I3) - (I2 * I4); ----------------------------------------------------------------------- -- This is the master equation that solves for the scaling coefficients ----------------------------------------------------------------------- Kout(index) := num / den; ------------------------------------------------------------------------- end loop; ------------------------------------------------------------------------- return Kout; end function Coeff; --=========================================================================== constant K_pu_on : real_vector := Coeff("K_pu_on", V_pu_on_common, V_pd_off_common, T_common, Rfx_pu_on, Rfx_pd_off, Vfx_pu_on, Vfx_pd_off, I_pu, V_pu, I_pd, V_pd, V_pu_ref, V_pd_ref); constant K_pd_off : real_vector := Coeff("K_pd_off", V_pu_on_common, V_pd_off_common, T_common, Rfx_pu_on, Rfx_pd_off, Vfx_pu_on, Vfx_pd_off, I_pu, V_pu, I_pd, V_pd, V_pu_ref, V_pd_ref); constant K_pd_on : real_vector := Coeff("K_pd_on", V_pu_off_common, V_pd_on_common, T_common, Rfx_pu_off, Rfx_pd_on, Vfx_pu_off, Vfx_pd_on, I_pu, V_pu, I_pd, V_pd, V_pu_ref, V_pd_ref); constant K_pu_off : real_vector := Coeff("K_pu_off", V_pu_off_common, V_pd_on_common, T_common, Rfx_pu_off, Rfx_pd_on, Vfx_pu_off, Vfx_pd_on, I_pu, V_pu, I_pd, V_pd, V_pu_ref, V_pd_ref); --=========================================================================== begin --=========================================================================== Catch: process (In_D, En_D) is --------------------------------------------------------------------------- begin Rcv_D <= In_D; -- Dummy receiver logic ------------------------------------------------------------------------- if (En_D = '1') and (In_D = '1') then -- Find logic state pu_on <= '1'; pd_off <= '1'; pd_on <= '0'; pu_off <= '0'; elsif (En_D = '1') and (In_D = '0') then pu_on <= '0'; pd_off <= '0'; pd_on <= '1'; pu_off <= '1'; elsif (En_D = '0') then pu_on <= '0'; pd_off <= '1'; pd_on <= '0'; pu_off <= '1'; else pu_on <= '1'; pd_off <= '0'; pd_on <= '1'; pu_off <= '0'; end if; --------------------------------------------------------------------------- end process Catch; --=========================================================================== pu_on_event_time: process (pu_on) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_on_event <= now; --------------------------------------------------------------------------- end process pu_on_event_time; --=========================================================================== pu_off_event_time: process (pu_off) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpu_off_event <= now; --------------------------------------------------------------------------- end process pu_off_event_time; --=========================================================================== pd_on_event_time: process (pd_on) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpd_on_event <= now; --------------------------------------------------------------------------- end process pd_on_event_time; --=========================================================================== pd_off_event_time: process (pd_off) is -- Update event time if changed --------------------------------------------------------------------------- begin Tpd_off_event <= now; --------------------------------------------------------------------------- end process pd_off_event_time; --=========================================================================== break on pu_on; break on pu_off; break on pd_on; break on pd_off; --=========================================================================== -- This section contains the simultaneous analog equations to find the -- appropriate scaling coefficients according to the state the buffer. --------------------------------------------------------------------------- if (Tpu_on_event = 0.0 and Tpu_off_event = 0.0 and Tpd_on_event = 0.0 and Tpd_off_event = 0.0) use -- Initialization if (pu_on = '1') use -- Start with the end of the k_pu_p == K_pu_on(K_pu_on'right); -- Vt curves for those which k_pd_n == K_pd_on(K_pd_on'right); -- are fully on initially elsif (pu_off = '1') use k_pu_p == K_pu_off(K_pu_off'right); k_pd_n == K_pd_off(K_pd_off'right); else k_pu_p == 0.0; k_pd_n == 0.0; end use; if (pd_on = '1') use k_pd_p == K_pd_on(K_pd_on'right); k_pu_n == K_pu_on(K_pu_on'right); elsif (pd_off = '1') use k_pd_p == K_pd_off(K_pd_off'right); k_pu_n == K_pu_off(K_pu_off'right); else k_pd_p == 0.0; k_pu_n == 0.0; end use; else -- Look up coefficients in normal operation if (pu_on = '1') use k_pu_p == Lookup("Vt", now - Tpu_on_event, K_pu_on, T_common); k_pd_n == Lookup("Vt", now - Tpd_on_event, K_pd_on, T_common); elsif (pu_off = '1') use k_pu_p == Lookup("Vt", now - Tpu_off_event, K_pu_off, T_common); k_pd_n == Lookup("Vt", now - Tpd_off_event, K_pd_off, T_common); else k_pu_p == K_pu_on(K_pu_on'left); k_pd_n == K_pd_on(K_pd_on'left); end use; if (pd_on = '1') use k_pd_p == Lookup("Vt", now - Tpd_on_event, K_pd_on, T_common); k_pu_n == Lookup("Vt", now - Tpu_on_event, K_pu_on, T_common); elsif (pd_off = '1') use k_pd_p == Lookup("Vt", now - Tpd_off_event, K_pd_off, T_common); k_pu_n == Lookup("Vt", now - Tpu_off_event, K_pu_off, T_common); else k_pd_p == K_pd_on(K_pd_on'left); k_pu_n == 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 and C_comp --------------------------------------------------------------------------- Ipc_p == -1.0 *Lookup("IV", Vpc_p, I_pc, V_pc) + k_C_comp_pc*C_comp*Vpc_p'dot; Ipu_p == -1.0*k_pu_p*Lookup("IV", Vpu_p, I_pu, V_pu) + k_C_comp_pu*C_comp*Vpu_p'dot; Idn_p == k_pd_p*Lookup("IV", Vdn_p, I_pd, V_pd) + Lookup("IV", Vdn_p, I_gc, V_gc) + k_C_comp_dn*C_comp*Vdn_p'dot; Ipc_n == -1.0 *Lookup("IV", Vpc_n, I_pc, V_pc) + k_C_comp_pc*C_comp*Vpc_n'dot; Ipu_n == -1.0*k_pu_n*Lookup("IV", Vpu_n, I_pu, V_pu) + k_C_comp_pu*C_comp*Vpu_n'dot; Idn_n == k_pd_n*Lookup("IV", Vdn_n, I_pd, V_pd) + Lookup("IV", Vdn_n, I_gc, V_gc) + k_C_comp_dn*C_comp*Vdn_n'dot; --------------------------------------------------------------------------- -- Differential IV surface and C_comp --------------------------------------------------------------------------- I_pn == k0 + k1*Vdn_p + k2*Vdn_n + k3*Vdn_p*Vdn_n + k4*(Vdn_p**2) + k5*(Vdn_n**2) + C_diff*V_pn'dot; --I_pn == V_pn/R_diff + C_diff*V_pn'dot; -- In case a linear resistor does the job --I_pn == 0.0; -- In case we don't want differential currents --=========================================================================== end architecture DIFF_IO_2EQ; --===========================================================================