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; Path: TYPE = LIST OF RECORD[node: Node, fet: Fet]; PathList: TYPE = LIST OF Path; Delay: TYPE = REF DelayRec; DelayRec: TYPE = RECORD [tup, tdown: ps]; ExtendedCircuit: TYPE = REF ExtendedCircuitRec; ExtendedCircuitRec: TYPE = RECORD [circuit: Circuit, data: REF ANY]; TimedPlot: TYPE = REF TimedPlotRec; TimedPlotRec: TYPE = RECORD [plot: PlotGraph.Plot _ NIL, oldt: ps _ 0.0]; gndName: Rope.ROPE _ "public.Gnd"; vddName: Rope.ROPE _ "public.Vdd"; VddVal: mVolt _ 5000.0; GndVal: mVolt _ 0.0; pVtVal: mVolt _ -0.800; nVtVal: mVolt _ 0.780; 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 _ 5.0; tInc: ps _ 100.0; approx: REAL _ 1.4; overlapFactor: REAL _ 0.5; matrixCacheSize: CARDINAL _ 100; 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 i: NAT IN [0..iNodeList.first.fetSeq.nUsed) DO fet: Fet = iNodeList.first.fetSeq[i]; IF NOT fet.done THEN IF fet.gate # iNodeList.first THEN { fetList _ CONS[fet, fetList]; set.lFets _ CONS[fet, set.lFets]; fet.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.type FROM nE => status _ (vGate1 >= threshold); pE => status _ (vGate1 <= threshold); ENDCASE => ERROR; IF status#fet.switch THEN { UNTIL t1-t0matrixCacheSize THEN RETURN[LinearSystem.Copy[matrix]]; FOR i: CARDINAL IN [0..n) DO TRUSTED { subij: LONG POINTER TO REAL _ @circuit.private.subMatrix[i][0]; limitIJ: LONG POINTER TO REAL _ @circuit.private.subMatrix[i][n-1]; matrixij: LONG POINTER TO REAL _ @matrix[i][0]; DO subij^ _ matrixij^; IF subij = limitIJ THEN EXIT; subij _ subij + SIZE[REAL]; matrixij _ matrixij + SIZE[REAL]; ENDLOOP; }; ENDLOOP; RETURN[circuit.private.subMatrix]; }; MySolveN: PROC [matrix: LinearSystem.MatrixN, cstTerm: LinearSystem.ColumnN, nActiveNodes: CARDINAL, circuit: Circuit] RETURNS [vFinal: LinearSystem.ColumnN] ~ { IF nActiveNodes>matrixCacheSize THEN RETURN[LinearSystem.SolveN[LinearSystem.Copy[matrix], cstTerm, nActiveNodes]]; FOR i: CARDINAL IN [0..nActiveNodes) DO TRUSTED { copyij: LONG POINTER TO REAL _ @circuit.private.copyMatrix[i][0]; limitIJ: LONG POINTER TO REAL _ @circuit.private.copyMatrix[i][nActiveNodes-1]; matrixij: LONG POINTER TO REAL _ @matrix[i][0]; DO copyij^ _ matrixij^; IF copyij = limitIJ THEN EXIT; copyij _ copyij + SIZE[REAL]; matrixij _ matrixij + SIZE[REAL]; ENDLOOP; }; ENDLOOP; RETURN[LinearSystem.SolveN[circuit.private.copyMatrix, cstTerm, nActiveNodes]] }; RCSolve: PROC [set: Set, t: ps, circuit: Circuit] RETURNS [nextTime: ps] ~ { matrix, subMatrix: LinearSystem.MatrixN; cstTerm, vInit, vFinal, tau, vFinal2: LinearSystem.ColumnN; tFinal: ps _ 0.0; halfVddVal: REAL _ VddVal/2.0; triState: BOOLEAN _ TRUE; nNodes, nActiveNodes, lastAct: CARDINAL _ 0; IF set.fixedV=NIL THEN RETURN[t]; -- this cell is isolated (triState). FOR iNodeList: NodeList _ set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.index _ nNodes; nNodes _ nNodes+1; ENDLOOP; nActiveNodes _ nNodes; FOR iNodeList: NodeList _ set.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.index _ nNodes; nNodes _ nNodes+1; ENDLOOP; IF nNodes>matrixCacheSize THEN { matrix _ NEW[LinearSystem.MatrixSeq[nNodes]]; cstTerm _ NEW[LinearSystem.VecSeq[nNodes]]; vInit _ NEW[LinearSystem.VecSeq[nNodes]]; tau _ NEW[LinearSystem.VecSeq[nNodes]]; } ELSE { matrix _ circuit.private.matrix; cstTerm _ circuit.private.cstTerm; vInit _ circuit.private.vInit; tau _ circuit.private.tau; }; FOR iNodeList: NodeList _ set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO vInit[iNodeList.first.index] _ Schedule.VFromHistory[iNodeList.first.history, t]; ENDLOOP; FOR iNodeList: NodeList _ set.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO vInit[iNodeList.first.index] _ Schedule.VFromHistory[iNodeList.first.history, t]; ENDLOOP; FOR iFetList: FetList _ set.lFets, iFetList.rest UNTIL iFetList = NIL DO iFetList.first.done _ FALSE; ENDLOOP; FOR iRow: CARDINAL IN [0..nNodes) DO IF matrix[iRow]=NIL THEN matrix[iRow] _ NEW[LinearSystem.VecSeq[nNodes]]; cstTerm[iRow] _ 0.0; TRUSTED { limitIJ: LONG POINTER TO REAL _ @matrix[iRow][nNodes-1]; matrixij: LONG POINTER TO REAL _ @matrix[iRow][0]; DO matrixij^ _ 0.0; IF matrixij = limitIJ THEN EXIT; matrixij _ matrixij + SIZE[REAL]; ENDLOOP; }; ENDLOOP; FOR iFetList: FetList _ set.lFets, iFetList.rest UNTIL iFetList = NIL DO IF ~iFetList.first.done AND iFetList.first.switch THEN Coeff[matrix, iFetList.first]; ENDLOOP; FOR i: CARDINAL IN [nActiveNodes..nNodes) DO IF matrix[i][i]#0.0 THEN { triState _ FALSE; EXIT; }; ENDLOOP; IF triState THEN ERROR; FOR i: CARDINAL IN [0..nActiveNodes) DO FOR j: CARDINAL IN [nActiveNodes..nNodes) DO cstTerm[i] _ cstTerm[i] - matrix[i][j]*vInit[j]; ENDLOOP; ENDLOOP; FOR iNodeList: NodeList _ set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.history _ Schedule.AddToHistory[iNodeList.first.history, t, vInit[iNodeList.first.index]]; ENDLOOP; IF nNodes=nActiveNodes+1 THEN { vFinal _ NEW[LinearSystem.VecSeq[nActiveNodes]]; FOR i: CARDINAL IN [0..nActiveNodes) DO vFinal[i] _ vInit[nActiveNodes]; ENDLOOP; } ELSE vFinal _ MySolveN[matrix, cstTerm, nActiveNodes, circuit]; lastAct _ nActiveNodes-1; IF lastAct#0 THEN FOR i: CARDINAL IN [0..nActiveNodes) DO vTemp: ps _ IF vFinal[i]>halfVddVal THEN GndVal ELSE VddVal; subMatrix _ XchIndexes[matrix, i, lastAct, nNodes, circuit]; vInit[lastAct] _ vTemp; --this node becomes a V source FOR k: CARDINAL IN [0..lastAct) DO cstTerm[k] _ 0.0; FOR j: CARDINAL IN [lastAct..nNodes) DO cstTerm[k] _ cstTerm[k] - subMatrix[k][j]*vInit[j]; ENDLOOP; ENDLOOP; vFinal2 _ MySolveN[subMatrix, cstTerm, lastAct, circuit]; cstTerm[lastAct] _ 0.0; FOR j: CARDINAL IN [0..lastAct) DO cstTerm[lastAct] _ cstTerm[lastAct] + subMatrix[lastAct][j]*(vTemp-vFinal2[j]); ENDLOOP; FOR j: CARDINAL IN (lastAct..nNodes) DO cstTerm[lastAct] _ cstTerm[lastAct] + subMatrix[lastAct][j]*(vTemp-vInit[j]); ENDLOOP; tau[i] _ (vTemp-vFinal[i])/cstTerm[lastAct]; tFinal _ tFinal+tau[i]; ENDLOOP ELSE { tau[0] _ -1.0/matrix[0][0]; tFinal _ tau[0] }; tFinal _ approx*tFinal; --performs the estimation of the pt where v[t] = vFinal nextTime _ t+tFinal; FOR iNodeList: NodeList _ set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.history _ Schedule.AddToHistory[iNodeList.first.history, nextTime, vFinal[iNodeList.first.index]]; IF debug THEN IO.PutF[StdOut,"%g : %dmV @ %dps\n", IO.rope[RopeFromNode[iNodeList.first, circuit]], IO.real[vFinal[iNodeList.first.index]], IO.real[nextTime]]; ENDLOOP; }; Initialize: PROC [circuit: Circuit] RETURNS [t: ps _ 1e30] ~ { SetEvent: HashTable.EachPairAction ~ { node: Node _ NARROW[value]; t0: ps; IF ~node.input THEN RETURN; t0 _ Schedule.FirstTimeOfHistory[node.history]; t _ MIN[t, t0]; FOR setList: SetList _ node.setList, setList.rest UNTIL setList=NIL DO Schedule.InsertInAgenda[circuit.agenda, setList.first, t0]; ENDLOOP; }; Schedule.InsertInAgenda[circuit.agenda, NIL, -1e30]; [] _ HashTable.Pairs[circuit.nodeTable, SetEvent]; [] _ VisitLibrary[circuit.library, ResetSets]; SetTime[t, circuit]; }; CircuitSimulate: PUBLIC PROC[circuit: Circuit, from: ps _ 0.0] RETURNS [t: ps] ~{ gndNode, vddNode: Node; lastNodes: NodeList; circuit.info.nbOfSimulations _ 0; gndNode _ NodeFromRope[gndName, circuit]; gndNode.history _ Schedule.CreateHistory[from, GndVal]; vddNode _ NodeFromRope[vddName, circuit]; vddNode.history _ Schedule.CreateHistory[from, VddVal]; circuit.agenda _ Schedule.CreateAgenda[SimulateSet, circuit]; t _ Initialize[circuit]; t _ Schedule.ExecuteAgenda[circuit.agenda]; [t, lastNodes] _ LastTime[circuit, 1]; IO.PutF[StdOut, "\nfinished after %d set simulations at %d ps(%g)\n", IO.int[circuit.info.nbOfSimulations], IO.real[t], IO.rope[RopeFromNode[lastNodes.first, circuit]]]; }; -- CircuitSimulate SimulateAndPlot: PROC [ref: REF ANY, t: ps, data: REF ANY] ~ { tPlot: TimedPlot ~ NARROW[data]; deltat: ps _ t-tPlot.oldt; rect: PlotGraph.Rectangle _ [tPlot.oldt-deltat, GndVal, MAX[4*deltat, 1.0], VddVal-GndVal]; SimulateSet[ref, t, tPlot.plot.data]; PlotGraph.RefreshPlot[plot: tPlot.plot, within: rect, eraseFirst: FALSE]; tPlot.oldt _ t; }; InteractiveSimulate: PUBLIC PROC [circuit: Circuit, watchList: NodeList _ NIL, from: ps _ 0.0] ~ { t: ps; gndNode, vddNode: Node; tPlot: TimedPlot _ NEW[TimedPlotRec]; circuit.info.nbOfSimulations _ 0; gndNode _ NodeFromRope[gndName, circuit]; gndNode.history _ Schedule.CreateHistory[from, GndVal]; vddNode _ NodeFromRope[vddName, circuit]; vddNode.history _ Schedule.CreateHistory[from, VddVal]; IF watchList=NIL THEN watchList _ WatchedListOf[circuit]; tPlot.plot _ DrawNodeList[watchList, circuit]; circuit.agenda _ Schedule.CreateAgenda[SimulateAndPlot, tPlot]; t _ Initialize[circuit]; t _ Schedule.ExecuteAgenda[circuit.agenda]; }; NextSets: PROC [c: CaminoCell, setCache: HashTable.Table] RETURNS [camino: Camino] ~ { set: Set ~ c.set; node: Node ~ c.node; value: HashTable.Value; boolVal: BOOLEAN; subSets: SetList; [boolVal, value] _ HashTable.Fetch[setCache, set]; IF boolVal THEN RETURN[[0.0, NARROW[value, LIST OF CaminoCell]]]; FOR iFetList: FetList _ set.lFets, iFetList.rest UNTIL iFetList=NIL DO QuickSetFet[iFetList.first]; ENDLOOP; subSets _ ClipSet[set]; FOR iSetList: SetList _ subSets, iSetList.rest UNTIL iSetList=NIL DO subSet: Set _ iSetList.first; boolVal _ FALSE; FOR iFetList: FetList _ subSet.lFets, iFetList.rest UNTIL iFetList=NIL DO IF iFetList.first.gate=node THEN {boolVal _ TRUE; EXIT}; ENDLOOP; IF boolVal THEN { FOR iNodeList: NodeList _ subSet.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO IF iNodeList.first.ignoreMe THEN LOOP; IF iNodeList.first.watched THEN camino.data _ CONS[[NEW[SetRec _ [inList: LIST[iNodeList.first]]], iNodeList.first], camino.data]; FOR iSetList2: SetList _ iNodeList.first.setList, iSetList2.rest UNTIL iSetList2=NIL DO camino.data _ CONS[[iSetList2.first, iNodeList.first], camino.data]; ENDLOOP; ENDLOOP; }; ENDLOOP; KillSetList[subSets, TRUE]; [] _ HashTable.Store[setCache, set, camino.data]; }; SimulateOrRegister: PROC [ref: REF ANY, t: ps, data: REF ANY] ~ { set: Set ~ NARROW[ref]; extdCirc: ExtendedCircuit _ NARROW[data]; startTable: HashTable.Table _ NARROW[extdCirc.data]; FOR inode: NodeList _ set.inList, inode.rest UNTIL inode=NIL DO IF inode.first.history=NIL THEN { [] _ HashTable.Store[startTable, set, $Start]; RETURN; }; ENDLOOP; [] _ HashTable.Delete[startTable, set]; --in case we registered it too early SimulateSet[ref, t, extdCirc.circuit]; }; MaxFreqEvaluate: PUBLIC PROC [circuit: Circuit, clkList: NodeList, numberOfPaths: CARD, from: ps _ 0.0, histOk: BOOLEAN _ TRUE] RETURNS [worst: ps _ 0.0, caminos: Caminos]~ { EraseHistory: HashTable.EachPairAction ~ { node: Node _ NARROW[value]; FOR inodeList: NodeList _ clkList, inodeList.rest UNTIL inodeList=NIL DO IF inodeList.first=node THEN RETURN; ENDLOOP; node.history _ NIL; IF ~node.input THEN RETURN; FOR setList: SetList _ node.setList, setList.rest UNTIL setList=NIL DO Schedule.InsertInAgenda[circuit.agenda, setList.first, from]; ENDLOOP; }; CreateStart: HashTable.EachPairAction ~ { set: Set _ NARROW[key]; liveCaminos _ CONS[[0.0, LIST[[set, set.inList.first]]], liveCaminos]; }; RecordOrForget: PROC [camino: Camino] ~ { delay: Delay _ ThruTime[camino.data.rest, camino.data.first.node, delayCache, delayListCache, circuit]; camino.length _ MAX[delay.tup, delay.tdown]; IF histOk THEN Histograms.ChangeTransformed[hist, camino.length]; nTotal _ nTotal+1; SELECT alreadyIn FROM 0 => { caminos _ LIST[camino]; nthTime _ camino.length; worst _ camino.length; alreadyIn _ 1; }; IN [1..numberOfPaths) => { caminos _ CONS[camino, caminos]; alreadyIn _ alreadyIn+1; IF camino.length>nthTime THEN nthTime _ camino.length; IF camino.length>worst THEN worst _ camino.length }; ENDCASE => IF camino.length>nthTime THEN { IF camino.length>worst THEN worst _ camino.length; FOR iCaminos: Caminos _ caminos, iCaminos.rest DO IF camino.length>iCaminos.first.length THEN { iCaminos.first _ camino; nthTime _ camino.length; RETURN; }; ENDLOOP; }; }; level, nTotal, alreadyIn: CARD _ 0; nthTime: REAL _ 0.0; found, finished: BOOLEAN _ FALSE; gndNode: Node = NodeFromRope[gndName, circuit]; vddNode: Node = NodeFromRope[vddName, circuit]; startTable: HashTable.Table _ HashTable.Create[]; liveCaminos: Caminos; extdCirc: ExtendedCircuit _ NEW[ExtendedCircuitRec _ [circuit, startTable]]; setCache: HashTable.Table _ HashTable.Create[]; delayCache: HashTable.Table _ HashTable.Create[]; delayListCache: HashTable.Table _ HashTable.Create[]; setListCache: HashTable.Table _ HashTable.Create[]; hist: Histograms.Histogram; --in ns circuit.info.nbOfSimulations _ 0; circuit.agenda _ Schedule.CreateAgenda[SimulateOrRegister, extdCirc]; [] _ HashTable.Pairs[circuit.nodeTable, EraseHistory]; gndNode.history _ Schedule.CreateHistory[from, GndVal]; vddNode.history _ Schedule.CreateHistory[from, VddVal]; [] _ VisitLibrary[circuit.library, ResetSets]; FOR inode: NodeList _ clkList, inode.rest UNTIL inode=NIL DO IF inode.first.history=NIL THEN inode.first.history _ Schedule.CreateHistory[from, VddVal]; FOR setList: SetList _ inode.first.setList, setList.rest UNTIL setList=NIL DO Schedule.InsertInAgenda[circuit.agenda, setList.first, from]; ENDLOOP; ENDLOOP; [] _ Schedule.ExecuteAgenda[circuit.agenda]; [] _ HashTable.Pairs[startTable, CreateStart]; IF histOk THEN hist _ Histograms.Create1D[100.0, 0.0]; UNTIL liveCaminos=NIL DO n2: INT _ 0; oldCaminos: Caminos _ liveCaminos; liveCaminos _ NIL; level _ level+1; FOR iCaminos: Caminos _ oldCaminos, iCaminos.rest UNTIL iCaminos=NIL DO thisCamino: Camino _ iCaminos.first; nextOnes: Camino _ NextSets[thisCamino.data.first, setCache]; FOR iNext: LIST OF CaminoCell _ nextOnes.data, iNext.rest UNTIL iNext=NIL DO found _ FALSE; FOR iCamino: LIST OF CaminoCell _ thisCamino.data, iCamino.rest UNTIL iCamino=NIL DO IF iNext.first.set=iCamino.first.set THEN { newCamino: Camino _ [0.0, CONS[iNext.first, thisCamino.data]]; RecordOrForget[newCamino]; found _ TRUE; EXIT } ENDLOOP; IF ~found THEN { newCamino: Camino _ [0.0, CONS[iNext.first, thisCamino.data]]; liveCaminos _ CONS[newCamino, liveCaminos]; n2 _ n2+1; }; ENDLOOP; IF nextOnes.data=NIL THEN { RecordOrForget[thisCamino]; }; ENDLOOP; KillCaminos[oldCaminos]; IF verbose THEN IO.PutF[StdOut, "level: %d, total %d, in use %d, worst:%d\n", IO.int[level], IO.int[nTotal], IO.int[n2], IO.real[worst/1000.0]] ENDLOOP; FOR iCaminos: Caminos _ caminos, iCaminos.rest UNTIL iCaminos=NIL DO IF iCaminos.first.length=worst THEN { camino: Camino _ iCaminos.first; iCaminos.first _ caminos.first; caminos.first _ camino; EXIT; }; ENDLOOP; IF histOk THEN [] _ Histograms.Show[hist]; }; ThruTime: PROC [caminoData: LIST OF CaminoCell, node: Node, setCache, setListCache: HashTable.Table, circuit: Circuit] RETURNS [delay: Delay] ~ { setDelay, prevDelay: Delay; delay _ NEW[DelayRec _ [0.0, 0.0]]; IF caminoData=NIL THEN RETURN; setDelay _ DelayOfSet[caminoData.first.set, node, setCache, circuit]; prevDelay _ ThruTime[caminoData.rest, caminoData.first.node, setCache, setListCache, circuit]; delay.tup _ overlapFactor*setDelay.tup+prevDelay.tdown; delay.tdown _ overlapFactor*setDelay.tdown+prevDelay.tup; }; DelayOfSet: PROC [set: Set, node: Node, setCache: HashTable.Table, circuit: Circuit] 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 iNList: NodeList _ set.inList, iNList.rest UNTIL iNList=NIL DO iNList.first.done _ iNList.first.history#NIL; 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 QuickSetFet[iFetList.first]; ENDLOOP; [tup, tdown] _ EvalRC[node, set, circuit]; delay.tup _ tup; delay.tdown _ tdown; FOR iNodeList: NodeList _ set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO iNodeList.first.history _ NIL; ENDLOOP; [] _ HashTable.Store[setCache, set, delay]; }; FindSetOfNode: PROC [node: Node] RETURNS [set: Set] ~ { found: BOOLEAN _ FALSE; FOR i: NAT IN [0..node.fetSeq.nUsed) DO fet: Fet = node.fetSeq[i]; FOR iSetList: SetList _ fet.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; oldPathList _ LIST[LIST[[node, NIL]]]; node.index _ 1; UNTIL finished DO level _ level+1; [finished, oldPathList, pathList] _ IncPaths[set.lFets, oldPathList, pathList, level]; ENDLOOP; }; IncPaths: PROC [fetList: FetList, oldPathList, completedPathList: PathList, level: NAT] RETURNS [finished: BOOLEAN _ TRUE, newPathList, newCompletedPathList: PathList _ NIL] ~ { FOR iPathList: PathList _ oldPathList, iPathList.rest UNTIL iPathList=NIL DO path: Path _ iPathList.first; thisNode: Node _ path.first.node; terminal: BOOLEAN _ TRUE; IF ~thisNode.input THEN FOR iFetList: FetList _ fetList, iFetList.rest UNTIL iFetList=NIL DO thisFet: Fet _ iFetList.first; nextNode: Node; SELECT thisNode FROM thisFet.ch1 => nextNode _ thisFet.ch2; thisFet.ch2 => nextNode _ thisFet.ch1; ENDCASE => LOOP; IF nextNode.index=0 OR nextNode.index>=level THEN { newPathList _ CONS[ CONS[[nextNode, thisFet], path], newPathList]; IF ~nextNode.input THEN nextNode.index _ level; terminal _ FALSE; finished _ FALSE; }; ENDLOOP; IF terminal THEN completedPathList _ CONS[path, completedPathList]; ENDLOOP; newCompletedPathList _ completedPathList; }; EvalRC: PROC [node: Node, set: Set, circuit: Circuit] RETURNS [tup, tdown: ps _ 0] ~ { subSets: SetList; pathList: PathList; pathToPower: Path; 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.node.input THEN { n _ n+1; pathToPower _ iPathList.first; }; ENDLOOP; SELECT n FROM 0 => ERROR; 1 => { t: ps _ 0.0; r: REAL _ 0.0; FOR iPath: Path _ pathToPower, iPath.rest UNTIL iPath.rest=NIL DO r _ r+1.0/iPath.first.fet.type.rOnInv; t _ t+iPath.rest.first.node.cap*r; ENDLOOP; IF GetNode[pathToPower.first.node] THEN tup _ approx*t ELSE tdown _ approx*t; }; ENDCASE => { 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 i: NAT IN [0..node.fetSeq.nUsed) DO fet: Fet = node.fetSeq[i]; fet.switch _ IF bool THEN fet.type.type=nE ELSE fet.type.type=pE; ENDLOOP; subSets _ ClipSet[set]; FOR iSetList: SetList _ subSets, iSetList.rest UNTIL iSetList=NIL DO [tempup, tempdown] _ EvalRC[node, iSetList.first, circuit]; 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, circuit]; 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: PUBLIC PROC [camino: Camino, circuit: Circuit] ~ { IO.PutF[StdOut,"\n %d ", IO.real[camino.length]]; FOR iCamino: LIST OF CaminoCell _ camino.data, iCamino.rest UNTIL iCamino=NIL DO PrintNode[ iCamino.first.node, circuit]; ENDLOOP; }; PrintCaminos: PUBLIC 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; }; WatchedListOf: PUBLIC PROC [circuit: Circuit] RETURNS [wList: NodeList] ~ { SearchWatched: HashTable.EachPairAction ~ { node: Node _ NARROW[value]; IF node.watched THEN wList _ CONS[node, wList]; }; [] _ HashTable.Pairs[circuit.nodeTable, SearchWatched] }; 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>VddVal/2.0; }; QuickSetFet: PROC [fet: Fet] ~ { IF fet.gate.history#NIL THEN { v: REAL _ Schedule.LastValueOfHistory[fet.gate.history]; fet.switch _ SELECT fet.type.type FROM nE => v>nVtVal, pE => v ERROR; } ELSE fet.switch _ TRUE; }; 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 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]; FOR i: NAT IN [0..node.fetSeq.nUsed) DO node.fetSeq[i] _ NIL; ENDLOOP; 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 IF inodeList.first.history#NIL THEN { 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.CreateStream[]; IO.PutRope[StdOut, "\nMint loaded\n"]; END. âMintImpl.mesa Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved. Christian LeCocq April 21, 1987 9:09:51 pm PDT RealFns, RealFns, MintPrivateData: PUBLIC TYPE = REF MintPrivateDataRec; MintPrivateDataRec: TYPE = RECORD[ matrix: LinearSystem.MatrixN, cstTerm: LinearSystem.ColumnN, vInit: LinearSystem.ColumnN, tau: LinearSystem.ColumnN, copyMatrix: LinearSystem.MatrixN ]; 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; }; 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-t0matrixCacheSize THEN RETURN[LinearSystem.Copy[matrix]]; FOR i: CARDINAL IN [0..n) DO FOR j: CARDINAL IN [0..n) DO circuit.private.subMatrix[i][j] _ matrix[i][j]; ENDLOOP; ENDLOOP; RETURN[circuit.private.subMatrix]; }; FOR j: CARDINAL IN [0..nActiveNodes) DO circuit.private.copyMatrix[i][j] _ matrix[i][j]; ENDLOOP; Initialisations (no ALL[0.0] for sequences...) FOR iColumn: CARDINAL IN [0..nNodes) DO matrix[iRow][iColumn] _ 0.0; ENDLOOP; If fixed voltages are not connected to the set then ERROR. IF triState THEN RETURN[t]; Fixed voltages are removed from the system to solve. mark the point where the value begins to change Solve the RC system, which as a side effect destroys cstTerm. mark the point where the value stabilizes Execution PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN _ FALSE]; Timing Evaluation Detection of circularities: never twice the same set. If circularities then add the set (if not zero length circularity) and give up this camino. no circularities so add the set to the current Camino, and the Camino to the next round candidates no further ways available so record it in the finished caminos. value: HashTable.Value; found: BOOLEAN; [found, value] _ HashTable.Fetch[setListCache, caminoData]; IF found THEN RETURN[NARROW[value, Delay]]; [] _ HashTable.Store[setListCache, caminoData, delay]; does this set contain the specified node ? does this set contain one of the power node ? is there only one path to a power node ? either no further input specification reduces the poblem, or the set has only one path to power PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN _ FALSE]; PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN _ FALSE]; Utilities PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN _ FALSE]; add node to fixed voltages and remove it from lNodes add node to lNodes and remove it from fixed voltages list PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN _ FALSE]; PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN _ FALSE]; Plot Management �Ê:˜codešœ ™ KšœB™BK™.K™K™—šÏk ˜ K˜ K˜Kšœ ˜ Kšœ ˜ Kšœ˜Kš�œ˜Kšœ ˜ Kšœ˜K˜ Kšœ˜Kšœ™Kšœ˜Kšœ ˜ K˜ Kšœ ˜ Kšœ ˜ K˜—KšÏnœ�œ�˜š�˜K˜ K˜Kšœ ˜ Kšœ ˜ Kšœ˜Kš�œ˜Kšœ ˜ K˜ Kšœ™Kšœ ˜ K˜ Kšœ ˜ Kšœ˜K˜—š�˜K˜—š�˜Kšœ˜—šœ�œ�œ˜Kšœ�œ�œ�œ™6šœ�œ�œ™"Kšœ™Kšœ™Kšœ™Kšœ™Kšœ ™ Kšœ™—Kš œ�œ�œ�œ�œ˜2Kšœ �œ�œ�œ˜Kšœ�œ�œ ˜Kšœ �œ�œ˜)Kšœ�œ�œ˜/Kš œ�œ�œ�œ�œ˜DKšœ �œ�œ˜#Kšœ�œ�œ�œ˜IK˜K™Kšœ�œ˜"Kšœ�œ˜"Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ�œÏc+˜GKšœ˜Kšœ �œ ˜K˜K˜Kšœ�œ˜Kšœ�œ˜K˜K˜Kšœ�œ˜ Kšœ �œ˜Kšœ�œ�œ˜Kš œ�œ�œ�œ�œ˜Kšœ�œ�œ�œ˜Kšœ �œ�œ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ�œ˜Kšœ �œ�œ�œ˜+Kšœ�œ˜'Kšœ �œ˜K˜—head™š ž œ�œ�œ�œ�œ�œ˜:Kšœ�œ˜ Kšœ �œ˜Kšœ)˜)Kšœ˜K˜Kšœ�œ�œ˜%Kšœ�œ�œ˜)Kšœ �œ�œ˜Kšœ!˜!Kš�œ�œ�œ�œ˜Kš�œ �œ�œ˜Kšœ �œ˜Kš �œ�œ�œ�œ#�œ˜sKšœ8�œ˜Aš�œ(�œ�œ�˜=Kš�œ �œ�œ&�œ*˜dKš�œ˜—Kšœ:˜:Kšœ�œ˜š�œ*�œ�œ�˜?Kš�œ�œ!˜.Kšœ�œ&˜;Kš�œ˜—š�œ*�œ�œ�˜?Kš�œ�œ˜7Kš�œ˜—š�œ*�œ�œ�˜?Kš�œ�œ˜4Kš�œ˜—Kš�œ�œ�œ˜,Kšœ-˜-Kšœ ˜ š�œ�œ�œ�˜2Kšœ˜Kš�œ˜—Kšœ˜Kš�œ�œ�œ-˜Gš� œ �˜Kšœ;˜;Kš�œ �œ �œ˜#Kšœ �œ˜š�œ �œ˜Kšœ˜Kšœ˜š�œ*�œ �œ�˜AKšœ-˜-Kšœ �œ˜Kšœ �œ˜š�œ�œ �œ˜Kš�œ,�œ �œ ˜LJšœ-˜-K˜—Kš�œ˜—Kšœ�œ˜K˜—š�œ˜Kšœ˜š�œ�œ�œ�˜1Kšœ˜Kš�œ˜—Kš�œ�œ#�œ �œ˜?Kšœ �œ�œ�œ ˜EK˜—Kš�˜—š�œ*�œ�œ�˜?š�œ6�œ �œ�˜MKšœe˜eKšœ�œ˜Kš�œ˜—Kš�œ˜—Kšœ>˜>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š�œ�œ�œ#�˜2Kšœ%˜%š�œ�œ �œ˜š�œ�œ˜$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˜—š ž œ�œ�œ �œ�œ™_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šœ˜Kšœ˜Kšœ%˜%Kšœ%˜%Kšœ%˜%Kšœ%˜%Kšœ �œ˜K˜K˜—šž œ�œ)� œ�œ#˜Kšœ˜Kšœ�œ˜ Kšœ$˜$Kšœ˜Kšœ˜Kšœ˜š�œ�œ�œ�˜Kšœ˜Kšœ˜Kšœ˜Kš�œ˜—K˜K˜—šž œ� œ˜1Kšœ�œ˜*Kšœ�œ*˜FKšœ�œ'˜DKšœ�œ'˜BKšœ�œ'˜@Kšœ�œ*˜JKšœ�œ*˜Iš�œ�œ�œ�˜-Kšœ�œ'˜IKšœ#�œ'˜MKšœ"�œ'˜LKš�œ˜—K˜K˜K˜—šžœ�œ#�œ�œ"™tKš�œ�œ�œ™<š�œ�œ�œ�™š�œ�œ�œ�™Kšœ/™/Kš�œ™—Kš�œ™—Kš�œ™"K™K™—šžœ�œ#�œ�œ"˜tKš�œ�œ�œ˜<š�œ�œ�œ�˜š�œ˜ Jš œ�œ�œ�œ�œ$˜?Jš œ �œ�œ�œ�œ&˜CJš œ �œ�œ�œ�œ˜/š�˜Jšœ˜Jš�œ�œ�œ˜Jšœ�œ�œ˜Jšœ�œ�œ˜!Jš�œ˜—Jšœ˜—Kš�œ˜—Kš�œ˜"K˜K˜—šžœ�œM�œ�œ#˜¡Kš�œ�œ�œH˜sš�œ�œ�œ�˜'š�œ�œ�œ�™'Kšœ0™0Kš�œ™—š�œ˜ Jš œ�œ�œ�œ�œ%˜AJš œ �œ�œ�œ�œ2˜OJš œ �œ�œ�œ�œ˜/š�˜Jšœ˜Jš�œ�œ�œ˜Jšœ�œ�œ˜Jšœ�œ�œ˜!Jš�œ˜—Jšœ˜—Kš�œ˜—Kš�œH˜NK˜K˜—šžœ�œ%�œ˜LKšœ(˜(Kšœ;˜;Kšœ˜Kšœ �œ˜Kšœ �œ�œ˜Kšœ�œ˜,Kš �œ �œ�œ�œŸ$˜Fš�œ2�œ �œ�˜KKšœ˜Kšœ˜Kš�œ˜—Kšœ˜š�œ2�œ �œ�˜KKšœ˜Kšœ˜Kš�œ˜—š�œ�œ˜ Kšœ �œ!˜-Kšœ �œ˜+Kšœ�œ˜)Kšœ�œ˜'K˜—š�œ˜Kšœ ˜ Kšœ"˜"Kšœ˜Kšœ˜K˜K˜—š�œ2�œ �œ�˜KKšœQ˜QKš�œ˜—š�œ2�œ �œ�˜KKšœQ˜QKš�œ˜—š�œ.�œ �œ�˜HKšœ�œ˜Kš�œ˜—K™.š�œ�œ�œ �˜$Kš�œ�œ�œ�œ˜IKšœ˜š�œ �œ�œ �™'Kšœ™Kš�œ™—š�œ˜ Jš œ �œ�œ�œ�œ˜8Jš œ �œ�œ�œ�œ˜2š�˜Jšœ˜Jš�œ�œ�œ˜ Jšœ�œ�œ˜!Jš�œ˜—Jšœ˜—Kš�œ˜—š�œ.�œ �œ�˜HKš�œ�œ�œ˜UKš�œ˜—Kšœ4�œ™:š�œ�œ�œ�˜,š�œ�œ˜Kšœ �œ˜Kš�œ˜K˜—Kš�œ˜—Kš�œ �œ�œ˜Kš�œ �œ�œ™K™5š�œ�œ�œ�˜'š�œ�œ�œ�˜,Kšœ0˜0Kš�œ˜—Kš�œ˜—K™/š�œ2�œ �œ�˜KKšœj˜jKš�œ˜—Kšœ=™=š�œ�œ˜Kšœ �œ$˜0š�œ�œ�œ�˜'Kšœ ˜ Kš�œ˜—K˜—Kš�œ;˜?Kšœ˜š �œ �œ�œ�œ�œ�˜9Kšœ �œ�œ�œ˜šžœ˜&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šœ˜Kšœ8�œ ˜[Kšœ%˜%KšœB�œ˜IKšœ˜K˜K˜—šžœ�œ�œ*�œ˜bKšœ˜Kšœ˜Kšœ�œ˜%Kšœ!˜!Kšœ)˜)Kšœ7˜7Kšœ)˜)Kšœ7˜7Kš�œ �œ�œ$˜9Kšœ.˜.Kšœ?˜?Kšœ˜Kšœ+˜+K˜——™šžœ�œ,�œ˜VKšœ˜Kšœ˜Kšœ˜Kšœ �œ˜Kšœ˜Kšœ2˜2Kš �œ �œ�œ�œ�œ�œ˜Aš�œ.�œ �œ�˜FKšœ˜Kš�œ˜—K˜š�œ,�œ �œ�˜DKšœ˜Kšœ �œ˜š�œ1�œ �œ�˜IKš�œ�œ �œ�œ˜8Kš�œ˜—š�œ �œ˜š�œ5�œ �œ�˜NKš�œ�œ�œ˜&Kš �œ�œ�œ�œ�œ4˜‚š�œ>�œ �œ�˜WKšœ�œ2˜DKš�œ˜—Kš�˜Kšœ˜——Kš�œ˜—Kšœ�œ˜Kšœ1˜1K˜K˜—š  œ�œ�œ�œ�œ�œ˜AKšœ �œ˜Kšœ�œ˜)Kšœ�œ˜4š�œ*�œ�œ�˜?š�œ�œ�œ˜!Kšœ.˜.Kš�œ˜K˜—Kš�œ˜—Kšœ(Ÿ$˜LKšœ&˜&K˜K˜—šžœ�œ�œ6�œ�œ�œ�œ'˜®šž œ˜*Kšœ �œ˜š�œ/�œ �œ�˜HKš�œ�œ�œ˜$Kš�œ˜—Kšœ�œ˜Kš�œ �œ�œ˜š�œ/�œ �œ�˜FKšœ=˜=Kš�œ˜—K˜—šž œ˜)Kšœ �œ˜Kšœ�œ�œ)˜FK˜—šžœ�œ˜)Kšœg˜gJšœ�œ˜,Jš�œ�œ3˜AJšœ˜š�œ �˜šœ˜Kšœ �œ ˜Kšœ˜Kšœ˜Kšœ˜Kšœ˜—š�œ˜Jšœ �œ˜ Jšœ˜Kš�œ�œ˜6Kš�œ�œ˜1Jšœ˜—š�œ�œ�œ˜*Kš�œ�œ˜2š�œ,�˜1š�œ$�œ˜-Kšœ˜Kšœ˜Kš�œ˜K˜—Kš�œ˜—Jšœ˜——K˜—Kšœ�œ˜#Kšœ �œ˜Kšœ�œ˜!Kšœ/˜/Kšœ/˜/Kšœ1˜1Kšœ˜Kšœ�œ-˜LKšœ/˜/Kšœ1˜1Kšœ5˜5Kšœ3˜3KšœŸ˜#Kšœ!˜!KšœE˜EKšœ6˜6Kšœ7˜7Kšœ7˜7Kšœ.˜.š�œ'�œ�œ�˜Kšœ˜Kšœ�œ˜ Kš�˜Kšœ˜—Kš�œ˜—š�œ�œ˜Kšœb™bKšœ�œ ˜>Kšœ�œ˜+K˜ K˜—Kš�œ˜—š�œ�œ�œ˜Kšœ?™?Kšœ˜K˜—Kš�œ˜—Kšœ˜Kš�œ �œ�œ<�œ �œ�œ �œ˜�Kš�œ˜—š�œ,�œ �œ�˜Dš�œ�œ˜%Jšœ ˜ Jšœ˜Jšœ˜Jš�˜J˜—Kš�œ˜—Kš�œ�œ˜*K˜K˜—š žœ�œ�œ�œT�œ˜‘Kšœ™Kšœ�œ™Kšœ˜Kšœ;™;Kš�œ�œ�œ�œ™+Kšœ�œ˜#Jš�œ �œ�œ�œ˜JšœE˜EKšœ^˜^Kšœ7˜7Kšœ9˜9Kšœ6™6K˜K˜—šž œ�œE�œ˜oKšœ˜Kšœ�œ˜K˜Kšœ0˜0Kš�œ�œ�œ�œ˜+Kšœ�œ˜#š�œ,�œ�œ�˜BKšœ)�œ˜-Kš�œ˜—š�œ,�œ�œ�˜BKšœ�œ˜Kš�œ˜—š�œ.�œ �œ�˜HKšœ˜Kš�œ˜—Kšœ*˜*Kšœ˜Kšœ˜š�œ2�œ �œ�˜KKšœ�œ˜Kš�œ˜—Kšœ,˜,K˜K˜—šž œ�œ�œ˜7Kšœ�œ�œ˜š�œ�œ�œ�˜'K˜š�œ5�œ �œ�˜Mš�œ=�œ �œ�˜VKš�œ�œ�œ˜4Kš�œ˜—Kš�œ˜—Kš�œŸ=˜DKš�œ˜—K˜K˜—šž œ�œ�œ˜JKšœ �œ�œ˜Kšœ˜Kšœ�œ˜š�œ2�œ �œ�˜KKšœ˜Kš�œ˜—š�œ2�œ �œ�˜KKšœ˜Kš�œ˜—Kšœ�œ�œ�œ˜&Kšœ˜š�œ �˜Kšœ˜KšœV˜VKš�œ˜—K˜K˜—šžœ�œE�œ�œ �œ�œ!�œ�œ˜±š�œ3�œ �œ�˜LKšœ˜Kšœ!˜!Kšœ �œ�œ˜š �œ�œ�œ,�œ �œ�˜\Kšœ˜Kšœ˜š�œ �˜Kšœ&˜&Kšœ&˜&Kš�œ�œ˜—š�œ�œ�œ˜3Kšœ�œ�œ*˜BKš�œ�œ˜/Kšœ �œ˜Kšœ �œ˜K˜—Kš�œ˜—Kš�œ �œ�œ˜CKš�œ˜—Kšœ)˜)K˜K˜—šžœ�œ*�œ˜VKšœ˜Kšœ˜K˜Kšœ�œ˜K˜Kšœ�œ˜ Kšœ*™*š�œ2�œ �œ�˜Kš�œ�œ˜Kšœ�œ˜ Kš�œ˜Kšœ˜—Kš�œ˜—Kš�œ�œ�œ˜Kšœ-™-Kš�œ �œ�œ�œ˜K™(Kšœ#˜#š�œ0�œ �œ�˜Iš�œ!�œ˜*Kšœ˜Kšœ˜K˜—Kš�œ˜—š�œ�˜ Kšœ�œ˜ ˜K˜ Kšœ�œ˜š�œ'�œ �œ�˜AKšœ&˜&Kšœ"˜"Kš�œ˜—Kš�œ!�œ�œ˜MK˜—š�œ˜ Kšœ˜š�œ2�œ �œ�˜Kš�œ�œ˜Kšœ�œ˜š �œ�œ�œ�œ�˜š�œ�œ�œ�˜'K˜Kšœ �œ�œ�œ˜AKš�œ˜—K˜š�œ,�œ �œ�˜DKšœ;˜;Kšœ�œ˜Kšœ�œ˜Kš�œ˜—Kšœ�œ˜—Kš�œ˜K˜—Kš�œ˜K˜———š�œ �œ �œ˜K™_Kšœ˜š�œ.�œ �œ�˜HKšœ�œ˜Kš�œ˜—Kšœ.�œ�œ˜:Kšœ˜Kš�œ�œ �œ ˜-K˜—K˜K˜—š žœ�œ�œ�œ�œ �œ˜aš  œ�œ �œ�œ˜5Kšœ>™>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šœd˜dKšœÝ˜Ý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˜—šž œ� œ'˜?Kš�œ1˜3š �œ �œ�œ(�œ �œ�˜PKšœ(˜(Kš�œ˜—K˜K˜—šž œ� œ)˜BKš�œ˜š�œ,�œ �œ�˜DKšœ&˜&Kš�œ˜—K˜K˜—šžœ�œ�œ˜?š�œ0�œ �œ�˜IKšœ˜Kš�œ˜—K˜K˜—šž œ�œ�œ�œ˜Kš  œ˜+Kšœ>™>Kšœ �œ˜Kš�œ�œ �œ˜/K˜—Kšœ6˜6K˜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˜—š¡ œ�œ�œ˜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šœ�œ˜Kšœ2˜2Kšœ#˜#Kšœ$˜$š�œ�œ�˜Jšœ+�œ˜1Jšœ�œ˜!Jšœ�œ˜Jšœ˜Kšœ'˜'Kšœ �œ˜Kš�œ˜—Kšœ�œ˜K˜——™šžœ�œs�œ�œ�œ�œ�œ�œ˜¾šžœ˜ Kšœ˜K˜—Kšœ�œ�œ˜Kšœ �œ ˜ Kš œ�œ�œ�œ�œ˜