DIRECTORY CoreFlat, CoreOps, HashTable, Histograms, Icons, IO, LinearSystem, Mint, PlotGraph, Real, Rope, Schedule, TerminalIO, TypeScript, ViewerIO; MintImpl: CEDAR PROGRAM IMPORTS CoreFlat, CoreOps, HashTable, Histograms, Icons, IO, LinearSystem, PlotGraph, Schedule, TerminalIO, TypeScript, ViewerIO EXPORTS Mint SHARES Schedule ~ BEGIN OPEN Mint; PathList: TYPE = LIST OF NodeList; Caminos: TYPE = LIST OF Camino; Camino: TYPE = LIST OF RECORD[set: Set, node: Node]; Delay: TYPE = REF DelayRec; DelayRec: TYPE = RECORD [tup, tdown: ps]; ExtendedCircuit: TYPE = REF ExtendedCircuitRec; ExtendedCircuitRec: TYPE = RECORD [circuit: Circuit, data: REF ANY]; gndName: Rope.ROPE _ "public.Gnd"; vddName: Rope.ROPE _ "public.Vdd"; VddVal: mVolt _ 5000.0; GndVal: mVolt _ 0.0; VtVal: mVolt _ 2000.0; threshold: mVolt _ 2500.0; gamma: REAL = 0.4*31.62277; -- 31.62277 = SqRt[1000.0] due to unit = mV phi: mVolt _ 1000.0; sqrtPhi: REAL _ 31.62277; timeSpecs: ps _ 50.0; tInc: ps _ 100.0; totalSets: CARDINAL _ 0; separateView: BOOL _ FALSE; StdOut: PUBLIC IO.STREAM _ NIL; debug: PUBLIC BOOL _ FALSE; verbose: PUBLIC BOOL _ FALSE; debugCircuit: Circuit _ NIL; debugNode: Node _ NIL; debugNodeList: NodeList _ NIL; debugHList: LIST OF Schedule.History _ NIL; statsNumberOfSimulations: CARDINAL _ 0; nSimInc: CARDINAL _ 50; SimulateSet: PROC [ref: REF ANY, t: ps, data: REF ANY] ~ { circuit: Circuit ~ NARROW[data]; set: Set ~ NARROW[ref]; agenda: Schedule.Agenda ~ circuit.agenda; subsets: SetList; nodeList: NodeList; finished, firstTime: BOOLEAN _ FALSE; inputHistories: LIST OF Schedule.History; timeList: LIST OF ps; tmin, tmax, tmaxmin, tmaxmax: ps; IF set=NIL THEN RETURN; IF set.done THEN RETURN; set.done _ TRUE; IF debug THEN {IO.PutF[StdOut, "\n\n%5d ~~~>",IO.real[t]]; PrintSetType[set.type]; IO.PutF[StdOut, "\nInputs :"];}; nodeList _ ScanHistoriesOfNodeList[set.inList, t, agenda, FALSE]; FOR inode: NodeList _ nodeList, inode.rest UNTIL inode=NIL DO IF verbose THEN IO.PutF[StdOut,"\n Unknown Input: %g ", IO.rope[RopeFromNode[inode.first, circuit]]] ENDLOOP; nodeList _ ScanHistoriesOfNodeList[set.lNodes, t, agenda]; firstTime _ nodeList#NIL; FOR inode: NodeList _ set.inList, inode.rest UNTIL inode=NIL DO IF debug THEN PrintNode[inode.first, circuit]; inputHistories _ CONS[inode.first.history, inputHistories]; ENDLOOP; FOR inode: NodeList _ set.fixedV, inode.rest UNTIL inode=NIL DO IF ~inode.first.input THEN ResetInput[inode.first, set] ENDLOOP; FOR inode: NodeList _ set.lNodes, inode.rest UNTIL inode=NIL DO IF inode.first.input THEN SetInput[inode.first, set] ENDLOOP; IF debug THEN IO.PutF[StdOut, "\nOutputs:"]; timeList _ Schedule.Schedule[inputHistories]; tmin _ t; UNTIL timeList.first>=tmin OR timeList.rest=NIL DO timeList _ timeList.rest; ENDLOOP; tmaxmin _ timeList.first; IF set.type.solve#NIL THEN tmaxmin _ set.type.solve[set, tmin, circuit] ELSE UNTIL finished DO [finished , tmin] _ FlipSwitches[set.lFets, tmin, tmaxmin]; IF firstTime THEN finished _ FALSE; firstTime _ FALSE; IF ~finished THEN { tmaxmax _ tmaxmin; subsets _ ClipSet[set]; FOR isubset: SetList _ subsets, isubset.rest UNTIL isubset=NIL DO tmax _ RCSolve[isubset.first, tmin, circuit]; tmaxmin _ MIN[tmaxmin, tmax]; tmaxmax _ MAX[tmaxmax, tmax]; IF debug AND verbose THEN { IO.PutF[StdOut, "\nsubset between %g and %g", IO.real[tmin], IO.real[tmax]]; PrintNodeList[isubset.first.lNodes, circuit]; }; ENDLOOP; KillSetList[subsets, TRUE]; } ELSE { tmin _ tmaxmin; UNTIL timeList.first>tmin OR timeList.rest=NIL DO timeList _ timeList.rest; ENDLOOP; IF MAX[tmaxmax, timeList.first]> tmaxmin THEN finished _ FALSE; tmaxmin _ IF timeList.first>tmaxmin THEN timeList.first ELSE tmaxmax; }; ENDLOOP; FOR inode: NodeList _ set.lNodes, inode.rest UNTIL inode=NIL DO FOR setList: SetList _ inode.first.setList, setList.rest UNTIL setList=NIL DO Schedule.InsertInAgenda[agenda, setList.first, Schedule.NextTimeOfHistory[inode.first.history, t+1]]; setList.first.done _ FALSE; ENDLOOP; ENDLOOP; circuit.info.nbOfSimulations _ circuit.info.nbOfSimulations+1; IF verbose THEN IF (circuit.info.nbOfSimulations MOD nSimInc) = 0 THEN IO.PutF[StdOut, "\n%5d t : %5d, No of events : %7d", IO.int[circuit.info.nbOfSimulations], IO.real[agenda.list.first.t], IO.int[agenda.nbOfEvents]]; }; ScanHistoriesOfNodeList: PROC [nodeList: NodeList, t: ps, agenda: Schedule.Agenda, cut: BOOLEAN _ TRUE] RETURNS [uninitialized: NodeList] ~ { CutHistory: PROC[node: Node] RETURNS [quit: BOOLEAN _ FALSE] ~ { IF node.history=NIL THEN RETURN; IF node.input THEN RETURN; t1 _ Schedule.NextTimeOfHistory[node.history, t+tInc]; IF t1>t AND Schedule.LastTimeOfHistory[node.history]>t1 THEN { node.history _ Schedule.AddToHistory[node.history, t1, Schedule.VFromHistory[node.history, t1]]; FOR iSetList: SetList _ node.setList, iSetList.rest UNTIL iSetList=NIL DO Schedule.InsertInAgenda[agenda, iSetList.first, t1]; iSetList.first.done _ FALSE; FOR inodeList: NodeList _ iSetList.first.lNodes, inodeList.rest UNTIL inodeList=NIL DO quit _ CutHistory[inodeList.first]; ENDLOOP; ENDLOOP; }; }; t1: ps _ t+tInc; FOR inode: NodeList _ nodeList, inode.rest UNTIL inode=NIL DO IF inode.first.history=NIL THEN { uninitialized _ CONS[inode.first, uninitialized]; inode.first.history _ Schedule.CreateHistory[t, GndVal+0.0314159]; } ELSE { IF ~inode.first.watched THEN inode.first.history _ Schedule.ForgetBeginings[inode.first.history, t]; IF cut THEN [] _ CutHistory[inode.first]; }; ENDLOOP; }; FindInputs2: PROC [set: Set] ~ { found: BOOLEAN; FOR ifet: FetList _ set.lFets, ifet.rest UNTIL ifet=NIL DO found _ FALSE; FOR inode: NodeList _ set.lNodes, inode.rest UNTIL inode=NIL DO IF inode.first=ifet.first.gate THEN { found _ TRUE; EXIT; }; ENDLOOP; IF ~found THEN { found _ FALSE; FOR inode: NodeList _ set.inList, inode.rest UNTIL inode=NIL DO IF inode.first=ifet.first.gate THEN { found _ TRUE; EXIT; }; ENDLOOP; IF ~found THEN set.inList _ CONS[ifet.first.gate, set.inList]; }; ENDLOOP; }; NextFetList2: PROC [set: Set, nodeList: NodeList] RETURNS [fetList: FetList _ NIL] ~ { FOR iNodeList: NodeList _ nodeList, iNodeList.rest UNTIL iNodeList = NIL DO FOR iFetList: FetList _ iNodeList.first.fetList, iFetList.rest UNTIL iFetList = NIL DO IF NOT iFetList.first.done THEN IF iFetList.first.gate # iNodeList.first THEN { fetList _ CONS[iFetList.first, fetList]; set.lFets _ CONS[iFetList.first, set.lFets]; iFetList.first.done _ TRUE; }; ENDLOOP; ENDLOOP; }; --NextFetList2 NextNodeList2: PROC [set: Set, fetList: FetList] RETURNS [nodeList: NodeList _ NIL] ~ { FOR iFetList: FetList _ fetList, iFetList.rest UNTIL iFetList = NIL DO IF NOT iFetList.first.ch1.done THEN { nodeList _ CONS[iFetList.first.ch1, nodeList]; set.lNodes _ CONS[iFetList.first.ch1, set.lNodes]; iFetList.first.ch1.done _ TRUE; }; IF NOT iFetList.first.ch2.done THEN { nodeList _ CONS[iFetList.first.ch2, nodeList]; set.lNodes _ CONS[iFetList.first.ch2, set.lNodes]; iFetList.first.ch2.done _ TRUE; }; ENDLOOP; }; --NextNodeList2 ClipSet: PROC [totalSet: Set, cutNodes: NodeList _ NIL] RETURNS [setList: SetList _ NIL] ~ { set: Set; nodeList: NodeList; fetList: FetList; FOR iFetList: FetList _ totalSet.lFets, iFetList.rest UNTIL iFetList = NIL DO iFetList.first.done _ ~iFetList.first.switch; ENDLOOP; FOR iNodeList: NodeList _ totalSet.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.done _ FALSE; ENDLOOP; FOR iNodeList: NodeList _ totalSet.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.done _ TRUE; ENDLOOP; FOR iNodeList: NodeList _ cutNodes, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.done _ TRUE; ENDLOOP; FOR inodeList: NodeList _ totalSet.lNodes, inodeList.rest UNTIL inodeList=NIL DO IF inodeList.first.done THEN LOOP; set _ NEW[SetRec]; nodeList _ LIST[inodeList.first]; set.lNodes _ nodeList; inodeList.first.done _ TRUE; UNTIL nodeList=NIL DO fetList _ NextFetList2[set, nodeList]; nodeList _ NextNodeList2[set, fetList]; ENDLOOP; FOR iNodeList: NodeList _ totalSet.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.done _ FALSE; ENDLOOP; FOR iFetList: FetList _ set.lFets, iFetList.rest UNTIL iFetList=NIL DO IF iFetList.first.ch1.input THEN IF ~iFetList.first.ch1.done AND iFetList.first.switch THEN { iFetList.first.ch1.done _ TRUE; set.fixedV _ CONS[iFetList.first.ch1, set.fixedV]; }; IF iFetList.first.ch2.input THEN IF ~iFetList.first.ch2.done AND iFetList.first.switch THEN { iFetList.first.ch2.done _ TRUE; set.fixedV _ CONS[iFetList.first.ch2, set.fixedV]; }; ENDLOOP; FOR iNodeList: NodeList _ totalSet.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.done _ TRUE; ENDLOOP; setList _ CONS[set, setList]; ENDLOOP; }; CheckSwitch: PROC [fet: Fet, t0, t1: ps] RETURNS [change: BOOLEAN _ FALSE, changet: ps _ 0] ~ { status: BOOLEAN; vGate1: mVolt _ Schedule.VFromHistory[fet.gate.history, t1]; SELECT fet.type FROM nE => status _ (vGate1 >= threshold); pE => status _ (vGate1 <= threshold); ENDCASE => ERROR; IF status#fet.switch THEN { UNTIL t1-t0worst OR delay.tdown>worst THEN { camino _ iCaminos.first; worst _ MAX[delay.tup, delay.tdown]; }; Histograms.ChangeTransformed[hist, delay.tup]; Histograms.ChangeTransformed[hist, delay.tdown]; ENDLOOP; [] _ Histograms.Show[hist]; setList _ LIST[camino.first.set]; camino _ camino.rest; {iSetList3: SetList _ setList; UNTIL camino=NIL DO iSetList3.rest _ LIST[camino.first.set]; camino _ camino.rest; iSetList3 _ iSetList3.rest; ENDLOOP;} }; ThruTime: PROC [camino: Camino, setCache, setListCache: HashTable.Table] RETURNS [delay: Delay] ~ { value: HashTable.Value; found: BOOLEAN; setDelay, prevDelay: Delay; [found, value] _ HashTable.Fetch[setListCache, camino]; IF found THEN RETURN[NARROW[value, Delay]]; delay _ NEW[DelayRec _ [0.0, 0.0]]; setDelay _ DelayOfSet[camino.first.set, setCache]; IF camino.rest=NIL THEN RETURN; prevDelay _ ThruTime[camino.rest, setCache, setListCache]; delay.tup _ setDelay.tup+prevDelay.tdown; delay.tdown _ setDelay.tdown+prevDelay.tup; [] _ HashTable.Store[setListCache, camino, delay]; }; DelayOfSet: PROC [set: Set, setCache: HashTable.Table] RETURNS [delay: Delay] ~ { value: HashTable.Value; found: BOOLEAN; tup, tdown: ps _ 0.0; [found, value] _ HashTable.Fetch[setCache, set]; IF found THEN RETURN[NARROW[value, Delay]]; delay _ NEW[DelayRec _ [0.0, 0.0]]; FOR iNodeList: NodeList _ set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO IF iNodeList.first.setList#NIL THEN { FOR iNList: NodeList _ set.inList, iNList.rest UNTIL iNList=NIL DO iNList.first.done _ FALSE; ENDLOOP; FOR iNList: NodeList _ set.fixedV, iNList.rest UNTIL iNList=NIL DO iNList.first.done _ TRUE; ENDLOOP; FOR iFetList: FetList _ set.lFets, iFetList.rest UNTIL iFetList = NIL DO iFetList.first.switch _ TRUE; ENDLOOP; [tup, tdown] _ EvalRC[iNodeList.first, set]; delay.tup _ MAX[delay.tup, tup]; delay.tdown _ MAX[delay.tdown, tdown]; } ENDLOOP; [] _ HashTable.Store[setCache, set, delay]; }; FindSetOfNode: PROC [node: Node] RETURNS [set: Set] ~ { found: BOOLEAN _ FALSE; FOR iFetList: FetList _ node.fetList, iFetList.rest UNTIL iFetList=NIL DO FOR iSetList: SetList _ iFetList.first.gate.setList, iSetList.rest UNTIL iSetList=NIL DO FOR iNodeList: NodeList _ iSetList.first.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO IF iNodeList.first=node THEN RETURN[iSetList.first]; ENDLOOP; ENDLOOP; ERROR; -- who did some hand editing on the internal data structure ? ENDLOOP; }; FindAllPaths: PROC [node: Node, set: Set] RETURNS [pathList: PathList] ~ { finished: BOOLEAN _ FALSE; oldPathList: PathList; level: NAT _ 1; FOR iNodeList: NodeList _ set.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.index _ 0; ENDLOOP; FOR iNodeList: NodeList _ set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.index _ 0; ENDLOOP; pathList _ LIST[LIST[node]]; node.index _ 1; UNTIL finished DO level _ level+1; oldPathList _ pathList; [finished, pathList] _ IncPaths[set.lFets, oldPathList, level]; ENDLOOP; }; IncPaths: PROC [fetList: FetList, oldPathList: PathList, level: NAT] RETURNS [finished: BOOLEAN _ TRUE, newPathList: PathList _ NIL] ~ { nodeList: NodeList; terminal: BOOLEAN; FOR iPathList: LIST OF NodeList _ oldPathList, iPathList.rest UNTIL iPathList=NIL DO nodeList _ iPathList.first; terminal _ TRUE; IF ~nodeList.first.input THEN FOR iFetList: FetList _ fetList, iFetList.rest UNTIL iFetList=NIL DO IF iFetList.first.ch1=nodeList.first THEN IF iFetList.first.ch2.index=0 OR iFetList.first.ch2.index>=level THEN { newPathList _ CONS[ CONS[iFetList.first.ch2, nodeList], newPathList]; iFetList.first.ch2.index _ level; terminal _ FALSE; finished _ FALSE; }; IF iFetList.first.ch2=nodeList.first THEN IF iFetList.first.ch1.index=0 OR iFetList.first.ch1.index>=level THEN { newPathList _ CONS[ CONS[iFetList.first.ch1, nodeList], newPathList]; iFetList.first.ch1.index _ level; finished _ FALSE; terminal _ FALSE; }; ENDLOOP; IF terminal THEN newPathList _ CONS[nodeList, newPathList]; ENDLOOP; }; EvalRC: PROC [node: Node, set: Set] RETURNS [tup, tdown: ps _ 0] ~ { subSets: SetList; pathList: PathList; found: BOOLEAN _ FALSE; tempup, tempdown: ps _ 0.0; n: NAT _ 0; FOR iNodeList: NodeList _ set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO IF iNodeList.first=node THEN { found _ TRUE; EXIT; }; ENDLOOP; IF ~found THEN RETURN; IF set.fixedV=NIL THEN RETURN; pathList _ FindAllPaths[node, set]; FOR iPathList: PathList _ pathList, iPathList.rest UNTIL iPathList=NIL DO IF iPathList.first.first.input THEN n _ n+1; ENDLOOP; IF n=0 THEN ERROR; IF n#1 THEN { FindInputs2[set]; FOR iNodeList: NodeList _ set.inList, iNodeList.rest UNTIL iNodeList=NIL DO IF ~iNodeList.first.done THEN { iNodeList.first.done _ TRUE; FOR bool: BOOLEAN IN BOOLEAN DO FOR iFetList: FetList _ iNodeList.first.fetList, iFetList.rest UNTIL iFetList = NIL DO iFetList.first.switch _ IF bool THEN iFetList.first.type=pE ELSE iFetList.first.type=nE; ENDLOOP; subSets _ ClipSet[set]; FOR iSetList: SetList _ subSets, iSetList.rest UNTIL iSetList=NIL DO [tempup, tempdown] _ EvalRC[node, iSetList.first]; tup _ MAX[tempup, tup]; tdown _ MAX[tempdown, tdown]; ENDLOOP; KillSetList[subSets, TRUE]; ENDLOOP; }; ENDLOOP; }; IF tup=0.0 AND tdown=0.0 THEN { t: ps; FOR iFetList: FetList _ set.lFets, iFetList.rest UNTIL iFetList = NIL DO iFetList.first.switch _ TRUE; ENDLOOP; [] _ ScanHistoriesOfNodeList[set.lNodes, 0.0, NIL, FALSE]; t _ RCSolve[set, 0.0, NIL]; IF GetNode[node] THEN tup _ t ELSE tdown _ t; }; }; MaxCapa: PUBLIC PROC [circuit: Circuit, n: NAT _ 1] RETURNS [fatest: REAL, fatNodes: NodeList]~ { FindFatOnes: PROC[set: Set] RETURNS [ok: BOOLEAN] ~ { ok _ TRUE; FOR iNodeList: NodeList _ set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO node _ iNodeList.first; totalC _ totalC+node.cap; IF node.cap>data.table[0].x THEN FOR ind: NAT IN [0..n) DO IF ind=n-1 OR node.cap PutFL }; PrintNode: PUBLIC PROC [node: Node, circuit: Circuit] ~ { IF node=NIL THEN RETURN; IO.PutF[StdOut,"\n %g(%g) -> ", IO.rope[RopeFromNode[node, circuit]], IO.real[node.cap]]; FOR ih: Schedule.History _ node.history, ih.rest UNTIL ih=NIL DO IO.PutF[StdOut, "t:%d, V:%5d; ", IO.real[ih.first.t], IO.real[ih.first.v]]; ENDLOOP; }; PrintFetList: PUBLIC PROC [fetList: FetList, circuit: Circuit] ~ { FOR ifetList: FetList _ fetList, ifetList.rest UNTIL ifetList=NIL DO PrintFet[ifetList.first, circuit]; ENDLOOP; }; PrintNodeList: PUBLIC PROC [nodeList: NodeList, circuit: Circuit] ~ { IO.PutF[StdOut,"\n --"]; FOR inodeList: NodeList _ nodeList, inodeList.rest UNTIL inodeList=NIL DO PrintNode[inodeList.first, circuit]; ENDLOOP; }; PrintCamino: PROC [camino: Camino, circuit: Circuit] ~ { IO.PutF[StdOut,"\n ~~"]; FOR iCamino: Camino _ camino, iCamino.rest UNTIL iCamino=NIL DO PrintNode[ iCamino.first.node, circuit]; ENDLOOP; }; PrintCaminos: PROC [caminos: Caminos, circuit: Circuit] ~ { IO.PutF[StdOut,"\n **"]; FOR iCaminos: Caminos _ caminos, iCaminos.rest UNTIL iCaminos=NIL DO PrintCamino[ iCaminos.first, circuit]; ENDLOOP; }; SetDoneInNodeList: PROC [nodeList: NodeList, done: BOOLEAN] ~ { FOR inodeList: NodeList _ nodeList, inodeList.rest UNTIL inodeList=NIL DO inodeList.first.done _ done; ENDLOOP; }; Watch: PUBLIC PROC [watchList: NodeList] ~ { FOR inodeList: NodeList _ watchList, inodeList.rest UNTIL inodeList=NIL DO inodeList.first.watched _ TRUE; ENDLOOP; }; SetInput: PROC [node: Node, set: Set] ~ { prev: NodeList; node.input _ TRUE; node.done _ TRUE; set.fixedV _ CONS[node, set.fixedV]; IF node=set.lNodes.first THEN { set.lNodes _ set.lNodes.rest; RETURN; }; prev _ set.lNodes; FOR nodeList: NodeList _ set.lNodes.rest, nodeList.rest DO IF nodeList.first=node THEN { prev.rest _ nodeList.rest; EXIT; }; prev _ nodeList; ENDLOOP; }; ResetInput: PROC [node: Node, set: Set] ~ { prev: NodeList; node.input _ FALSE; node.done _ FALSE; set.lNodes _ CONS[node, set.lNodes]; IF node=set.fixedV.first THEN { set.lNodes _ set.fixedV.rest; RETURN; }; prev _ set.fixedV; FOR nodeList: NodeList _ set.fixedV.rest, nodeList.rest DO IF nodeList.first=node THEN { prev.rest _ nodeList.rest; EXIT; }; prev _ nodeList; ENDLOOP; }; VisitLibrary: PROC [lib: Library, action: PROC[set: Set] RETURNS [ok: BOOLEAN]] RETURNS [ok: BOOLEAN] ~ { UNTIL lib=NIL DO FOR iSetList: SetList _ lib.first.setList, iSetList.rest UNTIL iSetList=NIL DO ok _ action[iSetList.first]; IF ~ok THEN RETURN; ENDLOOP; lib _ lib.rest ENDLOOP; }; SetTime: PUBLIC PROC [t: ps, circuit: Circuit] ~ { CutHistory: HashTable.EachPairAction ~ { node: Node _ NARROW[value]; IF node.history=NIL THEN RETURN; IF node.input THEN RETURN; IF Schedule.FirstTimeOfHistory[node.history]>t THEN node.history _ NIL ELSE node.history _ Schedule.AddToHistory[node.history, t, Schedule.VFromHistory[node.history, t]]; }; [] _ HashTable.Pairs[circuit.nodeTable, CutHistory] }; NodeFromRope: PUBLIC PROC [id: Rope.ROPE, circuit: Circuit] RETURNS [node: Node] ~ { flatWire: CoreFlat.FlatWire _ NEW[CoreFlat.FlatWireRec _ CoreFlat.ParseWirePath[circuit.rootCell, id]]; node _ NARROW[HashTable.Fetch[circuit.nodeTable, flatWire].value]; }; RopeFromNode: PUBLIC PROC [node: Node, circuit: Circuit] RETURNS [id: Rope.ROPE] ~ { id _ CoreFlat.WirePathRope[circuit.rootCell, node.flatWire^]; }; SetNode: PUBLIC PROC [node: Node, val, input: BOOLEAN _ TRUE, t: ps _ 0.0] ~ { v: REAL _ IF val THEN VddVal ELSE GndVal; node.history _ IF node.history=NIL THEN Schedule.CreateHistory[t, v] ELSE Schedule.AddToHistory[node.history, t, v]; node.input _ input; }; GetNode: PUBLIC PROC [node: Node] RETURNS [val: BOOLEAN] ~ { v: REAL _ Schedule.LastValueOfHistory[node.history]; val _ v>2500.0; }; SettledValuesOfNode: PUBLIC PROC [node: Node] RETURNS [t: ps, v: mVolt] ~ { t _ Schedule.LastTimeOfHistory[node.history]; v _ Schedule.LastValueOfHistory[node.history]; }; EditNodeHistory: PUBLIC PROC [node: Node, t: ps, v: mVolt] ~ { IF node.history=NIL THEN node.history _ Schedule.CreateHistory[t, v] ELSE node.history _ Schedule.AddToHistory[node.history, t, v]; }; EditNodeInputBool: PUBLIC PROC [node: Node, forcedInput: BOOLEAN] ~ { node.input _ forcedInput; }; KillCaminos: PUBLIC PROC [caminos: Caminos] ~ { cam: Caminos; UNTIL caminos=NIL DO caminos.first _ NIL; cam _ caminos; caminos _ caminos.rest; cam.rest _ NIL; ENDLOOP; }; KillFetList: PUBLIC PROC [fetList: FetList] ~ { fList: FetList; UNTIL fetList=NIL DO fetList.first _ NIL; fList _ fetList; fetList _ fetList.rest; fList.rest _ NIL; ENDLOOP; }; KillNodeList: PUBLIC PROC [nodeList: NodeList] ~ { nList: NodeList; UNTIL nodeList=NIL DO nodeList.first _ NIL; nList _ nodeList; nodeList _ nodeList.rest; nList.rest _ NIL; ENDLOOP; }; KillSetList: PUBLIC PROC [setList: SetList, killSets: BOOLEAN _ TRUE] ~ { sList: SetList; UNTIL setList=NIL DO IF killSets THEN { KillFetList[setList.first.lFets]; KillNodeList[setList.first.lNodes]; KillNodeList[setList.first.inList]; KillNodeList[setList.first.fixedV]; setList.first.type _ NIL; }; setList.first _ NIL; sList _ setList; setList _ setList.rest; sList.rest _ NIL; ENDLOOP; }; KillNode: HashTable.EachPairAction ~ { node: Node _ NARROW[value]; node.flatWire _ NIL; Schedule.KillHistory[node.history]; KillFetList[node.fetList]; KillSetList[node.setList, FALSE]; }; KillCircuit: PUBLIC PROC [circuit: Circuit] ~ { lib: Library; circuit.rootCell _ NIL; [] _ HashTable.Pairs[circuit.nodeTable, KillNode]; HashTable.Erase[circuit.nodeTable]; Schedule.KillAgenda[circuit.agenda]; UNTIL circuit.library=NIL DO KillSetList[circuit.library.first.setList, TRUE]; circuit.library.first.type _ NIL; circuit.library.first _ NIL; lib _ circuit.library; circuit.library _ circuit.library.rest; lib.rest _ NIL; ENDLOOP; circuit.info _ NIL; }; MintEnum: PROC [plot: PlotGraph.Plot, graph: PlotGraph.Graph, bounds: PlotGraph.Rectangle, eachPoint: PlotGraph.PointProc, data: REF ANY _ NIL] RETURNS [invalidEnumeration: BOOL _ FALSE] ~ { Action: Schedule.HistoryProc ~ { quit _ eachPoint[t, v, data]; }; quit: BOOLEAN _ FALSE; node: Node _ NARROW[graph.data]; to: REAL _ IF bounds.w=0.0 THEN 1e24 ELSE bounds.x+bounds.w; from: REAL _ IF bounds.w=0.0 THEN -1e24 ELSE bounds.x; quit _ Schedule.EnumerateHistory[node.history, from, to, Action]; }; AddNodeToPlot: PUBLIC PROC [node: Node, plot: PlotGraph.Plot, r: Rope.ROPE _ NIL] ~ { circuit: Circuit _ NARROW[plot.data]; rect: PlotGraph.Rectangle _ [plot.lowerBounds.x, 0.0, plot.upperBounds.x - plot.lowerBounds.x, 5000.0]; IF r=NIL THEN r _ RopeFromNode[node, circuit]; PlotGraph.LockPlot[plot]; plot.axis _ CONS[ NEW[PlotGraph.AxisRec _ [ graphs: LIST[NEW[PlotGraph.GraphRec _ [ class: mintGClass, data: node, name: "" ]]], bounds: rect, name: IF r#NIL THEN r ELSE RopeFromNode[node, circuit], style: analog, axisData: [mintAxisData, mintAxisData] ]], plot.axis]; PlotGraph.UnlockPlot[plot]; PlotGraph.RefreshPlot[plot: plot, within: rect, eraseFirst: TRUE]; }; DrawNodeList: PUBLIC PROC [nodeList: NodeList, circuit: Circuit] RETURNS[plot: PlotGraph.Plot] ~ { rect: PlotGraph.Rectangle; plot _ PlotGraph.CreatePlot[CoreOps.GetCellTypeName[circuit.rootCell]]; PlotGraph.LockPlot[plot]; plot.data _ circuit; plot.lowerBounds _ [1.0e24, 0.0]; plot.upperBounds _ [-1.0e24, 5000.0]; FOR inodeList: NodeList _ nodeList, inodeList.rest UNTIL inodeList=NIL DO plot.lowerBounds.x _ MIN[plot.lowerBounds.x, Schedule.FirstTimeOfHistory[inodeList.first.history]]; plot.upperBounds.x _ MAX[plot.upperBounds.x, Schedule.LastTimeOfHistory[inodeList.first.history]]; ENDLOOP; plot.upperBounds.x _ MAX[plot.upperBounds.x, 1.0+plot.lowerBounds.x]; rect _ [plot.lowerBounds.x, 0.0, plot.upperBounds.x - plot.lowerBounds.x, 5000.0]; FOR inodeList: NodeList _ nodeList, inodeList.rest UNTIL inodeList=NIL DO plot.axis _ CONS[ NEW[PlotGraph.AxisRec _ [ graphs: LIST[NEW[PlotGraph.GraphRec _ [ class: mintGClass, data: inodeList.first, name: "" ]]], bounds: rect, name: RopeFromNode[inodeList.first, circuit], style: analog, axisData: [mintAxisData, mintAxisData] ]], plot.axis]; ENDLOOP; PlotGraph.UnlockPlot[plot]; PlotGraph.RefreshPlot[plot: plot, within: rect, eraseFirst: TRUE]; }; mintGClass: PlotGraph.GraphClass _ NEW[PlotGraph.GraphClassRec _ [ insert: NIL, delete: NIL, enumerate: MintEnum ]]; mintAxisData: PlotGraph.AxisData _ [1000.0, TRUE, FALSE]; IF separateView THEN { typeScript: TypeScript.TS _ TypeScript.Create[info: [name: "Mint", iconic: TRUE, icon: Icons.NewIconFromFile["Mint.icons", 1]]]; StdOut _ ViewerIO.CreateViewerStreams[name: "Mint", viewer: typeScript].out; } ELSE StdOut _ TerminalIO.TOS[]; IO.PutRope[StdOut, "\nMint loaded\n"]; END. vMintImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Christian LeCocq January 14, 1987 4:32:25 pm PST RealFns, RealFns, some usefull definitions Simulation Computations evaluates the time interval and verifies inputs Propagate: PROC [node: Node, action: PROC[node: Node] RETURNS [quit: BOOLEAN _ FALSE]] RETURNS [quit: BOOLEAN _ FALSE] ~ { Calls action for all the nodes of the sets activated by node. FOR iSetList: SetList _ node.setList, iSetList.rest UNTIL iSetList=NIL DO FOR inodeList: NodeList _ iSetList.first.lNodes, inodeList.rest UNTIL inodeList=NIL DO quit _ action[inodeList.first]; IF quit THEN RETURN; ENDLOOP; ENDLOOP; }; Swap: PROC [A: LinearSystem.MatrixN, b:LinearSystem.ColumnN, i, j, n: CARDINAL] ~ { tempRow: LinearSystem.RowN; tempReal: REAL; tempRow _ A[i]; A[i] _ A[j]; A[j] _ tempRow; tempReal _ b[i]; b[i] _ b[j]; b[j] _ tempReal; FOR k:CARDINAL IN [0..n) DO tempReal _ A[k][i]; A[k][i] _ A[k][j]; A[k][j] _ tempReal; ENDLOOP; }; CheckSwitch: PROC [fet: Fet, t0, t1: ps] RETURNS [change: BOOLEAN _ FALSE, changet: ps _ 0] ~ { status is TRUE if fet is on. Version with substrate effect. vSource, vTran, vGate, vCh1, vCh2: mVolt; chMin, chMax, chActive: Node; status: BOOLEAN; vGate _ Schedule.VFromHistory[fet.gate.history, t1]; vCh1 _ Schedule.VFromHistory[fet.ch1.history, t1]; vCh2 _ Schedule.VFromHistory[fet.ch2.history, t1]; IF vCh1 { chActive _ chMin; vSource _ MIN[vCh1, vCh2]; vDrain _ MAX[vCh1, vCh2]; vTran _ vSource+VtVal+gamma*(RealFns.SqRt[vSource+phi]-sqrtPhi); status _ (vGate > vTran); SELECT TRUE FROM vGate<=vSource => status _ FALSE; vGate>=vDrain => status _ TRUE; ENDCASE => { vTran _ vSource+VtVal+gamma*(RealFns.SqRt[vSource+phi]-sqrtPhi); status _ (vGate > vTran); }; }; pE => { chActive _ chMax; vSource _ MAX[vCh1, vCh2]; vDrain _ MIN[vCh1, vCh2]; vTran _ vSource-(VtVal+gamma*(RealFns.SqRt[VddVal-vSource+phi] - sqrtPhi)); status _ (vGate < vTran); SELECT TRUE FROM vGate>=vSource => status _ FALSE; vGate<=vDrain => status _ TRUE; ENDCASE => { vTran _ vSource-(VtVal+gamma*(RealFns.SqRt[VddVal-vSource+phi] - sqrtPhi)); status _ (vGate < vTran); }; }; ENDCASE => ERROR; IF status#fet.switch THEN { UNTIL t1-t0˜>Kšœœœœœ6œ$œœ˜ήK˜K˜—š žœœ;œœœ˜š ž œœ œœœ˜@Kšœœœœ˜ Kšœ œœ˜Kšœ6˜6šœœ-œ˜>Kšœ`˜`šœ1œ œ˜IKšœ4˜4Kšœœ˜šœ=œ œ˜VKšœ#˜#Kšœ˜—Kšœ˜—K˜—K˜—K˜šœ(œœ˜=K™/šœœœ˜!Kšœœ˜1KšœB˜BK˜—šœ˜KšœœH˜dKšœœ˜)K˜—Kšœ˜—K˜K˜—šž œœœ œœœœœœ™zK™=šœ1œ œ™Išœ=œ œ™VKšœ™Kšœœœ™Kšœ™—Kšœ™—K™K™—šž œœ˜ Kšœœ˜šœ&œœ˜:Kšœœ˜šœ*œœ˜?šœœ˜%Kšœœ˜ Kšœ˜K˜—Kšœ˜—šœœ˜Kšœœ˜šœ*œœ˜?šœœ˜%Kšœœ˜ Kšœ˜K˜—Kšœ˜—Kšœœœ˜>K˜—Kšœ˜—K˜K˜—šž œœ œœ˜Všœ0œ œ˜Kšœ<œ œ˜Všœœœ˜ šœ'œ˜/Kšœ œ˜(Kšœ œ˜,Kšœœ˜K˜——Kšœ˜—Kšœ˜—KšœŸ˜K˜K˜—šž œœœœ˜Wšœ,œ œ˜Fšœœœ˜%Kšœ œ˜.Kšœ œ!˜2Kšœœ˜K˜—šœœœ˜%Kšœ œ˜.Kšœ œ!˜2Kšœœ˜K˜—Kšœ˜—KšœŸ˜K˜—š žœœ&œœœ˜\Kšœ ˜ Kšœ˜Kšœ˜šœ3œ œ˜MKšœ-˜-Kšœ˜—šœ7œ œ˜PKšœœ˜Kšœ˜—šœ7œ œ˜PKšœœ˜Kšœ˜—šœ0œ œ˜IKšœœ˜Kšœ˜—šœ7œ œ˜PKšœœœ˜"Kšœœ ˜Kšœ œ˜!Kšœ˜Kšœœ˜šœ œ˜K˜&K˜'Kšœ˜—šœ7œ œ˜PKšœœ˜Kšœ˜—šœ.œ œ˜Fš œœœœœ˜]Kšœœ˜Kšœ œ!˜2K˜—š œœœœœ˜^Kšœœ˜Kšœ œ!˜2K˜—Kšœ˜—šœ7œ œ˜PKšœœ˜Kšœ˜—Kšœ œ˜Kšœ˜—K˜K˜—šœS™SKšœ™Kšœ™Kšœ™K™ Kšœ™Kšœ™Kšœ ™ Kšœ™šœ™Kšœ™K™Kšœ™Kšœ™—K™K™—š ž œœœ œœ™_Kšœ;™;Kšœ)™)Kšœ™Kšœœ™Kšœ4™4Kšœ2™2Kšœ2™2šœ œ%™6Kšœ$™(—šœ ™™Kšœ™Kšœ œ ™Kšœ œ ™Kšœ@™@Kšœ™šœœ™Kšœœ™!Kšœœ™šœ™ Kšœ@™@Kšœ™K™——Kšœ™—™Kšœ™Kšœ œ ™Kšœ œ ™KšœK™KKšœ™šœœ™Kšœœ™!Kšœœ™šœ™ KšœK™KKšœ™K™——Kšœ™—Kšœœ™—šœœ™šœ™K™Kšœ!œ™/Kšœ ™ Kšœ™ —Kšœ œ™Kšœ ™ K™—K™K™—š ž œœœ œœ˜_Kšœ>™>Kšœœ˜Kšœ<˜<šœ ˜Kšœ%˜%Kšœ%˜%Kšœœ˜—šœœ˜šœ˜K˜Kšœ!œ˜/Kšœ ˜ Kšœ˜ —Kšœ œ˜Kšœ ˜ K˜—K˜K˜—š ž œœ œ œœ˜bK˜Kšœœ˜Kšœœ˜Kšœ ˜ šœ,œ œ˜DKšœ2˜2šœœ˜K˜/Kšœ œ˜šœœ˜šœ3œ œ˜LKšœ1˜1Kšœ˜—Kšœœ˜Kšœ˜Kšœ ˜ K˜—Kšœœ˜2K˜—Kšœ˜—K˜K˜—šž œœ œœ˜3Kšœ œ˜šœ.œ œ˜FKšœœ˜Kšœ˜—Kšœœ˜ K˜K˜—šžœœ-˜8Kšœœ˜Kšœ˜Kšœ˜Kšœ9˜9Kšœ9˜9Kšœ9˜9Kšœ9˜9Kšœ œ˜K˜K˜—šž œœ&œœ#˜jKšœ˜Kšœœ˜ Kšœ#˜#Kšœ˜Kšœ˜Kšœ˜šœœœ˜&Kšœ˜Kšœ˜Kšœ˜Kšœ˜—K˜K˜—šžœœ%œ˜LKšœ(˜(Kšœ;˜;Kšœ˜Kšœœ˜Kšœ œœ˜Kšœœ˜,Kš œ œœœŸ$˜Fšœ2œ œ˜KKšœ˜Kšœ˜Kšœ˜—Kšœ˜šœ2œ œ˜KKšœ˜Kšœ˜Kšœ˜—Kšœ œ!˜-Kšœ œ˜+Kšœœ˜)Kšœœ˜'šœ2œ œ˜KKšœQ˜QKšœ˜—šœ2œ œ˜KKšœQ˜QKšœ˜—šœ.œ œ˜HKšœœ˜Kšœ˜—K™.šœœœ ˜$Kšœœ˜0Kšœ˜šœ œœ ˜'Kšœ˜Kšœ˜—Kšœ˜—šœ2œ œ™Kšœ<œ œ™Všœœœ™8Kšœ%œ™JK™+K™—Kšœ™—Kšœ™—šœ.œ œ˜HKšœœœ˜UKšœ˜—K™;šœœœ˜,šœœ˜Kšœ œ˜Kšœ˜K˜—Kšœ˜—Kšœ œœ˜Kšœ œœ™K™5šœœœ˜'Kšœ!™!šœœœ˜,Kšœ0˜0Kšœ˜—Kšœ˜—K™/šœ2œ œ˜KKšœj˜jKšœ˜—Kšœ=™=šœœ˜Kšœ œ$˜0šœœœ˜'Kšœ ˜ Kšœ˜—K˜—KšœP˜TKšœ˜š œ œœœœ˜9Kšœ+˜+KšœŸ˜6šœœœ˜"Kšœ˜šœœœ˜'Kšœ3˜3Kšœ˜—Kšœ˜—KšœN˜NKšœ˜šœœœ˜"KšœO˜OKšœ˜—šœœœ˜'KšœM˜MKšœ˜—Kšœ,˜,Kšœ˜Kš˜—Kšœ1˜5K™)Kšœ˜šœ2œ œ˜KKšœr˜rKšœœœ˜ŸKšœ˜—K˜K˜——™ šž œœœ˜>šžœ˜&Kšœ>™>Kšœ œ˜K˜Kšœ œœ˜Kšœ/˜/Kšœœ˜šœ/œ œ˜FKšœ;˜;Kšœ˜—K˜—Kšœ(œ ˜4Kšœ2˜2Kšœ.˜.Kšœ˜K˜K˜—šžœœœ#œ ˜QK˜K˜Kšœ!˜!Kšœ)˜)Kšœ7˜7Kšœ)˜)Kšœ7˜7Kšœ=˜=Kšœ˜Kšœ+˜+Kšœ&˜&KšœEœ$œ œ/˜ͺKšœŸ˜K˜—š Οbœœœœœœ˜>Kšœœ˜$Kšœg˜gKšœ˜Kšœ<œ˜BK˜K˜—šžœ œ<˜\Kšœ˜Kšœ˜Kšœ˜Kšœ!˜!Kšœ)˜)Kšœ7˜7Kšœ)˜)Kšœ7˜7Kšœ(˜(Kšœ>˜>Kšœ˜Kšœ+˜+K˜——™šžœœœ3œ˜hKšœ˜Kšœ˜Kšœ˜Kšœ œ˜Kšœ˜Kšœ2˜2Kšœ œœœ˜.šœ.œ œ˜Fšœœœ˜)Kšœ'˜'Kšœœ œœ˜[K˜—Kšœœ˜"Kšœ˜—K˜šœ,œ œ˜DKšœ œ˜šœ9œ œ˜QKšœœ œœ˜8Kšœ˜—šœ œ˜šœ=œ œ˜Všœ>œ œ˜WKšœ œ-˜:Kšœ˜—Kš˜Kšœ˜——Kšœ˜—Kšœœ˜Kšœ,˜,K˜K˜—š  œœœœœœ˜AKšœ œ˜Kšœœ˜)Kšœœ˜4šœ*œœ˜?šœœœ˜!Kšœ.˜.Kšœ˜K˜—Kšœ˜—Kšœ&˜&K˜K˜—šžœœœ7œ'˜šž œ˜*Kšœ œ˜šœ/œ œ˜HKšœœœ˜$Kšœ˜—Kšœœ˜Kšœ œœ˜šœ/œ œ˜FKšœ=˜=Kšœ˜—K˜—šž œ˜)Kšœ œ˜Kšœœœ(˜?K˜—Kšœœ˜ Kšœœ˜!Kšœ/˜/Kšœ/˜/Kšœ1˜1Kšœ œ˜$Kšœœ˜Kšœœ-˜LKšœ/˜/Kšœ3˜3Kšœ>Ÿ˜EKšœ!˜!KšœE˜EKšœ6˜6Kšœ7˜7Kšœ7˜7Kšœ.˜.šœ'œœ˜™>Jšœœ˜ šœ2œ œ˜KKšœ˜Kšœ˜šœœ˜!šœœœ˜šœ œœ˜1šœœœ ˜Kšœ&˜&Kšœ˜—Kšœ-˜-Kšœ˜K˜—Kšœ˜——Kšœ˜—K˜K˜—Kšœ œœ ˜!Kšœ œœ œœœœœ˜dKšœœ˜%K˜ Kšœœ˜šœœœ˜Kšœ˜Kšœ˜—Kšœ0˜0K˜~Kšœ ˜ Kšœ˜šœœœ˜šœœœ˜"šœBœ œ˜[Kšœœ˜Kšœ˜—šœBœ œ˜[Kšœœ˜Kšœ˜—šœ>œ œ˜XKšœœ˜Kšœ˜—Kšœ[˜[Kšœέ˜έKšœ œœ0˜@Kšœ œ!˜0Kšœ˜—Kšœ˜—K˜K˜—š žœœœœœ+˜gš  œ˜*Kšœ>™>Kšœœ˜ Kšœ œ˜Kšœœœœ˜ Kšœ œœ˜Kšœ#˜#Kšœœœ˜"šœœœ˜šœ œœ˜*šœœœ ˜Kšœ&˜&Kšœ˜—Kšœ˜Kšœ˜K˜—Kšœ˜—K˜K˜—Kšœ œœ ˜!Kš œ œœ œœœœ˜UKšœœ˜%šœœœ˜Kšœ˜Kšœ˜—Kšœ6˜6šœœœ˜Kšœœœ œ"˜SKšœ˜—Kšœ!˜!K˜K˜——™ šž œœ˜*Kšœœœ˜TKš œ%œœœœ˜‹K˜K˜—šžœ œ!˜6Kšœœœœ˜Kšœ6œœœ œœœœ œœ œœ(œ'œ)Ÿœ˜ΝK˜K˜—šž œœœ#˜9Kšœœœœ˜Kšœ œ$œ˜[šœ.œœ˜@Kšœ œœ˜LKšœ˜—˜K˜——šž œ œ)˜Bšœ,œ œ˜DKšœ"˜"Kšœ˜—K˜K˜—šž œ œ+˜EKšœ˜šœ0œ œ˜IKšœ$˜$Kšœ˜—K˜K˜—šž œœ'˜8Kšœ˜šœ(œ œ˜?Kšœ(˜(Kšœ˜—K˜K˜—šž œœ)˜;Kšœ˜šœ,œ œ˜DKšœ&˜&Kšœ˜—K˜K˜—šžœœœ˜?šœ0œ œ˜IKšœ˜Kšœ˜—K˜K˜—šžœœœ˜,šœ1œ œ˜JKšœœ˜Kšœ˜—K˜K˜—šžœœ˜)Kšœ˜Kšœ œ˜Kšœ œ˜Kšœ™Kšœ œ˜$Kšœ™šœœ˜Kšœ˜Kšœ˜K˜—Kšœ˜šœ5˜:šœœ˜Kšœ˜Kšœ˜K˜—Kšœ˜Kšœ˜—K˜K˜—šž œœ˜+Kšœ˜Kšœ œ˜Kšœ œ˜Kšœ™Kšœ œ˜$Kšœ&™&šœœ˜Kšœ˜Kšœ˜K˜—Kšœ˜šœ5˜:šœœ˜Kšœ˜Kšœ˜K˜—Kšœ˜Kšœ˜—K˜K˜—šž œœœ œœœœ˜išœœ˜šœ6œ œ˜NKšœ˜Kšœœœ˜Kšœ˜—Kšœ˜Kšœ˜—K˜K˜—šžœœœ˜2šž œ˜(Kšœ>™>Kšœ œ˜Kšœœœœ˜ Kšœ œœ˜Kšœ-œ˜FKšœ`˜dK˜—K˜Kšœ3˜3K˜K˜—š ž œœœ œœ˜TKšœœF˜gKšœœ5˜BK˜K˜—šž œ œ œ œ˜TKšœ=˜=K˜K˜—š žœœœœœ˜NKš œœœœœ˜)Kš œœœœœ+˜tKšœ˜K˜K˜—šžœ œœœ˜Kšœœœ,˜DKšœ:˜>K˜K˜—šžœœœœ˜EKšœ˜K˜K˜—šΠbn œœœ˜/Kšœ ˜ šœ œ˜Kšœœ˜Kšœ˜Kšœ˜Kšœ œ˜Kšœ˜—K˜K˜—š‘ œœœ˜/Kšœ˜šœ œ˜Kšœœ˜Kšœ˜Kšœ˜Kšœ œ˜Kšœ˜—K˜K˜—š‘ œœœ˜2Kšœ˜šœ œ˜Kšœœ˜Kšœ˜Kšœ˜Kšœ œ˜Kšœ˜—K˜K˜—š ž œœœœœ˜IKšœ˜šœ œ˜šœ œ˜Kšœ!˜!Kšœ#˜#Kšœ#˜#Kšœ#˜#Kšœœ˜K˜—Kšœœ˜Kšœ˜Kšœ˜Kšœ œ˜Kšœ˜—K˜K˜—šžœ˜&Kšœ>™>Kšœ œ˜Kšœœ˜Kšœ#˜#Kšœ˜Kšœœ˜!K˜K˜—šž œœœ˜/K˜ Kšœœ˜Kšœ2˜2Kšœ#˜#Kšœ$˜$šœœ˜Jšœ+œ˜1Jšœœ˜!Jšœœ˜Jšœ˜Kšœ'˜'Kšœ œ˜Kšœ˜—Kšœœ˜K˜——™šžœœsœœœœœœ˜Ύšžœ˜ Kšœ˜K˜—Kšœœœ˜Kšœ œ ˜ Kš œœœœœ˜