-- ChipWireImpl.mesa

-- Subroutines to maintain and use of a slice of features
-- with constant x.

-- last modified by E. McCreight, November 5, 1982  11:28 AM
-- written by E. McCreight, March 5, 1982  10:12 AM

DIRECTORY
  ChipNetDefs,
  ChipDRC,
  ChipExpand,
  ChipWire,
  FeaturePST,
  ppdddefs,
  ppdefs,
  StringDefs;

ChipWireImpl: PROGRAM
  IMPORTS ChipDRC, ChipExpand, ChipNetDefs,
    FeaturePST, ppdddefs, StringDefs
  EXPORTS ChipWire =
  BEGIN OPEN ppdefs, ChipNetDefs, FeaturePST,
    ChipExpand, ChipDRC, ChipWire;


  NewSlice: PUBLIC PROCEDURE RETURNS[SlicePtr] =
    BEGIN
    slice: SlicePtr ← uz.NEW[Slice];
    FOR lev: ExtractLevel IN ExtractLevel DO
      slice[lev] ← NewFeaturePST[uz];
      ENDLOOP;
    RETURN[slice];
    END;


  DestroySlice: PUBLIC PROCEDURE[slice: SlicePtr]
    RETURNS[SlicePtr] =
    BEGIN
    FOR lev: ExtractLevel IN ExtractLevel DO
      slice[lev] ← DestroyFeaturePST[slice[lev]];
      ENDLOOP;
    uz.FREE[@slice];
    RETURN[NIL];
    END;

  WireEntered: PUBLIC PROCEDURE[f: FeaturePtr, slice: SlicePtr] =
    BEGIN

    CheckBuriedContact: PROCEDURE[item: FeaturePtr] =
      BEGIN

      BogusTransistor1: PROCEDURE[int: Interval] =
        BEGIN
        IF int.min<int.max THEN
          NoteViolation[[
            place: RefCoordPt[SharedArea[f.cover, item.cover]],
            type: bogusTransistor,
            lev1: nPlus]];
        END;

      MergeNetsInBuriedContact: PROCEDURE[int: Interval,
        repItem: FeaturePtr] =
        {IF int.min<int.max THEN MergeFeatureNets[f, item]};

      IF HaveSharedArea[f.cover, item.cover] THEN
        ClassifyFeaturePSTInterval[p: slice[nBuriedContact],
          int: SharedYInterval[f, item],
          covered: MergeNetsInBuriedContact,
          gap: BogusTransistor1];
      END;

    BogusPTransistor: PROCEDURE[r: CoordRect] =
      {NoteViolation[[
        place: RefCoordPt[r],
        type: bogusTransistor,
        lev1: pPlus]]};

    JoinConductors[f, slice];

    SELECT f.lev FROM
      poly =>
        BEGIN
        SearchFeaturePST[p: slice[nPlus],
          int: [min: f.cover.y1, max: f.cover.y2],
          touch: CheckBuriedContact];
        OverlapIsViolation[p: slice[pPlus],
          f: f, problem: BogusPTransistor];
        END;
      pPlus =>
        BEGIN
        OverlapIsViolation[p: slice[poly],
          f: f, problem: BogusPTransistor];
        END;
      nPlus =>
        BEGIN
        SearchFeaturePST[p: slice[poly],
          int: [min: f.cover.y1, max: f.cover.y2],
          touch: CheckBuriedContact];
        END;
      ENDCASE => NULL;

    END; -- of WireEntered

  WireLeft: PUBLIC PROCEDURE[f: FeaturePtr, slice: SlicePtr] =
    BEGIN
    deltaSides: INTEGER ← 2;
    deltaWidth: Coord ← f.cover.y2-f.cover.y1;
    dw: locNum; -- deltaWidth in locNum's

    LeaveTouch: PROCEDURE[int: Interval, repItem: FeaturePtr] =
      BEGIN
      deltaWidth ← deltaWidth-
        (MIN[int.max, yMax]-MAX[int.min, yMin]);
      deltaSides ← deltaSides-2;
      END;

    PolyIsBogusTransistor: PROCEDURE[item: FeaturePtr] =
      BEGIN
      difFeature ← item;
      SearchFeaturePST[p: slice[poly],
        int: SharedYInterval[difFeature, f],
        touch: BogusTransistor2];
      END;

    BogusTransistor2: PROCEDURE[item: FeaturePtr] =
      {NoteViolation[[
        place: RefCoordPt[
          SharedArea[difFeature.cover, item.cover]],
        type: bogusTransistor,
        lev1: nPlus]]};

    cond: Conductors;
    caps: LayerCapPtr;
    id: NormalNetIdPtr;
    difFeature: FeaturePtr;
    yMin: Coord ← f.cover.y1;
    yMax: Coord ← f.cover.y2;

    SELECT f.lev FROM
      nPlus, pPlus => cond ← diffusion;
      poly => cond ← poly;
      metal => cond ← metal;
      metal2 => cond ← metal2;
      nBuriedContact =>
        BEGIN
        SearchFeaturePST[p: slice[nPlus],
          int: [min: f.cover.y1, max: f.cover.y2],
          touch: PolyIsBogusTransistor];
        RETURN;
        END;
      ENDCASE => RETURN;

    UpdateAreas[GetNormalNetId[@f.net]];

    ClassifyFeaturePSTInterval[p: slice[f.lev],
      int: [min: yMin-1, max: yMax+1],
      covered: LeaveTouch,
      gap: NullFeatureGap];
    dw ← ScaleToChipmonk[deltaWidth];

    id ← GetNormalNetId[@f.net];
    caps ← @id.caps[cond];
    caps.cutSides ← caps.cutSides-deltaSides;
    caps.cutWidth ← caps.cutWidth-dw;
    caps.perimeter ← caps.perimeter+dw;

    WITH dc: f.caller.head SELECT FROM
      cell =>
        BEGIN
        lp: listPtr ← ItemRefToLp[f.caller];
        IF ppdddefs.getTextProp[lp]#NIL THEN
          SetupCluster[(f.net ← CanonNet[f.net]),
            f.caller, @dc, ppdddefs.getTextProp[lp].s];
        END;
      ENDCASE => NULL;
    END; -- of WireLeft

  JoinConductors: PROCEDURE[f: FeaturePtr, slice: SlicePtr] =
    BEGIN
    deltaSides: INTEGER ← 2;
    deltaWidth: Coord ← f.cover.y2-f.cover.y1;
    dw: locNum; -- deltaWidth in locNum's
    yMin: Coord ← f.cover.y1;
    yMax: Coord ← f.cover.y2;

    Strength: TYPE = {wire, well, none};
    StrengthCond: TYPE = RECORD[
      strength: Strength,
      cond: Conductors
      ];

    EnterTouch: PROCEDURE[int: Interval, repItem: FeaturePtr] =
      BEGIN
      deltaWidth ← deltaWidth-
        (MIN[int.max, yMax]-MAX[int.min, yMin]);
      deltaSides ← deltaSides-2;
      MergeFeatureNets[f, repItem];
      END;

    strength: Strength;
    cond: Conductors;

    [strength: strength, cond: cond] ← SELECT f.lev FROM
      nPlus, pPlus => StrengthCond[wire, diffusion],
      poly => StrengthCond[wire, poly],
      metal => StrengthCond[wire, metal],
      metal2 => StrengthCond[wire, metal2],
      pWell, nWell => StrengthCond[well, diffusion],
      ENDCASE => StrengthCond[none, diffusion];

    SELECT strength FROM
      wire =>
        BEGIN
        caps: LayerCapPtr;
        IF f.net=NIL THEN
          BEGIN
          nid: NormalNetIdPtr;
          f.net ← NewNet[];
          nid ← GetNormalNetId[@f.net];
          nid.source ← NearestCellInstance[f.caller.head];
          nid.final ← [lev: f.lev, r: f.cover];
          END;
    
        UpdateAreas[GetNormalNetId[@f.net]];
    
        ClassifyFeaturePSTInterval[p: slice[f.lev],
          int: [min: yMin-1, max: yMax+1], covered: EnterTouch,
          gap: NullFeatureGap];
        dw ← ScaleToChipmonk[deltaWidth];
    
        caps ← @GetNormalNetId[@f.net].caps[cond];
        caps.cutSides ← caps.cutSides+deltaSides;
        caps.cutWidth ← caps.cutWidth+dw;
        caps.perimeter ← caps.perimeter+dw;
        END;
      well =>
        BEGIN
        IF f.net=NIL THEN
          BEGIN
          cn: CanonNetPtr ← f.net ← NewNet[];
          cn.id.details ← well[attachedTo: NIL];
          cn.id.final ← [lev: f.lev, r: f.cover];
          END;
        ClassifyFeaturePSTInterval[p: slice[f.lev],
          int: [min: yMin-1, max: yMax+1], covered: EnterTouch,
          gap: NullFeatureGap];
        END;
      ENDCASE => NULL;
    END; -- of JoinConductors

  MergeFeatureNets: PROCEDURE[f1, f2: FeaturePtr] =
    BEGIN
    id: NetIdPtr;
    net: netPtr;
    SELECT f1.net FROM
      #NIL =>
        SELECT f2.net FROM
          #NIL => net ← MergeNets[f1.net, f2.net];
          ENDCASE => net ← RefCanonNet[f1.net];
      ENDCASE => 
        SELECT f2.net FROM
          #NIL => net ← RefCanonNet[f2.net];
          ENDCASE =>
            BEGIN
            net ← NewNet[2];
            SELECT f1.lev FROM
              nWell, pWell =>
                CanonNet[net].id.details ← well[attachedTo: NIL];
              ENDCASE =>
                GetNormalNetId[@net].source ←
                  NearestCellInstance[f1.caller.head];
            END;
    id ← (f1.net ← f2.net ← CanonNet[net]).id;
    IF id.final.r.x2<f1.cover.x2 THEN
      id.final ← [lev: f1.lev, r: f1.cover];
    IF id.final.r.x2<f2.cover.x2 THEN
      id.final ← [lev: f2.lev, r: f2.cover];
    END; -- of MergeFeatureNets


  HaveSharedArea: PUBLIC PROCEDURE[r1, r2: CoordRect]
    RETURNS[BOOLEAN] =
    {RETURN[MAX[r1.x1, r2.x1]<MIN[r1.x2, r2.x2]
      AND MAX[r1.y1, r2.y1]<MIN[r1.y2, r2.y2]]};

  SharedArea: PUBLIC PROCEDURE[r1, r2: CoordRect]
    RETURNS[CoordRect] =
    {RETURN[[x1: MAX[r1.x1, r2.x1],
      x2: MIN[r1.x2, r2.x2],
      y1: MAX[r1.y1, r2.y1],
      y2: MIN[r1.y2, r2.y2]]]};

  SharedYInterval: PROCEDURE[f1, f2: FeaturePtr]
    RETURNS[Interval] =
    {RETURN[[min: MAX[f1.cover.y1, f2.cover.y1],
      max: MIN[f1.cover.y2, f2.cover.y2]]]};


  OverlapIsViolation: PUBLIC PROCEDURE[p: FeaturePSTHandle,
    f: FeaturePtr, problem: PROCEDURE[r: CoordRect]] =
    BEGIN

    CouldBeBad: PROCEDURE[item: FeaturePtr] =
      {IF HaveSharedArea[f.cover, item.cover] THEN
        problem[SharedArea[f.cover, item.cover]]};

    IF f.cover.y1+1<=f.cover.y2-1 THEN
      SearchFeaturePST[p: p, int: [f.cover.y1+1, f.cover.y2-1],
        touch: CouldBeBad];
    END;

  SetupCluster: PROCEDURE[fNet: CanonNetPtr, source: ItemRef,
    c: CellCallPtr, name: STRING] =
    BEGIN
    FOR cluster: ClusterPtr ← c.clusters, cluster.next
      WHILE cluster#NIL DO
      IF StringDefs.EquivalentString[name, cluster.netName] THEN
        BEGIN
        FOR mustConnect: MustConnectPtr ← @cluster.first,
          mustConnect.next
          WHILE mustConnect#NIL DO
          IF (mustConnect.net ←
            CanonNet[mustConnect.net])=fNet THEN
            GOTO Finished;
          ENDLOOP;
        cluster.first.next ← clusterZ.NEW[MustConnect ← [
          next: cluster.first.next, net: RefCanonNet[fNet],
          source: source]];
        GOTO Finished;
        END;
      ENDLOOP;
    c.clusters ← clusterZ.NEW[Cluster ←
      [next: c.clusters,
      netName: name,
      first: [net: RefCanonNet[fNet], source: source]]];
    EXITS Finished => NULL
    END;


  END. -- of ChipWireImpl