<> <> <> <> <<>> 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 ANY _ NIL, wireName: RefTab.Ref]; <> 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]]]; <> 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]; }; <> 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: REAL _ ABS[r], x*1000.0 UNTIL x>=1.0 DO c _ c/1000.0; ENDLOOP; FOR x: REAL _ ABS[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... }; <> 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]; <> 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]]; <> 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]]]; < { localStream: IO.STREAM _ IO.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.ROPE _ NIL] = CODE; END.