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