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