SpiceInputGenImpl.mesa
Copyright Ó 1987 by Xerox Corporation. All rights reserved.
Christian Le Cocq September 27, 1988 5:09:10 pm PDT
Last Edited by: Richley June 26, 1987 6:23:17 pm PDT
DIRECTORY
Convert,
Core,
CoreFlat,
CoreOps,
CoreClasses,
CoreProperties,
ElectricalCoreClasses,
IO,
Real,
RefTab,
Rope,
SpiceOps,
SymTab,
TerminalIO;
SpiceInputGenImpl: CEDAR PROGRAM    
IMPORTS
Convert, CoreFlat, CoreOps, CoreClasses, CoreProperties, ElectricalCoreClasses, IO, RefTab, Real, Rope, SpiceOps, SymTab, TerminalIO
EXPORTS
SpiceOps
= 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 ANYNIL, 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: NATLAST[NAT];
gndName: PUBLIC ROPE ← "public.Gnd";
vddName: PUBLIC ROPE ← "public.Vdd";
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]]];
Public Procs
WriteSpiceDeck: PUBLIC PROC [cellType: CellType, convData: ConvData] ~ {
InitSpiceDeck[cellType, convData];
NetFromCore[convData];
CloseSpiceDeck[convData];
};
CreateConvData: PUBLIC PROC [inputStream, outputStream: IO.STREAM] RETURNS [convData: ConvData] ~ {
convData ← NEW[SpiceOps.ConvDataRec];
convData.inS ← inputStream;
convData.outS ← outputStream;
convData.modelsUsed ← SymTab.Create[];
};
InitSpiceDeck: PUBLIC PROC [cellType: CellType, convData: ConvData] ~ {
convData.rootCell ← cellType;
convData.wTable ← RefTab.Create[equal: CoreFlat.FlatWireEqual, hash: CoreFlat.FlatWireHash];
convData.invTable ← SymTab.Create[];
PutHeader[convData];
};
Print Procs
WriteInstance: PROC [convData: ConvData, rope: ROPE] ~ {
IF Rope.Length[rope]<=lineLength THEN IO.PutRope[convData.outS, Rope.Concat[rope, "\l"]]
ELSE {
index, index2: INT ← 0;
UNTIL index2>=lineLength DO
index ← index2;
index2 ← Rope.Index[rope, index+1, sep];
ENDLOOP;
IO.PutRope[convData.outS, Rope.Concat[Rope.Substr[rope, 0, index], "\l"]];
WriteInstance[convData, Rope.Concat["+", Rope.Substr[rope, index+1]]];
};
};
WireId: PROC [convData: ConvData, wire: FlatWire] RETURNS [id: ROPE] ~ {
found: BOOL;
val: RefTab.Val;
[found, val] ← RefTab.Fetch[convData.wTable, wire];
IF found THEN RETURN [NARROW[val, ROPE]];
id ← NextInstanceId[convData];
[] ← RefTab.Insert[convData.wTable, wire, id];
[] ← SymTab.Insert[convData.invTable, id, wire];
Comment[convData, Rope.Cat[id, ": ", CoreFlat.WirePathRope[convData.rootCell, wire^]]];
};
NextInstanceId: PROC [convData: ConvData] RETURNS [id: ROPE] ~ {
convData.nextId ← convData.nextId+1;
id ← Convert.RopeFromCard[from: convData.nextId, showRadix: FALSE];
id ← Rope.Concat[id, " "];
};
RealToRope: PROC [r: REAL, m: REAL ← 1.0] RETURNS [rope: ROPE] ~ {
c: REAL ← 1.0;
r ← r*m;
IF r=0.0 THEN RETURN["0 "];
FOR x: REALABS[r], x*1000.0 UNTIL x>=1.0 DO
c ← c/1000.0;
ENDLOOP;
FOR x: REALABS[r], x/1000.0 UNTIL x<1000.0 DO
c ← c*1000.0;
ENDLOOP;
rope ← Rope.Concat[Convert.RopeFromReal[r/c], SELECT c FROM
1e12 => "T ",
1e09 => "G ",
1e06 => "MEG ",
1e03 => "K ",
1e00 => " ",
1e-3 => "M ",
1e-6 => "U ",
1e-9 => "N ",
1e-12 => "P ",
1e-15 => "F ",
ENDCASE => ERROR]; -- Value outside of range...
};
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: ROPENIL;
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, 5.0]
ELSE TerminalIO.PutRope[warningMsg];
};
CloseSpiceDeck: PUBLIC PROC [convData: ConvData] ~ {
WriteModels: SymTab.EachPairAction ~ {Model[convData, key]};
extraLine: ROPENARROW[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"];
};
Input From Core
NextCellType: PROC [cell: Core.CellType, target: CoreFlat.FlatCellTypeRec, flatCell: CoreFlat.FlatCellTypeRec, instance: CoreClasses.CellInstance, parent: Core.CellType, flatParent: CoreFlat.FlatCellTypeRec, data: REF ANY, wireName: RefTab.Ref, proc: FlatCellProc] = {
BindCellType: CoreFlat.UnboundFlatCellProc = {
BindPublicToActual: CoreOps.EachWirePairProc = {
PROC [actualWire, publicWire: Wire]
IF publicWire.size=0 THEN {
flatWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[x: wireName, key: actualWire].val];
[] ← RefTab.Store[x: wireName, key: publicWire, val: flatWire];
};
};
IF CoreOps.VisitBinding[actual: IF instance=NIL OR instance.type#cell THEN previous.public ELSE instance.actual, public: cell.public, eachWirePair: BindPublicToActual] THEN ERROR;
proc[cell, target, flatCell, instance, parent, flatParent, data, wireName];
};
previous: Core.CellType ← cell;
CoreFlat.NextUnboundCellType[cell, target, flatCell, instance, defaultIndex, parent, flatParent, data, BindCellType];
};
Flatten: FlatCellProc = {
convData: ConvData ← NARROW[data];
SELECT cell.class FROM
ElectricalCoreClasses.resistorCellClass => {
n0Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
n1Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1]].val];
res: ElectricalCoreClasses.Resistor ← NARROW[cell.data];
Resistor[convData, n0Wire, n1Wire, res.value];
};
ElectricalCoreClasses.inductorCellClass => {
n0Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
n1Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1]].val];
ind: ElectricalCoreClasses.Inductor ← NARROW[cell.data];
Inductor[convData, n0Wire, n1Wire, ind.value];
};
ElectricalCoreClasses.capacitorCellClass => {
n0Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
n1Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1]].val];
capa: ElectricalCoreClasses.Capacitor ← NARROW[cell.data];
Capacitor[convData, n0Wire, n1Wire, capa.value];
};
ElectricalCoreClasses.diodeCellClass => {
n0Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
n1Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1]].val];
diode: ElectricalCoreClasses.Diode ← NARROW[cell.data];
model: ROPE ← GetModelName[cell, instance];
IF diode.type#Junction AND model=NIL THEN TerminalIO.PutRope["***Diode model should be manually edited"];
IF model=NIL THEN model ← diodeModel;
Diode[convData, n0Wire, n1Wire, model, diode.area];
};
ElectricalCoreClasses.bjtCellClass => {
cWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
bWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1]].val];
eWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[2]].val];
bjt: ElectricalCoreClasses.BJT ← NARROW[cell.data];
model: ROPE ← GetModelName[cell, instance];
IF model=NIL THEN model ← SELECT bjt.type FROM
npn => npnModel,
pnp => pnpModel,
ENDCASE => ERROR;
BJT[convData, cWire, bWire, eWire, model, bjt.area];
};
ElectricalCoreClasses.coupledIndCellClass => {
n0Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0][0]].val];
n1Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0][1]].val];
n2Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1][0]].val];
n3Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1][1]].val];
coupledInd: ElectricalCoreClasses.CoupledInd ← NARROW[cell.data];
CoupledInductors[convData, n0Wire, n1Wire, n2Wire, n3Wire, coupledInd.l1, coupledInd.l2, coupledInd.k];
};
ElectricalCoreClasses.losslessLineCellClass => {
n0Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0][0]].val];
n1Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0][1]].val];
n2Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1][0]].val];
n3Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1][1]].val];
losslessLine: ElectricalCoreClasses.LosslessLine ← NARROW[cell.data];
LosslessLine[convData, n0Wire, n1Wire, n2Wire, n3Wire, losslessLine.z0, losslessLine.td];
};
ElectricalCoreClasses.linearSourceCellClass => {
n0Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0][0]].val];
n1Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0][1]].val];
n2Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1][0]].val];
n3Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1][1]].val];
linearSource: ElectricalCoreClasses.LinearSource ← NARROW[cell.data];
SELECT linearSource.type FROM
VCCS => Vccs[convData, n0Wire, n1Wire, n2Wire, n3Wire, linearSource.value];
VCVS => Vcvs[convData, n0Wire, n1Wire, n2Wire, n3Wire, linearSource.value];
CCCS => Cccs[convData, n0Wire, n1Wire, n2Wire, n3Wire, linearSource.value];
ccvs => Ccvs[convData, n0Wire, n1Wire, n2Wire, n3Wire, linearSource.value];
ENDCASE => ERROR; -- a change in ElectricalCoreClasses ???
};
ElectricalCoreClasses.signalGeneratorCellClass => {
nWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
gndWire: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec ← CoreFlat.ParseWirePath[convData.rootCell, gndName]];
sig: ElectricalCoreClasses.SignalGenerator ← NARROW[cell.data];
SELECT sig.type FROM
DC => VSource[convData, nWire, gndWire, sig.onLevel];
RectWave => PulseVS[convData, nWire, gndWire, sig.offLevel, sig.onLevel, sig.tDelay, sig.tRise, sig.tFall, sig.width-sig.tRise-sig.tFall, sig.period];
OneShot => PulseVS[convData, nWire, gndWire, sig.offLevel, sig.onLevel, sig.tDelay, sig.tRise, sig.tFall, sig.width-sig.tRise-sig.tFall, infinity];
Step => PulseVS[convData, nWire, gndWire, sig.offLevel, sig.onLevel, sig.tDelay, sig.tRise, sig.tFall, infinity, infinity];
ENDCASE => ERROR;
};
ElectricalCoreClasses.sineGeneratorCellClass => {
nWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
gndWire: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec ← CoreFlat.ParseWirePath[convData.rootCell, gndName]];
sig: ElectricalCoreClasses.SineGenerator ← NARROW[cell.data];
SineGen[convData, nWire, gndWire, sig.v0, sig.vA, sig.freq, sig.td, sig.theta];
};
ElectricalCoreClasses.acSourceCellClass => {
nWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
gndWire: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec ← CoreFlat.ParseWirePath[convData.rootCell, gndName]];
ac: ElectricalCoreClasses.ACSource ← NARROW[cell.data];
ACSource[convData, nWire, gndWire, ac.mag, ac.phase];
};
ElectricalCoreClasses.probeCellClass => {
probe: ElectricalCoreClasses.Probe ← NARROW[cell.data];
SELECT probe.type FROM
Voltage => {
name: Rope.ROPE ← Rope.Cat[" V", probe.acKind, "("];
nWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
convData.printList ← Rope.Cat[convData.printList, name, WireId[convData, nWire], ")"];
};
Current => {
name: Rope.ROPE ← Rope.Cat[" I", probe.acKind, "(V"];
n0Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
n1Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[1]].val];
VSource[convData, n0Wire, n1Wire];
it happens that we know the name of the fake voltage source from the last convData.nextId used due to the VSource implementation (berk !).
convData.printList ← Rope.Cat[convData.printList, name, Convert.RopeFromCard[from: convData.nextId, showRadix: FALSE], ")"];
};
ENDCASE => ERROR;
};
ElectricalCoreClasses.initCellClass => {
init: ElectricalCoreClasses.Init ← NARROW[cell.data];
SELECT init.type FROM
Voltage => {
nWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[wireName, cell.public[0]].val];
convData.initList ← Rope.Cat[convData.initList, " V(", WireId[convData, nWire], ")=", RealToRope[init.value]];
};
Current => {
NYI
};
ENDCASE => ERROR;
};
ElectricalCoreClasses.panelCellClass => {
propVal: REF;
panel: ElectricalCoreClasses.Panel ← NARROW[cell.data];
convData.limpts ← Real.Fix[(panel.tMax - panel.tMin)/panel.tStep]+1;
convData.tranList ← Rope.Cat[RealToRope[panel.tStep, nano], RealToRope[panel.tMax, nano], RealToRope[panel.tMin, nano]];
convData.optList ← Rope.Concat[convData.optList, NARROW[CoreProperties.GetCellInstanceProp[instance, spiceOptions]]];
propVal ← CoreProperties.GetCellInstanceProp[instance, SpiceOps.analysisType];
IF propVal=NIL THEN propVal ← CoreProperties.GetCellTypeProp[cell, SpiceOps.analysisType];
convData.analysis ← IF propVal=NIL THEN "TRAN" ELSE NARROW[propVal];
};
CoreClasses.transistorCellClass => {
fourthWire: CoreFlat.FlatWire;
gateWire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[x: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.gate]]].val];
ch1Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[x: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.ch1]]].val];
ch2Wire: CoreFlat.FlatWire ← NARROW[RefTab.Fetch[x: wireName, key: cell.public[ORD[CoreClasses.TransistorPort.ch2]]].val];
tran: CoreClasses.Transistor ← NARROW[cell.data];
model: ROPE ← GetModelName[cell, instance];
transistorLength: INTNARROW[CoreProperties.GetCellTypeProp[cell, CoreClasses.lengthProp], REF INT]^;
transistorWidth: INTNARROW[CoreProperties.GetCellTypeProp[cell, CoreClasses.widthProp], REF INT]^;
SELECT tran.type FROM
pE => {
fourthWire ← NEW[CoreFlat.FlatWireRec ← CoreFlat.ParseWirePath[convData.rootCell, vddName]];
IF model=NIL THEN model ← pModel;
};
nE => {
fourthWire ← NEW[CoreFlat.FlatWireRec ← CoreFlat.ParseWirePath[convData.rootCell, gndName]];
IF model=NIL THEN model ← nModel;
};
ENDCASE => ERROR;
[] ← SymTab.Insert[convData.modelsUsed, model, $TRUE];
MOSFet[convData, gateWire, ch1Wire, ch2Wire, fourthWire, model, transistorLength, transistorWidth];
};
CoreClasses.recordCellClass => {
MarkAtomicPublic: PROC[wire: Core.Wire] = {
[] ← RefTab.Store[x: publics, key: wire, val: $Public];
};
InsertInternal: PROC[wire: Core.Wire] = {
IF NOT RefTab.Fetch[x: publics, key: wire].found THEN {
InsertWire[wire, flatCell, wireName];
};
};
rct: CoreClasses.RecordCellType;
publics: RefTab.Ref ← RefTab.Create[cell.public.size+1];
rct ← NARROW[cell.data];
CoreOps.VisitRootAtomics[root: cell.public, eachWire: MarkAtomicPublic];
CoreOps.VisitRootAtomics[root: rct.internal, eachWire: InsertInternal];
NextCellType[cell, target, flatCell, instance, parent, flatParent, data, wireName, Flatten]
};
ENDCASE => {
IF cell.class.recast=NIL THEN TerminalIO.PutRopes[" What is a ", cell.class.name, "?\n"]
ELSE NextCellType[cell, target, flatCell, instance, parent, flatParent, data, wireName, Flatten]
};
};
InsertWire: PROC [wire: Core.Wire, flatCell: CoreFlat.FlatCellTypeRec, wireName: RefTab.Ref, wireRoot: CoreFlat.WireRoot ← internal] = {
flatWire: CoreFlat.FlatWire ← NEW[CoreFlat.FlatWireRec];
flatWire.flatCell ← flatCell;
flatWire.wireRoot ← wireRoot;
flatWire.wire ← wire;
[] ← RefTab.Store[x: wireName, key: wire, val: flatWire];
};
NetFromCore: PUBLIC PROC[convData: ConvData] = {
InsertPublic: PROC[wire: Core.Wire] = {
InsertWire[wire, CoreFlat.rootCellType, wireName, public];
};
wireName: RefTab.Ref ← RefTab.Create[];
CoreOps.VisitRootAtomics[root: convData.rootCell.public, eachWire: InsertPublic];
Flatten[cell: convData.rootCell, data: convData, wireName: wireName];
};
GetModelName: PROC [cellType: Core.CellType, instance: CoreClasses.CellInstance] RETURNS [mName: ROPE] ~ {
mName ← NARROW[CoreProperties.GetCellInstanceProp[instance, spiceModel]];
IF mName=NIL THEN mName ← NARROW[CoreProperties.GetCellTypeProp[cellType, spiceModel]];
};
ReadModels: PUBLIC PROC [file: IO.STREAM] ~ {
modelRope: ROPE = ".MODEL";
line, thisModel, thisName: ROPENIL;
UNTIL IO.EndOf[file] DO
line ← IO.GetLineRope[file ! IO.EndOfStream => CONTINUE];
IF line#NIL THEN SELECT Rope.Fetch[line, 0] FROM
'. => {
localStream: IO.STREAMIO.RIS[line];
IF NOT Rope.Equal[IO.GetTokenRope[localStream, IO.IDProc].token, modelRope] THEN Signal[Rope.Cat["Unknown Syntax: ", line]]
ELSE {
thisName ← IO.GetTokenRope[localStream, IO.IDProc].token;
thisModel ← line;
IF NOT SymTab.Store[modelTable, thisName, thisModel] THEN TerminalIO.PutRopes["SpiceOps: model ", thisName, " overwritten\n"];
}
};
'+ => {
thisModel ← Rope.Cat[thisModel, " ", Rope.Substr[line, 1]];
[] ← SymTab.Store[modelTable, thisName, thisModel];
};
'* => NULL;
' => NULL;
ENDCASE => Signal[Rope.Cat["Unknown Syntax: ", line]];
ENDLOOP;
};
Signal: SIGNAL[msg: Rope.ROPENIL] = CODE;
END.