-- ChipNetExtract.mesa

-- A circuit extraction package
-- that runs inside Chipmonk.

-- last modified by E. McCreight, December 21, 1982  3:26 PM
-- written by E. McCreight, November 3, 1981  3:06 PM

DIRECTORY
  Ascii,
  CellInstPQ,
  ChipDRC,
  ChipExpand,
  ChipFeature,
  ChipNetDefs,
  ChipOrient,
  ChipReticle,
  ChipUserInt,
  ChipWire,
  CWF,
  FeaturePST,
  InlineDefs,
  LeftFeaturePQ,
  ppdefs,
  RightFeaturePQ,
  ZoneAllocDefs;

ChipNetExtract: PROGRAM
  IMPORTS CellInstPQ, ChipDRC, ChipExpand, ChipFeature,
    ChipNetDefs, ChipOrient, ChipReticle,
    ChipUserInt, ChipWire, CWF, FeaturePST,
    InlineDefs, LeftFeaturePQ,
    ppdefs, RightFeaturePQ,
    ZoneAllocDefs
  EXPORTS ChipNetDefs, ppdefs =
  BEGIN OPEN ppdefs,
    ChipUserInt, ChipNetDefs, CellInstPQ;

  aux: PUBLIC TYPE = CellProto;

  currentX: PUBLIC Coord;
  deltaOrigin: PUBLIC CoordPoint;

  notingMark: PUBLIC BOOLEAN ← FALSE;

  ItemInWorld: PUBLIC PROCEDURE[c: ItemRef]
    RETURNS[CoordRect] =
    BEGIN
    ob: obPtr ← c.head.proto.ob;
    r: Rect ← ChipOrient.MapRect[
      itemInCell: getRect[ItemRefToLp[c]],
      cellInstOrient: c.head.orient,
      cellSize: [x: ob.size[0], y: ob.size[1]]];
    min: CoordPoint ← c.head.min;
    scale: Coord ← coordScale[c.head.proto.locNumScale];
    RETURN[[x1: min.x+scale*r.x1, y1: min.y+scale*r.y1,
      x2: min.x+scale*r.x2, y2: min.y+scale*r.y2]];
    END; -- of ItemInWorld


  ShowFeature: PUBLIC PROCEDURE[f: FeaturePtr] =
    BEGIN
    s: STRING ← [100];
    CWF.SWF1[sto: s, s: "Feature on layer %s.", a: levelNames[f.lev]];
    RemarkAtPoint[p: RefCoordPt[f.cover], s: s];
    END;


  RefCoordPt: PUBLIC PROCEDURE[r: CoordRect]
    RETURNS[Point] =
    BEGIN
    corner1, corner2: Point;
    corner1 ← ScalePointToChipmonk[[x: r.x1, y: r.y1]];
    corner2 ← ScalePointToChipmonk[[x: r.x2, y: r.y2]];
    RETURN[ChipOrient.RefPt[
      [x1: corner1.x, y1: corner1.y,
      x2: corner2.x, y2: corner2.y]]];
    END; -- of RefCoordPt


  DistributeNetsToSources: PROCEDURE[id: NetIdPtr]
    RETURNS[NetIdPtr] =
    BEGIN
    nextNetId: NetIdPtr;
    unclaimed: NetIdPtr ← NIL;
    FOR netId: NetIdPtr ← id, nextNetId WHILE netId#NIL DO
      nextNetId ← netId.next;
      WITH did: netId SELECT FROM
        free => {did.next ← unclaimed; unclaimed ← @did};
        well => NULL;
        normal =>
          IF did.source#NIL THEN
            {did.next ← did.source.nets; did.source.nets ← @did}
          ELSE  {did.next ← unclaimed; unclaimed ← @did};
        ENDCASE;
      ENDLOOP;
    RETURN[unclaimed];
    END; -- of DistributeNetsToSources


  HeSetsParamsAndSaysYes: PUBLIC PROCEDURE[
    s1, s2: STRING ← NIL] RETURNS[bit: BOOLEAN] =
    BEGIN
    DO
      answer: STRING;
        BEGIN
        bit ← ChipUserInt.HeSaysYes[s1, s2
          ! Punt => GOTO SetParameters];
        RETURN;
        EXITS SetParameters => NULL;
        END;
      answer ← RequestString["Set debugging parameters:"L,
        "(Pause at -M-ark)"];
      IF answer.length>=1 THEN
        SELECT answer[0] FROM
          'm, 'M => notingMark ← NOT notingMark;
          ENDCASE => NULL;
      ppdefs.FreeString[answer];
      ENDLOOP;
    END; -- of HeSetsParamsAndSaysYes

  ExtractNets: PROCEDURE[univLp: listPtr] =
    BEGIN OPEN ChipOrient, LeftFeaturePQ, RightFeaturePQ;

    -- Scan proceeds from left to right.

    univ: Rect;
    leftFq: LeftFeaturePQHandle;
    rightFq: RightFeaturePQHandle;
    cq, deadcq: CellInstPQHandle;
    rootC: CellCallPtr;
    c: InstancePtr;
    lp: listPtr;
    slice: ChipWire.SlicePtr;
    topSelections, topItemCount: CARDINAL ← 0;

    Action: TYPE = {enterCellItem, enterFeatures,
        exitFeatures, exitCell, none};

    delay: ARRAY Action OF Coord ← [
      enterCellItem: ScaleFromChipmonk[0],
      enterFeatures: ScaleFromChipmonk[featureDelay],
      exitFeatures: ScaleFromChipmonk[featureDelay],
      exitCell: ScaleFromChipmonk[3*featureDelay],
      none: ScaleFromChipmonk[0]];

    SelectNext: PROCEDURE RETURNS [next: Action] =
      BEGIN
      x: Coord;
      next ← none;
      IF CellInstPQSize[cq]>0 THEN
        {next ← enterCellItem; x ← CellInstPQMin[cq].x};
      IF LeftFeaturePQSize[leftFq]>0 AND
        (LeftFeaturePQMin[leftFq].cover.x1+delay[enterFeatures]<
          x+delay[next] OR next=none) THEN
        BEGIN
        next ← enterFeatures;
        x ← LeftFeaturePQMin[leftFq].cover.x1
        END;
      IF RightFeaturePQSize[rightFq]>0 AND
        (RightFeaturePQMin[rightFq].cover.x2+delay[exitFeatures]<
          x+delay[next] OR next=none) THEN
        BEGIN
        next ← exitFeatures;
        x ← RightFeaturePQMin[rightFq].cover.x2
        END;
      IF CellInstPQSize[deadcq]>0 AND
        (CellInstPQMin[deadcq].x+delay[exitCell]<
          x+delay[next] OR next=none) THEN
        {next ← exitCell; x ← CellInstPQMin[deadcq].x};
      END;

    IF univLp=NIL THEN RETURN;

    FOR lpp: listPtr ← univLp, lpp.nxt WHILE lpp#NIL DO
      topItemCount ← topItemCount+1;
      IF lpp.selected THEN topSelections ← topSelections+1;
      ENDLOOP;

    IF topSelections=0 THEN
      BEGIN
      Explain["Nothing selected, nothing extracted!"];
      RETURN;
      END;

    univ ← ChipOrient.BoundingRect[univLp];
    deltaOrigin ← [x: ScaleFromChipmonk[univ.x1-featureDelay],
      y: ScaleFromChipmonk[univ.y1-featureDelay]];

    rootC ← instanceZ.NEW[cell Instance ←
      [min: ScalePointFromChipmonk[[x: 0, y: 0]],
      proto: ChipExpand.MakeProto[
        ob: uz.NEW[cell object ←
          [p: NIL,
          size: [univ.x2-univ.x1,
            univ.y2-univ.y1,
            univ.x2-univ.x1],
          refCnt: 1,
          l: snerd, -- if anybody uses this, he's in trouble
          returnable: FALSE,
          marked: FALSE,
          varpart: cell[cnt: topItemCount, ptr: univLp]]],
        name: "Top level design"],
      caller: [NIL, 0],
      nets: cell[]
      ]];

    ColorOff[];
    rightFq ← NewRightFeaturePQ[uz];
    leftFq ← NewLeftFeaturePQ[uz];
    cq ← NewCellInstPQ[uz];
    deadcq ← NewCellInstPQ[uz];
    slice ← ChipWire.NewSlice[];
    [] ← ChipExpand.ProtoSeq[rootC];
    InsertCellInstPQ[p: cq,
      item: [ScalePointFromChipmonk[[univ.x1, univ.y1]].x,
        [rootC, 0]]];
    InsertCellInstPQ[p: deadcq,
      item: [ScalePointFromChipmonk[[univ.x2, univ.y2]].x,
        [rootC, 0]]];

    DO SELECT SelectNext[] FROM
      enterCellItem =>
        BEGIN -- enter a new item from a cell
        lps: ListPtrSeqPtr;
        cir: ItemRef;
        idx: CellIndex;
        cqi: CellInstPt ← ExtractCellInstPQ[cq];
        [x: currentX, call: cir] ← cqi;
        [head: c, idx: idx] ← cir;
        lps ← c.proto.seq[orientToSortClass[c.orient]];
        lp ← lps[idx];
        ChipExpand.MakeInstance[item: [c, idx],
          slice: slice, futureFeatures: leftFq, presentFeatures: rightFq,
          cellQ: cq, deadCellQ: deadcq];
        END;

      enterFeatures =>
        BEGIN

        EnterAFeature: PROCEDURE[f: FeaturePtr] =
          BEGIN
          IF notingMark THEN
            ChipFeature.NoteMark[f.cover,
              "New %s feature at f↑ contains mark.", levelNames[f.lev]];
          ChipWire.WireEntered[f, slice];
          FeaturePST.InsertFeaturePST[p: slice[f.lev], item: f];
          InsertRightFeaturePQ[rightFq, f];
          END; -- of EnterAFeature

        sampleCover: CoordRect ← LeftFeaturePQMin[leftFq].cover;
        currentX ← sampleCover.x1;
        ChipFeature.BWCursor[world: [
          x: sampleCover.x1, y: sampleCover.y1]];
        MapEqualLeftFeaturePQ[p: leftFq, proc: EnterAFeature];
        IF ChipDRC.doingDRC THEN ChipDRC.LeftEdges[leftFq];
        DeleteEqualLeftFeaturePQ[leftFq];
        END;

      exitFeatures =>
        BEGIN

        ExitAFeature: PROCEDURE[f: FeaturePtr] =
          BEGIN
          FeaturePST.DeleteFeaturePST[p: slice[f.lev], item: f];
          IF notingMark THEN
            ChipFeature.NoteMark[f.cover,
              "Old %s feature at f↑ contains mark.", levelNames[f.lev]];
          ChipWire.WireLeft[f, slice];
          IF NOT ChipDRC.doingDRC THEN
            f ← ChipFeature.DestroyFeature[f];
          END; -- of ExitAFeature

        currentX ← RightFeaturePQMin[rightFq].cover.x2;
        MapEqualRightFeaturePQ[p: rightFq, proc: ExitAFeature];
        IF ChipDRC.doingDRC THEN ChipDRC.RightEdges[rightFq];
        DeleteEqualRightFeaturePQ[rightFq];
        END;

      exitCell =>
        BEGIN
        cqi: CellInstPt ← ExtractCellInstPQ[deadcq];
        [x: currentX, call: [head: c]] ← cqi;
        ChipExpand.ExitInstance[c];
        END;

      ENDCASE => EXIT;
      ENDLOOP;

    slice ← ChipWire.DestroySlice[slice];
    cq ← DestroyCellInstPQ[cq];
    leftFq ← DestroyLeftFeaturePQ[leftFq];
    rightFq ← DestroyRightFeaturePQ[rightFq];

    IF ChipDRC.doingDRC THEN
      BEGIN
      currentX ← ScalePointFromChipmonk[[univ.x2, univ.y2]].x+1;
      FOR id: NetIdPtr ← allNets, id.next WHILE id#NIL DO
        ChipDRC.PurgeDRCViolations[id];
        ENDLOOP;
      END;
    allNets ← DistributeNetsToSources[allNets];
    ChipDRC.FinishDRC[rootC];
    WriteSimFile[rootC];
    ColorOn[];
    END; -- of ExtractNets

  -- M a i n   P r o g r a m

  featureZ: PUBLIC UNCOUNTED ZONE ←
    ZoneAllocDefs.GetAnXMZone[checkSegments: TRUE];
  netZ: PUBLIC UNCOUNTED ZONE ←
    ZoneAllocDefs.GetAnXMZone[checkSegments: TRUE];
  netIdZ: PUBLIC UNCOUNTED ZONE ←
    ZoneAllocDefs.GetAnXMZone[checkSegments: TRUE];
  instanceZ: PUBLIC UNCOUNTED ZONE ←
    ZoneAllocDefs.GetAnXMZone[checkSegments: TRUE];
  clusterZ: PUBLIC UNCOUNTED ZONE ←
    ZoneAllocDefs.GetAnXMZone[checkSegments: TRUE];
  uz: PUBLIC UNCOUNTED ZONE ←
    ZoneAllocDefs.GetAnXMZone[checkSegments: TRUE];
  transZ: PUBLIC UNCOUNTED ZONE ←
    ZoneAllocDefs.GetAnXMZone[checkSegments: TRUE];

  levelNames: PUBLIC ARRAY ExtractLevel OF STRING ← ALL[NIL];
  isConductor: PUBLIC ARRAY ExtractLevel OF BOOLEAN ← 
    ALL[FALSE];

  levelNames[unknown] ← "?";
  levelNames[nWell] ← "nWell";
  levelNames[nWellRequired] ← "nWellRequired";
  levelNames[nWellForbidden] ← "nWellForbidden";
  levelNames[pWell] ← "pWell";
  levelNames[pWellRequired] ← "pWellRequired";
  levelNames[pWellForbidden] ← "pWellForbidden";
  levelNames[nDepletion] ← "nDepletionImplant";
  levelNames[nDepletionRequired] ← "nDepletionRequired";
  levelNames[nDepletionForbidden] ← "nDepletionForbidden";
  levelNames[nBuriedContact] ← "nBuriedContact";
  levelNames[nBuriedContactRequired] ← "nBuriedContactRequired";
  levelNames[nBuriedContactForbidden] ← "nBuriedContactForbidden";
  levelNames[thinOx] ← "ThinOx";
  levelNames[nPlus] ← "nPlus";
  levelNames[nPlusRequired] ← "nPlusRequired";
  levelNames[nPlusForbidden] ← "nPlusForbidden";
  levelNames[pPlus] ← "pPlus";
  levelNames[pPlusRequired] ← "pPlusRequired";
  levelNames[pPlusForbidden] ← "pPlusForbidden";
  levelNames[nImplant] ← "nSDImplant";
  levelNames[pImplant] ← "pSDImplant";
  levelNames[nGate] ← "nGate";
  levelNames[nGateRequired] ← "nGateRequired";
  levelNames[nGateForbidden] ← "nGateForbidden";
  levelNames[pGate] ← "pGate";
  levelNames[pGateRequired] ← "pGateRequired";
  levelNames[pGateForbidden] ← "pGateForbidden";
  levelNames[poly] ← "Poly";
  levelNames[polyRequired] ← "polyRequired";
  levelNames[polyForbidden] ← "polyForbidden";
  levelNames[cut] ← "Cut";
  levelNames[metal] ← "Metal";
  levelNames[via] ← "Via";
  levelNames[metal2] ← "Metal2";
  levelNames[pad] ← "Pad";

  isConductor[nPlus] ← TRUE;
  isConductor[pPlus] ← TRUE;
  isConductor[poly] ← TRUE;
  isConductor[metal] ← TRUE;
  isConductor[metal2] ← TRUE;

  BEGIN
  ENABLE
    BEGIN
    Punt => GOTO Exit;  -- for exits
    UNWIND => ColorOn[];
    END;

  SELECT TRUE FROM
    HeSetsParamsAndSaysYes["Extract selected circuit?"L] =>
      BEGIN
      ChipDRC.SetupDRC[
        HeSetsParamsAndSaysYes[
          "Shall I also check design rules?"L,
          "(..slows things down a bit...)"L]];
      ExtractNets[masterList];
      END;
    HeSetsParamsAndSaysYes["Then I'll make reticles, OK?"L] =>
      ChipReticle.ExtractReticles[masterList];
    ENDCASE => Explain["That's all I can do at the moment."L];
  EXITS Exit => NULL;
  END;

  -- give back the storage we allocated

  featureZ ← ZoneAllocDefs.DestroyAnXMZone[featureZ];
  netZ ← ZoneAllocDefs.DestroyAnXMZone[netZ];
  netIdZ ← ZoneAllocDefs.DestroyAnXMZone[netIdZ];
  instanceZ ← ZoneAllocDefs.DestroyAnXMZone[instanceZ];
  clusterZ ← ZoneAllocDefs.DestroyAnXMZone[clusterZ];
  uz ← ZoneAllocDefs.DestroyAnXMZone[uz];
  transZ ← ZoneAllocDefs.DestroyAnXMZone[transZ];

  END. -- of ChipNetExtract