MintImpl.mesa
Copyright c 1986 by Xerox Corporation. All rights reserved.
Christian LeCocq January 14, 1987 4:32:25 pm PST
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;
PathList: TYPE = LIST OF NodeList;
Caminos: TYPE = LIST OF Camino;
Camino: TYPE = LIST OF RECORD[set: Set, node: Node];
Delay: TYPE = REF DelayRec;
DelayRec: TYPE = RECORD [tup, tdown: ps];
ExtendedCircuit: TYPE = REF ExtendedCircuitRec;
ExtendedCircuitRec: TYPE = RECORD [circuit: Circuit, data: REF ANY];
some usefull definitions
gndName: Rope.ROPE ← "public.Gnd";
vddName: Rope.ROPE ← "public.Vdd";
VddVal: mVolt ← 5000.0;
GndVal: mVolt ← 0.0;
VtVal: mVolt ← 2000.0;
threshold: mVolt ← 2500.0;
gamma: REAL = 0.4*31.62277; -- 31.62277 = SqRt[1000.0] due to unit = mV
phi: mVolt ← 1000.0;
sqrtPhi: REAL ← 31.62277;
timeSpecs: ps ← 50.0;
tInc: ps ← 100.0;
totalSets: CARDINAL ← 0;
separateView: 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 iFetList: FetList ← iNodeList.first.fetList, iFetList.rest UNTIL iFetList = NIL DO
IF NOT iFetList.first.done THEN
IF iFetList.first.gate # iNodeList.first THEN {
fetList ← CONS[iFetList.first, fetList];
set.lFets ← CONS[iFetList.first, set.lFets];
iFetList.first.done ← TRUE;
};
ENDLOOP;
ENDLOOP;
}; --NextFetList2
NextNodeList2: PROC [set: Set, fetList: FetList] RETURNS [nodeList: NodeList ← NIL] ~ {
FOR iFetList: FetList ← fetList, iFetList.rest UNTIL iFetList = NIL DO
IF NOT iFetList.first.ch1.done THEN {
nodeList ← CONS[iFetList.first.ch1, nodeList];
set.lNodes ← CONS[iFetList.first.ch1, set.lNodes];
iFetList.first.ch1.done ← TRUE;
};
IF NOT iFetList.first.ch2.done THEN {
nodeList ← CONS[iFetList.first.ch2, nodeList];
set.lNodes ← CONS[iFetList.first.ch2, set.lNodes];
iFetList.first.ch2.done ← TRUE;
};
ENDLOOP;
}; --NextNodeList2
ClipSet: PROC [totalSet: Set, cutNodes: NodeList ← NIL] RETURNS [setList: SetList ← NIL] ~ {
set: Set;
nodeList: NodeList;
fetList: FetList;
FOR iFetList: FetList ← totalSet.lFets, iFetList.rest UNTIL iFetList = NIL DO
iFetList.first.done ← ~iFetList.first.switch;
ENDLOOP;
FOR iNodeList: NodeList ← totalSet.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO
iNodeList.first.done ← FALSE;
ENDLOOP;
FOR iNodeList: NodeList ← totalSet.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO
iNodeList.first.done ← TRUE;
ENDLOOP;
FOR iNodeList: NodeList ← cutNodes, iNodeList.rest UNTIL iNodeList=NIL DO
iNodeList.first.done ← TRUE;
ENDLOOP;
FOR inodeList: NodeList ← totalSet.lNodes, inodeList.rest UNTIL inodeList=NIL DO
IF inodeList.first.done THEN LOOP;
set ← NEW[SetRec];
nodeList ← LIST[inodeList.first];
set.lNodes ← nodeList;
inodeList.first.done ← TRUE;
UNTIL nodeList=NIL DO
fetList ← NextFetList2[set, nodeList];
nodeList ← NextNodeList2[set, fetList];
ENDLOOP;
FOR iNodeList: NodeList ← totalSet.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO
iNodeList.first.done ← FALSE;
ENDLOOP;
FOR iFetList: FetList ← set.lFets, iFetList.rest UNTIL iFetList=NIL DO
IF iFetList.first.ch1.input THEN IF ~iFetList.first.ch1.done AND iFetList.first.switch THEN {
iFetList.first.ch1.done ← TRUE;
set.fixedV ← CONS[iFetList.first.ch1, set.fixedV];
};
IF iFetList.first.ch2.input THEN IF ~iFetList.first.ch2.done AND iFetList.first.switch THEN {
iFetList.first.ch2.done ← TRUE;
set.fixedV ← CONS[iFetList.first.ch2, set.fixedV];
};
ENDLOOP;
FOR iNodeList: NodeList ← totalSet.fixedV, iNodeList.rest UNTIL iNodeList=NIL DO
iNodeList.first.done ← TRUE;
ENDLOOP;
setList ← CONS[set, setList];
ENDLOOP;
};
Swap: PROC [A: LinearSystem.MatrixN, b:LinearSystem.ColumnN, i, j, n: CARDINAL] ~ {
tempRow: LinearSystem.RowN;
tempReal: REAL;
tempRow ← A[i];
A[i] ← A[j];
A[j] ← tempRow;
tempReal ← b[i];
b[i] ← b[j];
b[j] ← tempReal;
FOR k:CARDINAL IN [0..n) DO
tempReal ← A[k][i];
A[k][i] ← A[k][j];
A[k][j] ← tempReal;
ENDLOOP;
};
CheckSwitch: PROC [fet: Fet, t0, t1: ps] RETURNS [change: 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 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;
i1 ← fet.ch1.index;
i2 ← fet.ch2.index;
matrix[i1][i1] ← matrix[i1][i1] - fet.rOnInv/fet.ch1.cap;
matrix[i1][i2] ← matrix[i1][i2] + fet.rOnInv/fet.ch1.cap;
matrix[i2][i2] ← matrix[i2][i2] - fet.rOnInv/fet.ch2.cap;
matrix[i2][i1] ← matrix[i2][i1] + fet.rOnInv/fet.ch2.cap;
fet.done ← TRUE;
};
XchIndexes: PROC [matrix: LinearSystem.MatrixN, i, j: CARDINAL] RETURNS [xChged: LinearSystem.MatrixN] ~ {
rowN: LinearSystem.RowN;
elt: REAL;
xChged ← LinearSystem.Copy[matrix];
rowN ← xChged[i];
xChged[i] ← xChged[j];
xChged[j] ← rowN;
FOR k: INTEGER IN [0..xChged.nrows) DO
elt ← xChged[k][i];
xChged[k][i] ← xChged[k][j];
xChged[k][j] ← elt;
ENDLOOP;
};
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;
vTemp: 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;
matrix ← NEW[LinearSystem.MatrixSeq[nNodes]];
cstTerm ← NEW[LinearSystem.VecSeq[nNodes]];
vInit ← NEW[LinearSystem.VecSeq[nNodes]];
tau ← NEW[LinearSystem.VecSeq[nNodes]];
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
matrix[iRow] ← NEW[LinearSystem.VecSeq[nNodes]];
cstTerm[iRow] ← 0.0;
FOR iColumn: CARDINAL IN [0..nNodes) DO
matrix[iRow][iColumn] ← 0.0;
ENDLOOP;
ENDLOOP;
FOR iNodeList: NodeList ← set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO
FOR iFetList: FetList ← iNodeList.first.fetList, iFetList.rest UNTIL iFetList = NIL DO
IF ~iFetList.first.done AND iFetList.first.switch THEN {
IF iNodeList.first#iFetList.first.gate THEN Coeff[matrix, iFetList.first];
What about a gate connected to ch1 or ch2 ?
};
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 return.
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
tFinal ← tFinal-1.0/matrix[i][i];
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 ← LinearSystem.SolveN[LinearSystem.Copy[matrix], cstTerm, nActiveNodes];
lastAct ← nActiveNodes-1;
IF lastAct#0 THEN FOR i: CARDINAL IN [0..nActiveNodes) DO
subMatrix ← XchIndexes[matrix, i, lastAct];
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 ← LinearSystem.SolveN[LinearSystem.Copy[subMatrix], cstTerm, lastAct];
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
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] ~ {
plot: PlotGraph.Plot ~ NARROW[data];
rect: PlotGraph.Rectangle ← [plot.lowerBounds.x, 0.0, plot.upperBounds.x - plot.lowerBounds.x, 5000.0];
SimulateSet[ref, t, plot.data];
PlotGraph.RefreshPlot[plot: plot, within: rect, eraseFirst: TRUE];
};
InteractiveSimulate: PUBLIC PROC [circuit: Circuit, watchList: NodeList, from: ps ← 0.0] ~ {
t: ps;
gndNode, vddNode: Node;
plot: PlotGraph.Plot;
circuit.info.nbOfSimulations ← 0;
gndNode ← NodeFromRope[gndName, circuit];
gndNode.history ← Schedule.CreateHistory[from, GndVal];
vddNode ← NodeFromRope[vddName, circuit];
vddNode.history ← Schedule.CreateHistory[from, VddVal];
plot ← DrawNodeList[watchList, circuit];
circuit.agenda ← Schedule.CreateAgenda[SimulateAndPlot, plot];
t ← Initialize[circuit];
t ← Schedule.ExecuteAgenda[circuit.agenda];
};
Timing Evaluation
NextSets: PROC [c: RECORD[set: Set, node: Node], 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[NARROW[value, Camino]];
FOR iFetList: FetList ← set.lFets, iFetList.rest UNTIL iFetList=NIL DO
IF iFetList.first.gate.history#NIL THEN {
boolVal ← GetNode[iFetList.first.gate];
iFetList.first.switch ← IF boolVal THEN iFetList.first.type=pE ELSE iFetList.first.type=nE;
}
ELSE iFetList.first.switch ← TRUE;
ENDLOOP;
subSets ← ClipSet[set];
FOR iSetList: SetList ← subSets, iSetList.rest UNTIL iSetList=NIL DO
boolVal ← FALSE;
FOR iFetList: FetList ← iSetList.first.lFets, iFetList.rest UNTIL iFetList=NIL DO
IF iFetList.first.gate=node THEN {boolVal ← TRUE; EXIT};
ENDLOOP;
IF boolVal THEN {
FOR iNodeList: NodeList ← iSetList.first.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO
FOR iSetList2: SetList ← iNodeList.first.setList, iSetList2.rest UNTIL iSetList2=NIL DO
camino ← CONS[[iSetList2.first, iNodeList.first], camino];
ENDLOOP;
ENDLOOP;
};
ENDLOOP;
KillSetList[subSets, TRUE];
[] ← HashTable.Store[setCache, set, camino];
};
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;
SimulateSet[ref, t, extdCirc.circuit];
};
MaxFreqEvaluate: PUBLIC PROC [circuit: Circuit, clkList: NodeList, from: ps ← 0.0] RETURNS [worst: ps ← 0.0, setList: SetList]~ {
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[LIST[[set, set.inList.first]], liveCaminos];
};
n: INT ← 0;
found, finished: BOOLEAN ← FALSE;
gndNode: Node = NodeFromRope[gndName, circuit];
vddNode: Node = NodeFromRope[vddName, circuit];
startTable: HashTable.Table ← HashTable.Create[];
caminos, liveCaminos: Caminos ← NIL;
camino: Camino ← NIL;
extdCirc: ExtendedCircuit ← NEW[ExtendedCircuitRec ← [circuit, startTable]];
setCache: HashTable.Table ← HashTable.Create[];
setListCache: HashTable.Table ← HashTable.Create[];
hist: Histograms.Histogram ← Histograms.Create1D[100.0, 0.0]; --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, GndVal];
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];
UNTIL liveCaminos=NIL DO
n2: INT ← 0;
oldCaminos: Caminos ← liveCaminos;
liveCaminos ← NIL;
FOR iCaminos: Caminos ← oldCaminos, iCaminos.rest UNTIL iCaminos=NIL DO
thisCamino: Camino ← iCaminos.first;
nextOnes: Camino ← NextSets[thisCamino.first, setCache];
oneAdded: BOOLEANFALSE;
FOR iNext: Camino ← nextOnes, iNext.rest UNTIL iNext=NIL DO
found ← FALSE;
FOR iCamino: Camino ← iCaminos.first, iCamino.rest UNTIL iCamino=NIL DO
IF iNext.first=iCamino.first THEN {found ← TRUE; EXIT}
ENDLOOP;
IF ~found THEN {
oneAdded ← TRUE;
liveCaminos ← CONS[CONS[iNext.first, thisCamino], liveCaminos];
n2 ← n2+1;
};
ENDLOOP;
IF ~oneAdded THEN {
caminos ← CONS[thisCamino, caminos];
n ← n+1;
};
ENDLOOP;
KillCaminos[oldCaminos];
IO.PutF[StdOut, "total %d, in use %d\n", IO.int[n], IO.int[n2]]
ENDLOOP;
setCache ← HashTable.Create[HashTable.GetSize[setCache]];
FOR iCaminos: Caminos ← caminos, iCaminos.rest UNTIL iCaminos=NIL DO
delay: Delay ← ThruTime[iCaminos.first, setCache, setListCache];
IF delay.tup>worst OR delay.tdown>worst THEN {
camino ← iCaminos.first;
worst ← MAX[delay.tup, delay.tdown];
};
Histograms.ChangeTransformed[hist, delay.tup];
Histograms.ChangeTransformed[hist, delay.tdown];
ENDLOOP;
[] ← Histograms.Show[hist];
setList ← LIST[camino.first.set];
camino ← camino.rest;
{iSetList3: SetList ← setList;
UNTIL camino=NIL DO
iSetList3.rest ← LIST[camino.first.set];
camino ← camino.rest;
iSetList3 ← iSetList3.rest;
ENDLOOP;}
};
ThruTime: PROC [camino: Camino, setCache, setListCache: HashTable.Table] RETURNS [delay: Delay] ~ {
value: HashTable.Value;
found: BOOLEAN;
setDelay, prevDelay: Delay;
[found, value] ← HashTable.Fetch[setListCache, camino];
IF found THEN RETURN[NARROW[value, Delay]];
delay ← NEW[DelayRec ← [0.0, 0.0]];
setDelay ← DelayOfSet[camino.first.set, setCache];
IF camino.rest=NIL THEN RETURN;
prevDelay ← ThruTime[camino.rest, setCache, setListCache];
delay.tup ← setDelay.tup+prevDelay.tdown;
delay.tdown ← setDelay.tdown+prevDelay.tup;
[] ← HashTable.Store[setListCache, camino, delay];
};
DelayOfSet: PROC [set: Set, setCache: HashTable.Table] RETURNS [delay: Delay] ~ {
value: HashTable.Value;
found: BOOLEAN;
tup, tdown: ps ← 0.0;
[found, value] ← HashTable.Fetch[setCache, set];
IF found THEN RETURN[NARROW[value, Delay]];
delay ← NEW[DelayRec ← [0.0, 0.0]];
FOR iNodeList: NodeList ← set.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO
IF iNodeList.first.setList#NIL THEN {
FOR iNList: NodeList ← set.inList, iNList.rest UNTIL iNList=NIL DO
iNList.first.done ← FALSE;
ENDLOOP;
FOR iNList: NodeList ← set.fixedV, iNList.rest UNTIL iNList=NIL DO
iNList.first.done ← TRUE;
ENDLOOP;
FOR iFetList: FetList ← set.lFets, iFetList.rest UNTIL iFetList = NIL DO
iFetList.first.switch ← TRUE;
ENDLOOP;
[tup, tdown] ← EvalRC[iNodeList.first, set];
delay.tup ← MAX[delay.tup, tup];
delay.tdown ← MAX[delay.tdown, tdown];
}
ENDLOOP;
[] ← HashTable.Store[setCache, set, delay];
};
FindSetOfNode: PROC [node: Node] RETURNS [set: Set] ~ {
found: BOOLEANFALSE;
FOR iFetList: FetList ← node.fetList, iFetList.rest UNTIL iFetList=NIL DO
FOR iSetList: SetList ← iFetList.first.gate.setList, iSetList.rest UNTIL iSetList=NIL DO
FOR iNodeList: NodeList ← iSetList.first.lNodes, iNodeList.rest UNTIL iNodeList=NIL DO
IF iNodeList.first=node THEN RETURN[iSetList.first];
ENDLOOP;
ENDLOOP;
ERROR; -- who did some hand editing on the internal data structure ?
ENDLOOP;
};
FindAllPaths: PROC [node: Node, set: Set] RETURNS [pathList: PathList] ~ {
finished: 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;
pathList ← LIST[LIST[node]];
node.index ← 1;
UNTIL finished DO
level ← level+1;
oldPathList ← pathList;
[finished, pathList] ← IncPaths[set.lFets, oldPathList, level];
ENDLOOP;
};
IncPaths: PROC [fetList: FetList, oldPathList: PathList, level: NAT] RETURNS [finished: BOOLEANTRUE, newPathList: PathList ← NIL] ~ {
nodeList: NodeList;
terminal: BOOLEAN;
FOR iPathList: LIST OF NodeList ← oldPathList, iPathList.rest UNTIL iPathList=NIL DO
nodeList ← iPathList.first;
terminal ← TRUE;
IF ~nodeList.first.input THEN FOR iFetList: FetList ← fetList, iFetList.rest UNTIL iFetList=NIL DO
IF iFetList.first.ch1=nodeList.first THEN
IF iFetList.first.ch2.index=0 OR iFetList.first.ch2.index>=level THEN {
newPathList ← CONS[ CONS[iFetList.first.ch2, nodeList], newPathList];
iFetList.first.ch2.index ← level;
terminal ← FALSE;
finished ← FALSE;
};
IF iFetList.first.ch2=nodeList.first THEN
IF iFetList.first.ch1.index=0 OR iFetList.first.ch1.index>=level THEN {
newPathList ← CONS[ CONS[iFetList.first.ch1, nodeList], newPathList];
iFetList.first.ch1.index ← level;
finished ← FALSE;
terminal ← FALSE;
};
ENDLOOP;
IF terminal THEN newPathList ← CONS[nodeList, newPathList];
ENDLOOP;
};
EvalRC: PROC [node: Node, set: Set] RETURNS [tup, tdown: ps ← 0] ~ {
subSets: SetList;
pathList: PathList;
found: BOOLEAN ← FALSE;
tempup, tempdown: ps ← 0.0;
n: NAT ← 0;
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.input THEN n ← n+1;
ENDLOOP;
IF n=0 THEN ERROR;
IF n#1 THEN {
FindInputs2[set];
FOR iNodeList: NodeList ← set.inList, iNodeList.rest UNTIL iNodeList=NIL DO
IF ~iNodeList.first.done THEN {
iNodeList.first.done ← TRUE;
FOR bool: BOOLEAN IN BOOLEAN DO
FOR iFetList: FetList ← iNodeList.first.fetList, iFetList.rest UNTIL iFetList = NIL DO
iFetList.first.switch ← IF bool THEN iFetList.first.type=pE ELSE iFetList.first.type=nE;
ENDLOOP;
subSets ← ClipSet[set];
FOR iSetList: SetList ← subSets, iSetList.rest UNTIL iSetList=NIL DO
[tempup, tempdown] ← EvalRC[node, iSetList.first];
tup ← MAX[tempup, tup];
tdown ← MAX[tempdown, tdown];
ENDLOOP;
KillSetList[subSets, TRUE];
ENDLOOP;
};
ENDLOOP;
};
IF tup=0.0 AND tdown=0.0 THEN {
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, NIL];
IF GetNode[node] THEN tup ← t ELSE tdown ← t;
};
};
MaxCapa: PUBLIC PROC [circuit: Circuit, n: NAT ← 1] RETURNS [fatest: REAL, fatNodes: NodeList]~ {
FindFatOnes: PROC[set: Set] RETURNS [ok: BOOLEAN] ~ {
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];
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=pE THEN "P" ELSE "N"], IO.rope[IF fet.switch THEN "ON" ELSE "OFF"], IO.real[1.0/fet.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: PROC [camino: Camino, circuit: Circuit] ~ {
IO.PutF[StdOut,"\n ~~"];
FOR iCamino: Camino ← camino, iCamino.rest UNTIL iCamino=NIL DO
PrintNode[ iCamino.first.node, circuit];
ENDLOOP;
};
PrintCaminos: PROC [caminos: Caminos, circuit: Circuit] ~ {
IO.PutF[StdOut,"\n **"];
FOR iCaminos: Caminos ← caminos, iCaminos.rest UNTIL iCaminos=NIL DO
PrintCamino[ iCaminos.first, circuit];
ENDLOOP;
};
SetDoneInNodeList: PROC [nodeList: NodeList, done: BOOLEAN] ~ {
FOR inodeList: NodeList ← nodeList, inodeList.rest UNTIL inodeList=NIL DO
inodeList.first.done ← done;
ENDLOOP;
};
Watch: PUBLIC PROC [watchList: NodeList] ~ {
FOR inodeList: NodeList ← watchList, inodeList.rest UNTIL inodeList=NIL DO
inodeList.first.watched ← TRUE;
ENDLOOP;
};
SetInput: PROC [node: Node, set: Set] ~ {
prev: NodeList;
node.input ← TRUE;
node.done ← TRUE;
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>2500.0;
};
SettledValuesOfNode: PUBLIC PROC [node: Node] RETURNS [t: ps, v: mVolt] ~ {
t ← Schedule.LastTimeOfHistory[node.history];
v ← Schedule.LastValueOfHistory[node.history];
};
EditNodeHistory: PUBLIC PROC [node: Node, t: ps, v: mVolt] ~ {
IF node.history=NIL THEN node.history ← Schedule.CreateHistory[t, v]
ELSE node.history ← Schedule.AddToHistory[node.history, t, v];
};
EditNodeInputBool: PUBLIC PROC [node: Node, forcedInput: BOOLEAN] ~ {
node.input ← forcedInput;
};
KillCaminos: PUBLIC PROC [caminos: Caminos] ~ {
cam: Caminos;
UNTIL caminos=NIL DO
caminos.first ← NIL;
cam ← caminos;
caminos ← caminos.rest;
cam.rest ← NIL;
ENDLOOP;
};
KillFetList: PUBLIC PROC [fetList: FetList] ~ {
fList: FetList;
UNTIL fetList=NIL DO
fetList.first ← NIL;
fList ← fetList;
fetList ← fetList.rest;
fList.rest ← NIL;
ENDLOOP;
};
KillNodeList: PUBLIC PROC [nodeList: NodeList] ~ {
nList: NodeList;
UNTIL nodeList=NIL DO
nodeList.first ← NIL;
nList ← nodeList;
nodeList ← nodeList.rest;
nList.rest ← NIL;
ENDLOOP;
};
KillSetList: PUBLIC PROC [setList: SetList, killSets: 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];
KillFetList[node.fetList];
KillSetList[node.setList, FALSE];
};
KillCircuit: PUBLIC PROC [circuit: Circuit] ~ {
lib: Library;
circuit.rootCell ← NIL;
[] ← HashTable.Pairs[circuit.nodeTable, KillNode];
HashTable.Erase[circuit.nodeTable];
Schedule.KillAgenda[circuit.agenda];
UNTIL circuit.library=NIL DO
KillSetList[circuit.library.first.setList, TRUE];
circuit.library.first.type ← NIL;
circuit.library.first ← NIL;
lib ← circuit.library;
circuit.library ← circuit.library.rest;
lib.rest ← NIL;
ENDLOOP;
circuit.info ← NIL;
};
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
plot.lowerBounds.x ← MIN[plot.lowerBounds.x, Schedule.FirstTimeOfHistory[inodeList.first.history]];
plot.upperBounds.x ← MAX[plot.upperBounds.x, Schedule.LastTimeOfHistory[inodeList.first.history]];
ENDLOOP;
plot.upperBounds.x ← MAX[plot.upperBounds.x, 1.0+plot.lowerBounds.x];
rect ← [plot.lowerBounds.x, 0.0, plot.upperBounds.x - plot.lowerBounds.x, 5000.0];
FOR inodeList: NodeList ← nodeList, inodeList.rest UNTIL inodeList=NIL DO
plot.axis ← CONS[
NEW[PlotGraph.AxisRec ← [
graphs: LIST[NEW[PlotGraph.GraphRec ← [
class: mintGClass,
data: inodeList.first,
name: ""
]]],
bounds: rect,
name: RopeFromNode[inodeList.first, circuit],
style: analog,
axisData: [mintAxisData, mintAxisData]
]],
plot.axis];
ENDLOOP;
PlotGraph.UnlockPlot[plot];
PlotGraph.RefreshPlot[plot: plot, within: rect, eraseFirst: TRUE];
};
mintGClass: PlotGraph.GraphClass ← NEW[PlotGraph.GraphClassRec ← [
insert: NIL,
delete: NIL,
enumerate: MintEnum
]];
mintAxisData: PlotGraph.AxisData ← [1000.0, TRUE, FALSE];
IF separateView THEN {
typeScript: TypeScript.TS ← TypeScript.Create[info: [name: "Mint", iconic: TRUE, icon: Icons.NewIconFromFile["Mint.icons", 1]]];
StdOut ← ViewerIO.CreateViewerStreams[name: "Mint", viewer: typeScript].out;
}
ELSE StdOut ← TerminalIO.TOS[];
IO.PutRope[StdOut, "\nMint loaded\n"];
END.