--=========================================================================== -- 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 supports only basic (incomplete) IBIS 2.1 features -- -- 2) This model uses 4 IV curves (I/O buffer model) -- -- 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 support for other buffer types (input, output, open_***, etc...) -- 2) Add support for the Ramp keyword -- 3) Add support for differencial buffers -- 4) Add support for the Submodel kewyword -- 5) Provisions for switching into unfinished edges -- 6) Receiver threshold modeling and logic (Vinh, Vinl, etc...) -- 7) File I/O to read IV, Vt, etc. data from external files -- 8) Add support for other, less important IBIS keywords, etc... --=========================================================================== library IEEE; use IEEE.math_real.all; use IEEE.std_logic_1164.all; library IEEE_proposed; use IEEE_proposed.electrical_systems.all; use IEEE_proposed.energy_systems.all; --=========================================================================== entity IBIS_IO is generic (C_comp : real := 5.0e-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; ------------------------------------------------------------------ -- [Pullup Reference] and [Pulldown Reference] values ------------------------------------------------------------------ V_pu_ref : real := 5.0; V_pd_ref : real := 0.0; ------------------------------------------------------------------ -- Vectors of the IV curve tables ------------------------------------------------------------------ I_pc : real_vector := ( 0.08, 0.00, 0.00, 0.00); V_pc : real_vector := (-5.00, -1.00, 5.00, 10.00); I_pu : real_vector := ( 0.10, 0.00, -0.10, -0.20); V_pu : real_vector := (-5.00, 0.00, 5.00, 10.00); I_pd : real_vector := (-0.10, 0.00, 0.10, 0.20); V_pd : real_vector := (-5.00, 0.00, 5.00, 10.00); I_gc : real_vector := (-0.08, 0.00, 0.00, 0.00); V_gc : real_vector := (-5.00, -1.00, 5.00, 10.00); ------------------------------------------------------------------ -- Vectors of the Vt curve tables ------------------------------------------------------------------ V_pu_on : real_vector := ( 0.00, 0.00, 2.50, 2.50); T_pu_on : real_vector := ( 0.00, 1.00e-9, 2.00e-9, 3.00e-9); V_pu_off : real_vector := ( 2.50, 2.50, 0.00, 0.00); T_pu_off : real_vector := ( 0.00, 0.50e-9, 0.80e-9, 3.00e-9); V_pd_on : real_vector := ( 5.00, 5.00, 2.50, 2.50); T_pd_on : real_vector := ( 0.00, 1.00e-9, 2.00e-9, 3.00e-9); V_pd_off : real_vector := ( 2.50, 2.50, 5.00, 5.00); T_pd_off : real_vector := ( 0.00, 0.50e-9, 0.80e-9, 3.00e-9); ------------------------------------------------------------------ -- V_fixture and R_fixture values ------------------------------------------------------------------ Vfx_pu_on : real := 0.0; Vfx_pu_off : real := 0.0; Vfx_pd_on : real := 5.0; Vfx_pd_off : real := 5.0; 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 := 200.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 : electrical; terminal PC_ref : electrical; terminal PU_ref : electrical; terminal PD_ref : electrical; terminal GC_ref : electrical); end entity IBIS_IO; --=========================================================================== architecture IO_buffer of IBIS_IO is quantity Vpc across Ipc through PC_ref to IO; quantity Vpu across Ipu through PU_ref to IO; quantity Vpd across Ipd through IO to PD_ref; quantity Vgc across Igc through IO to GC_ref; quantity Vc_pc across Ic_pc through PC_ref to IO; quantity Vc_pu across Ic_pu through PU_ref to IO; quantity Vc_pd across Ic_pd through IO to PD_ref; quantity Vc_gc across Ic_gc through IO to GC_ref; 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 : real := 0.0; quantity k_pd : 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 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, 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 possible bug 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; --=========================================================================== 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 == K_pu_on(K_pu_on'right); -- Vt curves for those which k_pd == K_pd_off(K_pd_off'right); -- are fully on initially elsif (State_D = '0') use k_pd == K_pd_on(K_pd_on'right); k_pu == K_pu_off(K_pu_off'right); else k_pu == 0.0; k_pd == 0.0; end use; else -- Look up coefficients in normal operation if (pu_on = '1') use k_pu == Lookup("Vt", now - Event_time, K_pu_on, T_common); elsif (pu_off = '1') use k_pu == Lookup("Vt", now - Event_time, K_pu_off, T_common); else k_pu == K_pu_on(K_pu_on'left); end use; if (pd_on = '1') use k_pd == Lookup("Vt", now - Event_time, K_pd_on, T_common); elsif (pd_off = '1') use k_pd == Lookup("Vt", now - Event_time, K_pd_off, T_common); else k_pd == K_pd_on(K_pd_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. --------------------------------------------------------------------------- Ipc == -1.0 * Lookup("IV", Vpc, I_pc, V_pc); Ipu == -1.0 * k_pu * Lookup("IV", Vpu, I_pu, V_pu); Ipd == k_pd * Lookup("IV", Vpd, I_pd, V_pd); Igc == Lookup("IV", Vgc, I_gc, V_gc); Ic_pc == k_C_comp_pc * C_comp * Vc_pc'dot; Ic_pu == k_C_comp_pu * C_comp * Vc_pu'dot; Ic_pd == k_C_comp_pd * C_comp * Vc_pd'dot; Ic_gc == k_C_comp_gc * C_comp * Vc_gc'dot; --=========================================================================== end architecture IO_buffer; --===========================================================================