//============================================================================= // Description: IBIS macro library implemented in Verilog-A(MS) // Created: September 2005 by Arpad Muranyi (Intel Corporation) //============================================================================= // List of building blocks contained in this library: // // IBIS_R (p, n); // IBIS_VCR (p, n, ps, ns); // IBIS_CCR (p, n, ps, ns); // // IBIS_C (p, n); // IBIS_VCC (p, n, ps, ns); // IBIS_CCC (p, n, ps, ns); // // IBIS_L (p, n); // IBIS_VCL (p, n, ps, ns); // IBIS_CCL (p, n, ps, ns); // IBIS_K (p1, n1, p2, n2); // // IBIS_V (p, n); // IBIS_VCVS (p, n, ps, ns); // IBIS_CCVS (p, n, ps, ns); // IBIS_VCVS_DELAY (p, n, ps, ns); // IBIS_CCVS_DELAY (p, n, ps, ns); // IBIS_VCVS_MIN (p, n, ps1, ns1, ps2, ns2); // IBIS_CCVS_MIN (p, n, ps1, ns1, ps2, ns2); // IBIS_VCVS_MAX (p, n, ps1, ns1, ps2, ns2); // IBIS_CCVS_MAX (p, n, ps1, ns1, ps2, ns2); // IBIS_VCVS_ABS (p, n, ps, ns); // IBIS_CCVS_ABS (p, n, ps, ns); // IBIS_VCVS_SUM (p, n, ps1, ns1, ps2, ns2); // IBIS_CCVS_SUM (p, n, ps1, ns1, ps2, ns2); // IBIS_VCVS_MULT (p, n, ps1, ns1, ps2, ns2); // IBIS_CCVS_MULT (p, n, ps1, ns1, ps2, ns2); // IBIS_VCVS_DIV (p, n, ps1, ns1, ps2, ns2); // IBIS_CCVS_DIV (p, n, ps1, ns1, ps2, ns2); // // IBIS_I (p, n); // IBIS_VCCS (p, n, ps, ns); // IBIS_CCCS (p, n, ps, ns); // IBIS_VCCS_DELAY (p, n, ps, ns); // IBIS_CCCS_DELAY (p, n, ps, ns); // IBIS_VCCS_MIN (p, n, ps1, ns1, ps2, ns2); // IBIS_CCCS_MIN (p, n, ps1, ns1, ps2, ns2); // IBIS_VCCS_MAX (p, n, ps1, ns1, ps2, ns2); // IBIS_CCCS_MAX (p, n, ps1, ns1, ps2, ns2); // IBIS_VCCS_ABS (p, n, ps, ns); // IBIS_CCCS_ABS (p, n, ps, ns); // IBIS_VCCS_SUM (p, n, ps1, ns1, ps2, ns2); // IBIS_CCCS_SUM (p, n, ps1, ns1, ps2, ns2); // IBIS_VCCS_MULT (p, n, ps1, ns1, ps2, ns2); // IBIS_CCCS_MULT (p, n, ps1, ns1, ps2, ns2); // IBIS_VCCS_DIV (p, n, ps1, ns1, ps2, ns2); // IBIS_CCCS_DIV (p, n, ps1, ns1, ps2, ns2); // // IBIS_T (n1, ref1, n2, ref2); // // IBIS_INPUT (PC_ref, GC_ref, Input, Rcv_D); // IBIS_OUTPUT (PU_ref, PD_ref, Output, In_D, PC_ref, GC_ref); // IBIS_IO (PU_ref, PD_ref, IO, In_D, En_D, Rcv_D, PC_ref, GC_ref); // IBIS_3STATE (PU_ref, PD_ref, IO, In_D, En_D, PC_ref, GC_ref); // IBIS_OPENSINK (PU_ref, PD_ref, IO, In_D, En_D, PC_ref, GC_ref); // IBIS_IO_OPENSINK (PU_ref, PD_ref, IO, In_D, En_D, Rcv_D, PC_ref, GC_ref); // IBIS_OPENSOURCE (PU_ref, PD_ref, IO, In_D, En_D, PC_ref, GC_ref); // IBIS_IO_OPENSOURCE (PU_ref, PD_ref, IO, In_D, En_D, Rcv_D, PC_ref, GC_ref); //----------------------------------------------------------------------------- // List of building blocks not implemented yet: // // // PWL sources: // // VCVS - voltage controlled voltage source // VCCS - voltage controlled current source // CCVS - current controlled voltage source // CCCS - current controlled current source // TCVS - time controlled voltage source // TCCS - time controlled current source // ECVS - event-time controlled voltage source // ECCS - event-time controlled current source // // // Remaining IBIS buffer types and keywords: // // Input_ECL, Output_ECL, I/O_ECL, 3-state_ECL, Terminator, // Series, and Series_switch. // // [R Series] - not necessary, it can be implemented by other elements // [L Series] - not necessary, it can be implemented by other elements // [Rl Series] - not necessary, it can be implemented by other elements // [C Series] - not necessary, it can be implemented by other elements // [Lc Series] - not necessary, it can be implemented by other elements // [Rc Series] - not necessary, it can be implemented by other elements // [Series Current] - not necessary, it can be implemented with VCCS_PWL // [Series MOSFET] - could be useful // [On], [Off] - TBD // // // IBIS_SPARAM - a building block using S-parameter data as input // //----------------------------------------------------------------------------- // Other ideas: // // More than 2 element mutual inductor(s)? // More than 2 input adder, multiplier? // Other math functions (power, root, exp, log, etc...)? // //----------------------------------------------------------------------------- // List of features to be implemented from Don Telian's list: // // Equation-based sources (voltage, current, numeric) // AM: This cannot be done due to language limitations. Even // though string parameters do exist, they cannot be // interpreted as expression (i.e. converted to "code"). // However, it would be easy to write equation based source // statements in the templates directly assuming some // familiarity with the language. This could prevent or // make the substitution of native SPICE elements impossible, // though. // // B element with c_comp on/off and table scaling (static/dynamic) // - Hspice can’t do c_comp or dynamic // AM: Both of these features can be added easily to the existing // *-AMS IBIS buffer implementations. Dynamic scaling would // require addition control ports, as discussed with the // controlled R, L, and C building blocks. We need to decide // how many and what type of control ports we want to add. // // Expressions in parameters // AM: Same answer as 1st entry above. // // Table-based PWL sources // AM: This can be done using the $table_model keyword. The // problem is that currently the table or the file name // reference to the table is hard coded, which prevents // mutiple instances of the same exact module name to be // used with different data tables. There is some hope // that in the LRM v2.3 this will be fixed. Until then // manual cutting and pasting will be required. // //*** The PWL tables can be passed into the module as numerical //*** arrays from the calling statement. This would eliminate //*** the need for cutting and pasting the module itself for //*** multiple instantiation with different data. // // Time-controlled sources // - Hspice can not do // AM: These can be implemented in *-AMS easily. We just need to // decide on what they should do. // // Use of previously computed value (prev(x)) in equation // - Hspice can not // AM: Need to check into this how it can be done in *-AMS. // // ML: Add block comments for IBIS_R through IBIS_K // //============================================================================= // // MODULE: IBIS_R (p, n) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // // PARAMETERS: // Rval Resistance value. // Scale Scaling factor for resistance value. // // DESCRIPTION: // A simple resistor. The resistance value is calculated: // R = Rval * Scale // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_R #(.Rval(100)) R1 (clk_n, clk_p); // SPICE: X1 clk_n clkp IBIS_R Rval=100 // //==================================================================== module IBIS_R (p, n); electrical p, n; branch (p, n) Out; parameter real Rval = 1.0; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * Rval * I(Out); end endmodule //============================================================================= // // MODULE: IBIS_VCR (p, n, ps, ns) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor for resistance value. // // DESCRIPTION: // A voltage-controlled resistor. The resistance value is // calculated: // R = V(ps,ns) * Scale // // The sense terminals ps and ns draw no current. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_VCR #(.Scale(50)) VCR1 (clkn, clk_p, vcrp, vcrn); // SPICE: X1 clkn clkp vcrp vcrn IBIS_VCR Scale=50 // //==================================================================== module IBIS_VCR (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * V(In) * I(Out); end endmodule //============================================================================= // // MODULE: IBIS_CCR (p, n, ps, ns) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor for resistance value. // // DESCRIPTION: // A current-controlled resistor. The resistance value is // calculated: // R = I(ps,ns) * Scale // // The sense terminals ps and ns behave as an ideal short circuit. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_CCR #(.Scale(0.020)) CCR1 (clkn, clk_p, ccrp, ccrn); // SPICE: X1 clkn clkp ccrp ccrn IBIS_CCR Scale=0.020 // //==================================================================== module IBIS_CCR (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In) <+ 0.0; V(Out) <+ Scale * I(In) * I(Out); end endmodule //============================================================================= // // MODULE: IBIS_C (p, n) // // TERMINALS: // p positive capacitor terminal. // n negative capacitor terminal. // // PARAMETERS: // Cval Capacitance value. // Scale Scaling factor for capacitance value. // // DESCRIPTION: // A simple capacitor. The capacitance value is calculated: // C = Cval * Scale // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_C #(.Cval(4.5),.Scale(1e-12))) C1 (clk_n, clk_p); // SPICE: X1 clk_n clkp IBIS_C Cval=4.5 Scale=1e-12 // //==================================================================== module IBIS_C (p, n); electrical p, n; branch (p, n) Out; parameter real Cval = 1.0; parameter real V0 = 0.0; parameter real Scale = 1.0; analog begin if (analysis("static")) V(Out) <+ V0; else I(Out) <+ Scale * Cval * ddt(V(Out)); end endmodule //============================================================================= // // MODULE: IBIS_VCC (p, n, ps, ns) // // TERMINALS: // p positive capacitor terminal. // n negative capacitor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor for capacitance value. // // DESCRIPTION: // A voltage-controlled capacitor. The capacitance value is // calculated: // C = V(ps,ns) * Scale // // The sense terminals ps and ns draw no current. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_VCC #(.Scale(1e-12)) VCC1 (clkn, clk_p, vccp, vccn); // SPICE: X1 clkn clkp vccp vccn IBIS_VCC Scale=1e-12 // //==================================================================== module IBIS_VCC (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real V0 = 0.0; parameter real Scale = 1.0; analog begin if (analysis("static")) V(Out) <+ V0; else I(Out) <+ V(Out) * ddt(Scale * V(In)) + Scale * V(In) * ddt(V(Out)); end endmodule //============================================================================= // // MODULE: IBIS_CCC (p, n, ps, ns) // // TERMINALS: // p positive capacitor terminal. // n negative capacitor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor for capacitance value. // // DESCRIPTION: // A current-controlled capacitor. The capacitance value is // calculated: // C = I(ps,ns) * Scale // // The sense terminals ps and ns behave as a short circuit. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_CCC #(.Scale(5e-12)) CCC1 (clkn, clk_p, cccp, cccn); // SPICE: X1 clkn clkp cccp cccn IBIS_CCC Scale=5e-12 // //==================================================================== module IBIS_CCC (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real V0 = 0.0; parameter real Scale = 1.0; analog begin V(In) <+ 0.0; if (analysis("static")) V(Out) <+ V0; else I(Out) <+ V(Out) * ddt(Scale * I(In)) + Scale * I(In) * ddt(V(Out)); end endmodule //============================================================================= // // MODULE: IBIS_L (p, n) // // TERMINALS: // p positive inductor terminal. // n negative inductor terminal. // // PARAMETERS: // Lval Inductance value. // Scale Scaling factor for inductance value. // // DESCRIPTION: // A simple inductor. The inductance value is calculated: // L = Lval * Scale // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_L #(.Lval(0.8),.Scale(1e-9)) L1 (clk_n, clk_p); // SPICE: X1 clk_n clkp IBIS_L Lval=0.8 Scale=1e-9 // //==================================================================== module IBIS_L (p, n); electrical p, n; branch (p, n) Out; parameter real Lval = 1.0; parameter real I0 = 0.0; parameter real Scale = 1.0; analog begin if (analysis("static")) I(Out) <+ I0; else V(Out) <+ Scale * Lval * ddt(I(Out)); end endmodule //============================================================================= // // MODULE: IBIS_VCL (p, n, ps, ns) // // TERMINALS: // p positive inductor terminal. // n negative inductor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor for inductance value. // // DESCRIPTION: // A voltage-controlled inductor. The inductance value is // calculated: // L = V(ps,ns) * Scale // // The sense terminals ps and ns draw no current. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_VCL #(.Scale(0.5e-9)) VCL1 (clkn, clk_p, vclp, vcln); // SPICE: X1 clkn clkp vclp vcln IBIS_VCL Scale=0.5e-9 // //==================================================================== module IBIS_VCL (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real I0 = 0.0; parameter real Scale = 1.0; analog begin if (analysis("static")) I(Out) <+ I0; else V(Out) <+ I(Out) * ddt(Scale * V(In)) + Scale * V(In) * ddt(I(Out)); end endmodule //============================================================================= // // MODULE: IBIS_CCL (p, n, ps, ns) // // TERMINALS: // p positive inductor terminal. // n negative inductor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor for inductance value. // // DESCRIPTION: // A current-controlled inductor. The inductance value is // calculated: // L = I(ps,ns) * Scale // // The sense terminals ps and ns behave as a short circuit. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_CCL #(.Scale(4e-9)) CCL1 (clkn, clk_p, cclp, ccln); // SPICE: X1 clkn clkp cclp ccln IBIS_CCL Scale=4e-9 // //==================================================================== module IBIS_CCL (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real I0 = 0.0; parameter real Scale = 1.0; analog begin V(In) <+ 0.0; if (analysis("static")) I(Out) <+ I0; else V(Out) <+ I(Out) * ddt(Scale * I(In)) + Scale * I(In) * ddt(I(Out)); end endmodule //============================================================================= // // MODULE: IBIS_K (p1, n1, p2, n2) // // TERMINALS: // p1 positive inductor 1 terminal. // n1 negative inductor 1 terminal. // p2 positive inductor 2 terminal. // n2 negative inductor 2 terminal. // // PARAMETERS: // Lval_1 Inductance value for inductor 1. // Lval_2 Inductance value for inductor 2. // Kval Mutual coupling value. // Scale Scaling factor for inductance value. // // DESCRIPTION: // A mutually-coupled inductor pair. The inductance values are // calculated: // L_1 = Lval_1 * Scale // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_K #(.Lval_1(0.8),.Lval_2(0.5),.Kval(0.15),.Scale(1e-9)) \ // K1 (pad_n, pad_p, pin_n, pin_p); // SPICE: X1 pad_n pad_p pin_n pin_p IBIS_K \ // + Lval_1=0.8 Lval_2=0.5 Kval=0.15 Scale=1e-9 // //==================================================================== module IBIS_K (p1, n1, p2, n2); electrical p1, n1, p2, n2; branch (p1, n1) Out1; branch (p2, n2) Out2; parameter real Lval_1 = 1.0; parameter real Lval_2 = 1.0; parameter real Kval = 0.0; parameter real I0_1 = 0.0; parameter real I0_2 = 0.0; parameter real Scale = 1.0; // This should really be a "localparam" to prevent it from being // changed from the outside. parameter real M = Kval * sqrt(Lval_1 * Lval_2); analog begin if (analysis("static")) begin I(Out1) <+ I0_1; I(Out2) <+ I0_2; end else begin V(Out1) <+ Scale * Lval_1 * ddt(I(Out1)) + M * ddt(I(Out2)); V(Out2) <+ Scale * Lval_2 * ddt(I(Out2)) + M * ddt(I(Out1)); end end endmodule //============================================================================= // // MODULE: IBIS_V (p, n) // // TERMINALS: // p positive voltage source terminal. // n negative voltage source terminal. // // PARAMETERS: // Vdc DC voltage value. // Scale Scaling factor for inductance value. // // DESCRIPTION: // A DC voltage source. Output voltage is calculated: // V(p,n) = Vdc * Scale // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_V #(.Vdc(3.3)) V1 (vddq, vss); // SPICE: X1 vddq vss IBIS_V Vdc=3.3 // //==================================================================== module IBIS_V (p, n); electrical p, n; branch (p, n) Out; parameter real Vdc = 1.0; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * Vdc; end endmodule //============================================================================= // // MODULE: IBIS_VCVS (p, n, ps, ns) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor to calculate output voltage. // // DESCRIPTION: // A voltage-controlled voltage source. The output voltage value // is calculated: // V(p,n) = V(ps,ns) * Scale // // The sense terminals draw no current at all. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_VCVS #(.Scale(50)) VCVS1 (clkn, clk_p, vcrp, vcrn); // SPICE: X1 clkn clkp vcrp vcrn IBIS_VCVS Scale=50 // //==================================================================== module IBIS_VCVS (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * V(In); end endmodule //============================================================================= // // MODULE: IBIS_CCVS (p, n, ps, ns) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor to convert current to voltage. // // DESCRIPTION: // A current-controlled voltage source. The output voltage value // is calculated: // V(p,n) = I(ps,ns) * Scale // // The sense terminals ps and ns behave as an ideal short circuit. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_CCVS #(.Scale(100)) CCVS1 (buf2in, vss, pad, padi); // SPICE: X1 buf2in vss pad padi IBIS_CCVS Scale=100 // //==================================================================== module IBIS_CCVS (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In) <+ 0.0; V(Out) <+ Scale * I(In); end endmodule //============================================================================= // // MODULE: IBIS_VCVS_DELAY (p, n, ps, ns) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor to convert current to voltage. // // DESCRIPTION: // A voltage-controlled voltage source with delay. All changes // at the sense terminals affect the output later, using the // specified delay in seconds. // The voltage value is calculated: // V(p,n) = V(ps,ns) * Scale // // The sense terminals draw no current at all. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_VCVS_DELAY #(.TD(200e-12)) \ // VCVS1 (buf2in, vss, pad, padi); // SPICE: X1 buf2in vss pad padi IBIS_VCVS_DELAY TD=200p // //==================================================================== module IBIS_VCVS_DELAY (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real TD = 0.0; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * absdelay(V(In), TD); end endmodule //============================================================================= // // MODULE: IBIS_CCVS_DELAY (p, n, ps, ns) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // ps positive sense terminal. // ns negative sense terminal. // // PARAMETERS: // Scale Scaling factor to convert current to voltage. // // DESCRIPTION: // A current-controlled voltage source with delay. All changes // at the sense terminals affect the output later, using the // specified delay in seconds. // The voltage value is calculated: // V(p,n) = I(ps,ns) * Scale // // The sense terminals ps and ns behave as an ideal short circuit. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_CCVS_DELAY #(.Scale(100),.TD(200e-12)) \ // CCVS1 (buf2in, vss, pad, padi); // SPICE: X1 buf2in vss pad padi IBIS_CCVS_DELAY Scale=100 TD=200p // //==================================================================== module IBIS_CCVS_DELAY (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real TD = 0.0; parameter real Scale = 1.0; analog begin V(In) <+ 0.0; V(Out) <+ Scale * absdelay(I(In), TD); end endmodule //============================================================================= // // MODULE: IBIS_VCVS_MIN (p, n, ps1, ns1, ps2, ns2) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // ps1 positive sense terminal for control voltage 1. // ns1 negative sense terminal for control voltage 1. // ps2 positive sense terminal for control voltage 2. // ns2 negative sense terminal for control voltage 2. // // PARAMETERS: // Scale Scaling factor to calculate output voltage. // // DESCRIPTION: // A voltage-controlled voltage source for taking the lesser // of two input voltages. // The output voltage value is calculated: // V(p,n) = min( V(ps1,ns1) V(ps2,ns2) ) * Scale // // The sense terminals draw no current at all. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_VCVS_MIN MIN1 (bufctl, vss, ctlmain, vss, boost, vss); // SPICE: X1 bufctl vss ctlmain vss boost vss IBIS_VCVS_MIN // //==================================================================== module IBIS_VCVS_MIN (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * min(V(In1), V(In2)); end endmodule //============================================================================= // // MODULE: IBIS_CCVS_MIN (p, n, ps1, ns1, ps2, ns2) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // ps1 positive sense terminal for control voltage 1. // ns1 negative sense terminal for control voltage 1. // ps2 positive sense terminal for control voltage 2. // ns2 negative sense terminal for control voltage 2. // // PARAMETERS: // Scale Scaling factor to calculate output voltage. // // DESCRIPTION: // A voltage-controlled voltage source for taking the lesser // of two input voltages. // The output voltage value is calculated: // V(p,n) = min( V(ps1,ns1) V(ps2,ns2) ) * Scale // // The sense terminals draw no current at all. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_CCVS_MIN MIN1 (bufctl, vss, ctlmain, vss, boost, vss); // SPICE: X1 bufctl vss ctlmain ctlmaini boost boosti IBIS_CCVS_MIN // //==================================================================== module IBIS_CCVS_MIN (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; V(Out) <+ Scale * min(I(In1), I(In2)); end endmodule //============================================================================= // // MODULE: IBIS_VCVS_MAX (p, n, ps1, ns1, ps2, ns2) // // TERMINALS: // p positive resistor terminal. // n negative resistor terminal. // ps1 positive sense terminal for control voltage 1. // ns1 negative sense terminal for control voltage 1. // ps2 positive sense terminal for control voltage 2. // ns2 negative sense terminal for control voltage 2. // // PARAMETERS: // Scale Scaling factor to calculate output voltage. // // DESCRIPTION: // A voltage-controlled voltage source for taking the lesser // of two input voltages. // The output voltage value is calculated: // V(p,n) = min( V(ps1,ns1) V(ps2,ns2) ) * Scale // // The sense terminals draw no current at all. // // INSTANCE CALL EXAMPLES: // VAMS: IBIS_VCVS_MAX MAX1 (bufctl, vss, ctlmain, vss, boost, vss); // SPICE: X1 bufctl vss ctlmain vss boost vss IBIS_VCVS_MAX // //==================================================================== module IBIS_VCVS_MAX (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * max(V(In1), V(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_CCVS_MAX (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; V(Out) <+ Scale * max(I(In1), I(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_VCVS_ABS (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * abs(V(In)); end endmodule //============================================================================= //============================================================================= module IBIS_CCVS_ABS (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In) <+ 0.0; V(Out) <+ Scale * abs(I(In)); end endmodule //============================================================================= //============================================================================= module IBIS_VCVS_SUM (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * (V(In1) + V(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_CCVS_SUM (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; V(Out) <+ Scale * (I(In1) + I(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_VCVS_MULT (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(Out) <+ Scale * V(In1) * V(In2); end endmodule //============================================================================= //============================================================================= module IBIS_CCVS_MULT (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; V(Out) <+ Scale * I(In1) * I(In2); end endmodule //============================================================================= //============================================================================= module IBIS_VCVS_DIV (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin if (V(In2) != 0.0) begin V(Out) <+ Scale * V(In1) / V(In2); end else begin V(Out) <+ 1.0e+15; // instead of inf; end end endmodule //============================================================================= //============================================================================= module IBIS_CCVS_DIV (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; if (I(In2) != 0.0) begin V(Out) <+ Scale * I(In1) / I(In2); end else begin V(Out) <+ 1.0e+15; // instead of inf; end end endmodule //============================================================================= //============================================================================= module IBIS_I (p, n); electrical p, n; branch (p, n) Out; parameter real Idc = 1.0; parameter real Scale = 1.0; analog begin I(Out) <+ Scale * Idc; end endmodule //============================================================================= //============================================================================= module IBIS_VCCS (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin I(Out) <+ Scale * V(In); end endmodule //============================================================================= //============================================================================= module IBIS_CCCS (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In) <+ 0.0; I(Out) <+ Scale * I(In); end endmodule //============================================================================= //============================================================================= module IBIS_VCCS_DELAY (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real TD = 0.0; parameter real Scale = 1.0; analog begin I(Out) <+ Scale * absdelay(V(In), TD); end endmodule //============================================================================= //============================================================================= module IBIS_CCCS_DELAY (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real TD = 0.0; parameter real Scale = 1.0; analog begin V(In) <+ 0.0; I(Out) <+ Scale * absdelay(I(In), TD); end endmodule //============================================================================= //============================================================================= module IBIS_VCCS_MIN (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin I(Out) <+ Scale * min(V(In1), V(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_CCCS_MIN (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; I(Out) <+ Scale * min(I(In1), I(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_VCCS_MAX (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin I(Out) <+ Scale * max(V(In1), V(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_CCCS_MAX (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; I(Out) <+ Scale * max(I(In1), I(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_VCCS_ABS (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin I(Out) <+ Scale * abs(V(In)); end endmodule //============================================================================= //============================================================================= module IBIS_CCCS_ABS (p, n, ps, ns); electrical p, n, ps, ns; branch (ps, ns) In; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In) <+ 0.0; I(Out) <+ Scale * abs(I(In)); end endmodule //============================================================================= //============================================================================= module IBIS_VCCS_SUM (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin I(Out) <+ Scale * (V(In1) + V(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_CCCS_SUM (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; I(Out) <+ Scale * (I(In1) + I(In2)); end endmodule //============================================================================= //============================================================================= module IBIS_VCCS_MULT (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin I(Out) <+ Scale * V(In1) * V(In2); end endmodule //============================================================================= //============================================================================= module IBIS_CCCS_MULT (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; I(Out) <+ Scale * I(In1) * I(In2); end endmodule //============================================================================= //============================================================================= module IBIS_VCCS_DIV (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin if (V(In2) != 0.0) begin I(Out) <+ Scale * V(In1) / V(In2); end else begin I(Out) <+ 1.0e+15; // instead of inf; end end endmodule //============================================================================= //============================================================================= module IBIS_CCCS_DIV (p, n, ps1, ns1, ps2, ns2); electrical p, n, ps1, ns1, ps2, ns2; branch (ps1, ns1) In1; branch (ps2, ns2) In2; branch (p, n) Out; parameter real Scale = 1.0; analog begin V(In1) <+ 0.0; V(In2) <+ 0.0; if (I(In2) != 0.0) begin I(Out) <+ Scale * I(In1) / I(In2); end else begin I(Out) <+ 1.0e+15; // instead of inf; end end endmodule //============================================================================= //============================================================================= module IBIS_T (n1, ref1, n2, ref2); electrical n1, ref1, n2, ref2; branch (n1, ref1) End1; branch (n2, ref2) End2; parameter real Z0 = 50.0; parameter real TD = 1.0e-9; analog begin V(End1) <+ absdelay(V(End2) + Z0*I(End2), TD) + Z0*I(End1); V(End2) <+ absdelay(V(End1) + Z0*I(End1), TD) + Z0*I(End2); end endmodule //============================================================================= //============================================================================= module IBIS_INPUT (PC_ref, GC_ref, Input, Rcv_D); output Rcv_D; electrical Rcv_D; inout Input, PC_ref, GC_ref; electrical Input, PC_ref, GC_ref; branch (PC_ref, Input) pc; // branches driven in model branch (Input, GC_ref) gc; parameter real //--------------------------------------------------------------------------- // IBIS parameters //--------------------------------------------------------------------------- C_comp = 5.0p, // Default C_comp value k_C_comp_pc = 0.50, // C_comp splitting coefficients k_C_comp_gc = 0.50, Vinh = 2.0, // Default Vinh value Vinl = 0.8; // Default Vinl value //--------------------------------------------------------------------------- // Vectors of the IV curve tables //--------------------------------------------------------------------------- parameter integer IVpc_length = 4, IVgc_length = 4; parameter real I_pc[1:IVpc_length] = { 0.08, 0.00, 0.00, 0.00}, V_pc[1:IVpc_length] = {-5.00, -1.00, 5.00, 10.00}, I_gc[1:IVgc_length] = {-0.08, 0.00, 0.00, 0.00}, V_gc[1:IVgc_length] = {-5.00, -1.00, 5.00, 10.00}; //=========================================================================== analog begin //========================================================================= // This section contains the analog expressions which calculate // the clamping currents from the IV curves and C_comp capacitors. //------------------------------------------------------------------------- I(pc) <+ -$table_model(V(pc), V_pc, I_pc, "LL") + k_C_comp_pc*C_comp*ddt(V(pc)); I(gc) <+ $table_model(V(gc), V_gc, I_gc, "LL") + k_C_comp_gc*C_comp*ddt(V(gc)); //------------------------------------------------------------------------- // A simple receiver logic //------------------------------------------------------------------------- if (V(gc) > Vinh) V(Rcv_D) <+ 1.0; else if (V(gc) < Vinl) V(Rcv_D) <+ 0.0; else V(Rcv_D) <+ 0.5; //------------------------------------------------------------------------- end endmodule // IBIS_Input //============================================================================= //============================================================================= module IBIS_OUTPUT (PU_ref, PD_ref, Output, In_D, PC_ref, GC_ref); input In_D; electrical In_D; inout Output, PC_ref, PU_ref, PD_ref, GC_ref; electrical Output, PC_ref, PU_ref, PD_ref, GC_ref; branch (PC_ref, Output) pc; // branches driven in model branch (PU_ref, Output) pu; branch (Output, PD_ref) pd; branch (Output, GC_ref) gc; parameter real //--------------------------------------------------------------------------- // IBIS parameters //--------------------------------------------------------------------------- C_comp = 5.0p, // Default C_comp value k_C_comp_pc = 0.25, // C_comp splitting coefficients k_C_comp_pu = 0.25, k_C_comp_pd = 0.25, k_C_comp_gc = 0.25, V_pc_ref = 5.0, // Power clamp reference voltage V_pu_ref = 5.0, // Pullup reference voltage V_pd_ref = 0.0, // Pulldown reference voltage V_gc_ref = 0.0; // Ground clamp reference voltage //--------------------------------------------------------------------------- // Vectors of the IV curve tables //--------------------------------------------------------------------------- parameter integer IVpc_length = 4, IVpu_length = 4, IVpd_length = 4, IVgc_length = 4; parameter real I_pc[1:IVpc_length] = { 0.08, 0.00, 0.00, 0.00}, V_pc[1:IVpc_length] = {-5.00, -1.00, 5.00, 10.00}, I_pu[1:IVpu_length] = { 0.10, 0.00, -0.10, -0.20}, V_pu[1:IVpu_length] = {-5.00, 0.00, 5.00, 10.00}, I_pd[1:IVpd_length] = {-0.10, 0.00, 0.10, 0.20}, V_pd[1:IVpd_length] = {-5.00, 0.00, 5.00, 10.00}, I_gc[1:IVgc_length] = {-0.08, 0.00, 0.00, 0.00}, V_gc[1:IVgc_length] = {-5.00, -1.00, 5.00, 10.00}; //--------------------------------------------------------------------------- // Vectors of the Vt curve tables //--------------------------------------------------------------------------- parameter integer VTr1_length = 4, VTr2_length = 4, VTf1_length = 4, VTf2_length = 4; parameter real Vr1[1:VTr1_length] = {0.00, 0.00, 2.50, 2.50}, Tr1[1:VTr1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}, Vr2[1:VTr2_length] = {2.50, 2.50, 5.00, 5.00}, Tr2[1:VTr2_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}, Vf1[1:VTf1_length] = {5.00, 5.00, 2.50, 2.50}, Tf1[1:VTf1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}, Vf2[1:VTf2_length] = {2.50, 2.50, 0.00, 0.00}, Tf2[1:VTf2_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}; //--------------------------------------------------------------------------- parameter real Vfx_r1 = 0.0, // V_fixture values Vfx_r2 = 5.0, Vfx_f1 = 5.0, Vfx_f2 = 0.0, Rfx_r1 = 50.0 from (0:inf), // R_fixture values Rfx_r2 = 50.0 from (0:inf), Rfx_f1 = 50.0 from (0:inf), Rfx_f2 = 50.0 from (0:inf), //=========================================================================== // Non-IBIS parameters //--------------------------------------------------------------------------- Max_dt = 1.0e-12 from (0:inf), // Maximum dt between time points Vth = 0.5; // Logic input threshold voltage //--------------------------------------------------------------------------- // Internal variables //--------------------------------------------------------------------------- // Calculate maximum array length for common time and K_*** tables // and declare the arrays //--------------------------------------------------------------------------- // parameter real Max_t = max(max(max(Tr1[VTr1_length], Tr2[VTr2_length]), Tf1[VTf1_length]), Tf2[VTf2_length]); // parameter real Min_t = min(min(min( Tr1[1], Tr2[1]), Tf1[1]), Tf2[1]); // parameter integer Max_length = ceil((Max_t-Min_t)/Max_dt) + VTr1_length + VTr2_length + VTf1_length + VTf2_length; parameter integer Max_length = 3016; // Delete this when the above 3 lines work real T_common[1:Max_length]; // Common time axis array real Kr1[1:Max_length]; // Scaling coefficient arrays real Kr2[1:Max_length]; real Kf1[1:Max_length]; real Kf2[1:Max_length]; integer pu_on; // Logic state variables integer pu_off; integer pd_on; integer pd_off; real Tpu_on_event; // Variables to store event time real Tpu_off_event; real Tpd_on_event; real Tpd_off_event; real Kpu; // Output current scaling coefficients real Kpd; //--------------------------------------------------------------------------- // variables used in Common_time / Common_wfm / Kcoef "function" //--------------------------------------------------------------------------- integer i; integer Common_length; integer index_r1; integer index_r2; integer index_f1; integer index_f2; integer new_index_r1; integer new_index_r2; integer new_index_f1; integer new_index_f2; real old_t; real new_t; real last_t; real additional_pts; real new_dt; real Vr1_common[1:3]; // Need 3 elements in order to do derivatives real Vr2_common[1:3]; real Vf1_common[1:3]; real Vf2_common[1:3]; real dVwfm_r1; real dVwfm_r2; real dVwfm_f1; real dVwfm_f2; real Iout1; real Iout2; real Ipd1; real Ipd2; real Ipu1; real Ipu2; real Igc1; real Igc2; real Ipc1; real Ipc2; real den; //=========================================================================== analog begin @(initial_step) begin //======================================================================= // This "function" makes a common time axis for all Vt curves and // calculates the corresponding voltage points with linear interpolation // and/or linear extrapolation if necessary. After that it converts the // Vt curves to K coefficients which will be used in the analog equations // to scale the IV curves. The K coefficients are stored in arrays. //----------------------------------------------------------------------- // Initialize variables //----------------------------------------------------------------------- Common_length = 1; index_r1 = 1; index_r2 = 1; index_f1 = 1; index_f2 = 1; new_index_r1 = VTr1_length; new_index_r2 = VTr2_length; new_index_f1 = VTf1_length; new_index_f2 = VTf2_length; //----------------------------------------------------------------------- // Put the earliest time value of all given time vectors into "old_t" //----------------------------------------------------------------------- old_t = min(Tr1[1], Tr2[1]); old_t = min(old_t, Tf1[1]); old_t = min(old_t, Tf2[1]); //----------------------------------------------------------------------- // Put the latest time value of all given time vectors into "new_t" //----------------------------------------------------------------------- last_t = max(Tr1[VTr1_length], Tr2[VTr2_length]); last_t = max(new_t, Tf1[VTf1_length]); last_t = max(new_t, Tf2[VTf2_length]); new_t = last_t; //----------------------------------------------------------------------- // Loop until latest time value is reached in each given time vector //----------------------------------------------------------------------- while (old_t < new_t) begin //--------------------------------------------------------------------- // Save the time value from old_t in T_common // and increment Common_length counter //--------------------------------------------------------------------- T_common[Common_length] = old_t; Common_length = Common_length + 1; //--------------------------------------------------------------------- // Find which given time vector(s) have the lowest time value and // advance their temporary indexes //--------------------------------------------------------------------- if (Tr1[index_r1] <= old_t) new_index_r1 = index_r1 + 1; if (Tr2[index_r2] <= old_t) new_index_r2 = index_r2 + 1; if (Tf1[index_f1] <= old_t) new_index_f1 = index_f1 + 1; if (Tf2[index_f2] <= old_t) new_index_f2 = index_f2 + 1; //--------------------------------------------------------------------- // Find the lowest value at the new indexes in the given vector(s) // and update indexes for next iteration //--------------------------------------------------------------------- if (new_index_r1 <= VTr1_length) begin if (Tr1[new_index_r1] < new_t) new_t = Tr1[new_index_r1]; index_r1 = new_index_r1; end if (new_index_r2 <= VTr2_length) begin if (Tr2[new_index_r2] < new_t) new_t = Tr2[new_index_r2]; index_r2 = new_index_r2; end if (new_index_f1 <= VTf1_length) begin if (Tf1[new_index_f1] < new_t) new_t = Tf1[new_index_f1]; index_f1 = new_index_f1; end if (new_index_f2 <= VTf2_length) begin if (Tf2[new_index_f2] < new_t) new_t = Tf2[new_index_f2]; index_f2 = new_index_f2; end //--------------------------------------------------------------------- // Add points if dt is larger than Max_dt //--------------------------------------------------------------------- if ((new_t-old_t) > Max_dt) begin additional_pts = ceil((new_t-old_t)/Max_dt); new_dt = (new_t-old_t) / additional_pts; for (i = 1; i < additional_pts; i = i + 1) begin //$strobe("\ndif = %e\tAdd = %d\tCL = %d\t T = %e\tnew_dt = ", (new_t-old_t), additional_pts, Common_length, T_common[Common_length-1]+new_dt, new_dt); T_common[Common_length] = T_common[Common_length-1] + new_dt; Common_length = Common_length + 1; end end //--------------------------------------------------------------------- // Update variables for next iteration //--------------------------------------------------------------------- old_t = new_t; new_t = last_t; //--------------------------------------------------------------------- end // while loop T_common[Common_length] = last_t; //======================================================================= //======================================================================= // Calculate the scaling coefficients for each time point along T_common //----------------------------------------------------------------------- // Store the first voltage point in the common waveform variables //----------------------------------------------------------------------- Vr1_common[2] = $table_model(T_common[1], Tr1, Vr1, "LL"); Vr2_common[2] = $table_model(T_common[1], Tr2, Vr2, "LL"); Vf1_common[2] = $table_model(T_common[1], Tf1, Vf1, "LL"); Vf2_common[2] = $table_model(T_common[1], Tf2, Vf2, "LL"); for (i = 1; i <= Common_length; i = i + 1) begin //----------------------------------------------------------------------- // Store the next point (for the derivative calculations) //----------------------------------------------------------------------- if (i < Common_length) begin Vr1_common[3] = $table_model(T_common[i+1], Tr1, Vr1, "LL"); Vr2_common[3] = $table_model(T_common[i+1], Tr2, Vr2, "LL"); Vf1_common[3] = $table_model(T_common[i+1], Tf1, Vf1, "LL"); Vf2_common[3] = $table_model(T_common[i+1], Tf2, Vf2, "LL"); end //$strobe("\nTcom = %e\tR1 = %e\tR2 = %e\tF1 = %e\tF2 = %e", T_common[i], Vr1_common[2], Vr2_common[2], Vf1_common[2], Vf2_common[2]); //--------------------------------------------------------------------- // Calculate the derivative of each waveform for C_comp compensation //--------------------------------------------------------------------- if ((i <= 1) || (i >= Common_length)) begin dVwfm_r1 = 0.0; // Force the end point derivatives to zero dVwfm_r2 = 0.0; dVwfm_f1 = 0.0; dVwfm_f2 = 0.0; end else begin dVwfm_r1 = ((Vr1_common[2] - Vr1_common[1]) / (T_common[i] - T_common[i-1]) + (Vr1_common[3] - Vr1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_r2 = ((Vr2_common[2] - Vr2_common[1]) / (T_common[i] - T_common[i-1]) + (Vr2_common[3] - Vr2_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f1 = ((Vf1_common[2] - Vf1_common[1]) / (T_common[i] - T_common[i-1]) + (Vf1_common[3] - Vf1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f2 = ((Vf2_common[2] - Vf2_common[1]) / (T_common[i] - T_common[i-1]) + (Vf2_common[3] - Vf2_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; end //$strobe("dR1 = %e\tdR2 = %e\tdF1 = %e\tdF2 = %e", dVwfm_r1, dVwfm_r2, dVwfm_f1, dVwfm_f2); //--------------------------------------------------------------------- // Calculate intermediate variables and the Kr1 Kr2 coefficients //--------------------------------------------------------------------- Iout1 = ((Vr1_common[2] - Vfx_r1) / Rfx_r1) + C_comp * dVwfm_r1; Iout2 = ((Vr2_common[2] - Vfx_r2) / Rfx_r2) + C_comp * dVwfm_r2; Ipc1 = -1.0 * $table_model(V_pc_ref - Vr1_common[2], V_pc, I_pc, "LL"); Ipc2 = -1.0 * $table_model(V_pc_ref - Vr2_common[2], V_pc, I_pc, "LL"); Ipu1 = -1.0 * $table_model(V_pu_ref - Vr1_common[2], V_pu, I_pu, "LL"); Ipu2 = -1.0 * $table_model(V_pu_ref - Vr2_common[2], V_pu, I_pu, "LL"); Ipd1 = $table_model(Vr1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Ipd2 = $table_model(Vr2_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vr1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); Igc2 = $table_model(Vr2_common[2] - V_gc_ref, V_gc, I_gc, "LL"); den = (Ipu1 * Ipd2) - (Ipd1 * Ipu2); // Since these are rising waveforms // Kr1 == Kpu_on and Kr2 == Kpd_off Kr1[i] = (Ipd2*(Iout1+Igc1-Ipc1) + Ipd1*(Ipc2-Igc2-Iout2)) / den; Kr2[i] = (Ipu2*(Iout1+Igc1-Ipc1) + Ipu1*(Ipc2-Igc2-Iout2)) / den; //--------------------------------------------------------------------- // Calculate intermediate variables and the Kf1 Kf2 coefficients //--------------------------------------------------------------------- Iout1 = ((Vf1_common[2] - Vfx_f1) / Rfx_f1) + C_comp * dVwfm_f1; Iout2 = ((Vf2_common[2] - Vfx_f2) / Rfx_f2) + C_comp * dVwfm_f2; Ipc1 = -1.0 * $table_model(V_pc_ref - Vf1_common[2], V_pc, I_pc, "LL"); Ipc2 = -1.0 * $table_model(V_pc_ref - Vf2_common[2], V_pc, I_pc, "LL"); Ipu1 = -1.0 * $table_model(V_pu_ref - Vf1_common[2], V_pu, I_pu, "LL"); Ipu2 = -1.0 * $table_model(V_pu_ref - Vf2_common[2], V_pu, I_pu, "LL"); Ipd1 = $table_model(Vf1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Ipd2 = $table_model(Vf2_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vf1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); Igc2 = $table_model(Vf2_common[2] - V_gc_ref, V_gc, I_gc, "LL"); den = (Ipu1 * Ipd2) - (Ipd1 * Ipu2); // Since these are falling waveforms // Kf1 == Kpd_on and Kf2 == Kpu_off Kf1[i] = (Ipu2*(Iout1+Igc1-Ipc1) + Ipu1*(Ipc2-Igc2-Iout2)) / den; Kf2[i] = (Ipd2*(Iout1+Igc1-Ipc1) + Ipd1*(Ipc2-Igc2-Iout2)) / den; //$strobe("\nTcom = %e\tKr1 = %e\tKr2 = %e\tKf1 = %e\tKf2 = %e", T_common[i], Kr1[i], Kr2[i], Kf1[i], Kf2[i]); //--------------------------------------------------------------------- // Shift points by one index for next iteration (for C_comp compensation) //--------------------------------------------------------------------- Vr1_common[1] = Vr1_common[2]; Vr2_common[1] = Vr2_common[2]; Vf1_common[1] = Vf1_common[2]; Vf2_common[1] = Vf2_common[2]; Vr1_common[2] = Vr1_common[3]; Vr2_common[2] = Vr2_common[3]; Vf1_common[2] = Vf1_common[3]; Vf2_common[2] = Vf2_common[3]; end // for loop //----------------------------------------------------------------------- // Fill the unused portion of the arrays with reasonable values // to prevent any misbehaving later with $table_model //======================================================================= for (i = Common_length + 1; i <= Max_length; i = i + 1) begin T_common[i] = T_common[i-1] + Max_dt; Kr1[i] = Kr1[Common_length]; Kr2[i] = Kr2[Common_length]; Kf1[i] = Kf1[Common_length]; Kf2[i] = Kf2[Common_length]; end // for loop //----------------------------------------------------------------------- // End of Common_time / Common_wfm / Kcoef "function" //======================================================================= //======================================================================= // Initialize logic state variables //----------------------------------------------------------------------- if (V(In_D) > Vth) begin // Find initial logic state pu_on = 1; pd_off = 1; pd_on = 0; pu_off = 0; end else if (V(In_D) < Vth) begin pu_on = 0; pd_off = 0; pd_on = 1; pu_off = 1; end else begin pu_on = 1; pd_off = 0; pd_on = 1; pu_off = 0; end //======================================================================= end // @(initial_step) //========================================================================= // Catch: process to catch threshold crossings in In_D //------------------------------------------------------------------------- @(cross(V(In_D)-Vth, 0, 100p, 0.5)) begin if (V(In_D) > Vth) begin // Find logic state pu_on = 1; pd_off = 1; pd_on = 0; pu_off = 0; end else if (V(In_D) < Vth) begin pu_on = 0; pd_off = 0; pd_on = 1; pu_off = 1; end else begin pu_on = 1; pd_off = 0; pd_on = 1; pu_off = 0; end end //------------------------------------------------------------------------- // Save time of event when In_D changed //------------------------------------------------------------------------- @(cross(pu_on-0.5, 0)) begin Tpu_on_event = $abstime; //$strobe("\nPU_ON = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pu_on, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end @(cross(pu_off-0.5, 0)) begin Tpu_off_event = $abstime; //$strobe("\nPU_OFF = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pu_off, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end @(cross(pd_on-0.5, 0)) begin Tpd_on_event = $abstime; //$strobe("\nPD_ON = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pd_on, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end @(cross(pd_off-0.5, 0)) begin Tpd_off_event = $abstime; //$strobe("\nPD_OFF = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pd_off, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end //------------------------------------------------------------------------- // End of process Catch; //========================================================================= //========================================================================= // 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 && Tpu_off_event == 0.0 && Tpd_on_event == 0.0 && Tpd_off_event == 0.0) begin // Initialization if (pu_on == 1) begin // Start with the end of the Kpu = Kr1[Common_length]; // Vt curves for those which end else if (pu_off == 1) begin // are fully on initially Kpu = Kf2[Common_length]; end else begin Kpu = 0.0; end if (pd_on == 1) begin Kpd = Kf1[Common_length]; end else if (pd_off == 1) begin Kpd = Kr2[Common_length]; end else begin Kpd = 0.0; end end else begin // Look up coefficients in normal operation if (pu_on == 1) Kpu = $table_model($abstime - Tpu_on_event, T_common, Kr1, "LL"); else if (pu_off == 1) Kpu = $table_model($abstime - Tpu_off_event, T_common, Kf2, "LL"); else Kpu = Kr1[1]; if (pd_on == 1) Kpd = $table_model($abstime - Tpd_on_event, T_common, Kf1, "LL"); else if (pd_off == 1) Kpd = $table_model($abstime - Tpd_off_event, T_common, Kr2, "LL"); else Kpd = Kf1[1]; end //========================================================================= // This section contains the analog expressions which calculate // the output currents of the IV curves and C_comp capacitors. //------------------------------------------------------------------------- I(pc) <+ -$table_model(V(pc), V_pc, I_pc, "LL") + k_C_comp_pc*C_comp*ddt(V(pc)); I(pu) <+ Kpu * -$table_model(V(pu), V_pu, I_pu, "LL") + k_C_comp_pu*C_comp*ddt(V(pu)); I(pd) <+ Kpd * $table_model(V(pd), V_pd, I_pd, "LL") + k_C_comp_pd*C_comp*ddt(V(pd)); I(gc) <+ $table_model(V(gc), V_gc, I_gc, "LL") + k_C_comp_gc*C_comp*ddt(V(gc)); //------------------------------------------------------------------------- end endmodule // IBIS_Output //============================================================================= //============================================================================= module IBIS_IO (PU_ref, PD_ref, IO, In_D, En_D, Rcv_D, PC_ref, GC_ref); input In_D, En_D; electrical In_D, En_D; output Rcv_D; electrical Rcv_D; inout IO, PC_ref, PU_ref, PD_ref, GC_ref; electrical IO, PC_ref, PU_ref, PD_ref, GC_ref; branch (PC_ref, IO) pc; // branches driven in model branch (PU_ref, IO) pu; branch (IO, PD_ref) pd; branch (IO, GC_ref) gc; parameter real //--------------------------------------------------------------------------- // IBIS parameters //--------------------------------------------------------------------------- C_comp = 5.0p, // Default C_comp value k_C_comp_pc = 0.25, // C_comp splitting coefficients k_C_comp_pu = 0.25, k_C_comp_pd = 0.25, k_C_comp_gc = 0.25, Vinh = 2.0, // Default Vinh value Vinl = 0.8, // Default Vinl value V_pc_ref = 5.0, // Power clamp reference voltage V_pu_ref = 5.0, // Pullup reference voltage V_pd_ref = 0.0, // Pulldown reference voltage V_gc_ref = 0.0; // Ground clamp reference voltage //--------------------------------------------------------------------------- // Vectors of the IV curve tables //--------------------------------------------------------------------------- parameter integer IVpc_length = 4, IVpu_length = 4, IVpd_length = 4, IVgc_length = 4; parameter real I_pc[1:IVpc_length] = { 0.08, 0.00, 0.00, 0.00}, V_pc[1:IVpc_length] = {-5.00, -1.00, 5.00, 10.00}, I_pu[1:IVpu_length] = { 0.10, 0.00, -0.10, -0.20}, V_pu[1:IVpu_length] = {-5.00, 0.00, 5.00, 10.00}, I_pd[1:IVpd_length] = {-0.10, 0.00, 0.10, 0.20}, V_pd[1:IVpd_length] = {-5.00, 0.00, 5.00, 10.00}, I_gc[1:IVgc_length] = {-0.08, 0.00, 0.00, 0.00}, V_gc[1:IVgc_length] = {-5.00, -1.00, 5.00, 10.00}; //--------------------------------------------------------------------------- // Vectors of the Vt curve tables //--------------------------------------------------------------------------- parameter integer VTr1_length = 4, VTr2_length = 4, VTf1_length = 4, VTf2_length = 4; parameter real Vr1[1:VTr1_length] = {0.00, 0.00, 2.50, 2.50}, Tr1[1:VTr1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}, Vr2[1:VTr2_length] = {2.50, 2.50, 5.00, 5.00}, Tr2[1:VTr2_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}, Vf1[1:VTf1_length] = {5.00, 5.00, 2.50, 2.50}, Tf1[1:VTf1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}, Vf2[1:VTf2_length] = {2.50, 2.50, 0.00, 0.00}, Tf2[1:VTf2_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}; //--------------------------------------------------------------------------- parameter real Vfx_r1 = 0.0, // V_fixture values Vfx_r2 = 5.0, Vfx_f1 = 5.0, Vfx_f2 = 0.0, Rfx_r1 = 50.0 from (0:inf), // R_fixture values Rfx_r2 = 50.0 from (0:inf), Rfx_f1 = 50.0 from (0:inf), Rfx_f2 = 50.0 from (0:inf), //=========================================================================== // Non-IBIS parameters //--------------------------------------------------------------------------- Max_dt = 1.0e-12 from (0:inf), // Maximum dt between time points Vth = 0.5; // Logic input threshold voltage //--------------------------------------------------------------------------- // Internal variables //--------------------------------------------------------------------------- // Calculate maximum array length for common time and K_*** tables // and declare the arrays //--------------------------------------------------------------------------- // parameter real Max_t = max(max(max(Tr1[VTr1_length], Tr2[VTr2_length]), Tf1[VTf1_length]), Tf2[VTf2_length]); // parameter real Min_t = min(min(min( Tr1[1], Tr2[1]), Tf1[1]), Tf2[1]); // parameter integer Max_length = ceil((Max_t-Min_t)/Max_dt) + VTr1_length + VTr2_length + VTf1_length + VTf2_length; parameter integer Max_length = 3016; // Delete this when the above 3 lines work real T_common[1:Max_length]; // Common time axis array real Kr1[1:Max_length]; // Scaling coefficient arrays real Kr2[1:Max_length]; real Kf1[1:Max_length]; real Kf2[1:Max_length]; integer pu_on; // Logic state variables integer pu_off; integer pd_on; integer pd_off; real Tpu_on_event; // Variables to store event time real Tpu_off_event; real Tpd_on_event; real Tpd_off_event; real Kpu; // Output current scaling coefficients real Kpd; //--------------------------------------------------------------------------- // variables used in Common_time / Common_wfm / Kcoef "function" //--------------------------------------------------------------------------- integer i; integer Common_length; integer index_r1; integer index_r2; integer index_f1; integer index_f2; integer new_index_r1; integer new_index_r2; integer new_index_f1; integer new_index_f2; real old_t; real new_t; real last_t; real additional_pts; real new_dt; real Vr1_common[1:3]; // Need 3 elements in order to do derivatives real Vr2_common[1:3]; real Vf1_common[1:3]; real Vf2_common[1:3]; real dVwfm_r1; real dVwfm_r2; real dVwfm_f1; real dVwfm_f2; real Iout1; real Iout2; real Ipd1; real Ipd2; real Ipu1; real Ipu2; real Igc1; real Igc2; real Ipc1; real Ipc2; real den; //=========================================================================== analog begin @(initial_step) begin //======================================================================= // This "function" makes a common time axis for all Vt curves and // calculates the corresponding voltage points with linear interpolation // and/or linear extrapolation if necessary. After that it converts the // Vt curves to K coefficients which will be used in the analog equations // to scale the IV curves. The K coefficients are stored in arrays. //----------------------------------------------------------------------- // Initialize variables //----------------------------------------------------------------------- Common_length = 1; index_r1 = 1; index_r2 = 1; index_f1 = 1; index_f2 = 1; new_index_r1 = VTr1_length; new_index_r2 = VTr2_length; new_index_f1 = VTf1_length; new_index_f2 = VTf2_length; //----------------------------------------------------------------------- // Put the earliest time value of all given time vectors into "old_t" //----------------------------------------------------------------------- old_t = min(Tr1[1], Tr2[1]); old_t = min(old_t, Tf1[1]); old_t = min(old_t, Tf2[1]); //----------------------------------------------------------------------- // Put the latest time value of all given time vectors into "new_t" //----------------------------------------------------------------------- last_t = max(Tr1[VTr1_length], Tr2[VTr2_length]); last_t = max(new_t, Tf1[VTf1_length]); last_t = max(new_t, Tf2[VTf2_length]); new_t = last_t; //----------------------------------------------------------------------- // Loop until latest time value is reached in each given time vector //----------------------------------------------------------------------- while (old_t < new_t) begin //--------------------------------------------------------------------- // Save the time value from old_t in T_common // and increment Common_length counter //--------------------------------------------------------------------- T_common[Common_length] = old_t; Common_length = Common_length + 1; //--------------------------------------------------------------------- // Find which given time vector(s) have the lowest time value and // advance their temporary indexes //--------------------------------------------------------------------- if (Tr1[index_r1] <= old_t) new_index_r1 = index_r1 + 1; if (Tr2[index_r2] <= old_t) new_index_r2 = index_r2 + 1; if (Tf1[index_f1] <= old_t) new_index_f1 = index_f1 + 1; if (Tf2[index_f2] <= old_t) new_index_f2 = index_f2 + 1; //--------------------------------------------------------------------- // Find the lowest value at the new indexes in the given vector(s) // and update indexes for next iteration //--------------------------------------------------------------------- if (new_index_r1 <= VTr1_length) begin if (Tr1[new_index_r1] < new_t) new_t = Tr1[new_index_r1]; index_r1 = new_index_r1; end if (new_index_r2 <= VTr2_length) begin if (Tr2[new_index_r2] < new_t) new_t = Tr2[new_index_r2]; index_r2 = new_index_r2; end if (new_index_f1 <= VTf1_length) begin if (Tf1[new_index_f1] < new_t) new_t = Tf1[new_index_f1]; index_f1 = new_index_f1; end if (new_index_f2 <= VTf2_length) begin if (Tf2[new_index_f2] < new_t) new_t = Tf2[new_index_f2]; index_f2 = new_index_f2; end //--------------------------------------------------------------------- // Add points if dt is larger than Max_dt //--------------------------------------------------------------------- if ((new_t-old_t) > Max_dt) begin additional_pts = ceil((new_t-old_t)/Max_dt); new_dt = (new_t-old_t) / additional_pts; for (i = 1; i < additional_pts; i = i + 1) begin //$strobe("\ndif = %e\tAdd = %d\tCL = %d\t T = %e\tnew_dt = ", (new_t-old_t), additional_pts, Common_length, T_common[Common_length-1]+new_dt, new_dt); T_common[Common_length] = T_common[Common_length-1] + new_dt; Common_length = Common_length + 1; end end //--------------------------------------------------------------------- // Update variables for next iteration //--------------------------------------------------------------------- old_t = new_t; new_t = last_t; //--------------------------------------------------------------------- end // while loop T_common[Common_length] = last_t; //======================================================================= //======================================================================= // Calculate the scaling coefficients for each time point along T_common //----------------------------------------------------------------------- // Store the first voltage point in the common waveform variables //----------------------------------------------------------------------- Vr1_common[2] = $table_model(T_common[1], Tr1, Vr1, "LL"); Vr2_common[2] = $table_model(T_common[1], Tr2, Vr2, "LL"); Vf1_common[2] = $table_model(T_common[1], Tf1, Vf1, "LL"); Vf2_common[2] = $table_model(T_common[1], Tf2, Vf2, "LL"); for (i = 1; i <= Common_length; i = i + 1) begin //----------------------------------------------------------------------- // Store the next point (for the derivative calculations) //----------------------------------------------------------------------- if (i < Common_length) begin Vr1_common[3] = $table_model(T_common[i+1], Tr1, Vr1, "LL"); Vr2_common[3] = $table_model(T_common[i+1], Tr2, Vr2, "LL"); Vf1_common[3] = $table_model(T_common[i+1], Tf1, Vf1, "LL"); Vf2_common[3] = $table_model(T_common[i+1], Tf2, Vf2, "LL"); end //$strobe("\nTcom = %e\tR1 = %e\tR2 = %e\tF1 = %e\tF2 = %e", T_common[i], Vr1_common[2], Vr2_common[2], Vf1_common[2], Vf2_common[2]); //--------------------------------------------------------------------- // Calculate the derivative of each waveform for C_comp compensation //--------------------------------------------------------------------- if ((i <= 1) || (i >= Common_length)) begin dVwfm_r1 = 0.0; // Force the end point derivatives to zero dVwfm_r2 = 0.0; dVwfm_f1 = 0.0; dVwfm_f2 = 0.0; end else begin dVwfm_r1 = ((Vr1_common[2] - Vr1_common[1]) / (T_common[i] - T_common[i-1]) + (Vr1_common[3] - Vr1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_r2 = ((Vr2_common[2] - Vr2_common[1]) / (T_common[i] - T_common[i-1]) + (Vr2_common[3] - Vr2_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f1 = ((Vf1_common[2] - Vf1_common[1]) / (T_common[i] - T_common[i-1]) + (Vf1_common[3] - Vf1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f2 = ((Vf2_common[2] - Vf2_common[1]) / (T_common[i] - T_common[i-1]) + (Vf2_common[3] - Vf2_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; end //$strobe("dR1 = %e\tdR2 = %e\tdF1 = %e\tdF2 = %e", dVwfm_r1, dVwfm_r2, dVwfm_f1, dVwfm_f2); //--------------------------------------------------------------------- // Calculate intermediate variables and the Kr1 Kr2 coefficients //--------------------------------------------------------------------- Iout1 = ((Vr1_common[2] - Vfx_r1) / Rfx_r1) + C_comp * dVwfm_r1; Iout2 = ((Vr2_common[2] - Vfx_r2) / Rfx_r2) + C_comp * dVwfm_r2; Ipc1 = -1.0 * $table_model(V_pc_ref - Vr1_common[2], V_pc, I_pc, "LL"); Ipc2 = -1.0 * $table_model(V_pc_ref - Vr2_common[2], V_pc, I_pc, "LL"); Ipu1 = -1.0 * $table_model(V_pu_ref - Vr1_common[2], V_pu, I_pu, "LL"); Ipu2 = -1.0 * $table_model(V_pu_ref - Vr2_common[2], V_pu, I_pu, "LL"); Ipd1 = $table_model(Vr1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Ipd2 = $table_model(Vr2_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vr1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); Igc2 = $table_model(Vr2_common[2] - V_gc_ref, V_gc, I_gc, "LL"); den = (Ipu1 * Ipd2) - (Ipd1 * Ipu2); // Since these are rising waveforms // Kr1 == Kpu_on and Kr2 == Kpd_off Kr1[i] = (Ipd2*(Iout1+Igc1-Ipc1) + Ipd1*(Ipc2-Igc2-Iout2)) / den; Kr2[i] = (Ipu2*(Iout1+Igc1-Ipc1) + Ipu1*(Ipc2-Igc2-Iout2)) / den; //--------------------------------------------------------------------- // Calculate intermediate variables and the Kf1 Kf2 coefficients //--------------------------------------------------------------------- Iout1 = ((Vf1_common[2] - Vfx_f1) / Rfx_f1) + C_comp * dVwfm_f1; Iout2 = ((Vf2_common[2] - Vfx_f2) / Rfx_f2) + C_comp * dVwfm_f2; Ipc1 = -1.0 * $table_model(V_pc_ref - Vf1_common[2], V_pc, I_pc, "LL"); Ipc2 = -1.0 * $table_model(V_pc_ref - Vf2_common[2], V_pc, I_pc, "LL"); Ipu1 = -1.0 * $table_model(V_pu_ref - Vf1_common[2], V_pu, I_pu, "LL"); Ipu2 = -1.0 * $table_model(V_pu_ref - Vf2_common[2], V_pu, I_pu, "LL"); Ipd1 = $table_model(Vf1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Ipd2 = $table_model(Vf2_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vf1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); Igc2 = $table_model(Vf2_common[2] - V_gc_ref, V_gc, I_gc, "LL"); den = (Ipu1 * Ipd2) - (Ipd1 * Ipu2); // Since these are falling waveforms // Kf1 == Kpd_on and Kf2 == Kpu_off Kf1[i] = (Ipu2*(Iout1+Igc1-Ipc1) + Ipu1*(Ipc2-Igc2-Iout2)) / den; Kf2[i] = (Ipd2*(Iout1+Igc1-Ipc1) + Ipd1*(Ipc2-Igc2-Iout2)) / den; //$strobe("\nTcom = %e\tKr1 = %e\tKr2 = %e\tKf1 = %e\tKf2 = %e", T_common[i], Kr1[i], Kr2[i], Kf1[i], Kf2[i]); //--------------------------------------------------------------------- // Shift points by one index for next iteration (for C_comp compensation) //--------------------------------------------------------------------- Vr1_common[1] = Vr1_common[2]; Vr2_common[1] = Vr2_common[2]; Vf1_common[1] = Vf1_common[2]; Vf2_common[1] = Vf2_common[2]; Vr1_common[2] = Vr1_common[3]; Vr2_common[2] = Vr2_common[3]; Vf1_common[2] = Vf1_common[3]; Vf2_common[2] = Vf2_common[3]; end // for loop //----------------------------------------------------------------------- // Fill the unused portion of the arrays with reasonable values // to prevent any misbehaving later with $table_model //======================================================================= for (i = Common_length + 1; i <= Max_length; i = i + 1) begin T_common[i] = T_common[i-1] + Max_dt; Kr1[i] = Kr1[Common_length]; Kr2[i] = Kr2[Common_length]; Kf1[i] = Kf1[Common_length]; Kf2[i] = Kf2[Common_length]; end // for loop //----------------------------------------------------------------------- // End of Common_time / Common_wfm / Kcoef "function" //======================================================================= //======================================================================= // Initialize logic state variables //----------------------------------------------------------------------- if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find initial logic state pu_on = 1; pd_off = 1; pd_on = 0; pu_off = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pu_on = 0; pd_off = 0; pd_on = 1; pu_off = 1; end else if ((V(En_D) < Vth)) begin pu_on = 0; pd_off = 1; pd_on = 0; pu_off = 1; end else begin pu_on = 1; pd_off = 0; pd_on = 1; pu_off = 0; end //======================================================================= end // @(initial_step) //========================================================================= // Catch: process to catch threshold crossings in In_D, En_D //------------------------------------------------------------------------- @(cross(V(In_D)-Vth, 0, 100p, 0.5) or cross(V(En_D)-Vth, 0, 100p, 0.5)) begin if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find logic state pu_on = 1; pd_off = 1; pd_on = 0; pu_off = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pu_on = 0; pd_off = 0; pd_on = 1; pu_off = 1; end else if ((V(En_D) < Vth)) begin pu_on = 0; pd_off = 1; pd_on = 0; pu_off = 1; end else begin pu_on = 1; pd_off = 0; pd_on = 1; pu_off = 0; end end //------------------------------------------------------------------------- // Save time of event when In_D or En_D changed //------------------------------------------------------------------------- @(cross(pu_on-0.5, 0)) begin Tpu_on_event = $abstime; //$strobe("\nPU_ON = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pu_on, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end @(cross(pu_off-0.5, 0)) begin Tpu_off_event = $abstime; //$strobe("\nPU_OFF = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pu_off, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end @(cross(pd_on-0.5, 0)) begin Tpd_on_event = $abstime; //$strobe("\nPD_ON = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pd_on, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end @(cross(pd_off-0.5, 0)) begin Tpd_off_event = $abstime; //$strobe("\nPD_OFF = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pd_off, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end //------------------------------------------------------------------------- // End of process Catch; //========================================================================= //========================================================================= // 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 && Tpu_off_event == 0.0 && Tpd_on_event == 0.0 && Tpd_off_event == 0.0) begin // Initialization if (pu_on == 1) begin // Start with the end of the Kpu = Kr1[Common_length]; // Vt curves for those which end else if (pu_off == 1) begin // are fully on initially Kpu = Kf2[Common_length]; end else begin Kpu = 0.0; end if (pd_on == 1) begin Kpd = Kf1[Common_length]; end else if (pd_off == 1) begin Kpd = Kr2[Common_length]; end else begin Kpd = 0.0; end end else begin // Look up coefficients in normal operation if (pu_on == 1) Kpu = $table_model($abstime - Tpu_on_event, T_common, Kr1, "LL"); else if (pu_off == 1) Kpu = $table_model($abstime - Tpu_off_event, T_common, Kf2, "LL"); else Kpu = Kr1[1]; if (pd_on == 1) Kpd = $table_model($abstime - Tpd_on_event, T_common, Kf1, "LL"); else if (pd_off == 1) Kpd = $table_model($abstime - Tpd_off_event, T_common, Kr2, "LL"); else Kpd = Kf1[1]; end //========================================================================= // This section contains the analog expressions which calculate // the output currents of the IV curves and C_comp capacitors. //------------------------------------------------------------------------- I(pc) <+ -$table_model(V(pc), V_pc, I_pc, "LL") + k_C_comp_pc*C_comp*ddt(V(pc)); I(pu) <+ Kpu * -$table_model(V(pu), V_pu, I_pu, "LL") + k_C_comp_pu*C_comp*ddt(V(pu)); I(pd) <+ Kpd * $table_model(V(pd), V_pd, I_pd, "LL") + k_C_comp_pd*C_comp*ddt(V(pd)); I(gc) <+ $table_model(V(gc), V_gc, I_gc, "LL") + k_C_comp_gc*C_comp*ddt(V(gc)); //------------------------------------------------------------------------- // A simple receiver logic //------------------------------------------------------------------------- if (V(pd) > Vinh) V(Rcv_D) <+ 1.0; else if (V(pd) < Vinl) V(Rcv_D) <+ 0.0; else V(Rcv_D) <+ 0.5; //------------------------------------------------------------------------- end endmodule // IBIS_IO //============================================================================= //============================================================================= module IBIS_3STATE (PU_ref, PD_ref, IO, In_D, En_D, PC_ref, GC_ref); input In_D, En_D; electrical In_D, En_D; inout IO, PC_ref, PU_ref, PD_ref, GC_ref; electrical IO, PC_ref, PU_ref, PD_ref, GC_ref; branch (PC_ref, IO) pc; // branches driven in model branch (PU_ref, IO) pu; branch (IO, PD_ref) pd; branch (IO, GC_ref) gc; parameter real //--------------------------------------------------------------------------- // IBIS parameters //--------------------------------------------------------------------------- C_comp = 5.0p, // Default C_comp value k_C_comp_pc = 0.25, // C_comp splitting coefficients k_C_comp_pu = 0.25, k_C_comp_pd = 0.25, k_C_comp_gc = 0.25, Vinh = 2.0, // Default Vinh value Vinl = 0.8, // Default Vinl value V_pc_ref = 5.0, // Power clamp reference voltage V_pu_ref = 5.0, // Pullup reference voltage V_pd_ref = 0.0, // Pulldown reference voltage V_gc_ref = 0.0; // Ground clamp reference voltage //--------------------------------------------------------------------------- // Vectors of the IV curve tables //--------------------------------------------------------------------------- parameter integer IVpc_length = 4, IVpu_length = 4, IVpd_length = 4, IVgc_length = 4; parameter real I_pc[1:IVpc_length] = { 0.08, 0.00, 0.00, 0.00}, V_pc[1:IVpc_length] = {-5.00, -1.00, 5.00, 10.00}, I_pu[1:IVpu_length] = { 0.10, 0.00, -0.10, -0.20}, V_pu[1:IVpu_length] = {-5.00, 0.00, 5.00, 10.00}, I_pd[1:IVpd_length] = {-0.10, 0.00, 0.10, 0.20}, V_pd[1:IVpd_length] = {-5.00, 0.00, 5.00, 10.00}, I_gc[1:IVgc_length] = {-0.08, 0.00, 0.00, 0.00}, V_gc[1:IVgc_length] = {-5.00, -1.00, 5.00, 10.00}; //--------------------------------------------------------------------------- // Vectors of the Vt curve tables //--------------------------------------------------------------------------- parameter integer VTr1_length = 4, VTr2_length = 4, VTf1_length = 4, VTf2_length = 4; parameter real Vr1[1:VTr1_length] = {0.00, 0.00, 2.50, 2.50}, Tr1[1:VTr1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}, Vr2[1:VTr2_length] = {2.50, 2.50, 5.00, 5.00}, Tr2[1:VTr2_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}, Vf1[1:VTf1_length] = {5.00, 5.00, 2.50, 2.50}, Tf1[1:VTf1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}, Vf2[1:VTf2_length] = {2.50, 2.50, 0.00, 0.00}, Tf2[1:VTf2_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}; //--------------------------------------------------------------------------- parameter real Vfx_r1 = 0.0, // V_fixture values Vfx_r2 = 5.0, Vfx_f1 = 5.0, Vfx_f2 = 0.0, Rfx_r1 = 50.0 from (0:inf), // R_fixture values Rfx_r2 = 50.0 from (0:inf), Rfx_f1 = 50.0 from (0:inf), Rfx_f2 = 50.0 from (0:inf), //=========================================================================== // Non-IBIS parameters //--------------------------------------------------------------------------- Max_dt = 1.0e-12 from (0:inf), // Maximum dt between time points Vth = 0.5; // Logic input threshold voltage //--------------------------------------------------------------------------- // Internal variables //--------------------------------------------------------------------------- // Calculate maximum array length for common time and K_*** tables // and declare the arrays //--------------------------------------------------------------------------- // parameter real Max_t = max(max(max(Tr1[VTr1_length], Tr2[VTr2_length]), Tf1[VTf1_length]), Tf2[VTf2_length]); // parameter real Min_t = min(min(min( Tr1[1], Tr2[1]), Tf1[1]), Tf2[1]); // parameter integer Max_length = ceil((Max_t-Min_t)/Max_dt) + VTr1_length + VTr2_length + VTf1_length + VTf2_length; parameter integer Max_length = 3016; // Delete this when the above 3 lines work real T_common[1:Max_length]; // Common time axis array real Kr1[1:Max_length]; // Scaling coefficient arrays real Kr2[1:Max_length]; real Kf1[1:Max_length]; real Kf2[1:Max_length]; integer pu_on; // Logic state variables integer pu_off; integer pd_on; integer pd_off; real Tpu_on_event; // Variables to store event time real Tpu_off_event; real Tpd_on_event; real Tpd_off_event; real Kpu; // Output current scaling coefficients real Kpd; //--------------------------------------------------------------------------- // variables used in Common_time / Common_wfm / Kcoef "function" //--------------------------------------------------------------------------- integer i; integer Common_length; integer index_r1; integer index_r2; integer index_f1; integer index_f2; integer new_index_r1; integer new_index_r2; integer new_index_f1; integer new_index_f2; real old_t; real new_t; real last_t; real additional_pts; real new_dt; real Vr1_common[1:3]; // Need 3 elements in order to do derivatives real Vr2_common[1:3]; real Vf1_common[1:3]; real Vf2_common[1:3]; real dVwfm_r1; real dVwfm_r2; real dVwfm_f1; real dVwfm_f2; real Iout1; real Iout2; real Ipd1; real Ipd2; real Ipu1; real Ipu2; real Igc1; real Igc2; real Ipc1; real Ipc2; real den; //=========================================================================== analog begin @(initial_step) begin //======================================================================= // This "function" makes a common time axis for all Vt curves and // calculates the corresponding voltage points with linear interpolation // and/or linear extrapolation if necessary. After that it converts the // Vt curves to K coefficients which will be used in the analog equations // to scale the IV curves. The K coefficients are stored in arrays. //----------------------------------------------------------------------- // Initialize variables //----------------------------------------------------------------------- Common_length = 1; index_r1 = 1; index_r2 = 1; index_f1 = 1; index_f2 = 1; new_index_r1 = VTr1_length; new_index_r2 = VTr2_length; new_index_f1 = VTf1_length; new_index_f2 = VTf2_length; //----------------------------------------------------------------------- // Put the earliest time value of all given time vectors into "old_t" //----------------------------------------------------------------------- old_t = min(Tr1[1], Tr2[1]); old_t = min(old_t, Tf1[1]); old_t = min(old_t, Tf2[1]); //----------------------------------------------------------------------- // Put the latest time value of all given time vectors into "new_t" //----------------------------------------------------------------------- last_t = max(Tr1[VTr1_length], Tr2[VTr2_length]); last_t = max(new_t, Tf1[VTf1_length]); last_t = max(new_t, Tf2[VTf2_length]); new_t = last_t; //----------------------------------------------------------------------- // Loop until latest time value is reached in each given time vector //----------------------------------------------------------------------- while (old_t < new_t) begin //--------------------------------------------------------------------- // Save the time value from old_t in T_common // and increment Common_length counter //--------------------------------------------------------------------- T_common[Common_length] = old_t; Common_length = Common_length + 1; //--------------------------------------------------------------------- // Find which given time vector(s) have the lowest time value and // advance their temporary indexes //--------------------------------------------------------------------- if (Tr1[index_r1] <= old_t) new_index_r1 = index_r1 + 1; if (Tr2[index_r2] <= old_t) new_index_r2 = index_r2 + 1; if (Tf1[index_f1] <= old_t) new_index_f1 = index_f1 + 1; if (Tf2[index_f2] <= old_t) new_index_f2 = index_f2 + 1; //--------------------------------------------------------------------- // Find the lowest value at the new indexes in the given vector(s) // and update indexes for next iteration //--------------------------------------------------------------------- if (new_index_r1 <= VTr1_length) begin if (Tr1[new_index_r1] < new_t) new_t = Tr1[new_index_r1]; index_r1 = new_index_r1; end if (new_index_r2 <= VTr2_length) begin if (Tr2[new_index_r2] < new_t) new_t = Tr2[new_index_r2]; index_r2 = new_index_r2; end if (new_index_f1 <= VTf1_length) begin if (Tf1[new_index_f1] < new_t) new_t = Tf1[new_index_f1]; index_f1 = new_index_f1; end if (new_index_f2 <= VTf2_length) begin if (Tf2[new_index_f2] < new_t) new_t = Tf2[new_index_f2]; index_f2 = new_index_f2; end //--------------------------------------------------------------------- // Add points if dt is larger than Max_dt //--------------------------------------------------------------------- if ((new_t-old_t) > Max_dt) begin additional_pts = ceil((new_t-old_t)/Max_dt); new_dt = (new_t-old_t) / additional_pts; for (i = 1; i < additional_pts; i = i + 1) begin //$strobe("\ndif = %e\tAdd = %d\tCL = %d\t T = %e\tnew_dt = ", (new_t-old_t), additional_pts, Common_length, T_common[Common_length-1]+new_dt, new_dt); T_common[Common_length] = T_common[Common_length-1] + new_dt; Common_length = Common_length + 1; end end //--------------------------------------------------------------------- // Update variables for next iteration //--------------------------------------------------------------------- old_t = new_t; new_t = last_t; //--------------------------------------------------------------------- end // while loop T_common[Common_length] = last_t; //======================================================================= //======================================================================= // Calculate the scaling coefficients for each time point along T_common //----------------------------------------------------------------------- // Store the first voltage point in the common waveform variables //----------------------------------------------------------------------- Vr1_common[2] = $table_model(T_common[1], Tr1, Vr1, "LL"); Vr2_common[2] = $table_model(T_common[1], Tr2, Vr2, "LL"); Vf1_common[2] = $table_model(T_common[1], Tf1, Vf1, "LL"); Vf2_common[2] = $table_model(T_common[1], Tf2, Vf2, "LL"); for (i = 1; i <= Common_length; i = i + 1) begin //----------------------------------------------------------------------- // Store the next point (for the derivative calculations) //----------------------------------------------------------------------- if (i < Common_length) begin Vr1_common[3] = $table_model(T_common[i+1], Tr1, Vr1, "LL"); Vr2_common[3] = $table_model(T_common[i+1], Tr2, Vr2, "LL"); Vf1_common[3] = $table_model(T_common[i+1], Tf1, Vf1, "LL"); Vf2_common[3] = $table_model(T_common[i+1], Tf2, Vf2, "LL"); end //$strobe("\nTcom = %e\tR1 = %e\tR2 = %e\tF1 = %e\tF2 = %e", T_common[i], Vr1_common[2], Vr2_common[2], Vf1_common[2], Vf2_common[2]); //--------------------------------------------------------------------- // Calculate the derivative of each waveform for C_comp compensation //--------------------------------------------------------------------- if ((i <= 1) || (i >= Common_length)) begin dVwfm_r1 = 0.0; // Force the end point derivatives to zero dVwfm_r2 = 0.0; dVwfm_f1 = 0.0; dVwfm_f2 = 0.0; end else begin dVwfm_r1 = ((Vr1_common[2] - Vr1_common[1]) / (T_common[i] - T_common[i-1]) + (Vr1_common[3] - Vr1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_r2 = ((Vr2_common[2] - Vr2_common[1]) / (T_common[i] - T_common[i-1]) + (Vr2_common[3] - Vr2_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f1 = ((Vf1_common[2] - Vf1_common[1]) / (T_common[i] - T_common[i-1]) + (Vf1_common[3] - Vf1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f2 = ((Vf2_common[2] - Vf2_common[1]) / (T_common[i] - T_common[i-1]) + (Vf2_common[3] - Vf2_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; end //$strobe("dR1 = %e\tdR2 = %e\tdF1 = %e\tdF2 = %e", dVwfm_r1, dVwfm_r2, dVwfm_f1, dVwfm_f2); //--------------------------------------------------------------------- // Calculate intermediate variables and the Kr1 Kr2 coefficients //--------------------------------------------------------------------- Iout1 = ((Vr1_common[2] - Vfx_r1) / Rfx_r1) + C_comp * dVwfm_r1; Iout2 = ((Vr2_common[2] - Vfx_r2) / Rfx_r2) + C_comp * dVwfm_r2; Ipc1 = -1.0 * $table_model(V_pc_ref - Vr1_common[2], V_pc, I_pc, "LL"); Ipc2 = -1.0 * $table_model(V_pc_ref - Vr2_common[2], V_pc, I_pc, "LL"); Ipu1 = -1.0 * $table_model(V_pu_ref - Vr1_common[2], V_pu, I_pu, "LL"); Ipu2 = -1.0 * $table_model(V_pu_ref - Vr2_common[2], V_pu, I_pu, "LL"); Ipd1 = $table_model(Vr1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Ipd2 = $table_model(Vr2_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vr1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); Igc2 = $table_model(Vr2_common[2] - V_gc_ref, V_gc, I_gc, "LL"); den = (Ipu1 * Ipd2) - (Ipd1 * Ipu2); // Since these are rising waveforms // Kr1 == Kpu_on and Kr2 == Kpd_off Kr1[i] = (Ipd2*(Iout1+Igc1-Ipc1) + Ipd1*(Ipc2-Igc2-Iout2)) / den; Kr2[i] = (Ipu2*(Iout1+Igc1-Ipc1) + Ipu1*(Ipc2-Igc2-Iout2)) / den; //--------------------------------------------------------------------- // Calculate intermediate variables and the Kf1 Kf2 coefficients //--------------------------------------------------------------------- Iout1 = ((Vf1_common[2] - Vfx_f1) / Rfx_f1) + C_comp * dVwfm_f1; Iout2 = ((Vf2_common[2] - Vfx_f2) / Rfx_f2) + C_comp * dVwfm_f2; Ipc1 = -1.0 * $table_model(V_pc_ref - Vf1_common[2], V_pc, I_pc, "LL"); Ipc2 = -1.0 * $table_model(V_pc_ref - Vf2_common[2], V_pc, I_pc, "LL"); Ipu1 = -1.0 * $table_model(V_pu_ref - Vf1_common[2], V_pu, I_pu, "LL"); Ipu2 = -1.0 * $table_model(V_pu_ref - Vf2_common[2], V_pu, I_pu, "LL"); Ipd1 = $table_model(Vf1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Ipd2 = $table_model(Vf2_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vf1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); Igc2 = $table_model(Vf2_common[2] - V_gc_ref, V_gc, I_gc, "LL"); den = (Ipu1 * Ipd2) - (Ipd1 * Ipu2); // Since these are falling waveforms // Kf1 == Kpd_on and Kf2 == Kpu_off Kf1[i] = (Ipu2*(Iout1+Igc1-Ipc1) + Ipu1*(Ipc2-Igc2-Iout2)) / den; Kf2[i] = (Ipd2*(Iout1+Igc1-Ipc1) + Ipd1*(Ipc2-Igc2-Iout2)) / den; //$strobe("\nTcom = %e\tKr1 = %e\tKr2 = %e\tKf1 = %e\tKf2 = %e", T_common[i], Kr1[i], Kr2[i], Kf1[i], Kf2[i]); //--------------------------------------------------------------------- // Shift points by one index for next iteration (for C_comp compensation) //--------------------------------------------------------------------- Vr1_common[1] = Vr1_common[2]; Vr2_common[1] = Vr2_common[2]; Vf1_common[1] = Vf1_common[2]; Vf2_common[1] = Vf2_common[2]; Vr1_common[2] = Vr1_common[3]; Vr2_common[2] = Vr2_common[3]; Vf1_common[2] = Vf1_common[3]; Vf2_common[2] = Vf2_common[3]; end // for loop //----------------------------------------------------------------------- // Fill the unused portion of the arrays with reasonable values // to prevent any misbehaving later with $table_model //======================================================================= for (i = Common_length + 1; i <= Max_length; i = i + 1) begin T_common[i] = T_common[i-1] + Max_dt; Kr1[i] = Kr1[Common_length]; Kr2[i] = Kr2[Common_length]; Kf1[i] = Kf1[Common_length]; Kf2[i] = Kf2[Common_length]; end // for loop //----------------------------------------------------------------------- // End of Common_time / Common_wfm / Kcoef "function" //======================================================================= //======================================================================= // Initialize logic state variables //----------------------------------------------------------------------- if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find initial logic state pu_on = 1; pd_off = 1; pd_on = 0; pu_off = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pu_on = 0; pd_off = 0; pd_on = 1; pu_off = 1; end else if ((V(En_D) < Vth)) begin pu_on = 0; pd_off = 1; pd_on = 0; pu_off = 1; end else begin pu_on = 1; pd_off = 0; pd_on = 1; pu_off = 0; end //======================================================================= end // @(initial_step) //========================================================================= // Catch: process to catch threshold crossings in In_D, En_D //------------------------------------------------------------------------- @(cross(V(In_D)-Vth, 0, 100p, 0.5) or cross(V(En_D)-Vth, 0, 100p, 0.5)) begin if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find logic state pu_on = 1; pd_off = 1; pd_on = 0; pu_off = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pu_on = 0; pd_off = 0; pd_on = 1; pu_off = 1; end else if ((V(En_D) < Vth)) begin pu_on = 0; pd_off = 1; pd_on = 0; pu_off = 1; end else begin pu_on = 1; pd_off = 0; pd_on = 1; pu_off = 0; end end //------------------------------------------------------------------------- // Save time of event when In_D or En_D changed //------------------------------------------------------------------------- @(cross(pu_on-0.5, 0)) begin Tpu_on_event = $abstime; //$strobe("\nPU_ON = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pu_on, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end @(cross(pu_off-0.5, 0)) begin Tpu_off_event = $abstime; //$strobe("\nPU_OFF = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pu_off, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end @(cross(pd_on-0.5, 0)) begin Tpd_on_event = $abstime; //$strobe("\nPD_ON = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pd_on, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end @(cross(pd_off-0.5, 0)) begin Tpd_off_event = $abstime; //$strobe("\nPD_OFF = %d\tTpu_on = %e\tTpu_off = %e\tTpd_on = %e\tTpd_off = %e", pd_off, Tpu_on_event, Tpu_off_event, Tpd_on_event, Tpd_off_event); end //------------------------------------------------------------------------- // End of process Catch; //========================================================================= //========================================================================= // 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 && Tpu_off_event == 0.0 && Tpd_on_event == 0.0 && Tpd_off_event == 0.0) begin // Initialization if (pu_on == 1) begin // Start with the end of the Kpu = Kr1[Common_length]; // Vt curves for those which end else if (pu_off == 1) begin // are fully on initially Kpu = Kf2[Common_length]; end else begin Kpu = 0.0; end if (pd_on == 1) begin Kpd = Kf1[Common_length]; end else if (pd_off == 1) begin Kpd = Kr2[Common_length]; end else begin Kpd = 0.0; end end else begin // Look up coefficients in normal operation if (pu_on == 1) Kpu = $table_model($abstime - Tpu_on_event, T_common, Kr1, "LL"); else if (pu_off == 1) Kpu = $table_model($abstime - Tpu_off_event, T_common, Kf2, "LL"); else Kpu = Kr1[1]; if (pd_on == 1) Kpd = $table_model($abstime - Tpd_on_event, T_common, Kf1, "LL"); else if (pd_off == 1) Kpd = $table_model($abstime - Tpd_off_event, T_common, Kr2, "LL"); else Kpd = Kf1[1]; end //========================================================================= // This section contains the analog expressions which calculate // the output currents of the IV curves and C_comp capacitors. //------------------------------------------------------------------------- I(pc) <+ -$table_model(V(pc), V_pc, I_pc, "LL") + k_C_comp_pc*C_comp*ddt(V(pc)); I(pu) <+ Kpu * -$table_model(V(pu), V_pu, I_pu, "LL") + k_C_comp_pu*C_comp*ddt(V(pu)); I(pd) <+ Kpd * $table_model(V(pd), V_pd, I_pd, "LL") + k_C_comp_pd*C_comp*ddt(V(pd)); I(gc) <+ $table_model(V(gc), V_gc, I_gc, "LL") + k_C_comp_gc*C_comp*ddt(V(gc)); //------------------------------------------------------------------------- end endmodule // IBIS_3state //============================================================================= //============================================================================= module IBIS_OPENSINK (PU_ref, PD_ref, IO, In_D, En_D, PC_ref, GC_ref); input In_D, En_D; electrical In_D, En_D; inout IO, PC_ref, PU_ref, PD_ref, GC_ref; electrical IO, PC_ref, PU_ref, PD_ref, GC_ref; branch (PC_ref, IO) pc; // branches driven in model branch (PU_ref, IO) pu; branch (IO, PD_ref) pd; branch (IO, GC_ref) gc; parameter real //--------------------------------------------------------------------------- // IBIS parameters //--------------------------------------------------------------------------- C_comp = 5.0p, // Default C_comp value k_C_comp_pc = 0.25, // C_comp splitting coefficients k_C_comp_pu = 0.25, k_C_comp_pd = 0.25, k_C_comp_gc = 0.25, V_pc_ref = 5.0, // Power clamp reference voltage V_pd_ref = 0.0, // Pulldown reference voltage V_gc_ref = 0.0; // Ground clamp reference voltage //--------------------------------------------------------------------------- // Vectors of the IV curve tables //--------------------------------------------------------------------------- parameter integer IVpc_length = 4, IVpd_length = 4, IVgc_length = 4; parameter real I_pc[1:IVpc_length] = { 0.08, 0.00, 0.00, 0.00}, V_pc[1:IVpc_length] = {-5.00, -1.00, 5.00, 10.00}, I_pd[1:IVpd_length] = {-0.10, 0.00, 0.10, 0.20}, V_pd[1:IVpd_length] = {-5.00, 0.00, 5.00, 10.00}, I_gc[1:IVgc_length] = {-0.08, 0.00, 0.00, 0.00}, V_gc[1:IVgc_length] = {-5.00, -1.00, 5.00, 10.00}; //--------------------------------------------------------------------------- // Vectors of the Vt curve tables //--------------------------------------------------------------------------- parameter integer VTr1_length = 4, VTf1_length = 4; parameter real Vr1[1:VTr1_length] = {2.50, 2.50, 5.00, 5.00}, Tr1[1:VTr1_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}, Vf1[1:VTf1_length] = {5.00, 5.00, 2.50, 2.50}, Tf1[1:VTf1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}; //--------------------------------------------------------------------------- parameter real Vfx_r1 = 5.0, // V_fixture values Vfx_f1 = 5.0, Rfx_r1 = 50.0 from (0:inf), // R_fixture values Rfx_f1 = 50.0 from (0:inf), //=========================================================================== // Non-IBIS parameters //--------------------------------------------------------------------------- Max_dt = 1.0e-12 from (0:inf), // Maximum dt between time points Vth = 0.5; // Logic input threshold voltage //--------------------------------------------------------------------------- // Internal variables //--------------------------------------------------------------------------- // Calculate maximum array length for common time and K_*** tables // and declare the arrays //--------------------------------------------------------------------------- // parameter real Max_t = max(max(max(Tr1[VTr1_length], Tr2[VTr2_length]), Tf1[VTf1_length]), Tf2[VTf2_length]); // parameter real Min_t = min(min(min( Tr1[1], Tr2[1]), Tf1[1]), Tf2[1]); // parameter integer Max_length = ceil((Max_t-Min_t)/Max_dt) + VTr1_length + VTr2_length + VTf1_length + VTf2_length; parameter integer Max_length = 3016; // Delete this when the above 3 lines work real T_common[1:Max_length]; // Common time axis array real Kr1[1:Max_length]; // Scaling coefficient arrays real Kf1[1:Max_length]; integer pd_on; // Logic state variables integer pd_off; real Tpd_on_event; // Variables to store event time real Tpd_off_event; real Kpd; // Output current scaling coefficients //--------------------------------------------------------------------------- // variables used in Common_time / Common_wfm / Kcoef "function" //--------------------------------------------------------------------------- integer i; integer Common_length; integer index_r1; integer index_f1; integer new_index_r1; integer new_index_f1; real old_t; real new_t; real last_t; real additional_pts; real new_dt; real Vr1_common[1:3]; // Need 3 elements in order to do derivatives real Vf1_common[1:3]; real dVwfm_r1; real dVwfm_f1; real Iout1; real Ipd1; real Igc1; real Ipc1; //=========================================================================== analog begin @(initial_step) begin //======================================================================= // This "function" makes a common time axis for all Vt curves and // calculates the corresponding voltage points with linear interpolation // and/or linear extrapolation if necessary. After that it converts the // Vt curves to K coefficients which will be used in the analog equations // to scale the IV curves. The K coefficients are stored in arrays. //----------------------------------------------------------------------- // Initialize variables //----------------------------------------------------------------------- Common_length = 1; index_r1 = 1; index_f1 = 1; new_index_r1 = VTr1_length; new_index_f1 = VTf1_length; //----------------------------------------------------------------------- // Put the earliest time value of all given time vectors into "old_t" //----------------------------------------------------------------------- old_t = min(Tr1[1], Tf1[1]); //----------------------------------------------------------------------- // Put the latest time value of all given time vectors into "new_t" //----------------------------------------------------------------------- last_t = max(Tr1[VTr1_length], Tf1[VTf1_length]); new_t = last_t; //----------------------------------------------------------------------- // Loop until latest time value is reached in each given time vector //----------------------------------------------------------------------- while (old_t < new_t) begin //--------------------------------------------------------------------- // Save the time value from old_t in T_common // and increment Common_length counter //--------------------------------------------------------------------- T_common[Common_length] = old_t; Common_length = Common_length + 1; //--------------------------------------------------------------------- // Find which given time vector(s) have the lowest time value and // advance their temporary indexes //--------------------------------------------------------------------- if (Tr1[index_r1] <= old_t) new_index_r1 = index_r1 + 1; if (Tf1[index_f1] <= old_t) new_index_f1 = index_f1 + 1; //--------------------------------------------------------------------- // Find the lowest value at the new indexes in the given vector(s) // and update indexes for next iteration //--------------------------------------------------------------------- if (new_index_r1 <= VTr1_length) begin if (Tr1[new_index_r1] < new_t) new_t = Tr1[new_index_r1]; index_r1 = new_index_r1; end if (new_index_f1 <= VTf1_length) begin if (Tf1[new_index_f1] < new_t) new_t = Tf1[new_index_f1]; index_f1 = new_index_f1; end //--------------------------------------------------------------------- // Add points if dt is larger than Max_dt //--------------------------------------------------------------------- if ((new_t-old_t) > Max_dt) begin additional_pts = ceil((new_t-old_t)/Max_dt); new_dt = (new_t-old_t) / additional_pts; for (i = 1; i < additional_pts; i = i + 1) begin //$strobe("\ndif = %e\tAdd = %d\tCL = %d\t T = %e\tnew_dt = ", (new_t-old_t), additional_pts, Common_length, T_common[Common_length-1]+new_dt, new_dt); T_common[Common_length] = T_common[Common_length-1] + new_dt; Common_length = Common_length + 1; end end //--------------------------------------------------------------------- // Update variables for next iteration //--------------------------------------------------------------------- old_t = new_t; new_t = last_t; //--------------------------------------------------------------------- end // while loop T_common[Common_length] = last_t; //======================================================================= //======================================================================= // Calculate the scaling coefficients for each time point along T_common //----------------------------------------------------------------------- // Store the first voltage point in the common waveform variables //----------------------------------------------------------------------- Vr1_common[2] = $table_model(T_common[1], Tr1, Vr1, "LL"); Vf1_common[2] = $table_model(T_common[1], Tf1, Vf1, "LL"); for (i = 1; i <= Common_length; i = i + 1) begin //----------------------------------------------------------------------- // Store the next point (for the derivative calculations) //----------------------------------------------------------------------- if (i < Common_length) begin Vr1_common[3] = $table_model(T_common[i+1], Tr1, Vr1, "LL"); Vf1_common[3] = $table_model(T_common[i+1], Tf1, Vf1, "LL"); end //$strobe("\nTcom = %e\tR1 = %e\tF1 = %e", T_common[i], Vr1_common[2], Vf1_common[2]); //--------------------------------------------------------------------- // Calculate the derivative of each waveform for C_comp compensation //--------------------------------------------------------------------- if ((i <= 1) || (i >= Common_length)) begin dVwfm_r1 = 0.0; // Force the end point derivatives to zero dVwfm_f1 = 0.0; end else begin dVwfm_r1 = ((Vr1_common[2] - Vr1_common[1]) / (T_common[i] - T_common[i-1]) + (Vr1_common[3] - Vr1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f1 = ((Vf1_common[2] - Vf1_common[1]) / (T_common[i] - T_common[i-1]) + (Vf1_common[3] - Vf1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; end //$strobe("dR1 = %e\tdF1 = %e", dVwfm_r1, dVwfm_f1); //--------------------------------------------------------------------- // Calculate intermediate variables and the Kr1 coefficients //--------------------------------------------------------------------- Iout1 = ((Vr1_common[2] - Vfx_r1) / Rfx_r1) + C_comp * dVwfm_r1; Ipc1 = -1.0 * $table_model(V_pc_ref - Vr1_common[2], V_pc, I_pc, "LL"); Ipd1 = $table_model(Vr1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vr1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); // Since these is a rising waveform Kr1 == Kpd_off if (Ipd1 == 0) Kr1[i] = 0.0; else Kr1[i] = (Ipc1 - Igc1 - Iout1) / Ipd1; //--------------------------------------------------------------------- // Calculate intermediate variables and the Kf1 coefficients //--------------------------------------------------------------------- Iout1 = ((Vf1_common[2] - Vfx_f1) / Rfx_f1) + C_comp * dVwfm_f1; Ipc1 = -1.0 * $table_model(V_pc_ref - Vf1_common[2], V_pc, I_pc, "LL"); Ipd1 = $table_model(Vf1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vf1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); // Since these is a falling waveform Kf1 == Kpd_on if (Ipd1 == 0) Kf1[i] = 0.0; else Kf1[i] = (Ipc1 - Igc1 - Iout1) / Ipd1; //$strobe("\nTcom = %e\tKr1 = %e\tKf1 = %e", T_common[i], Kr1[i], Kf1[i]); //--------------------------------------------------------------------- // Shift points by one index for next iteration (for C_comp compensation) //--------------------------------------------------------------------- Vr1_common[1] = Vr1_common[2]; Vf1_common[1] = Vf1_common[2]; Vr1_common[2] = Vr1_common[3]; Vf1_common[2] = Vf1_common[3]; end // for loop //----------------------------------------------------------------------- // Fill the unused portion of the arrays with reasonable values // to prevent any misbehaving later with $table_model //======================================================================= for (i = Common_length + 1; i <= Max_length; i = i + 1) begin T_common[i] = T_common[i-1] + Max_dt; Kr1[i] = Kr1[Common_length]; Kf1[i] = Kf1[Common_length]; end // for loop //----------------------------------------------------------------------- // End of Common_time / Common_wfm / Kcoef "function" //======================================================================= //======================================================================= // Initialize logic state variables //----------------------------------------------------------------------- if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find initial logic state pd_off = 1; pd_on = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pd_off = 0; pd_on = 1; end else if ((V(En_D) < Vth)) begin pd_off = 1; pd_on = 0; end else begin pd_off = 0; pd_on = 1; end //======================================================================= end // @(initial_step) //========================================================================= // Catch: process to catch threshold crossings in In_D, En_D //------------------------------------------------------------------------- @(cross(V(In_D)-Vth, 0, 100p, 0.5) or cross(V(En_D)-Vth, 0, 100p, 0.5)) begin if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find logic state pd_off = 1; pd_on = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pd_off = 0; pd_on = 1; end else if ((V(En_D) < Vth)) begin pd_off = 1; pd_on = 0; end else begin pd_off = 0; pd_on = 1; end end //------------------------------------------------------------------------- // Save time of event when In_D or En_D changed //------------------------------------------------------------------------- @(cross(pd_on-0.5, 0)) begin Tpd_on_event = $abstime; //$strobe("\nPD_ON = %d\tTpd_on = %e\tTpd_off = %e", pd_on, Tpd_on_event, Tpd_off_event); end @(cross(pd_off-0.5, 0)) begin Tpd_off_event = $abstime; //$strobe("\nPD_OFF = %d\tTpd_on = %e\tTpd_off = %e", pd_off, Tpd_on_event, Tpd_off_event); end //------------------------------------------------------------------------- // End of process Catch; //========================================================================= //========================================================================= // This section contains the simultaneous analog equations to find the // appropriate scaling coefficients according to the state the buffer. //------------------------------------------------------------------------- if (Tpd_on_event == 0.0 && Tpd_off_event == 0.0) begin // Initialization if (pd_on == 1) begin // Start with the end of the Kpd = Kf1[Common_length]; // Vt curves for those which end else if (pd_off == 1) begin // are fully on initially Kpd = Kr1[Common_length]; end else begin Kpd = 0.0; end end else begin // Look up coefficients in normal operation if (pd_on == 1) Kpd = $table_model($abstime - Tpd_on_event, T_common, Kf1, "LL"); else if (pd_off == 1) Kpd = $table_model($abstime - Tpd_off_event, T_common, Kr1, "LL"); else Kpd = Kf1[1]; end //========================================================================= // This section contains the analog expressions which calculate // the output currents of the IV curves and C_comp capacitors. //------------------------------------------------------------------------- I(pc) <+ -$table_model(V(pc), V_pc, I_pc, "LL") + k_C_comp_pc*C_comp*ddt(V(pc)); I(pu) <+ k_C_comp_pu*C_comp*ddt(V(pu)); I(pd) <+ Kpd * $table_model(V(pd), V_pd, I_pd, "LL") + k_C_comp_pd*C_comp*ddt(V(pd)); I(gc) <+ $table_model(V(gc), V_gc, I_gc, "LL") + k_C_comp_gc*C_comp*ddt(V(gc)); //------------------------------------------------------------------------- end endmodule // IBIS_OpenSink //============================================================================= //============================================================================= module IBIS_IO_OPENSINK (PU_ref, PD_ref, IO, In_D, En_D, Rcv_D, PC_ref, GC_ref); input In_D, En_D; electrical In_D, En_D; output Rcv_D; electrical Rcv_D; inout IO, PC_ref, PU_ref, PD_ref, GC_ref; electrical IO, PC_ref, PU_ref, PD_ref, GC_ref; branch (PC_ref, IO) pc; // branches driven in model branch (PU_ref, IO) pu; branch (IO, PD_ref) pd; branch (IO, GC_ref) gc; parameter real //--------------------------------------------------------------------------- // IBIS parameters //--------------------------------------------------------------------------- C_comp = 5.0p, // Default C_comp value k_C_comp_pc = 0.25, // C_comp splitting coefficients k_C_comp_pu = 0.25, k_C_comp_pd = 0.25, k_C_comp_gc = 0.25, Vinh = 2.0, // Default Vinh value Vinl = 0.8, // Default Vinl value V_pc_ref = 5.0, // Power clamp reference voltage V_pd_ref = 0.0, // Pulldown reference voltage V_gc_ref = 0.0; // Ground clamp reference voltage //--------------------------------------------------------------------------- // Vectors of the IV curve tables //--------------------------------------------------------------------------- parameter integer IVpc_length = 4, IVpd_length = 4, IVgc_length = 4; parameter real I_pc[1:IVpc_length] = { 0.08, 0.00, 0.00, 0.00}, V_pc[1:IVpc_length] = {-5.00, -1.00, 5.00, 10.00}, I_pd[1:IVpd_length] = {-0.10, 0.00, 0.10, 0.20}, V_pd[1:IVpd_length] = {-5.00, 0.00, 5.00, 10.00}, I_gc[1:IVgc_length] = {-0.08, 0.00, 0.00, 0.00}, V_gc[1:IVgc_length] = {-5.00, -1.00, 5.00, 10.00}; //--------------------------------------------------------------------------- // Vectors of the Vt curve tables //--------------------------------------------------------------------------- parameter integer VTr1_length = 4, VTf1_length = 4; parameter real Vr1[1:VTr1_length] = {2.50, 2.50, 5.00, 5.00}, Tr1[1:VTr1_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}, Vf1[1:VTf1_length] = {5.00, 5.00, 2.50, 2.50}, Tf1[1:VTf1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}; //--------------------------------------------------------------------------- parameter real Vfx_r1 = 5.0, // V_fixture values Vfx_f1 = 5.0, Rfx_r1 = 50.0 from (0:inf), // R_fixture values Rfx_f1 = 50.0 from (0:inf), //=========================================================================== // Non-IBIS parameters //--------------------------------------------------------------------------- Max_dt = 1.0e-12 from (0:inf), // Maximum dt between time points Vth = 0.5; // Logic input threshold voltage //--------------------------------------------------------------------------- // Internal variables //--------------------------------------------------------------------------- // Calculate maximum array length for common time and K_*** tables // and declare the arrays //--------------------------------------------------------------------------- // parameter real Max_t = max(max(max(Tr1[VTr1_length], Tr2[VTr2_length]), Tf1[VTf1_length]), Tf2[VTf2_length]); // parameter real Min_t = min(min(min( Tr1[1], Tr2[1]), Tf1[1]), Tf2[1]); // parameter integer Max_length = ceil((Max_t-Min_t)/Max_dt) + VTr1_length + VTr2_length + VTf1_length + VTf2_length; parameter integer Max_length = 3016; // Delete this when the above 3 lines work real T_common[1:Max_length]; // Common time axis array real Kr1[1:Max_length]; // Scaling coefficient arrays real Kf1[1:Max_length]; integer pd_on; // Logic state variables integer pd_off; real Tpd_on_event; // Variables to store event time real Tpd_off_event; real Kpd; // Output current scaling coefficients //--------------------------------------------------------------------------- // variables used in Common_time / Common_wfm / Kcoef "function" //--------------------------------------------------------------------------- integer i; integer Common_length; integer index_r1; integer index_f1; integer new_index_r1; integer new_index_f1; real old_t; real new_t; real last_t; real additional_pts; real new_dt; real Vr1_common[1:3]; // Need 3 elements in order to do derivatives real Vf1_common[1:3]; real dVwfm_r1; real dVwfm_f1; real Iout1; real Ipd1; real Igc1; real Ipc1; //=========================================================================== analog begin @(initial_step) begin //======================================================================= // This "function" makes a common time axis for all Vt curves and // calculates the corresponding voltage points with linear interpolation // and/or linear extrapolation if necessary. After that it converts the // Vt curves to K coefficients which will be used in the analog equations // to scale the IV curves. The K coefficients are stored in arrays. //----------------------------------------------------------------------- // Initialize variables //----------------------------------------------------------------------- Common_length = 1; index_r1 = 1; index_f1 = 1; new_index_r1 = VTr1_length; new_index_f1 = VTf1_length; //----------------------------------------------------------------------- // Put the earliest time value of all given time vectors into "old_t" //----------------------------------------------------------------------- old_t = min(Tr1[1], Tf1[1]); //----------------------------------------------------------------------- // Put the latest time value of all given time vectors into "new_t" //----------------------------------------------------------------------- last_t = max(Tr1[VTr1_length], Tf1[VTf1_length]); new_t = last_t; //----------------------------------------------------------------------- // Loop until latest time value is reached in each given time vector //----------------------------------------------------------------------- while (old_t < new_t) begin //--------------------------------------------------------------------- // Save the time value from old_t in T_common // and increment Common_length counter //--------------------------------------------------------------------- T_common[Common_length] = old_t; Common_length = Common_length + 1; //--------------------------------------------------------------------- // Find which given time vector(s) have the lowest time value and // advance their temporary indexes //--------------------------------------------------------------------- if (Tr1[index_r1] <= old_t) new_index_r1 = index_r1 + 1; if (Tf1[index_f1] <= old_t) new_index_f1 = index_f1 + 1; //--------------------------------------------------------------------- // Find the lowest value at the new indexes in the given vector(s) // and update indexes for next iteration //--------------------------------------------------------------------- if (new_index_r1 <= VTr1_length) begin if (Tr1[new_index_r1] < new_t) new_t = Tr1[new_index_r1]; index_r1 = new_index_r1; end if (new_index_f1 <= VTf1_length) begin if (Tf1[new_index_f1] < new_t) new_t = Tf1[new_index_f1]; index_f1 = new_index_f1; end //--------------------------------------------------------------------- // Add points if dt is larger than Max_dt //--------------------------------------------------------------------- if ((new_t-old_t) > Max_dt) begin additional_pts = ceil((new_t-old_t)/Max_dt); new_dt = (new_t-old_t) / additional_pts; for (i = 1; i < additional_pts; i = i + 1) begin //$strobe("\ndif = %e\tAdd = %d\tCL = %d\t T = %e\tnew_dt = ", (new_t-old_t), additional_pts, Common_length, T_common[Common_length-1]+new_dt, new_dt); T_common[Common_length] = T_common[Common_length-1] + new_dt; Common_length = Common_length + 1; end end //--------------------------------------------------------------------- // Update variables for next iteration //--------------------------------------------------------------------- old_t = new_t; new_t = last_t; //--------------------------------------------------------------------- end // while loop T_common[Common_length] = last_t; //======================================================================= //======================================================================= // Calculate the scaling coefficients for each time point along T_common //----------------------------------------------------------------------- // Store the first voltage point in the common waveform variables //----------------------------------------------------------------------- Vr1_common[2] = $table_model(T_common[1], Tr1, Vr1, "LL"); Vf1_common[2] = $table_model(T_common[1], Tf1, Vf1, "LL"); for (i = 1; i <= Common_length; i = i + 1) begin //----------------------------------------------------------------------- // Store the next point (for the derivative calculations) //----------------------------------------------------------------------- if (i < Common_length) begin Vr1_common[3] = $table_model(T_common[i+1], Tr1, Vr1, "LL"); Vf1_common[3] = $table_model(T_common[i+1], Tf1, Vf1, "LL"); end //$strobe("\nTcom = %e\tR1 = %e\tF1 = %e", T_common[i], Vr1_common[2], Vf1_common[2]); //--------------------------------------------------------------------- // Calculate the derivative of each waveform for C_comp compensation //--------------------------------------------------------------------- if ((i <= 1) || (i >= Common_length)) begin dVwfm_r1 = 0.0; // Force the end point derivatives to zero dVwfm_f1 = 0.0; end else begin dVwfm_r1 = ((Vr1_common[2] - Vr1_common[1]) / (T_common[i] - T_common[i-1]) + (Vr1_common[3] - Vr1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f1 = ((Vf1_common[2] - Vf1_common[1]) / (T_common[i] - T_common[i-1]) + (Vf1_common[3] - Vf1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; end //$strobe("dR1 = %e\tdF1 = %e", dVwfm_r1, dVwfm_f1); //--------------------------------------------------------------------- // Calculate intermediate variables and the Kr1 coefficients //--------------------------------------------------------------------- Iout1 = ((Vr1_common[2] - Vfx_r1) / Rfx_r1) + C_comp * dVwfm_r1; Ipc1 = -1.0 * $table_model(V_pc_ref - Vr1_common[2], V_pc, I_pc, "LL"); Ipd1 = $table_model(Vr1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vr1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); // Since these is a rising waveform Kr1 == Kpd_off if (Ipd1 == 0) Kr1[i] = 0.0; else Kr1[i] = (Ipc1 - Igc1 - Iout1) / Ipd1; //--------------------------------------------------------------------- // Calculate intermediate variables and the Kf1 coefficients //--------------------------------------------------------------------- Iout1 = ((Vf1_common[2] - Vfx_f1) / Rfx_f1) + C_comp * dVwfm_f1; Ipc1 = -1.0 * $table_model(V_pc_ref - Vf1_common[2], V_pc, I_pc, "LL"); Ipd1 = $table_model(Vf1_common[2] - V_pd_ref, V_pd, I_pd, "LL"); Igc1 = $table_model(Vf1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); // Since these is a falling waveform Kf1 == Kpd_on if (Ipd1 == 0) Kf1[i] = 0.0; else Kf1[i] = (Ipc1 - Igc1 - Iout1) / Ipd1; //$strobe("\nTcom = %e\tKr1 = %e\tKf1 = %e", T_common[i], Kr1[i], Kf1[i]); //--------------------------------------------------------------------- // Shift points by one index for next iteration (for C_comp compensation) //--------------------------------------------------------------------- Vr1_common[1] = Vr1_common[2]; Vf1_common[1] = Vf1_common[2]; Vr1_common[2] = Vr1_common[3]; Vf1_common[2] = Vf1_common[3]; end // for loop //----------------------------------------------------------------------- // Fill the unused portion of the arrays with reasonable values // to prevent any misbehaving later with $table_model //======================================================================= for (i = Common_length + 1; i <= Max_length; i = i + 1) begin T_common[i] = T_common[i-1] + Max_dt; Kr1[i] = Kr1[Common_length]; Kf1[i] = Kf1[Common_length]; end // for loop //----------------------------------------------------------------------- // End of Common_time / Common_wfm / Kcoef "function" //======================================================================= //======================================================================= // Initialize logic state variables //----------------------------------------------------------------------- if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find initial logic state pd_off = 1; pd_on = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pd_off = 0; pd_on = 1; end else if ((V(En_D) < Vth)) begin pd_off = 1; pd_on = 0; end else begin pd_off = 0; pd_on = 1; end //======================================================================= end // @(initial_step) //========================================================================= // Catch: process to catch threshold crossings in In_D, En_D //------------------------------------------------------------------------- @(cross(V(In_D)-Vth, 0, 100p, 0.5) or cross(V(En_D)-Vth, 0, 100p, 0.5)) begin if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find logic state pd_off = 1; pd_on = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pd_off = 0; pd_on = 1; end else if ((V(En_D) < Vth)) begin pd_off = 1; pd_on = 0; end else begin pd_off = 0; pd_on = 1; end end //------------------------------------------------------------------------- // Save time of event when In_D or En_D changed //------------------------------------------------------------------------- @(cross(pd_on-0.5, 0)) begin Tpd_on_event = $abstime; //$strobe("\nPD_ON = %d\tTpd_on = %e\tTpd_off = %e", pd_on, Tpd_on_event, Tpd_off_event); end @(cross(pd_off-0.5, 0)) begin Tpd_off_event = $abstime; //$strobe("\nPD_OFF = %d\tTpd_on = %e\tTpd_off = %e", pd_off, Tpd_on_event, Tpd_off_event); end //------------------------------------------------------------------------- // End of process Catch; //========================================================================= //========================================================================= // This section contains the simultaneous analog equations to find the // appropriate scaling coefficients according to the state the buffer. //------------------------------------------------------------------------- if (Tpd_on_event == 0.0 && Tpd_off_event == 0.0) begin // Initialization if (pd_on == 1) begin // Start with the end of the Kpd = Kf1[Common_length]; // Vt curves for those which end else if (pd_off == 1) begin // are fully on initially Kpd = Kr1[Common_length]; end else begin Kpd = 0.0; end end else begin // Look up coefficients in normal operation if (pd_on == 1) Kpd = $table_model($abstime - Tpd_on_event, T_common, Kf1, "LL"); else if (pd_off == 1) Kpd = $table_model($abstime - Tpd_off_event, T_common, Kr1, "LL"); else Kpd = Kf1[1]; end //========================================================================= // This section contains the analog expressions which calculate // the output currents of the IV curves and C_comp capacitors. //------------------------------------------------------------------------- I(pc) <+ -$table_model(V(pc), V_pc, I_pc, "LL") + k_C_comp_pc*C_comp*ddt(V(pc)); I(pu) <+ k_C_comp_pu*C_comp*ddt(V(pu)); I(pd) <+ Kpd * $table_model(V(pd), V_pd, I_pd, "LL") + k_C_comp_pd*C_comp*ddt(V(pd)); I(gc) <+ $table_model(V(gc), V_gc, I_gc, "LL") + k_C_comp_gc*C_comp*ddt(V(gc)); //------------------------------------------------------------------------- // A simple receiver logic //------------------------------------------------------------------------- if (V(pd) > Vinh) V(Rcv_D) <+ 1.0; else if (V(pd) < Vinl) V(Rcv_D) <+ 0.0; else V(Rcv_D) <+ 0.5; //------------------------------------------------------------------------- end endmodule // IBIS_IO_OpenSink //============================================================================= //============================================================================= module IBIS_OPENSOURCE (PU_ref, PD_ref, IO, In_D, En_D, PC_ref, GC_ref); input In_D, En_D; electrical In_D, En_D; inout IO, PC_ref, PU_ref, PD_ref, GC_ref; electrical IO, PC_ref, PU_ref, PD_ref, GC_ref; branch (PC_ref, IO) pc; // branches driven in model branch (PU_ref, IO) pu; branch (IO, PD_ref) pd; branch (IO, GC_ref) gc; parameter real //--------------------------------------------------------------------------- // IBIS parameters //--------------------------------------------------------------------------- C_comp = 5.0p, // Default C_comp value k_C_comp_pc = 0.25, // C_comp splitting coefficients k_C_comp_pu = 0.25, k_C_comp_pd = 0.25, k_C_comp_gc = 0.25, V_pc_ref = 5.0, // Power clamp reference voltage V_pu_ref = 5.0, // Pullup reference voltage V_gc_ref = 0.0; // Ground clamp reference voltage //--------------------------------------------------------------------------- // Vectors of the IV curve tables //--------------------------------------------------------------------------- parameter integer IVpc_length = 4, IVpu_length = 4, IVgc_length = 4; parameter real I_pc[1:IVpc_length] = { 0.08, 0.00, 0.00, 0.00}, V_pc[1:IVpc_length] = {-5.00, -1.00, 5.00, 10.00}, I_pu[1:IVpu_length] = { 0.10, 0.00, -0.10, -0.20}, V_pu[1:IVpu_length] = {-5.00, 0.00, 5.00, 10.00}, I_gc[1:IVgc_length] = {-0.08, 0.00, 0.00, 0.00}, V_gc[1:IVgc_length] = {-5.00, -1.00, 5.00, 10.00}; //--------------------------------------------------------------------------- // Vectors of the Vt curve tables //--------------------------------------------------------------------------- parameter integer VTr1_length = 4, VTf1_length = 4; parameter real Vr1[1:VTr1_length] = {0.00, 0.00, 2.50, 2.50}, Tr1[1:VTr1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}, Vf1[1:VTf1_length] = {2.50, 2.50, 0.00, 0.00}, Tf1[1:VTf1_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}; //--------------------------------------------------------------------------- parameter real Vfx_r1 = 0.0, // V_fixture values Vfx_f1 = 0.0, Rfx_r1 = 50.0 from (0:inf), // R_fixture values Rfx_f1 = 50.0 from (0:inf), //=========================================================================== // Non-IBIS parameters //--------------------------------------------------------------------------- Max_dt = 1.0e-12 from (0:inf), // Maximum dt between time points Vth = 0.5; // Logic input threshold voltage //--------------------------------------------------------------------------- // Internal variables //--------------------------------------------------------------------------- // Calculate maximum array length for common time and K_*** tables // and declare the arrays //--------------------------------------------------------------------------- // parameter real Max_t = max(max(max(Tr1[VTr1_length], Tr2[VTr2_length]), Tf1[VTf1_length]), Tf2[VTf2_length]); // parameter real Min_t = min(min(min( Tr1[1], Tr2[1]), Tf1[1]), Tf2[1]); // parameter integer Max_length = ceil((Max_t-Min_t)/Max_dt) + VTr1_length + VTr2_length + VTf1_length + VTf2_length; parameter integer Max_length = 3016; // Delete this when the above 3 lines work real T_common[1:Max_length]; // Common time axis array real Kr1[1:Max_length]; // Scaling coefficient arrays real Kf1[1:Max_length]; integer pu_on; // Logic state variables integer pu_off; real Tpu_on_event; // Variables to store event time real Tpu_off_event; real Kpu; // Output current scaling coefficients //--------------------------------------------------------------------------- // variables used in Common_time / Common_wfm / Kcoef "function" //--------------------------------------------------------------------------- integer i; integer Common_length; integer index_r1; integer index_f1; integer new_index_r1; integer new_index_f1; real old_t; real new_t; real last_t; real additional_pts; real new_dt; real Vr1_common[1:3]; // Need 3 elements in order to do derivatives real Vf1_common[1:3]; real dVwfm_r1; real dVwfm_f1; real Iout1; real Ipu1; real Igc1; real Ipc1; //=========================================================================== analog begin @(initial_step) begin //======================================================================= // This "function" makes a common time axis for all Vt curves and // calculates the corresponding voltage points with linear interpolation // and/or linear extrapolation if necessary. After that it converts the // Vt curves to K coefficients which will be used in the analog equations // to scale the IV curves. The K coefficients are stored in arrays. //----------------------------------------------------------------------- // Initialize variables //----------------------------------------------------------------------- Common_length = 1; index_r1 = 1; index_f1 = 1; new_index_r1 = VTr1_length; new_index_f1 = VTf1_length; //----------------------------------------------------------------------- // Put the earliest time value of all given time vectors into "old_t" //----------------------------------------------------------------------- old_t = min(Tr1[1], Tf1[1]); //----------------------------------------------------------------------- // Put the latest time value of all given time vectors into "new_t" //----------------------------------------------------------------------- last_t = max(Tr1[VTr1_length], Tf1[VTf1_length]); new_t = last_t; //----------------------------------------------------------------------- // Loop until latest time value is reached in each given time vector //----------------------------------------------------------------------- while (old_t < new_t) begin //--------------------------------------------------------------------- // Save the time value from old_t in T_common // and increment Common_length counter //--------------------------------------------------------------------- T_common[Common_length] = old_t; Common_length = Common_length + 1; //--------------------------------------------------------------------- // Find which given time vector(s) have the lowest time value and // advance their temporary indexes //--------------------------------------------------------------------- if (Tr1[index_r1] <= old_t) new_index_r1 = index_r1 + 1; if (Tf1[index_f1] <= old_t) new_index_f1 = index_f1 + 1; //--------------------------------------------------------------------- // Find the lowest value at the new indexes in the given vector(s) // and update indexes for next iteration //--------------------------------------------------------------------- if (new_index_r1 <= VTr1_length) begin if (Tr1[new_index_r1] < new_t) new_t = Tr1[new_index_r1]; index_r1 = new_index_r1; end if (new_index_f1 <= VTf1_length) begin if (Tf1[new_index_f1] < new_t) new_t = Tf1[new_index_f1]; index_f1 = new_index_f1; end //--------------------------------------------------------------------- // Add points if dt is larger than Max_dt //--------------------------------------------------------------------- if ((new_t-old_t) > Max_dt) begin additional_pts = ceil((new_t-old_t)/Max_dt); new_dt = (new_t-old_t) / additional_pts; for (i = 1; i < additional_pts; i = i + 1) begin //$strobe("\ndif = %e\tAdd = %d\tCL = %d\t T = %e\tnew_dt = ", (new_t-old_t), additional_pts, Common_length, T_common[Common_length-1]+new_dt, new_dt); T_common[Common_length] = T_common[Common_length-1] + new_dt; Common_length = Common_length + 1; end end //--------------------------------------------------------------------- // Update variables for next iteration //--------------------------------------------------------------------- old_t = new_t; new_t = last_t; //--------------------------------------------------------------------- end // while loop T_common[Common_length] = last_t; //======================================================================= //======================================================================= // Calculate the scaling coefficients for each time point along T_common //----------------------------------------------------------------------- // Store the first voltage point in the common waveform variables //----------------------------------------------------------------------- Vr1_common[2] = $table_model(T_common[1], Tr1, Vr1, "LL"); Vf1_common[2] = $table_model(T_common[1], Tf1, Vf1, "LL"); for (i = 1; i <= Common_length; i = i + 1) begin //----------------------------------------------------------------------- // Store the next point (for the derivative calculations) //----------------------------------------------------------------------- if (i < Common_length) begin Vr1_common[3] = $table_model(T_common[i+1], Tr1, Vr1, "LL"); Vf1_common[3] = $table_model(T_common[i+1], Tf1, Vf1, "LL"); end //$strobe("\nTcom = %e\tR1 = %e\tF1 = %e", T_common[i], Vr1_common[2], Vf1_common[2]); //--------------------------------------------------------------------- // Calculate the derivative of each waveform for C_comp compensation //--------------------------------------------------------------------- if ((i <= 1) || (i >= Common_length)) begin dVwfm_r1 = 0.0; // Force the end point derivatives to zero dVwfm_f1 = 0.0; end else begin dVwfm_r1 = ((Vr1_common[2] - Vr1_common[1]) / (T_common[i] - T_common[i-1]) + (Vr1_common[3] - Vr1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f1 = ((Vf1_common[2] - Vf1_common[1]) / (T_common[i] - T_common[i-1]) + (Vf1_common[3] - Vf1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; end //$strobe("dR1 = %e\tdF1 = %e", dVwfm_r1, dVwfm_f1); //--------------------------------------------------------------------- // Calculate intermediate variables and the Kr1 coefficients //--------------------------------------------------------------------- Iout1 = ((Vr1_common[2] - Vfx_r1) / Rfx_r1) + C_comp * dVwfm_r1; Ipc1 = -1.0 * $table_model(V_pc_ref - Vr1_common[2], V_pc, I_pc, "LL"); Ipu1 = $table_model(V_pu_ref - Vr1_common[2], V_pu, I_pu, "LL"); Igc1 = $table_model(Vr1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); // Since these is a rising waveform Kr1 == Kpu_on if (Ipu1 == 0) Kr1[i] = 0.0; else Kr1[i] = (Ipc1 - Igc1 - Iout1) / Ipu1; //--------------------------------------------------------------------- // Calculate intermediate variables and the Kf1 coefficients //--------------------------------------------------------------------- Iout1 = ((Vf1_common[2] - Vfx_f1) / Rfx_f1) + C_comp * dVwfm_f1; Ipc1 = -1.0 * $table_model(V_pc_ref - Vf1_common[2], V_pc, I_pc, "LL"); Ipu1 = $table_model(V_pu_ref - Vf1_common[2], V_pu, I_pu, "LL"); Igc1 = $table_model(Vf1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); // Since these is a falling waveform Kf1 == Kpu_off if (Ipu1 == 0) Kf1[i] = 0.0; else Kf1[i] = (Ipc1 - Igc1 - Iout1) / Ipu1; //$strobe("\nTcom = %e\tKr1 = %e\tKf1 = %e", T_common[i], Kr1[i], Kf1[i]); //--------------------------------------------------------------------- // Shift points by one index for next iteration (for C_comp compensation) //--------------------------------------------------------------------- Vr1_common[1] = Vr1_common[2]; Vf1_common[1] = Vf1_common[2]; Vr1_common[2] = Vr1_common[3]; Vf1_common[2] = Vf1_common[3]; end // for loop //----------------------------------------------------------------------- // Fill the unused portion of the arrays with reasonable values // to prevent any misbehaving later with $table_model //======================================================================= for (i = Common_length + 1; i <= Max_length; i = i + 1) begin T_common[i] = T_common[i-1] + Max_dt; Kr1[i] = Kr1[Common_length]; Kf1[i] = Kf1[Common_length]; end // for loop //----------------------------------------------------------------------- // End of Common_time / Common_wfm / Kcoef "function" //======================================================================= //======================================================================= // Initialize logic state variables //----------------------------------------------------------------------- if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find initial logic state pu_on = 1; pu_off = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pu_on = 0; pu_off = 1; end else if ((V(En_D) < Vth)) begin pu_on = 1; pu_off = 0; end else begin pu_on = 0; pu_off = 1; end //======================================================================= end // @(initial_step) //========================================================================= // Catch: process to catch threshold crossings in In_D, En_D //------------------------------------------------------------------------- @(cross(V(In_D)-Vth, 0, 100p, 0.5) or cross(V(En_D)-Vth, 0, 100p, 0.5)) begin if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find logic state pu_on = 1; pu_off = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pu_on = 0; pu_off = 1; end else if ((V(En_D) < Vth)) begin pu_on = 1; pu_off = 0; end else begin pu_on = 0; pu_off = 1; end end //------------------------------------------------------------------------- // Save time of event when In_D or En_D changed //------------------------------------------------------------------------- @(cross(pu_on-0.5, 0)) begin Tpu_on_event = $abstime; //$strobe("\nPU_ON = %d\tTpu_on = %e\tTpu_off = %e", pu_on, Tpu_on_event, Tpu_off_event); end @(cross(pu_off-0.5, 0)) begin Tpu_off_event = $abstime; //$strobe("\nPU_OFF = %d\tTpu_on = %e\tTpu_off = %e", pu_off, Tpu_on_event, Tpu_off_event); end //------------------------------------------------------------------------- // End of process Catch; //========================================================================= //========================================================================= // 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 && Tpu_off_event == 0.0) begin // Initialization if (pu_on == 1) begin // Start with the end of the Kpu = Kr1[Common_length]; // Vt curves for those which end else if (pu_off == 1) begin // are fully on initially Kpu = Kf1[Common_length]; end else begin Kpu = 0.0; end end else begin // Look up coefficients in normal operation if (pu_on == 1) Kpu = $table_model($abstime - Tpu_on_event, T_common, Kr1, "LL"); else if (pu_off == 1) Kpu = $table_model($abstime - Tpu_off_event, T_common, Kf1, "LL"); else Kpu = Kf1[1]; end //========================================================================= // This section contains the analog expressions which calculate // the output currents of the IV curves and C_comp capacitors. //------------------------------------------------------------------------- I(pc) <+ -$table_model(V(pc), V_pc, I_pc, "LL") + k_C_comp_pc*C_comp*ddt(V(pc)); I(pu) <+ Kpu * -$table_model(V(pu), V_pu, I_pu, "LL") + k_C_comp_pu*C_comp*ddt(V(pu)); I(pd) <+ k_C_comp_pd*C_comp*ddt(V(pd)); I(gc) <+ $table_model(V(gc), V_gc, I_gc, "LL") + k_C_comp_gc*C_comp*ddt(V(gc)); //------------------------------------------------------------------------- end endmodule // IBIS_OpenSource //============================================================================= //============================================================================= module IBIS_IO_OPENSOURCE (PU_ref, PD_ref, IO, In_D, En_D, Rcv_D, PC_ref, GC_ref); input In_D, En_D; electrical In_D, En_D; output Rcv_D; electrical Rcv_D; inout IO, PC_ref, PU_ref, PD_ref, GC_ref; electrical IO, PC_ref, PU_ref, PD_ref, GC_ref; branch (PC_ref, IO) pc; // branches driven in model branch (PU_ref, IO) pu; branch (IO, PD_ref) pd; branch (IO, GC_ref) gc; parameter real //--------------------------------------------------------------------------- // IBIS parameters //--------------------------------------------------------------------------- C_comp = 5.0p, // Default C_comp value k_C_comp_pc = 0.25, // C_comp splitting coefficients k_C_comp_pu = 0.25, k_C_comp_pd = 0.25, k_C_comp_gc = 0.25, Vinh = 2.0, // Default Vinh value Vinl = 0.8, // Default Vinl value V_pc_ref = 5.0, // Power clamp reference voltage V_pu_ref = 5.0, // Pullup reference voltage V_gc_ref = 0.0; // Ground clamp reference voltage //--------------------------------------------------------------------------- // Vectors of the IV curve tables //--------------------------------------------------------------------------- parameter integer IVpc_length = 4, IVpu_length = 4, IVgc_length = 4; parameter real I_pc[1:IVpc_length] = { 0.08, 0.00, 0.00, 0.00}, V_pc[1:IVpc_length] = {-5.00, -1.00, 5.00, 10.00}, I_pu[1:IVpu_length] = { 0.10, 0.00, -0.10, -0.20}, V_pu[1:IVpu_length] = {-5.00, 0.00, 5.00, 10.00}, I_gc[1:IVgc_length] = {-0.08, 0.00, 0.00, 0.00}, V_gc[1:IVgc_length] = {-5.00, -1.00, 5.00, 10.00}; //--------------------------------------------------------------------------- // Vectors of the Vt curve tables //--------------------------------------------------------------------------- parameter integer VTr1_length = 4, VTf1_length = 4; parameter real Vr1[1:VTr1_length] = {0.00, 0.00, 2.50, 2.50}, Tr1[1:VTr1_length] = {0.00, 1.00e-9, 2.00e-9, 3.00e-9}, Vf1[1:VTf1_length] = {2.50, 2.50, 0.00, 0.00}, Tf1[1:VTf1_length] = {0.00, 0.50e-9, 0.80e-9, 3.00e-9}; //--------------------------------------------------------------------------- parameter real Vfx_r1 = 0.0, // V_fixture values Vfx_f1 = 0.0, Rfx_r1 = 50.0 from (0:inf), // R_fixture values Rfx_f1 = 50.0 from (0:inf), //=========================================================================== // Non-IBIS parameters //--------------------------------------------------------------------------- Max_dt = 1.0e-12 from (0:inf), // Maximum dt between time points Vth = 0.5; // Logic input threshold voltage //--------------------------------------------------------------------------- // Internal variables //--------------------------------------------------------------------------- // Calculate maximum array length for common time and K_*** tables // and declare the arrays //--------------------------------------------------------------------------- // parameter real Max_t = max(max(max(Tr1[VTr1_length], Tr2[VTr2_length]), Tf1[VTf1_length]), Tf2[VTf2_length]); // parameter real Min_t = min(min(min( Tr1[1], Tr2[1]), Tf1[1]), Tf2[1]); // parameter integer Max_length = ceil((Max_t-Min_t)/Max_dt) + VTr1_length + VTr2_length + VTf1_length + VTf2_length; parameter integer Max_length = 3016; // Delete this when the above 3 lines work real T_common[1:Max_length]; // Common time axis array real Kr1[1:Max_length]; // Scaling coefficient arrays real Kf1[1:Max_length]; integer pu_on; // Logic state variables integer pu_off; real Tpu_on_event; // Variables to store event time real Tpu_off_event; real Kpu; // Output current scaling coefficients //--------------------------------------------------------------------------- // variables used in Common_time / Common_wfm / Kcoef "function" //--------------------------------------------------------------------------- integer i; integer Common_length; integer index_r1; integer index_f1; integer new_index_r1; integer new_index_f1; real old_t; real new_t; real last_t; real additional_pts; real new_dt; real Vr1_common[1:3]; // Need 3 elements in order to do derivatives real Vf1_common[1:3]; real dVwfm_r1; real dVwfm_f1; real Iout1; real Ipu1; real Igc1; real Ipc1; //=========================================================================== analog begin @(initial_step) begin //======================================================================= // This "function" makes a common time axis for all Vt curves and // calculates the corresponding voltage points with linear interpolation // and/or linear extrapolation if necessary. After that it converts the // Vt curves to K coefficients which will be used in the analog equations // to scale the IV curves. The K coefficients are stored in arrays. //----------------------------------------------------------------------- // Initialize variables //----------------------------------------------------------------------- Common_length = 1; index_r1 = 1; index_f1 = 1; new_index_r1 = VTr1_length; new_index_f1 = VTf1_length; //----------------------------------------------------------------------- // Put the earliest time value of all given time vectors into "old_t" //----------------------------------------------------------------------- old_t = min(Tr1[1], Tf1[1]); //----------------------------------------------------------------------- // Put the latest time value of all given time vectors into "new_t" //----------------------------------------------------------------------- last_t = max(Tr1[VTr1_length], Tf1[VTf1_length]); new_t = last_t; //----------------------------------------------------------------------- // Loop until latest time value is reached in each given time vector //----------------------------------------------------------------------- while (old_t < new_t) begin //--------------------------------------------------------------------- // Save the time value from old_t in T_common // and increment Common_length counter //--------------------------------------------------------------------- T_common[Common_length] = old_t; Common_length = Common_length + 1; //--------------------------------------------------------------------- // Find which given time vector(s) have the lowest time value and // advance their temporary indexes //--------------------------------------------------------------------- if (Tr1[index_r1] <= old_t) new_index_r1 = index_r1 + 1; if (Tf1[index_f1] <= old_t) new_index_f1 = index_f1 + 1; //--------------------------------------------------------------------- // Find the lowest value at the new indexes in the given vector(s) // and update indexes for next iteration //--------------------------------------------------------------------- if (new_index_r1 <= VTr1_length) begin if (Tr1[new_index_r1] < new_t) new_t = Tr1[new_index_r1]; index_r1 = new_index_r1; end if (new_index_f1 <= VTf1_length) begin if (Tf1[new_index_f1] < new_t) new_t = Tf1[new_index_f1]; index_f1 = new_index_f1; end //--------------------------------------------------------------------- // Add points if dt is larger than Max_dt //--------------------------------------------------------------------- if ((new_t-old_t) > Max_dt) begin additional_pts = ceil((new_t-old_t)/Max_dt); new_dt = (new_t-old_t) / additional_pts; for (i = 1; i < additional_pts; i = i + 1) begin //$strobe("\ndif = %e\tAdd = %d\tCL = %d\t T = %e\tnew_dt = ", (new_t-old_t), additional_pts, Common_length, T_common[Common_length-1]+new_dt, new_dt); T_common[Common_length] = T_common[Common_length-1] + new_dt; Common_length = Common_length + 1; end end //--------------------------------------------------------------------- // Update variables for next iteration //--------------------------------------------------------------------- old_t = new_t; new_t = last_t; //--------------------------------------------------------------------- end // while loop T_common[Common_length] = last_t; //======================================================================= //======================================================================= // Calculate the scaling coefficients for each time point along T_common //----------------------------------------------------------------------- // Store the first voltage point in the common waveform variables //----------------------------------------------------------------------- Vr1_common[2] = $table_model(T_common[1], Tr1, Vr1, "LL"); Vf1_common[2] = $table_model(T_common[1], Tf1, Vf1, "LL"); for (i = 1; i <= Common_length; i = i + 1) begin //----------------------------------------------------------------------- // Store the next point (for the derivative calculations) //----------------------------------------------------------------------- if (i < Common_length) begin Vr1_common[3] = $table_model(T_common[i+1], Tr1, Vr1, "LL"); Vf1_common[3] = $table_model(T_common[i+1], Tf1, Vf1, "LL"); end //$strobe("\nTcom = %e\tR1 = %e\tF1 = %e", T_common[i], Vr1_common[2], Vf1_common[2]); //--------------------------------------------------------------------- // Calculate the derivative of each waveform for C_comp compensation //--------------------------------------------------------------------- if ((i <= 1) || (i >= Common_length)) begin dVwfm_r1 = 0.0; // Force the end point derivatives to zero dVwfm_f1 = 0.0; end else begin dVwfm_r1 = ((Vr1_common[2] - Vr1_common[1]) / (T_common[i] - T_common[i-1]) + (Vr1_common[3] - Vr1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; dVwfm_f1 = ((Vf1_common[2] - Vf1_common[1]) / (T_common[i] - T_common[i-1]) + (Vf1_common[3] - Vf1_common[2]) / (T_common[i+1] - T_common[i])) / 2.0; end //$strobe("dR1 = %e\tdF1 = %e", dVwfm_r1, dVwfm_f1); //--------------------------------------------------------------------- // Calculate intermediate variables and the Kr1 coefficients //--------------------------------------------------------------------- Iout1 = ((Vr1_common[2] - Vfx_r1) / Rfx_r1) + C_comp * dVwfm_r1; Ipc1 = -1.0 * $table_model(V_pc_ref - Vr1_common[2], V_pc, I_pc, "LL"); Ipu1 = $table_model(V_pu_ref - Vr1_common[2], V_pu, I_pu, "LL"); Igc1 = $table_model(Vr1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); // Since these is a rising waveform Kr1 == Kpu_on if (Ipu1 == 0) Kr1[i] = 0.0; else Kr1[i] = (Ipc1 - Igc1 - Iout1) / Ipu1; //--------------------------------------------------------------------- // Calculate intermediate variables and the Kf1 coefficients //--------------------------------------------------------------------- Iout1 = ((Vf1_common[2] - Vfx_f1) / Rfx_f1) + C_comp * dVwfm_f1; Ipc1 = -1.0 * $table_model(V_pc_ref - Vf1_common[2], V_pc, I_pc, "LL"); Ipu1 = $table_model(V_pu_ref - Vf1_common[2], V_pu, I_pu, "LL"); Igc1 = $table_model(Vf1_common[2] - V_gc_ref, V_gc, I_gc, "LL"); // Since these is a falling waveform Kf1 == Kpu_off if (Ipu1 == 0) Kf1[i] = 0.0; else Kf1[i] = (Ipc1 - Igc1 - Iout1) / Ipu1; //$strobe("\nTcom = %e\tKr1 = %e\tKf1 = %e", T_common[i], Kr1[i], Kf1[i]); //--------------------------------------------------------------------- // Shift points by one index for next iteration (for C_comp compensation) //--------------------------------------------------------------------- Vr1_common[1] = Vr1_common[2]; Vf1_common[1] = Vf1_common[2]; Vr1_common[2] = Vr1_common[3]; Vf1_common[2] = Vf1_common[3]; end // for loop //----------------------------------------------------------------------- // Fill the unused portion of the arrays with reasonable values // to prevent any misbehaving later with $table_model //======================================================================= for (i = Common_length + 1; i <= Max_length; i = i + 1) begin T_common[i] = T_common[i-1] + Max_dt; Kr1[i] = Kr1[Common_length]; Kf1[i] = Kf1[Common_length]; end // for loop //----------------------------------------------------------------------- // End of Common_time / Common_wfm / Kcoef "function" //======================================================================= //======================================================================= // Initialize logic state variables //----------------------------------------------------------------------- if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find initial logic state pu_on = 1; pu_off = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pu_on = 0; pu_off = 1; end else if ((V(En_D) < Vth)) begin pu_on = 1; pu_off = 0; end else begin pu_on = 0; pu_off = 1; end //======================================================================= end // @(initial_step) //========================================================================= // Catch: process to catch threshold crossings in In_D, En_D //------------------------------------------------------------------------- @(cross(V(In_D)-Vth, 0, 100p, 0.5) or cross(V(En_D)-Vth, 0, 100p, 0.5)) begin if ((V(En_D) > Vth) && (V(In_D) > Vth)) begin // Find logic state pu_on = 1; pu_off = 0; end else if ((V(En_D) > Vth) && (V(In_D) < Vth)) begin pu_on = 0; pu_off = 1; end else if ((V(En_D) < Vth)) begin pu_on = 1; pu_off = 0; end else begin pu_on = 0; pu_off = 1; end end //------------------------------------------------------------------------- // Save time of event when In_D or En_D changed //------------------------------------------------------------------------- @(cross(pu_on-0.5, 0)) begin Tpu_on_event = $abstime; //$strobe("\nPU_ON = %d\tTpu_on = %e\tTpu_off = %e", pu_on, Tpu_on_event, Tpu_off_event); end @(cross(pu_off-0.5, 0)) begin Tpu_off_event = $abstime; //$strobe("\nPU_OFF = %d\tTpu_on = %e\tTpu_off = %e", pu_off, Tpu_on_event, Tpu_off_event); end //------------------------------------------------------------------------- // End of process Catch; //========================================================================= //========================================================================= // 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 && Tpu_off_event == 0.0) begin // Initialization if (pu_on == 1) begin // Start with the end of the Kpu = Kr1[Common_length]; // Vt curves for those which end else if (pu_off == 1) begin // are fully on initially Kpu = Kf1[Common_length]; end else begin Kpu = 0.0; end end else begin // Look up coefficients in normal operation if (pu_on == 1) Kpu = $table_model($abstime - Tpu_on_event, T_common, Kr1, "LL"); else if (pu_off == 1) Kpu = $table_model($abstime - Tpu_off_event, T_common, Kf1, "LL"); else Kpu = Kf1[1]; end //========================================================================= // This section contains the analog expressions which calculate // the output currents of the IV curves and C_comp capacitors. //------------------------------------------------------------------------- I(pc) <+ -$table_model(V(pc), V_pc, I_pc, "LL") + k_C_comp_pc*C_comp*ddt(V(pc)); I(pu) <+ Kpu * -$table_model(V(pu), V_pu, I_pu, "LL") + k_C_comp_pu*C_comp*ddt(V(pu)); I(pd) <+ k_C_comp_pd*C_comp*ddt(V(pd)); I(gc) <+ $table_model(V(gc), V_gc, I_gc, "LL") + k_C_comp_gc*C_comp*ddt(V(gc)); //------------------------------------------------------------------------- // A simple receiver logic //------------------------------------------------------------------------- if (V(pd) > Vinh) V(Rcv_D) <+ 1.0; else if (V(pd) < Vinl) V(Rcv_D) <+ 0.0; else V(Rcv_D) <+ 0.5; //------------------------------------------------------------------------- end endmodule // IBIS_IO_OpenSource //============================================================================= //============================================================================= ////******************************************************************** //// Separate module for each N-coupled tline ... ////******************************************************************** //module ibis_buffer_series // inout pad1, pad2 ; // electrical pad1, pad2 ; // parameter string ibis_file ; // parameter string ibis_model ; // // TBD: implementation //endmodule ////******************************************************************** //module ibis_sparam2 (a1, b1, ref1, a2, b2, ref2) ; // inout a1, b1, ref1, a2, b2, ref2 ; // electrical a1, b1, ref1, a2, b2, ref2 ; // parameter string tstone_file ; // // TBD: implementation //endmodule ////********************************************************************