~
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: 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;
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: 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
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: 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;
};
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: 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<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:
BOOLEAN ←
FALSE, 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:
BOOLEAN ←
TRUE, 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: 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;
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: BOOLEAN ← FALSE;
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: BOOLEAN ← FALSE;
FOR iFetList: FetList ← node.fetList, iFetList.rest
UNTIL iFetList=
NIL
DO
FOR iSetList: SetList ← iFetList.first.gate.setList, iSetList.rest
UNTIL iSetList=
NIL
DO
FOR iNodeList: NodeList ← iSetList.first.lNodes, iNodeList.rest
UNTIL iNodeList=
NIL
DO
IF iNodeList.first=node THEN RETURN[iSetList.first];
ENDLOOP;
ENDLOOP;
ERROR; -- who did some hand editing on the internal data structure ?
ENDLOOP;
};
FindAllPaths:
PROC [node: Node, set: Set]
RETURNS [pathList: PathList] ~ {
finished: BOOLEAN ← FALSE;
oldPathList: PathList;
level: NAT ← 1;
FOR iNodeList: NodeList ← set.fixedV, iNodeList.rest
UNTIL iNodeList=
NIL
DO
iNodeList.first.index ← 0;
ENDLOOP;
FOR iNodeList: NodeList ← set.lNodes, iNodeList.rest
UNTIL iNodeList=
NIL
DO
iNodeList.first.index ← 0;
ENDLOOP;
pathList ← LIST[LIST[node]];
node.index ← 1;
UNTIL finished
DO
level ← level+1;
oldPathList ← pathList;
[finished, pathList] ← IncPaths[set.lFets, oldPathList, level];
ENDLOOP;
};
IncPaths:
PROC [fetList: FetList, oldPathList: PathList, level:
NAT]
RETURNS [finished:
BOOLEAN ←
TRUE, newPathList
: PathList
← NIL] ~ {
nodeList: NodeList;
terminal: BOOLEAN;
FOR iPathList:
LIST
OF NodeList ← oldPathList, iPathList.rest
UNTIL iPathList=
NIL
DO
nodeList ← iPathList.first;
terminal ← TRUE;
IF ~nodeList.first.input
THEN
FOR iFetList: FetList ← fetList, iFetList.rest
UNTIL iFetList=
NIL
DO
IF iFetList.first.ch1=nodeList.first
THEN
IF iFetList.first.ch2.index=0
OR iFetList.first.ch2.index>=level
THEN {
newPathList ← CONS[ CONS[iFetList.first.ch2, nodeList], newPathList];
iFetList.first.ch2.index ← level;
terminal ← FALSE;
finished ← FALSE;
};
IF iFetList.first.ch2=nodeList.first
THEN
IF iFetList.first.ch1.index=0
OR iFetList.first.ch1.index>=level
THEN {
newPathList ← CONS[ CONS[iFetList.first.ch1, nodeList], newPathList];
iFetList.first.ch1.index ← level;
finished ← FALSE;
terminal ← FALSE;
};
ENDLOOP;
IF terminal THEN newPathList ← CONS[nodeList, newPathList];
ENDLOOP;
};
EvalRC:
PROC [node: Node, set: Set]
RETURNS [tup, tdown: ps ← 0] ~ {
subSets: SetList;
pathList: PathList;
found: BOOLEAN ← FALSE;
tempup, tempdown: ps ← 0.0;
n: NAT ← 0;
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;
Print
FetList:
PUBLIC PROC [fetList: FetList, circuit: Circuit] ~ {
FOR ifetList: FetList ← fetList, ifetList.rest
UNTIL ifetList=
NIL
DO
PrintFet[ifetList.first, circuit];
ENDLOOP;
};
Print
NodeList:
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:
BOOLEAN ←
TRUE, t: ps ← 0.0] ~ {
v: REAL ← IF val THEN VddVal ELSE GndVal;
node.history ← IF node.history=NIL THEN Schedule.CreateHistory[t, v] ELSE Schedule.AddToHistory[node.history, t, v];
node.input ← input;
};
GetNode:
PUBLIC PROC [node: Node]
RETURNS [val:
BOOLEAN] ~ {
v: REAL ← Schedule.LastValueOfHistory[node.history];
val ← v>2500.0;
};
SettledValuesOfNode:
PUBLIC
PROC [node: Node]
RETURNS [t: ps, v: mVolt] ~ {
t ← Schedule.LastTimeOfHistory[node.history];
v ← Schedule.LastValueOfHistory[node.history];
};
EditNodeHistory:
PUBLIC
PROC [node: Node, t: ps, v: mVolt] ~ {
IF node.history=NIL THEN node.history ← Schedule.CreateHistory[t, v]
ELSE node.history ← Schedule.AddToHistory[node.history, t, v];
};
EditNodeInputBool:
PUBLIC
PROC [node: Node, forcedInput:
BOOLEAN] ~ {
node.input ← forcedInput;
};
KillCaminos:
PUBLIC
PROC [caminos: Caminos] ~ {
cam: Caminos;
UNTIL caminos=
NIL
DO
caminos.first ← NIL;
cam ← caminos;
caminos ← caminos.rest;
cam.rest ← NIL;
ENDLOOP;
};
KillFetList:
PUBLIC
PROC [fetList: FetList] ~ {
fList: FetList;
UNTIL fetList=
NIL
DO
fetList.first ← NIL;
fList ← fetList;
fetList ← fetList.rest;
fList.rest ← NIL;
ENDLOOP;
};
KillNodeList:
PUBLIC
PROC [nodeList: NodeList] ~ {
nList: NodeList;
UNTIL nodeList=
NIL
DO
nodeList.first ← NIL;
nList ← nodeList;
nodeList ← nodeList.rest;
nList.rest ← NIL;
ENDLOOP;
};
KillSetList:
PUBLIC
PROC [setList: SetList, killSets:
BOOLEAN ←
TRUE] ~ {
sList: SetList;
UNTIL setList=
NIL
DO
IF killSets
THEN {
KillFetList[setList.first.lFets];
KillNodeList[setList.first.lNodes];
KillNodeList[setList.first.inList];
KillNodeList[setList.first.fixedV];
setList.first.type ← NIL;
};
setList.first ← NIL;
sList ← setList;
setList ← setList.rest;
sList.rest ← NIL;
ENDLOOP;
};
KillNode: HashTable.EachPairAction ~ {
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
ANY ←
NIL]
RETURNS [invalidEnumeration:
BOOL ←
FALSE] ~ {
Action: Schedule.HistoryProc ~ {
quit ← eachPoint[t, v, data];
};
quit: BOOLEAN ← FALSE;
node: Node ← NARROW[graph.data];
to: REAL ← IF bounds.w=0.0 THEN 1e24 ELSE bounds.x+bounds.w;
from: REAL ← IF bounds.w=0.0 THEN -1e24 ELSE bounds.x;
quit ← Schedule.EnumerateHistory[node.history, from, to, Action];
};
AddNodeToPlot:
PUBLIC
PROC [node: Node, plot: PlotGraph.Plot, r: Rope.
ROPE ←
NIL] ~ {
circuit: Circuit ← NARROW[plot.data];
rect: PlotGraph.Rectangle ← [plot.lowerBounds.x, 0.0, plot.upperBounds.x - plot.lowerBounds.x, 5000.0];
IF r=NIL THEN r ← RopeFromNode[node, circuit];
PlotGraph.LockPlot[plot];
plot.axis ←
CONS[
NEW[PlotGraph.AxisRec ← [
graphs:
LIST[
NEW[PlotGraph.GraphRec ← [
class: mintGClass,
data: node,
name: ""
]]],
bounds: rect,
name: IF r#NIL THEN r ELSE RopeFromNode[node, circuit],
style: analog,
axisData: [mintAxisData, mintAxisData]
]],
plot.axis];
PlotGraph.UnlockPlot[plot];
PlotGraph.RefreshPlot[plot: plot, within: rect, eraseFirst: TRUE];
};
DrawNodeList:
PUBLIC
PROC [nodeList: NodeList, circuit: Circuit]
RETURNS[plot: PlotGraph.Plot] ~ {
rect: PlotGraph.Rectangle;
plot ← PlotGraph.CreatePlot[CoreOps.GetCellTypeName[circuit.rootCell]];
PlotGraph.LockPlot[plot];
plot.data ← circuit;
plot.lowerBounds ← [1.0e24, 0.0];
plot.upperBounds ← [-1.0e24, 5000.0];
FOR inodeList: NodeList ← nodeList, inodeList.rest
UNTIL inodeList=
NIL
DO
plot.lowerBounds.x ← MIN[plot.lowerBounds.x, Schedule.FirstTimeOfHistory[inodeList.first.history]];
plot.upperBounds.x ← MAX[plot.upperBounds.x, Schedule.LastTimeOfHistory[inodeList.first.history]];
ENDLOOP;
plot.upperBounds.x ← MAX[plot.upperBounds.x, 1.0+plot.lowerBounds.x];
rect ← [plot.lowerBounds.x, 0.0, plot.upperBounds.x - plot.lowerBounds.x, 5000.0];
FOR inodeList: NodeList ← nodeList, inodeList.rest
UNTIL inodeList=
NIL
DO
plot.axis ←
CONS[
NEW[PlotGraph.AxisRec ← [
graphs:
LIST[
NEW[PlotGraph.GraphRec ← [
class: mintGClass,
data: inodeList.first,
name: ""
]]],
bounds: rect,
name: RopeFromNode[inodeList.first, circuit],
style: analog,
axisData: [mintAxisData, mintAxisData]
]],
plot.axis];
ENDLOOP;
PlotGraph.UnlockPlot[plot];
PlotGraph.RefreshPlot[plot: plot, within: rect, eraseFirst: TRUE];
};
mintGClass: PlotGraph.GraphClass ←
NEW[PlotGraph.GraphClassRec ← [
insert: NIL,
delete: NIL,
enumerate: MintEnum
]];
mintAxisData: PlotGraph.AxisData ← [1000.0, TRUE, FALSE];
IF separateView
THEN {
typeScript: TypeScript.TS ← TypeScript.Create[info: [name: "Mint", iconic: TRUE, icon: Icons.NewIconFromFile["Mint.icons", 1]]];
StdOut ← ViewerIO.CreateViewerStreams[name: "Mint", viewer: typeScript].out;
}
ELSE StdOut ← TerminalIO.TOS[];
IO.PutRope[StdOut, "\nMint loaded\n"];