--=========================================================================== -- 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. --=========================================================================== -- Features: -- -- 1) This model is a differential version of the VHDL-AMS base model -- (using the 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_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_pd : real_vector := ( -1.80000000E+0, 0.00000000E+0, 3.60000000E+0); I_pd : real_vector := ( -159.69000000E-6, -144.22200000E-6, 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, 1.20000000E-9, 1.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); ----------------------------------------------------------------------------- T_pd_on : real_vector := ( 0.00000000E+0, 1.20000000E-9, 1.80000000E-9, 2.00000000E-9); V_pd_on : real_vector := ( 1.60591168E+0, 1.60591168E+0, 1.22749223E+0, 1.22749223E+0); ----------------------------------------------------------------------------- T_pd_off : real_vector := ( 0.00000000E+0, 0.20000000E-9, 0.80000000E-9, 2.00000000E-9); V_pd_off : real_vector := ( 1.22749223E+0, 1.22749223E+0, 1.60591168E+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 PD_ref : electrical; terminal GC_ref : electrical); end entity IBIS_DIFF_IO; --=========================================================================== architecture Diff_IO_2eq of IBIS_DIFF_IO is --------------------------------------------------------------------------- -- Common mode components for IV curves --------------------------------------------------------------------------- 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 Vpd_p across Ipd_p through IO_p to PD_ref; quantity Vgc_p across Igc_p through IO_p to GC_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 Vpd_n across Ipd_n through IO_n to PD_ref; quantity Vgc_n across Igc_n 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 pu_on : std_logic := '0'; signal pu_off : std_logic := '0'; signal pd_on : std_logic := '0'; signal pd_off : std_logic := '0'; signal State_D : std_logic := 'U'; signal In_time : real := 0.0; signal En_time : real := 0.0; signal Event_time : 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)) := (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). --------------------------------------------------------------------------- -- 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 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'range); -- This is the better notation -- variable dVwfm_pu : real_vector(Vwfm_pu'range); -- but it doesn't work due to -- variable dVwfm_pd : real_vector(Vwfm_pd'range); -- a bug in SystemVision 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 (In_D'event) then In_time <= now; -- Save time of In_D events end if; if (En_D'event) then En_time <= now; -- Save time of En_D events end if; Event_time <= now; -- Save time of either event ------------------------------------------------------------------------- if (En_D = '1') and (In_D = '1') then -- Find logic state State_D <= '1'; elsif (En_D = '1') and (In_D = '0') then State_D <= '0'; elsif (En_D = '0') then State_D <= 'Z'; end if; --------------------------------------------------------------------------- end process Catch; --=========================================================================== -- Coeff_test: process (State_D) is -- --------------------------------------------------------------------------- -- -- This is a dummy process that is used for printing messages to the screen -- -- strictly for debugging purposes. -- --------------------------------------------------------------------------- -- begin -- -- if (State_D = 'U') then -- ---- for index in T_common'range loop -- for index in K_pu_on'range loop -- report " Time: " & real'image(T_common(index)) & -- " K_pu_on: " & real'image(K_pu_on(index)) & " K_pd_off: " & real'image(K_pd_off(index)) & -- " K_pd_on: " & real'image(K_pd_on(index)) & " K_pu_off: " & real'image(K_pu_off(index)); ---- report " Common length is: " & integer'image(Find_common_length(Delta_t, T_pu_on, T_pu_off, T_pd_on, T_pd_off)) & ---- report " Common length is: " & integer'image(T_common'length) & ---- " T_common: " & real'image(T_common(index)) & ---- " V_pu_on: " & real'image(V_pu_on_common(index)) & ---- " V_pu_off: " & real'image(V_pu_off_common(index)) & ---- " V_pd_on: " & real'image(V_pd_on_common(index)) & ---- " V_pd_off: " & real'image(V_pd_off_common(index)); -- end loop; -- -- end if; -- -- end process Coeff_test; --=========================================================================== Logic: process (State_D, In_time, En_time) is --------------------------------------------------------------------------- -- This process handles the logic events and sets the signals that control -- the analog equations. The logic includes all combinations of switching -- high-to-low or low-to-high with the enable on/off, going in and out of -- 3-state mode while the input is high/low, and input and enable -- switching together. --------------------------------------------------------------------------- begin --------------------------------------------------------------------------- if (domain = quiescent_domain) then -- Setting initial states if (State_D = 'Z') then -- 3-state pu_on <= '0'; pd_off <= '0'; pd_on <= '0'; pu_off <= '0'; elsif (State_D = '1') then -- Drive high pu_on <= '1'; pd_off <= '1'; pd_on <= '0'; pu_off <= '0'; elsif (State_D = '0') then -- Drive low pu_on <= '0'; pd_off <= '0'; pd_on <= '1'; pu_off <= '1'; end if; -- Normal operation elsif (State_D = '1') then -- En_D high, In_D high after if (In_time > En_time) then -- In_D changed (En_D steady) pu_on <= '1'; pd_off <= '1'; pd_on <= '0'; pu_off <= '0'; elsif (En_time > In_time) then -- En_D changed (In_D steady) pu_on <= '1'; pd_off <= '0'; pd_on <= '0'; pu_off <= '0'; elsif (En_time = In_time) then -- En_D and In_D both changed pu_on <= '1'; pd_off <= '0'; pd_on <= '0'; pu_off <= '0'; end if; elsif (State_D = '0') then -- En_D high, In_D low after if (In_time > En_time) then -- In_D changed (En_D steady) pu_on <= '0'; pd_off <= '0'; pd_on <= '1'; pu_off <= '1'; elsif (En_time > In_time) then -- En_D changed (In_D steady) pu_on <= '0'; pd_off <= '0'; pd_on <= '1'; pu_off <= '0'; elsif (En_time = In_time) then -- En_D and In_D both changed pu_on <= '0'; pd_off <= '0'; pd_on <= '1'; pu_off <= '0'; end if; elsif (State_D = 'Z') and (In_D = '1') then -- En_D low, In_D high after if (En_time > In_time) then -- En_D changed (In_D steady) pu_on <= '0'; pd_off <= '0'; pd_on <= '0'; pu_off <= '1'; elsif (En_time = In_time) then -- En_D and In_D both changed pu_on <= '0'; pd_off <= '1'; pd_on <= '0'; pu_off <= '0'; end if; elsif (State_D = 'Z') and (In_D = '0') then -- En_D low, In_D low after if (En_time > In_time) then -- En_D changed (In_D steady) pu_on <= '0'; pd_off <= '1'; pd_on <= '0'; pu_off <= '0'; elsif (En_time = In_time) then -- En_D and In_D both changed pu_on <= '0'; pd_off <= '0'; pd_on <= '0'; pu_off <= '1'; end if; end if; --------------------------------------------------------------------------- end process Logic; --=========================================================================== 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 (Event_time = 0.0) use -- Initialization if (State_D = '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_p == K_pd_off(K_pd_off'right); -- are fully on initially k_pd_n == K_pd_on(K_pd_on'right); k_pu_n == K_pu_off(K_pu_off'right); elsif (State_D = '0') use k_pd_p == K_pd_on(K_pd_on'right); k_pu_p == K_pu_off(K_pu_off'right); k_pu_n == K_pu_on(K_pu_on'right); k_pd_n == K_pd_off(K_pd_off'right); else k_pu_p == 0.0; k_pd_p == 0.0; k_pu_n == 0.0; k_pd_n == 0.0; end use; else -- Look up coefficients in normal operation if (pu_on = '1') use k_pu_p == Lookup("Vt", now - Event_time, K_pu_on, T_common); k_pd_n == Lookup("Vt", now - Event_time, K_pd_on, T_common); elsif (pu_off = '1') use k_pu_p == Lookup("Vt", now - Event_time, K_pu_off, T_common); k_pd_n == Lookup("Vt", now - Event_time, 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 - Event_time, K_pd_on, T_common); k_pu_n == Lookup("Vt", now - Event_time, K_pu_on, T_common); elsif (pd_off = '1') use k_pd_p == Lookup("Vt", now - Event_time, K_pd_off, T_common); k_pu_n == Lookup("Vt", now - Event_time, 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 --------------------------------------------------------------------------- Ipc_p == -1.0 * Lookup("IV", Vpc_p, I_pc, V_pc); Ipu_p == -1.0 * k_pu_p * Lookup("IV", Vpu_p, I_pu, V_pu); Ipd_p == k_pd_p * Lookup("IV", Vpd_p, I_pd, V_pd); Igc_p == Lookup("IV", Vgc_p, I_gc, V_gc); Ipc_n == -1.0 * Lookup("IV", Vpc_n, I_pc, V_pc); Ipu_n == -1.0 * k_pu_n * Lookup("IV", Vpu_n, I_pu, V_pu); Ipd_n == k_pd_n * Lookup("IV", Vpd_n, I_pd, V_pd); Igc_n == Lookup("IV", Vgc_n, 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*Vpd_p + k2*Vpd_n + k3*Vpd_p*Vpd_n + k4*(Vpd_p**2) + k5*(Vpd_n**2); -- I_pn == V_pn / R_diff; -- In case a linear resistor does the job Ic_diff == C_diff * Vc_diff'dot; --=========================================================================== end architecture Diff_IO_2eq; --===========================================================================