Tcl SpiceGenTcl package (v)

TipsTop, Main, Index

This page contains different tips that help you to use SpiceGenTcl more efficiently.

Define custom elementTop, Main, Index

To define custom element class we should use ::SpiceGenTcl::Device class as a superclass. Why we need this? One simple example is custom Verilog-A device, that could have arbitary number of pins and parameters. Let's try to define new element for next Verilog-A device:

module core(p,n);
magnetic p, n;
parameter real len=0.1 from (0:1000);   // effective magnetic length of core
parameter real area=1 from (0:inf);     // magnetic cross-sectional area of core
parameter real ms=1.6M from (0:inf);    // saturation magnetization
parameter real a=1100 from (0:inf);     // 
parameter real k=2000 from (0:inf);     // bulk coupliing coefficient
parameter real alpha=1.6m from (0:inf); // interdomain coupling coef.
parameter real c=0.2 from [0:1];        // coef. for reversable magnetization
magnetic Hdot;          // internal Hdot node
real H;                 // field intensity
real B;                 // flux density
real Manh;              // anhysteric magnetization
real Mirr;              // irreversible magnetization
real dMirr;             // dMirr/dH
real M;                 // total magnetization
real Heff;              // effective field intensity
integer delta;          // direction of the input MMF
integer migrating;      // flag indicating that the pinning sites are moving
// sign function
    analog function integer sign;
input arg;
real arg;
sign = (arg >= 0.0 ? 1 : -1);
    endfunction
// hyperbolic cotangent function
    analog function real coth;
input arg;
real arg;
real x;
begin
    x = exp(min(80,max(-80,arg)));
    coth = (x+1/x)/(x-1/x);
end
    endfunction
// core model
    analog begin
H = MMF(p,n) / len;
MMF(Hdot) <+ ddt(H);
delta = sign(MMF(Hdot));
B = Phi(p,n)/area;
M = B/`P_U0 - H;
Heff = H + alpha * M;
if (abs(Heff) > 0.001 * a) 
    Manh = ms * (coth(Heff/a) - a/Heff);
else
    Manh = ms * Heff/(3.0*a);   // Taylor series expansion of coth()
dMirr = (Manh - M)/(delta*k - alpha*(Manh - M)) * MMF(Hdot);
migrating = (delta > 0) ^ (M > Manh);
Mirr = idt( migrating * dMirr, Manh );
M = (1-c)*Mirr + c*Manh;
Phi(p,n) <+ area*`P_U0*(H+M);
    end
endmodule

This model is taken from designers-guide, that contains many Verilog-AMS models.

oo::class create Core {
    superclass ::SpiceGenTcl::Device
    mixin ::SpiceGenTcl::KeyArgsBuilder
    constructor {name pNode nNode args} {
        set paramsNames [list len area ms a k alpha c]
        set paramDefList [my buildArgStr $paramsNames]
        set arguments [argparse -inline "
            {-model= -required}
            $paramDefList
        "]
        lappend params "model [dict get $arguments model] -posnocheck"
        dict for {paramName value} $arguments {
            if {$paramName!="model"} {
                lappend params "$paramName $value"
            }
        }
        next n$name [list "p $pNode" "n $nNode"] $params
    }
}

In this block of code we define instance class of core. Let's go through the each line. First line is class definition:

oo::class create Core

It is good convention to start class name from capital letter.

Superclass for new element is ::SpiceGenTcl::Device:

superclass SpiceGenTcl::Device

We use mixin class ::SpiceGenTcl::KeyArgsBuilder to add it's method ::SpiceGenTcl::KeyArgsBuilder::buildArgStr, that helps to build arguments list for argparse package.

In next line we define arguments for constructor:

constructor {name pNode nNode args}

First argument is name of instance, then positive node and negative node names, args accepts model value after -model key and all optional parameters of device.

In these few lines we process args variable with argparse package:

set paramsNames [list len area ms a k alpha c]
set paramDefList [my buildArgStr $paramsNames]
set arguments [argparse -inline "
    {-model= -required}
    $paramDefList
"]

List [list len area ms a k alpha c] contains all parameters we have in core verilog-a model. Due to these line we can pass parameters to element in forms -paramName $paramValue $paramQual, for example: -area 1e-4 or -area l*m -eq.

Possible qualificator is -eq - it means that parameter should be inserted into SPICE netlist as paramName={expression}

In the next few lines we build parameter list that will be passed to ::SpiceGenTcl::Device constructor:

lappend params "model [dict get $arguments model] -posnocheck"
dict for {paramName value} $arguments {
    if {$paramName!="model"} {
        lappend params "$paramName $value"
    }
}

The last but not the least is step of passing arguments to ::SpiceGenTcl::Device constructor:

next n$name [list "p $pNode" "n $nNode"] $params

This superclass accept arguments in form constructor {name pins modelName instParams}. So, we pass string n$name as device name, n is reference designator for verilog-a devices in ngspice. Secondly we pass list of nodes [list "p $pNode" "n $nNode"] in form of {{Name0 NodeName} {Name1 NodeName} {Name2 NodeName} ...}. And the last is list of parameters in form {{model Value -posnocheck} {Name Value ?-eq?} {Name Value ?-eq?} {Name Value ?-eq?} ...}.

So, after that we can create a new instance of newly created class:

set coreInst [Core new 1 p n -model coreModel -area 1e-4 -len {l*5 -eq}]
puts [$coreInst genSPICEString]

Resulted SPICE string is:

n1 p n coreModel area=1e-4 len={l*5}