MintImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Christian LeCocq April 21, 1987 9:09:51 pm PDT
DIRECTORY
CoreFlat,
CoreOps,
HashTable,
Histograms,
Icons,
IO,
LinearSystem,
Mint,
PlotGraph,
Real,
RealFns,
Rope,
Schedule,
TerminalIO,
TypeScript,
ViewerIO;
MintImpl: CEDAR PROGRAM
IMPORTS
CoreFlat,
CoreOps,
HashTable,
Histograms,
Icons,
IO,
LinearSystem,
PlotGraph,
RealFns,
Schedule,
TerminalIO,
TypeScript,
ViewerIO
EXPORTS
Mint
SHARES
Schedule
~ BEGIN OPEN Mint;
MintPrivateData: PUBLIC TYPE = REF MintPrivateDataRec;
MintPrivateDataRec: TYPE = RECORD[
matrix: LinearSystem.MatrixN,
cstTerm: LinearSystem.ColumnN,
vInit: LinearSystem.ColumnN,
tau: LinearSystem.ColumnN,
copyMatrix: LinearSystem.MatrixN
];
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];
some usefull definitions
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: BOOLFALSE;
StdOut: PUBLIC IO.STREAMNIL;
debug: PUBLIC BOOLFALSE;
verbose: PUBLIC BOOLFALSE;
debugCircuit: Circuit ← NIL;
debugNode: Node ← NIL;
debugNodeList: NodeList ← NIL;
debugHList: LIST OF Schedule.History ← NIL;
statsNumberOfSimulations: CARDINAL ← 0;
nSimInc: CARDINAL ← 50;
Simulation Computations
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: BOOLEANFALSE;
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: BOOLEANTRUE] RETURNS [uninitialized: NodeList] ~ {
CutHistory: PROC[node: Node] RETURNS [quit: BOOLEANFALSE] ~ {
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
evaluates the time interval and verifies inputs
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;
};
Propagate: PROC [node: Node, action: PROC[node: Node] RETURNS [quit: BOOLEANFALSE]] RETURNS [quit: BOOLEANFALSE] ~ {
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;
};
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: BOOLEANFALSE, 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<vCh2 THEN { chMin ← fet.ch1; chMax ← fet.ch2}
ELSE {chMin ← fet.ch2; chMax ← fet.ch1};
SELECT fet.type FROM
nE => {
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<timeSpecs DO
ti: ps ← (t0 + t1)/2;
IF CheckSwitch[fet, t0, ti].change THEN t1 ← ti
ELSE t0 ← ti;
ENDLOOP;
change ← TRUE;
changet ← t1;
};
};
CheckSwitch: PROC [fet: Fet, t0, t1: ps] RETURNS [change: BOOLEANFALSE, changet: ps ← 0] ~ {
status is TRUE if fet is on. Version without substrate effect.
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-t0<timeSpecs DO
ti: ps ← (t0 + t1)/2;
IF CheckSwitch[fet, t0, ti].change THEN t1 ← ti
ELSE t0 ← ti;
ENDLOOP;
change ← TRUE;
changet ← t1;
};
};
FlipSwitches: PROC [fetList: FetList, t0, t1: ps] RETURNS [finished: BOOLEANTRUE, newt: ps] ~ {
t: ps;
change: BOOLEAN;
previousFets: FetList ← NIL;
newt ← t1;
FOR iFetList: FetList ← fetList, iFetList.rest UNTIL iFetList=NIL DO
[change, t] ← CheckSwitch[iFetList.first, t0, t1];
IF change THEN {
iFetList.first.switch ← ~iFetList.first.switch;
finished ← FALSE;
IF t<newt-timeSpecs THEN {
FOR iprevList: FetList ← previousFets, iprevList.rest UNTIL iprevList=NIL DO
iprevList.first.switch ← ~iprevList.first.switch;
ENDLOOP;
previousFets ← NIL;
t1 ← t;
newt ← t;
};
previousFets ← CONS[iFetList.first, previousFets];
};
ENDLOOP;
};
ResetSets: PROC [set: Set] RETURNS [ok: BOOLEAN]~ {
set.done ← FALSE;
FOR iFetList: FetList ← set.lFets, iFetList.rest UNTIL iFetList=NIL DO
iFetList.first.switch ← TRUE;
ENDLOOP;
RETURN[TRUE];
};
Coeff: PROC [matrix: LinearSystem.MatrixN, fet: Fet] ~ {
i1, i2: CARDINAL;
x1: REAL ← fet.type.rOnInv/fet.ch1.cap;
x2: REAL ← fet.type.rOnInv/fet.ch2.cap;
i1 ← fet.ch1.index;
i2 ← fet.ch2.index;
matrix[i1][i1] ← matrix[i1][i1] - x1;
matrix[i1][i2] ← matrix[i1][i2] + x1;
matrix[i2][i2] ← matrix[i2][i2] - x2;
matrix[i2][i1] ← matrix[i2][i1] + x2;
fet.done ← TRUE;
};
XchIndexes: PROC [matrix: LinearSystem.MatrixN, i, j, n: CARDINAL, circuit: Circuit] RETURNS [xChged: LinearSystem.MatrixN] ~ {
rowN: LinearSystem.RowN;
elt: REAL;
xChged ← MyCopy[matrix, n, circuit];
rowN ← xChged[i];
xChged[i] ← xChged[j];
xChged[j] ← rowN;
FOR k: CARDINAL IN [0..n) DO
elt ← xChged[k][i];
xChged[k][i] ← xChged[k][j];
xChged[k][j] ← elt;
ENDLOOP;
};
CreatePrivate: PUBLIC PROC [circuit: Circuit] ~ {
circuit.private ← NEW[MintPrivateDataRec];
circuit.private.matrix ← NEW[LinearSystem.MatrixSeq[matrixCacheSize]];
circuit.private.cstTerm ← NEW[LinearSystem.VecSeq[matrixCacheSize]];
circuit.private.vInit ← NEW[LinearSystem.VecSeq[matrixCacheSize]];
circuit.private.tau ← NEW[LinearSystem.VecSeq[matrixCacheSize]];
circuit.private.copyMatrix ← NEW[LinearSystem.MatrixSeq[matrixCacheSize]];
circuit.private.subMatrix ← NEW[LinearSystem.MatrixSeq[matrixCacheSize]];
FOR iRow: CARDINAL IN [0..matrixCacheSize) DO
circuit.private.matrix[iRow] ← NEW[LinearSystem.VecSeq[matrixCacheSize]];
circuit.private.copyMatrix[iRow] ← NEW[LinearSystem.VecSeq[matrixCacheSize]];
circuit.private.subMatrix[iRow] ← NEW[LinearSystem.VecSeq[matrixCacheSize]];
ENDLOOP;
};
MyCopy: PROC [matrix: LinearSystem.MatrixN, n: CARDINAL, circuit: Circuit] RETURNS [mCopy: LinearSystem.MatrixN] ~ {
IF n>matrixCacheSize 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];
};
MyCopy: PROC [matrix: LinearSystem.MatrixN, n: CARDINAL, circuit: Circuit] RETURNS [mCopy: LinearSystem.MatrixN] ~ {
IF n>matrixCacheSize 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
FOR j: CARDINAL IN [0..nActiveNodes) DO
circuit.private.copyMatrix[i][j] ← matrix[i][j];
ENDLOOP;
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: BOOLEANTRUE;
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;
Initialisations (no ALL[0.0] for sequences...)
FOR iRow: CARDINAL IN [0..nNodes) DO
IF matrix[iRow]=NIL THEN matrix[iRow] ← NEW[LinearSystem.VecSeq[nNodes]];
cstTerm[iRow] ← 0.0;
FOR iColumn: CARDINAL IN [0..nNodes) DO
matrix[iRow][iColumn] ← 0.0;
ENDLOOP;
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;
If fixed voltages are not connected to the set then ERROR.
FOR i: CARDINAL IN [nActiveNodes..nNodes) DO
IF matrix[i][i]#0.0 THEN {
triState ← FALSE;
EXIT;
};
ENDLOOP;
IF triState THEN ERROR;
IF triState THEN RETURN[t];
Fixed voltages are removed from the system to solve.
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;
mark the point where the value begins to change
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;
Solve the RC system, which as a side effect destroys cstTerm.
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] };
mark the point where the value stabilizes
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;
};
Execution
Initialize: PROC [circuit: Circuit] RETURNS [t: ps ← 1e30] ~ {
SetEvent: HashTable.EachPairAction ~ {
PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE];
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];
};
Timing Evaluation
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: BOOLEANTRUE] 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;
Detection of circularities: never twice the same set.
FOR iCamino: LIST OF CaminoCell ← thisCamino.data, iCamino.rest UNTIL iCamino=NIL DO
IF iNext.first.set=iCamino.first.set THEN {
If circularities then add the set (if not zero length circularity) and give up this camino.
newCamino: Camino ← [0.0, CONS[iNext.first, thisCamino.data]];
RecordOrForget[newCamino];
found ← TRUE;
EXIT
}
ENDLOOP;
IF ~found THEN {
no circularities so add the set to the current Camino, and the Camino to the next round candidates
newCamino: Camino ← [0.0, CONS[iNext.first, thisCamino.data]];
liveCaminos ← CONS[newCamino, liveCaminos];
n2 ← n2+1;
};
ENDLOOP;
IF nextOnes.data=NIL THEN {
no further ways available so record it in the finished caminos.
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] ~ {
value: HashTable.Value;
found: BOOLEAN;
setDelay, prevDelay: Delay;
[found, value] ← HashTable.Fetch[setListCache, caminoData];
IF found THEN RETURN[NARROW[value, 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;
[] ← HashTable.Store[setListCache, caminoData, delay];
};
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: BOOLEANFALSE;
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: BOOLEANFALSE;
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: BOOLEANTRUE, newPathList, newCompletedPathList: PathList ← NIL] ~ {
FOR iPathList: PathList ← oldPathList, iPathList.rest UNTIL iPathList=NIL DO
path: Path ← iPathList.first;
thisNode: Node ← path.first.node;
terminal: BOOLEANTRUE;
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;
does this set contain the specified node ?
FOR iNodeList: NodeList ← set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO
IF iNodeList.first=node THEN {
found ← TRUE;
EXIT;
};
ENDLOOP;
IF ~found THEN RETURN;
does this set contain one of the power node ?
IF set.fixedV=NIL THEN RETURN;
is there only one path to a power node ?
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 {
either no further input specification reduces the poblem, or the set has only one path to power
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] ~ {
PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE];
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<data.table[ind+1].x THEN {
FOR ind2: NAT IN [0..ind) DO
data.table[ind2] ← data.table[ind2+1];
ENDLOOP;
data.table[ind] ← [node.cap, 0.0, node, set];
EXIT;
};
ENDLOOP;
ENDLOOP;
};
DataType: TYPE = REF DataTypeRec;
DataTypeRec: TYPE = RECORD [table: SEQUENCE size: NAT OF RECORD [x, y: REAL, node: Node, set: Set]];
data: DataType ← NEW[DataTypeRec[n]];
node: Node;
totalC: REAL ← 0.0;
FOR ind: NAT IN [0..n) DO
data.table[ind].x ← -1e30;
ENDLOOP;
[] ← VisitLibrary[circuit.library, FindFatOnes];
IO.PutF[StdOut, "\ntotal Capacitance :%5.2fpf (C*V*V/f=%g W @ 25MHz)", IO.real[totalC], IO.real[totalC*VddVal*VddVal*25e-12]];
fatest ← 0.0;
SetTime[0.0, circuit];
FOR ind: NAT IN [0..n) DO
IF data.table[ind].node#NIL THEN {
FOR iNodeList: NodeList ← data.table[ind].set.inList, iNodeList.rest UNTIL iNodeList=NIL DO
iNodeList.first.done ← FALSE;
ENDLOOP;
FOR iNodeList: NodeList ← data.table[ind].set.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO
iNodeList.first.done ← TRUE;
ENDLOOP;
FOR iFetList: FetList ← data.table[ind].set.lFets, iFetList.rest UNTIL iFetList = NIL DO
iFetList.first.switch ← TRUE;
ENDLOOP;
[data.table[ind].x, data.table[ind].y] ← EvalRC[data.table[ind].node, data.table[ind].set, circuit];
IO.PutF[StdOut, "\n%g (%5.3fpf), tup: %4.1fns, tdown: %4.1fns", IO.rope[RopeFromNode[data.table[ind].node, circuit]], IO.real[data.table[ind].node.cap], IO.real[data.table[ind].x*0.001], IO.real[data.table[ind].y*0.001]];
fatest ← MAX[MAX[data.table[ind].x, data.table[ind].y], fatest];
fatNodes ← CONS[data.table[ind].node, fatNodes];
};
ENDLOOP;
};
LastTime: PUBLIC PROC [circuit: Circuit, n: NAT ← 1] RETURNS [veryLastTime: ps, slowNodes: NodeList]~ {
FindSlowOnes: HashTable.EachPairAction ~ {
PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE];
t, v: REAL;
node: Node ~ NARROW[value];
IF node.history=NIL THEN RETURN;
IF node.input THEN RETURN;
[t, v] ← SettledValuesOfNode[node];
IF t <data.table[0].t THEN RETURN;
FOR ind: NAT IN [0..n) DO
IF ind=n-1 OR t<data.table[ind+1].t THEN {
FOR ind2: NAT IN [0..ind) DO
data.table[ind2] ← data.table[ind2+1];
ENDLOOP;
data.table[ind] ← [t, node];
RETURN;
};
ENDLOOP;
};
DataType: TYPE = REF DataTypeRec;
DataTypeRec: TYPE = RECORD [table: SEQUENCE size: NAT OF RECORD [t: ps, node: Node]];
data: DataType ← NEW[DataTypeRec[n]];
FOR ind: NAT IN [0..n) DO
data.table[ind].t ← -1e30;
ENDLOOP;
[] ← HashTable.Pairs[circuit.nodeTable, FindSlowOnes];
FOR ind: NAT IN [0..n) DO
IF data.table[ind].node#NIL THEN slowNodes ← CONS[data.table[ind].node, slowNodes];
ENDLOOP;
veryLastTime ← data.table[n-1].t;
};
Utilities
PrintSetType: PROC [setType: SetType] ~ {
IO.PutF[StdOut, " %4d, %4d,", IO.int[setType.nFets[nE]], IO.int[setType.nFets[pE]]];
IO.PutF[StdOut, " %4d, %4d, %4d, %4d", IO.int[setType.nVddTran], IO.int[setType.nGndTran], IO.int[setType.nNodes], IO.int[setType.nInput]];
};
PrintFet: PUBLIC PROC [fet: Fet, circuit: Circuit] ~ {
IF fet=NIL THEN RETURN;
IO.PutFL[StdOut, "\n%g %g(%1.2d) g:%g, ch1:%g, ch2:%g", LIST[IO.rope[IF fet.type.type=pE THEN "P" ELSE "N"], IO.rope[IF fet.switch THEN "ON" ELSE "OFF"], IO.real[1.0/fet.type.rOnInv], IO.rope[RopeFromNode[fet.gate, circuit]], IO.rope[RopeFromNode[fet.ch1, circuit]], IO.rope[RopeFromNode[fet.ch2, circuit]]]]; -- more than 5 IO.Values => 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 ~ {
PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE];
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;
add node to fixed voltages
set.fixedV ← CONS[node, set.fixedV];
and remove it from lNodes
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;
add node to lNodes
set.lNodes ← CONS[node, set.lNodes];
and remove it from fixed voltages list
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 ~ {
PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE];
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: BOOLEANTRUE, t: ps ← 0.0] ~ {
v: REALIF 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<VddVal+pVtVal,
ENDCASE => 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: BOOLEANTRUE] ~ {
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 ~ {
PROC [key: Key, value: Value] RETURNS [quit: BOOLEAN ← FALSE];
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;
};
Plot Management
MintEnum: PROC [plot: PlotGraph.Plot, graph: PlotGraph.Graph, bounds: PlotGraph.Rectangle, eachPoint: PlotGraph.PointProc, data: REF ANYNIL] RETURNS [invalidEnumeration: BOOLFALSE] ~ {
Action: Schedule.HistoryProc ~ {
quit ← eachPoint[t, v, data];
};
quit: BOOLEANFALSE;
node: Node ← NARROW[graph.data];
to: REALIF bounds.w=0.0 THEN 1e24 ELSE bounds.x+bounds.w;
from: REALIF 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.ROPENIL] ~ {
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.