-- ChipSimFile.mesa
-- Subroutines to analyze the tree of cell calls and structure
-- of nets constructed by the net extraction.
-- last modified by E. McCreight, November 5, 1982 11:28 AM
-- last modified by R. Barth, July 8, 1983 12:11 PM
-- written by E. McCreight, November 3, 1981 3:06 PM
DIRECTORY
Ascii,
ChipNetDefs,
ChipUserInt,
InlineDefs,
ppdddefs,
ppdefs,
ppMainDefs,
StreamDefs,
StringDefs;
ChipSimFile: PROGRAM
IMPORTS ChipNetDefs, ChipUserInt,
InlineDefs, ppdddefs, ppdefs, ppMainDefs,
StreamDefs, StringDefs
EXPORTS ChipNetDefs =
BEGIN OPEN StringDefs, StreamDefs, ppdefs, ChipUserInt,
ChipNetDefs;
HashIndex: TYPE = INTEGER[0..253);
XstrHashTable: TYPE = ARRAY HashIndex OF XstrCallPtr;
XstrHashPtr: TYPE = LONG POINTER TO XstrHashTable;
simFile, thyFile: DiskHandle;
showHier, showEquivalences: BOOLEAN;
h: XstrHashPtr;
transNo: LONG CARDINAL;
WriteSimFile: PUBLIC PROCEDURE[c: CellCallPtr] =
BEGIN
ShouldMakeFile: PROCEDURE[name: STRING]
RETURNS[BOOLEAN] =
BEGIN
question: STRING ← [100];
question.length ← 0;
AppendString[to: question, from: "Make "];
AppendString[to: question, from: name];
AppendString[to: question, from: "?"];
RETURN[HeSetsParamsAndSaysYes[question]];
END;
s: STRING ← [300];
name: STRING;
h ← uz.NEW[XstrHashTable];
name ← RequestString["Output file name?"L];
IF name=NIL OR name.length=0 THEN
name ← newString[ppMainDefs.fileName];
simFile ← IF ShouldMakeFile[name ←
FixExtension[name, ".sim"L]] THEN
NewByteStream[name, WriteAppend] ELSE NIL;
thyFile ← IF ShouldMakeFile[name ←
FixExtension[name, ".thy"L]] THEN
NewByteStream[name, WriteAppend] ELSE NIL;
showHier ← HeSetsParamsAndSaysYes["Show hierarchy?"L];
showEquivalences ← simFile#NIL AND showHier AND
HeSetsParamsAndSaysYes["Show terminal equivalences?"L];
IF simFile#NIL THEN
BEGIN
HashTransistors[c];
WriteCellInst[s, c, 0, SimFileCellInst];
TruncateDiskStream[simFile];
END;
IF thyFile#NIL THEN
BEGIN -- introductory boiler plate
pCifScalesPerLambda: INTEGER = 100;
-- pCifScale is in centimicrons per lambda
s.length ← 0;
SayThyLine[""];
SayThyLine["-- N o d e s"L];
SayThyLine[""];
WriteThyNodes[s, c, 0];
HashTransistors[c];
transNo ← 0;
SayThyLine[""];
SayThyLine[""];
SayThyLine["-- T r a n s i s t o r s"L];
SayThyLine[""];
WriteCellInst[s, c, 0, ThyFileCellInst];
SayThyLine[""];
TruncateDiskStream[thyFile];
END;
FreeString[name];
uz.FREE[@h];
END; -- of WriteSimFile
WriteCellInst: PROCEDURE[s: STRING, call: CellCallPtr,
depth: CARDINAL,
HandleCell: PROCEDURE[s: STRING, call: CellCallPtr,
depth: CARDINAL]] =
BEGIN
IF depth>0 THEN HashTransistors[call];
HandleCell[s, call, depth];
FOR c: InstancePtr ← call.offspring, c.sibling
WHILE c#NIL DO
WITH dc: c SELECT FROM
cell =>
WriteCellInst[s, @dc,
depth+(IF showHier THEN 1 ELSE 0), HandleCell];
ENDCASE => NULL;
ENDLOOP;
END; -- of WriteCellInst
SimFileCellInst: PROCEDURE[s: STRING, call: CellCallPtr,
depth: CARDINAL] =
BEGIN
c: InstancePtr;
FOR c ← call.offspring, c.sibling WHILE c#NIL DO
WITH dc: c SELECT FROM
xstr => EXIT;
ENDCASE => NULL;
ENDLOOP;
IF depth>0 AND (c#NIL OR call.nets#NIL OR call.clusters#NIL)
THEN
BEGIN
SaySimLine[""];
Indent[s, depth];
AppendString[s, "| "];
AppendCallerChain[s, call];
SaySimLine[s];
END;
FOR c ← c, c.sibling WHILE c#NIL DO
WITH dc: c SELECT FROM
xstr => {Indent[s, depth]; WriteSimTransistor[s, c]};
ENDCASE => NULL;
ENDLOOP;
FOR netId: NetIdPtr ← call.nets, netId.next WHILE netId#NIL DO
WITH normNetId: netId SELECT FROM
normal =>
{Indent[s, depth]; WriteSimNetLine[s, @normNetId]};
ENDCASE => NULL;
ENDLOOP;
FOR cluster: ClusterPtr ← call.clusters, cluster.next
WHILE cluster#NIL DO
id: NormalNetIdPtr ← GetNormalNetId[@cluster.first.net];
idMakesItemRef: BOOLEAN;
itemRef: ItemRef;
-- print a net = line if it is not an identity
WITH did: id SELECT FROM
qualified =>
BEGIN
idMakesItemRef ← TRUE;
itemRef ← [did.source, did.see];
END;
ENDCASE => idMakesItemRef ← FALSE;
IF showEquivalences AND (NOT idMakesItemRef OR
itemRef#cluster.first.source) THEN
BEGIN
Indent[s, depth];
AppendString[s, "= "];
cluster.first.net ← AppendNet[s, cluster.first.net];
Space[s];
AppendTerminalName[s, cluster.first.source];
SaySimLine[s];
END;
ENDLOOP;
END; -- of SimFileCellInst
ThyFileCellInst: PROCEDURE[s: STRING, call: CellCallPtr,
depth: CARDINAL] =
BEGIN
c: InstancePtr;
FOR c ← call.offspring, c.sibling WHILE c#NIL DO
WITH dc: c SELECT FROM
xstr => EXIT;
ENDCASE => NULL;
ENDLOOP;
IF depth>0 AND c#NIL THEN
BEGIN
SayThyLine[""];
Indent[s, depth+2];
AppendString[s, "-- "];
AppendCallerChain[s, call];
SayThyLine[s];
END;
FOR c ← c, c.sibling WHILE c#NIL DO
WITH dc: c SELECT FROM
xstr => {Indent[s, depth+2]; WriteThyTransistor[s, c]};
ENDCASE => NULL;
ENDLOOP;
END; -- of ThyFileCellInst
WriteThyNodes: PROCEDURE[s: STRING, call: CellCallPtr,
depth: CARDINAL] =
BEGIN
IF depth>0 AND call.nets#NIL THEN
BEGIN
SayThyLine[""];
Indent[s, depth+2];
AppendString[s, "-- "];
AppendCallerChain[s, call];
SayThyLine[s];
END;
FOR netId: NetIdPtr ← call.nets, netId.next WHILE netId#NIL DO
WITH normNetId: netId SELECT FROM
normal =>
{Indent[s, depth+2]; WriteThyNetLine[s, @normNetId]};
ENDCASE => NULL;
ENDLOOP;
FOR c: InstancePtr ← call.offspring, c.sibling
WHILE c#NIL DO
WITH dc: c SELECT FROM
cell => WriteThyNodes[s, @dc,
depth+(IF showHier THEN 1 ELSE 0)];
ENDCASE => NULL;
ENDLOOP;
END; -- of WriteThyNodes
HashTransistors: PROCEDURE[c: CellCallPtr] =
BEGIN
HashLevel: PROCEDURE[c: CellCallPtr] =
BEGIN
FOR instance: InstancePtr ← c.offspring, instance.sibling
WHILE instance#NIL DO
WITH dinst: instance SELECT FROM
cell => IF NOT showHier THEN HashLevel[@dinst];
xstr =>
BEGIN
i: HashIndex;
dinst.inSimFile ← FALSE;
FOR t: XstrTerminals IN XstrTerminals DO
dinst.map[t] ← CanonNet[dinst.map[t]];
ENDLOOP;
i ← XstrHashFn[@dinst];
dinst.sameHash ← h[i];
h[i] ← @dinst;
END;
ENDCASE => NULL;
ENDLOOP;
END;
FOR i: HashIndex IN HashIndex DO
h[i] ← NIL;
ENDLOOP;
HashLevel[c];
END; -- of HashTransistors
CollectSimilarTransistors: PROCEDURE[model, candidates:
XstrCallPtr, modelOb: LONG POINTER TO xstr object]
RETURNS[locNum] =
BEGIN
width: CARDINAL ← 0; -- in 10ths of a Lambda
FOR cand: XstrCallPtr ← candidates, cand.sameHash
WHILE cand#NIL DO
IF cand.map[gate]=model.map[gate] AND
((cand.map[source]=model.map[source] AND
cand.map[drain]=model.map[drain]) OR
(cand.map[source]=model.map[drain] AND
cand.map[drain]=model.map[source])) THEN
BEGIN
WITH candOb: cand.proto.ob SELECT FROM
xstr =>
BEGIN
IF modelOb.length=candOb.length AND
modelOb.impl=candOb.impl AND
modelOb.l=candOb.l THEN
BEGIN
width ← width+(candOb.width*10)/Lambda;
cand.inSimFile ← TRUE;
END;
END;
ENDCASE;
END;
ENDLOOP;
RETURN[(Lambda*width)/10];
END;
XstrHashFn: PROCEDURE[xstr: XstrCallPtr]
RETURNS[HashIndex] =
BEGIN
RETURN[InlineDefs.LowHalf[
(LOOPHOLE[xstr.map[gate], LONG CARDINAL]+
LOOPHOLE[xstr.map[source], LONG CARDINAL]+
LOOPHOLE[xstr.map[drain], LONG CARDINAL]) MOD
(LAST[HashIndex]+1)]];
END;
WriteSimTransistor: PROCEDURE[s: STRING, t: InstancePtr] =
BEGIN
WITH trans: t SELECT FROM
xstr => IF NOT trans.inSimFile THEN
BEGIN
WITH tob: t.proto.ob SELECT FROM
xstr =>
BEGIN
p: Point;
AppendChar[s, IF tob.l=pdif
THEN (IF tob.impl THEN 'b ELSE 'c)
ELSE (IF tob.impl THEN 'd ELSE 'e)];
FOR term: XstrTerminals IN XstrTerminals DO
Space[s];
AppendNetId[s, GetNormalNetId[@trans.map[term]]];
ENDLOOP;
AppendLocNum[s, tob.length];
AppendLocNum[s,
CollectSimilarTransistors[@trans,
h[XstrHashFn[@trans]], @tob] -- width --];
p ← RefCoordPt[ItemInWorld[t.caller]];
AppendCoord[s,
LONG[(ppdddefs.pCifScale/Lambda)]*p.x];
AppendCoord[s,
-LONG[(ppdddefs.pCifScale/Lambda)]*p.y];
SaySimLine[s];
END;
ENDCASE => NULL;
END;
ENDCASE => NULL
END; -- of WriteSimTransistor
WriteThyTransistor: PROCEDURE[s: STRING, t: InstancePtr] =
BEGIN
WITH trans: t SELECT FROM
xstr => IF NOT trans.inSimFile THEN
BEGIN
WITH tob: t.proto.ob SELECT FROM
xstr =>
BEGIN
QType: TYPE = {ne, nd, pe, pd};
qName: ARRAY QType OF CHARACTER =
[ne: 'E, nd: 'D, pe: 'C, pd: 'B];
defaultL: ARRAY QType OF locNum =
[ne: 2*Lambda, nd: 4*Lambda,
pe: 2*Lambda, pd: 4*Lambda];
defaultW: ARRAY QType OF locNum =
[ne: 4*Lambda, nd: 2*Lambda,
pe: 4*Lambda, pd: 2*Lambda];
first: BOOLEAN;
qType: QType ← IF tob.l=pdif
THEN (IF tob.impl THEN pd ELSE pe)
ELSE (IF tob.impl THEN nd ELSE ne);
AppendChar[s, 'Q];
AppendCard[s, transNo ← transNo+1];
AppendChar[s, ':];
AppendChar[s, qName[qType]];
AppendString[s, "Tran["];
FOR term: XstrTerminals IN XstrTerminals DO
IF term#FIRST[XstrTerminals] THEN
AppendChar[s, ',];
AppendThyNetId[s, GetNormalNetId[@trans.map[term]]];
ENDLOOP;
first ← AppendThyDist[s, tob.length, "L",
defaultL[qType], TRUE];
[] ← AppendThyDist[s, CollectSimilarTransistors[@trans,
h[XstrHashFn[@trans]], @tob] -- width --, "W",
defaultW[qType], first];
AppendString[s, "];"];
SayThyLine[s];
END;
ENDCASE => NULL;
END;
ENDCASE => NULL
END; -- of WriteThyTransistor
WriteSimNetLine: PROCEDURE[s: STRING, id: NormalNetIdPtr] =
BEGIN
AppendString[s, "N "];
AppendNetId[s, id];
AppendLayerArea[s, id.caps[metal]];
AppendLayerArea[s, id.caps[poly]];
AppendLayerArea[s, id.caps[diffusion]];
AppendLayerPerim[s, id.caps[diffusion]];
AppendLayerArea[s, id.caps[metal2]];
SaySimLine[s];
END;
WriteThyNetLine: PROCEDURE[s: STRING, id: NormalNetIdPtr] =
BEGIN
nodeName: STRING ← [100];
first: BOOLEAN;
nodeName.length ← 0;
AppendThyNetId[nodeName, id];
SELECT TRUE FROM
EquivalentString[nodeName, "Gnd"],
EquivalentString[nodeName, "Vdd"] =>
AppendString[s, "-- "]; -- not allowed to describe these
ENDCASE => NULL;
AppendString[s, nodeName];
AppendString[s, ":node; ?:Stray["];
AppendString[s, nodeName];
first ← AppendThyLayerArea[s, id.caps[metal2], "aM2", TRUE];
first ← AppendThyLayerArea[s, id.caps[metal], "aM", first];
first ← AppendThyLayerArea[s, id.caps[poly], "aP", first];
first ← AppendThyLayerArea[s, id.caps[diffusion], "aD", first];
[] ← AppendThyDist[s, id.caps[diffusion].perimeter,
"pD", 0, first];
AppendString[s, "];"];
SayThyLine[s];
END;
AppendThyNetId: PROCEDURE[s: STRING, id: NormalNetIdPtr] =
BEGIN
name: STRING ← [100];
name.length ← 0;
AppendNetId[name, id];
SELECT TRUE FROM
EquivalentString[name, "Gnd"] =>
AppendString[s, "Gnd"];
EquivalentString[name, "Vdd"] =>
AppendString[s, "Vdd"];
ENDCASE =>
FOR i: CARDINAL IN [0..name.length) DO
SELECT name[i] FROM
IN ['0..'9], IN ['a..'z], IN ['A..'Z] => NULL;
ENDCASE => GOTO HasSpecialChar;
REPEAT
HasSpecialChar =>
BEGIN
AppendChar[s, '$];
AppendString[s, name];
AppendChar[s, '$];
END;
FINISHED => AppendString[s, name];
ENDLOOP;
END;
AppendLayerArea: PROCEDURE[s: STRING, cap: LayerCap] =
BEGIN
Space[s];
AppendCard[s, cap.area/(Lambda*Lambda)];
END;
AppendLayerPerim: PROCEDURE[s: STRING, cap: LayerCap] =
BEGIN
Space[s];
AppendCard[s, cap.perimeter/Lambda];
END;
AppendThyLayerArea: PROCEDURE[s: STRING, cap: LayerCap,
layer: STRING, first: BOOLEAN] RETURNS[BOOLEAN] =
BEGIN
IF cap.area>0 THEN
BEGIN
AppendChar[s, IF first THEN '| ELSE ',];
AppendString[s, layer];
AppendString[s, "←"];
AppendCard[s, cap.area/(Lambda*Lambda)];
RETURN[FALSE];
END;
RETURN[first];
END;
AppendThyDist: PROCEDURE[s: STRING, dist: locNum,
layer: STRING, default: locNum, first: BOOLEAN]
RETURNS[BOOLEAN] =
BEGIN
IF dist#default THEN
BEGIN
AppendChar[s, IF first THEN '| ELSE ',];
AppendString[s, layer];
AppendString[s, "←"];
AppendCard[s, dist/Lambda];
RETURN[FALSE];
END;
RETURN[first];
END;
Space: PROCEDURE[s: STRING] = INLINE
{AppendChar[s, ' ]};
Indent: PROCEDURE[s: STRING, depth: CARDINAL] =
BEGIN
FOR i: CARDINAL IN [0..2*depth) DO s[i] ← ' ENDLOOP;
s.length ← 2*depth;
END;
SaySimLine: PROCEDURE[s: STRING] =
BEGIN
IF simFile#NIL THEN
BEGIN
FOR i: CARDINAL IN [0..s.length) DO
simFile.put[simFile, s[i]] ENDLOOP;
simFile.put[simFile, Ascii.CR];
END;
END;
SayThyLine: PROCEDURE[s: STRING] =
BEGIN
IF thyFile#NIL THEN
BEGIN
FOR i: CARDINAL IN [0..s.length) DO
thyFile.put[thyFile, s[i]] ENDLOOP;
thyFile.put[thyFile, Ascii.CR];
END;
END;
END. -- of ChipSimFile