-- ChipDRCImpl2.mesa -- last modified by Dillon, April 11, 1984 12:28 AM -- to change the pCifScale calculation -- last modified by E. McCreight, September 8, 1983 1:05 PM -- written by E. McCreight, April 14, 1982 10:25 AM DIRECTORY ChipDRC, ChipExpand, ChipNetDefs, ChipUserInt, CWF, ppdefs, ppdddefs, ppMainDefs, StreamDefs, StringDefs; ChipDRCImpl2: PROGRAM IMPORTS ChipExpand, ChipNetDefs, ChipUserInt, CWF, ppdddefs, ppdefs, ppMainDefs, StreamDefs, StringDefs EXPORTS ChipDRC = BEGIN OPEN StreamDefs, CWF, ppdefs, ChipUserInt, ChipNetDefs; holdViolations: PUBLIC BOOLEAN ← FALSE; violations: ViolationListPtr ← NIL; NoteViolation: PUBLIC PROCEDURE[v: Violation] = BEGIN IF NOT holdViolations THEN TellUserAboutViolation[v: v, tell: RemarkAtPoint]; violations ← uz.NEW[ViolationList ← [next: violations, v: v]]; END; -- of NoteViolations EnumerateViolations: PUBLIC PROCEDURE[] = BEGIN IF violations#NIL THEN BEGIN IF HeSaysYes[IF holdViolations THEN "There are design errors. Want to see them?"L ELSE "Want to see the design errors again?"L] THEN DO FOR vl: ViolationListPtr ← violations, vl.next WHILE vl#NIL DO TellUserAboutViolation[v: vl.v, tell: RemarkAtPoint ! Punt => GOTO NoMore]; REPEAT NoMore => NULL; ENDLOOP; IF NOT HeSaysYes[ "Want to see the design errors again?"L] THEN EXIT; ENDLOOP; IF HeSaysYes["Write design errors to a file?"L] THEN BEGIN ViolationToShowFile: PROCEDURE[p: Point, s: LONG STRING] = BEGIN OPEN ppdddefs; cifX: LONG INTEGER ← LONG[(ppdddefs.pCifScale/Lambda)]*p.x; cifY: LONG INTEGER ← LONG[(ppdddefs.pCifScale/Lambda)]*p.y; -- Chipmonk no longer wants this y -- co-ordinate inverted! FWF3[showFile, "%ld %ld %s*n", @cifX, @cifY, s]; END; showFile: DiskHandle; name: STRING ← RequestString["Error file name?"L]; IF name=NIL OR name.length=0 THEN name ← newString[ppMainDefs.fileName]; name ← FixExtension[name, ".drc"]; showFile ← NewByteStream[name, WriteAppend]; FOR vl: ViolationListPtr ← violations, vl.next WHILE vl#NIL DO TellUserAboutViolation[v: vl.v, tell: ViolationToShowFile]; ENDLOOP; FreeString[name]; TruncateDiskStream[showFile]; END; END; END; -- of EnumerateViolations TellUserAboutViolation: PROCEDURE[v: Violation, tell: PROCEDURE[p: Point, s: LONG STRING]] = BEGIN GenerateInfo: PROC = BEGIN WITH dv: v SELECT FROM tooNarrow => SWF1[s, "%s geometry too small here"L, levelNames[dv.lev]]; tooClose => IF dv.lev1=dv.lev2 THEN SWF1[s, "%s features are too close here."L, levelNames[dv.lev1]] ELSE SWF2[s, "%s and %s features too close here."L, levelNames[dv.lev1], levelNames[dv.lev2]]; noNetToWell => SWF1[s, "%s is floating here."L, levelNames[dv.lev]]; differentNetsToWell => BEGIN SWF1[s, "Different nets to %s: "L, levelNames[dv.lev]]; WITH dw: (dv.wellNode ← CanonNet[dv.wellNode]).id SELECT FROM well => BEGIN dw.attachedTo ← AppendNet[s, dw.attachedTo]; AppendLongString[s, " and "L]; dv.n ← AppendNet[s, dv.n]; END; ENDCASE => ERROR; END; terminalsUnconnected => BEGIN AppendLongString[s, """"L]; AppendTerminalName[s: s, c: dv.item]; AppendLongString[s, """ terminals failed to connect."L]; END; terminalsShorted => BEGIN AppendLongString[s, "Terminals """L]; AppendTerminalName[s: s, c: dv.item1]; AppendLongString[s, """ and """L]; AppendTerminalName[s: s, c: dv.item2]; AppendLongString[s, """ connected"L]; END; coverageNeeded => SWF1[s, "%s coverage needed here."L, levelNames[dv.lev]]; coverageForbidden => SWF1[s, "%s coverage is forbidden here."L, levelNames[dv.lev]]; bogusTransistor => SWF1[s, "Illegal Chipmonk %s transistor here."L, levelNames[dv.lev]]; cantCheck => SWF0[s, "Bug in extractor prevented some checking here"L]; ENDCASE => SWF0[s, "Unknown design error"L]; END; s: STRING ← [200]; s.length ← 0; GenerateInfo[ ! StringDefs.StringBoundsFault => CONTINUE]; tell[p: v.place, s: s]; END; -- of TellUserAboutViolation CheckTerminalConnections: PUBLIC PROCEDURE[ call: CellCallPtr] = BEGIN ChipExpand.CheckClusters[call]; FOR cluster: ClusterPtr ← call.clusters, cluster.next WHILE cluster#NIL DO cluster.first.net ← CanonNet[cluster.first.net]; FOR c2: ClusterPtr ← call.clusters, c2.next WHILE c2#cluster DO IF c2.first.net = cluster.first.net THEN NoteViolation[[ place: RefCoordPt[ItemInWorld[cluster.first.source]], info: terminalsShorted[item1: cluster.first.source, item2: c2.first.source]]]; ENDLOOP; IF cluster.first.next#NIL THEN BEGIN NoteViolation[[ place: RefCoordPt[ItemInWorld[cluster.first.source]], info: terminalsUnconnected[item: cluster.first.source]]]; FOR mc: MustConnectPtr ← cluster.first.next, mc.next WHILE mc#NIL DO NoteViolation[[ place: RefCoordPt[ItemInWorld[mc.source]], info: terminalsUnconnected[item: mc.source]]]; ENDLOOP; END; ENDLOOP; FOR c: InstancePtr ← call.offspring, c.sibling WHILE c#NIL DO WITH dc: c SELECT FROM cell => CheckTerminalConnections[@dc]; ENDCASE => NULL; ENDLOOP; END; -- of CheckTerminalConnections PurgeDRCViolations: PUBLIC PROCEDURE[n: netPtr] = BEGIN id: NetIdPtr ← (n ← CanonNet[n]).id; remaining, ncv: ViolationListPtr ← NIL; cv: ViolationListPtr; Reconsider: PROCEDURE[certain, stillPossible: BOOLEAN] = INLINE BEGIN SELECT TRUE FROM certain => {NoteViolation[cv.v]; uz.FREE[@cv]}; NOT stillPossible => BEGIN WITH dv: cv.v SELECT FROM -- remove from conditional violations tooClose => BEGIN IF dv.n1#NIL THEN dv.n1 ← DeRefNet[dv.n1]; IF dv.n2#NIL THEN dv.n2 ← DeRefNet[dv.n2]; END; coverageForbiddenIfNetsDiffer => BEGIN IF dv.n1#NIL THEN dv.n1 ← DeRefNet[dv.n1]; IF dv.n2#NIL THEN dv.n2 ← DeRefNet[dv.n2]; END; differentNetsToWell => BEGIN IF dv.wellNode#NIL THEN dv.wellNode ← DeRefNet[dv.wellNode]; IF dv.n#NIL THEN dv.n ← DeRefNet[dv.n]; END; ENDCASE => NULL; uz.FREE[@cv]; END; ENDCASE => {cv.next ← remaining; remaining ← cv}; END; WITH did: id SELECT FROM normal => BEGIN FOR cv ← id.violations, ncv WHILE cv#NIL DO ncv ← cv.next; WITH dv: cv.v SELECT FROM tooNarrow => Reconsider[certain: NOT did.couldBeLogo, stillPossible: currentX<=id.final.r.x2]; tooClose => BEGIN id1: NormalNetIdPtr = GetNormalNetId[@dv.n1]; id2: NormalNetIdPtr = GetNormalNetId[@dv.n2]; Reconsider[ certain: id1#id2 AND NOT (id1.couldBeLogo AND id2.couldBeLogo) AND (id1.final.r.x2<currentX OR id2.final.r.x2<currentX), stillPossible: id1#id2 AND (currentX<=id1.final.r.x2 OR currentX<=id2.final.r.x2)]; END; coverageForbiddenIfNetsDiffer => BEGIN id1: NormalNetIdPtr = GetNormalNetId[@dv.n1]; id2: NormalNetIdPtr = GetNormalNetId[@dv.n2]; stillActive: BOOLEAN = currentX<=id1.final.r.x2 OR currentX<=id2.final.r.x2 OR NOT externalWiringFinished; Reconsider[ certain: id1#id2 AND NOT stillActive AND NOT (id1.couldBeLogo AND id2.couldBeLogo), stillPossible: id1#id2]; END; differentNetsToWell => BEGIN wn: NetIdPtr = (dv.wellNode ← CanonNet[dv.wellNode]).id; WITH dwn: wn SELECT FROM well => BEGIN id1: NormalNetIdPtr = GetNormalNetId[@dwn.attachedTo]; id2: NormalNetIdPtr = GetNormalNetId[@dv.n]; stillActive: BOOLEAN = currentX<=id1.final.r.x2 OR currentX<=id2.final.r.x2 OR NOT externalWiringFinished; duplicate: BOOLEAN ← FALSE; FOR pv: ViolationListPtr ← ncv, pv.next WHILE pv#NIL DO WITH dpv: pv.v SELECT FROM differentNetsToWell => IF (dpv.wellNode ← CanonNet[dpv.wellNode])=dv.wellNode AND (dpv.n ← CanonNet[dpv.n])=dv.n THEN {duplicate ← TRUE; EXIT}; ENDCASE => NULL; ENDLOOP; Reconsider[ certain: id1#id2 AND NOT duplicate AND NOT stillActive, stillPossible: id1#id2 AND NOT duplicate]; END; ENDCASE => NULL; END; ENDCASE => ERROR; ENDLOOP; id.violations ← remaining; END; well => IF id.final.r.x2<currentX AND did.attachedTo=NIL THEN NoteViolation[[place: RefCoordPt[id.final.r], info: noNetToWell[lev: id.final.lev]]]; ENDCASE => NULL; END; -- of PurgeDRCViolations END. -- of ChipDRCImpl2