SpiceInputGenImpl:
CEDAR
PROGRAM
IMPORTS
Convert, CoreFlat, CoreOps, CoreClasses, CoreProperties, ElectricalCoreClasses, IO, RefTab, Real, Rope, SpiceOps, SymTab, TerminalIO
= BEGIN
ConvData: TYPE = SpiceOps.ConvData;
ROPE: TYPE = Rope.ROPE;
CellType: TYPE = Core.CellType;
FlatWire: TYPE = CoreFlat.FlatWire;
FlatCellProc: TYPE = PROC [cell: Core.CellType, target: CoreFlat.FlatCellTypeRec ← CoreFlat.allFlatCells, flatCell: CoreFlat.FlatCellTypeRec ← [], instance: CoreClasses.CellInstance ← NIL, parent: Core.CellType ← NIL, flatParent: CoreFlat.FlatCellTypeRec ← [], data: REF ANY ← NIL, wireName: RefTab.Ref];
constants
lineLength: NAT = 80;
sep: ROPE ← " ";
infinity: NAT = LAST[NAT];
femto: REAL = 1e-15;
pico: REAL = 1e-12;
nano: REAL = 1e-9;
micro: REAL = 1e-6;
mili: REAL = 1e-3;
kilo: REAL = 1e3;
mega: REAL = 1e6;
giga: REAL = 1e9;
tera: REAL = 1e12;
defaultIndex: NAT ← LAST[NAT];
gndName: PUBLIC ROPE ← "public.Gnd";
vddName: PUBLIC ROPE ← "public.Vdd";
vddVal: REAL ← 5.0;
pModel: PUBLIC ROPE ← "VENPT";
nModel: PUBLIC ROPE ← "VENHT";
diodeModel: PUBLIC ROPE ← "D";
npnModel: PUBLIC ROPE ← "NPN";
pnpModel: PUBLIC ROPE ← "PNP";
modelTable: PUBLIC SymTab.Ref ← SymTab.Create[];
temp: PUBLIC REAL ← 27.0;
fetDifLength: REAL ← 5.0; --microns
spiceModel: PUBLIC ATOM ← CoreProperties.RegisterProperty[$SpiceOpsModel, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
spiceOptions: PUBLIC ATOM ← CoreProperties.RegisterProperty[$SpiceOpsOptions, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
analysisType: PUBLIC ATOM ← CoreProperties.RegisterProperty[$SpiceOpsAnalysis, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
spiceExtraLine: PUBLIC ATOM ← CoreProperties.RegisterProperty[$SpiceOpsExtraLine, CoreProperties.Props[[CoreProperties.propPrint, CoreProperties.PropDontPrint]]];
Elements to Spice input line procs
Comment:
PUBLIC PROC [convData: ConvData, comment:
ROPE] ~ {
WriteInstance[convData, Rope.Concat["* ", Rope.Substr[comment, 0, 78]]];
};
Resistor:
PUBLIC PROC [convData: ConvData, n1, n2: FlatWire, value:
REAL, tc1, tc2:
REAL ← 0.0] ~ {
res: ROPE ← Rope.Concat[base: "R", rest: NextInstanceId[convData]];
res ← Rope.Cat[res, WireId[convData, n1], WireId[convData, n2]];
res ← Rope.Concat[res, RealToRope[value, kilo]];
IF tc1#0.0 OR tc2#0.0 THEN res ← Rope.Cat[res, " TC=", RealToRope[tc1], ",", RealToRope[tc2]];
WriteInstance[convData, res];
};
Capacitor:
PUBLIC PROC [convData: ConvData, n1, n2: FlatWire, value:
REAL, incond:
REAL ← 0.0] ~ {
cap: ROPE ← Rope.Concat[base: "C", rest: NextInstanceId[convData]];
cap ← Rope.Cat[cap, WireId[convData, n1], WireId[convData, n2]];
cap ← Rope.Concat[cap, RealToRope[value, pico]];
IF incond#0.0 THEN cap ← Rope.Cat[cap, " IC=", RealToRope[incond]];
WriteInstance[convData, cap]
};
Inductor:
PUBLIC PROC [convData: ConvData, n1, n2: FlatWire, value:
REAL, incond:
REAL ← 0.0] ~ {
ind: ROPE ← Rope.Concat[base: "L", rest: NextInstanceId[convData]];
ind ← Rope.Cat[ind, WireId[convData, n1], WireId[convData, n2]];
ind ← Rope.Concat[ind, RealToRope[value, micro]];
IF incond#0.0 THEN ind ← Rope.Cat[ind, " IC=", RealToRope[incond]];
WriteInstance[convData, ind]
};
CoupledInductors:
PUBLIC PROC [convData: ConvData, n0, n1, n2, n3: FlatWire, l1, l2:
REAL, k:
REAL] ~ {
cind: ROPE ← Rope.Concat[base: "K", rest: NextInstanceId[convData]];
Inductor[convData, n0, n1, l1];
cind ← Rope.Cat[cind, "L", Convert.RopeFromCard[from: convData.nextId, showRadix: FALSE], " "];
Inductor[convData, n2, n3, l2];
cind ← Rope.Cat[cind, "L", Convert.RopeFromCard[from: convData.nextId, showRadix: FALSE], " "];
cind ← Rope.Concat[cind, RealToRope[k]];
WriteInstance[convData, cind]
};
LosslessLine:
PUBLIC PROC [convData: ConvData, n0, n1, n2, n3: FlatWire, z0:
REAL, td:
REAL] ~ {
lline: ROPE ← Rope.Concat[base: "T", rest: NextInstanceId[convData]];
lline ← Rope.Cat[lline, WireId[convData, n0], WireId[convData, n1]];
lline ← Rope.Cat[lline, WireId[convData, n2], WireId[convData, n3]];
lline ← Rope.Cat[lline, "Z0=", RealToRope[z0, kilo], "TD=", RealToRope[td, nano]];
WriteInstance[convData, lline]
};
Vccs:
PUBLIC PROC [convData: ConvData, n0, n1, n2, n3: FlatWire, value:
REAL] ~ {
lsource: ROPE ← Rope.Concat[base: "G", rest: NextInstanceId[convData]];
lsource ← Rope.Cat[lsource, WireId[convData, n0], WireId[convData, n1]];
lsource ← Rope.Cat[lsource, WireId[convData, n2], WireId[convData, n3]];
lsource ← Rope.Concat[lsource, RealToRope[value]];
WriteInstance[convData, lsource]
};
Vcvs:
PUBLIC PROC [convData: ConvData, n0, n1, n2, n3: FlatWire, value:
REAL] ~ {
lsource: ROPE ← Rope.Concat[base: "E", rest: NextInstanceId[convData]];
lsource ← Rope.Cat[lsource, WireId[convData, n0], WireId[convData, n1]];
lsource ← Rope.Cat[lsource, WireId[convData, n2], WireId[convData, n3]];
lsource ← Rope.Concat[lsource, RealToRope[value]];
WriteInstance[convData, lsource]
};
Cccs:
PUBLIC PROC [convData: ConvData, n0, n1, n2, n3: FlatWire, value:
REAL] ~ {
lsource: ROPE ← Rope.Concat[base: "F", rest: NextInstanceId[convData]];
lsource ← Rope.Cat[lsource, WireId[convData, n0], WireId[convData, n1]];
VSource[convData, n2, n3];
lsource ← Rope.Cat[lsource, "V", Convert.RopeFromCard[from: convData.nextId, showRadix: FALSE], " "];
lsource ← Rope.Concat[lsource, RealToRope[value]];
WriteInstance[convData, lsource]
};
Ccvs:
PUBLIC PROC [convData: ConvData, n0, n1, n2, n3: FlatWire, value:
REAL] ~ {
lsource: ROPE ← Rope.Concat[base: "H", rest: NextInstanceId[convData]];
lsource ← Rope.Cat[lsource, WireId[convData, n0], WireId[convData, n1]];
VSource[convData, n2, n3];
lsource ← Rope.Cat[lsource, "V", Convert.RopeFromCard[from: convData.nextId, showRadix: FALSE], " "];
lsource ← Rope.Concat[lsource, RealToRope[value]];
WriteInstance[convData, lsource]
};
Diode :
PUBLIC PROC [convData: ConvData, n1, n2: FlatWire, model:
ROPE, area:
REAL] ~ {
diode: ROPE ← Rope.Concat[base: "D", rest: NextInstanceId[convData]];
diode ← Rope.Cat[diode, WireId[convData, n1], WireId[convData, n2]];
diode ← Rope.Cat[diode, model, " "];
diode ← Rope.Concat[diode, RealToRope[area]];
WriteInstance[convData, diode]
};
BJT:
PUBLIC PROC [convData: ConvData, c, b, e: FlatWire, model:
ROPE, area:
REAL] ~ {
bjt: ROPE ← Rope.Concat[base: "Q", rest: NextInstanceId[convData]];
bjt ← Rope.Cat[bjt, WireId[convData, c], WireId[convData, b], WireId[convData, e]];
bjt ← Rope.Cat[bjt, model, " "];
bjt ← Rope.Concat[bjt, RealToRope[area]];
WriteInstance[convData, bjt]
};
MOSFet:
PUBLIC PROC [convData: ConvData, gate, drain, source, bulk: FlatWire, model:
ROPE, l, w:
REAL] ~ {
mos: ROPE ← Rope.Concat[base: "M", rest: NextInstanceId[convData]];
ad, as: REAL ← fetDifLength*w;
pd, ps: REAL ← 2*fetDifLength+w;
nrd, nrs: REAL ← fetDifLength/w;
mos ← Rope.Cat[mos, WireId[convData, drain], WireId[convData, gate], WireId[convData, source], WireId[convData, bulk]];
mos ← Rope.Concat[mos, model];
mos ← Rope.Cat[mos, " L=", RealToRope[l, micro], " W=", RealToRope[w, micro]];
mos ← Rope.Cat[mos, "AD=", RealToRope[ad, pico], " AS=", RealToRope[as, pico]];
mos ← Rope.Cat[mos, "PD=", RealToRope[pd, micro], " PS=", RealToRope[ps, micro]];
mos ← Rope.Cat[mos, " NRD=", RealToRope[nrd], " NRS=", RealToRope[nrs]];
WriteInstance[convData, mos]
};
VSource:
PUBLIC PROC [convData: ConvData, n1, n2: FlatWire, dc:
REAL ← 0.0] ~ {
vs: ROPE ← Rope.Concat[WireId[convData, n1], WireId[convData, n2]];
vs ← Rope.Cat["V", NextInstanceId[convData], vs];
hack to keep the InstanceId of the VSource in convData.nextId, wether the wires n1 and n2 were already declared or not. Used in current probes.
IF dc#0.0 THEN vs ← Rope.Cat[vs, " DC ", RealToRope[dc]];
WriteInstance[convData, vs]
};
ISource:
PUBLIC PROC [convData: ConvData, n1, n2: FlatWire, ma:
REAL ← 0.0] ~ {
is: ROPE ← Rope.Concat[base: "I", rest: NextInstanceId[convData]];
is ← Rope.Cat[is, WireId[convData, n1], WireId[convData, n2]];
IF ma#0.0 THEN is ← Rope.Cat[is, " DC ", RealToRope[ma, mili]];
WriteInstance[convData, is]
};
PulseVS:
PUBLIC PROC [convData: ConvData, n1, n2: FlatWire, v1, v2, td, tr, tf, pw, per:
REAL ← 0.0] ~ {
vs: ROPE ← Rope.Concat[base: "V", rest: NextInstanceId[convData]];
vs ← Rope.Cat[vs, WireId[convData, n1], WireId[convData, n2]];
vs ← Rope.Cat[vs, "PULSE(", RealToRope[v1], RealToRope[v2]];
vs ← Rope.Cat[vs, RealToRope[td, nano], RealToRope[tr, nano], RealToRope[tf, nano]];
vs ← Rope.Cat[vs, RealToRope[pw, nano], RealToRope[per, nano], ")"];
WriteInstance[convData, vs]
};
SineGen:
PUBLIC
PROC [convData: ConvData, n1, n2: FlatWire, v0, vA, freq, td, theta:
REAL ← 0.0] ~ {
vs: ROPE ← Rope.Concat[base: "V", rest: NextInstanceId[convData]];
vs ← Rope.Cat[vs, WireId[convData, n1], WireId[convData, n2]];
vs ← Rope.Cat[vs, "SIN(", RealToRope[v0], RealToRope[vA]];
vs ← Rope.Cat[vs, RealToRope[freq], RealToRope[td, nano]];
vs ← Rope.Cat[vs, RealToRope[theta], ")"];
WriteInstance[convData, vs]
};
ACSource:
PUBLIC
PROC [convData: ConvData, n1, n2: FlatWire, mag, phase:
REAL ← 0.0] ~ {
vs: ROPE ← "VSource ";
vs ← Rope.Cat[vs, WireId[convData, n1], WireId[convData, n2]];
vs ← Rope.Cat[vs, "DC AC", RealToRope[mag], RealToRope[phase], ")"];
WriteInstance[convData, vs]
};
Model:
PUBLIC
PROC [convData: ConvData, mName:
ROPE] ~ {
found: BOOL;
val: SymTab.Val;
[found, val] ← SymTab.Fetch[modelTable, mName];
IF NOT found THEN Signal[Rope.Concat["Unknown model: ", mName]]
ELSE WriteInstance[convData, NARROW[val]]
};
PutHeader:
PROC [convData: ConvData] ~ {
vddWire, gndWire: FlatWire;
node0: ROPE ← "0 ";
warningMsg: ROPE ← NIL;
Comment[convData, CoreOps.GetCellTypeName[convData.rootCell]];
establish the power through the Circuit, and set Gnd to node # 0
gndWire ← NEW[CoreFlat.FlatWireRec ← CoreFlat.ParseWirePath[convData.rootCell, gndName]];
[] ← RefTab.Insert[convData.wTable, gndWire, node0];
vddWire ← NEW[CoreFlat.FlatWireRec ← CoreFlat.ParseWirePath[convData.rootCell, vddName ! CoreFlat.PathError => {warningMsg ← "warning: no Vdd wire"; CONTINUE}]];
IF warningMsg=NIL THEN VSource[convData, vddWire, gndWire, vddVal]
ELSE TerminalIO.PutRope[warningMsg];
};
CloseSpiceDeck:
PUBLIC PROC [convData: ConvData] ~ {
WriteModels: SymTab.EachPairAction ~ {Model[convData, key]};
extraLine: ROPE ← NARROW[CoreProperties.GetCellTypeProp[convData.rootCell, spiceExtraLine]];
IF extraLine#NIL THEN WriteInstance[convData, extraLine];
[] ← SymTab.Pairs[x: convData.modelsUsed, action: WriteModels];
IF convData.initList#NIL THEN WriteInstance[convData, Rope.Concat[".IC ", convData.initList]];
WriteInstance[convData, Rope.Cat[".OPTIONS LIMPTS ", Convert.RopeFromInt[convData.limpts], " ", convData.optList]];
WriteInstance[convData, Rope.Concat[".TEMP ", RealToRope[convData.temp]]];
IF Rope.Fetch[convData.analysis, 0]='. THEN {
name: Rope.ROPE ← Rope.Substr[base: ROPE, start: INT ← 0, len: INT ← 2147483647]
WriteInstance[convData, Rope.Cat[".PRINT ", convData.analysis, " ", convData.printList]];
IF Rope.Equal[convData.analysis, "TRAN"]
THEN
WriteInstance[convData, Rope.Cat[".", convData.analysis, " ", convData.tranList]]
ELSE WriteInstance[convData, convData.analysis];
WriteInstance[convData, ".END"];
};