-- 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