-- ChipReticleImpl.mesa

-- A package to write files to drive the ISL/ICL ReticleMaker.

-- last modified by E. McCreight, November 23, 1982  12:22 PM
-- written by E. McCreight, March 19, 1982  1:28 PM

DIRECTORY
  CellInstPQ,
  ChipExpand,
  ChipFeature,
  ChipNetDefs,
  ChipOrient,
  ChipReticle,
  ChipUserInt,
  ChipWire,
  FeaturePST,
  LeftFeaturePQ,
  ppdefs,
  ppMainDefs,
  ReticleBandFormat,
  RightFeaturePQ,
  SegmentDefs,
  StringDefs;

ChipReticleImpl: PROGRAM
  IMPORTS CellInstPQ, ChipExpand, ChipFeature, ChipNetDefs,
    ChipOrient, ChipReticle, ChipUserInt,
    ChipWire, FeaturePST, LeftFeaturePQ,
    ppdefs, ppMainDefs, RightFeaturePQ, StringDefs
  EXPORTS ChipReticle SHARES ChipReticle =
  BEGIN OPEN ppdefs,
    ChipUserInt, ChipNetDefs, FeaturePST,
    ChipOrient, ChipReticle, LeftFeaturePQ;


  makingReticles: PUBLIC BOOLEAN ← FALSE;

  maskStates: PUBLIC ARRAY Masks OF ReticleState;

  reticleName: PUBLIC STRING ← NIL;

  herald: PUBLIC ReticleBandFormat.HeraldObject;

  reticleSize, reticleCenter: PUBLIC CoordPoint;
  reticleDesign, alignedDesign: PUBLIC CoordRect;


  ExtractReticles: PUBLIC PROCEDURE[univLp: listPtr] =
    BEGIN OPEN CellInstPQ,
      LeftFeaturePQ, RightFeaturePQ;

    -- Scan proceeds from left to right.

    univ: CoordRect ← [
      x1: LAST[Coord], x2: FIRST[Coord],
      y1: LAST[Coord], y2: FIRST[Coord]];
    leftFq: LeftFeaturePQHandle;
    rightFq: RightFeaturePQHandle;
    cq, deadcq: CellInstPQHandle;
    rootC: CellCallPtr;
    c: InstancePtr;
    lp: listPtr;
    topItemCount: CARDINAL ← 0;
    showMasks: BOOLEAN ← FALSE;
    screenClip: CoordRect ← [0,0,0,0];
    fineResolution: STRING ← NIL;


    Action: TYPE = {enterCellItem, enterFeature,
        exitFeature, exitCell, none};

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

    ToDecimal: PROCEDURE[s: STRING, default: INTEGER]
      RETURNS[result: INTEGER] =
      BEGIN
      IF s=NIL OR s.length=0 THEN GOTO UseDefault;
      result ← StringDefs.StringToDecimal[s: s
        ! StringDefs.InvalidNumber => GOTO UseDefault];
      EXITS
        UseDefault => result ← default;
      END;

    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[enterFeature]<
          x+delay[next] OR next=none) THEN
        BEGIN
        next ← enterFeature;
        x ← LeftFeaturePQMin[leftFq].cover.x1
        END;
      IF RightFeaturePQSize[rightFq]>0 AND
        (RightFeaturePQMin[rightFq].cover.x2+delay[exitFeature]<
          x+delay[next] OR next=none) THEN
        BEGIN
        next ← exitFeature;
        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;

    designSize: CoordPoint;

    IF univLp=NIL THEN RETURN; -- empty design

    makingReticles ← TRUE;
    reticleName ←
      ChipUserInt.RequestString["Prefix of reticle file names:"L];
    IF reticleName=NIL OR reticleName.length=0 THEN
      reticleName ← newString[ppMainDefs.fileName];
    reticleName ← ChipUserInt.FixExtension[reticleName, ""];
    herald ←  ReticleBandFormat.ReticleMakerHerald;
    herald.bandWidth ← 2*(herald.bandWidth/2);
      -- in case some silly interface writer thinks that the
      -- Alto can handle scan lines consisting of an
      -- odd number of words.

    Explain["Select an instance of every cell that is"L,
      "an ICL test structure in fine-resolution co-ordinates"L];

    fineResolution ← RequestString[
      "How many nanometers is a fine resolution lambda?"L,
      "(default is 500 nm)"L];
    coordScale[absolute] ←
      ToDecimal[s: fineResolution, default: 500]/2;
    IF fineResolution#NIL THEN
      {FreeString[fineResolution]; fineResolution ← NIL};


    FOR lpp: listPtr ← univLp, lpp.nxt WHILE lpp#NIL DO
      r: CoordRect ← univ;
      WITH ob: lpp.ob SELECT FROM
        cell =>
          BEGIN
          c: ProtoPtr ← ChipExpand.MakeProto[ob: @ob,
            locNumScale:
              (IF lpp.selected THEN absolute
                ELSE lambdaRelative)];
          univ ← [
            x1: MIN[r.x1, ScaleFromChipmonk[lpp.lx]],
            x2: MAX[r.x2, ScaleFromChipmonk[lpp.lx]+
              CoordSize[size: c.size, orient: lpp.idx].x],
            y1: MIN[r.y1, ScaleFromChipmonk[lpp.ly]],
            y2: MAX[r.y2, ScaleFromChipmonk[lpp.ly]+
              CoordSize[size: c.size, orient: lpp.idx].y]];
          END;
        ENDCASE =>
          univ ← [
            x1: MIN[r.x1, ScaleFromChipmonk[lpp.lx]],
            x2: MAX[r.x2, ScaleFromChipmonk[lpp.lx+
              ob.size[Rot90[lpp.idx]]]],
            y1: MIN[r.y1, ScaleFromChipmonk[lpp.ly]],
            y2: MAX[r.y2, ScaleFromChipmonk[lpp.ly+
              ob.size[1-Rot90[lpp.idx]]]]];
      topItemCount ← topItemCount+1;
      ENDLOOP;

    rightFq ← NewRightFeaturePQ[uz];
    leftFq ← NewLeftFeaturePQ[uz];
    cq ← NewCellInstPQ[uz];
    deadcq ← NewCellInstPQ[uz];

    reticleSize ← [
      x: coordsPerReticle*16*herald.bandWidth,
      y: coordsPerReticle*herald.bandCount*herald.bandHeight];
    reticleCenter ← [x: reticleSize.x/2, y: reticleSize.y/2];

    designSize ← [
      x: univ.x2-univ.x1,
      y: univ.y2-univ.y1];
    reticleDesign ← [
      x1: reticleCenter.x-designSize.x/2,
      x2: (reticleCenter.x-designSize.x/2)+designSize.x,
      y1: reticleCenter.y-designSize.y/2,
      y2: (reticleCenter.y-designSize.y/2)+designSize.y];
    deltaOrigin ← [
      x: univ.x1-reticleDesign.x1,
      y: univ.y1-reticleDesign.y1];

    InitMaskStates[];
    CircumscribeAndBeyond[q: leftFq, design: reticleDesign];

    rootC ← instanceZ.NEW[cell Instance ←
      [min: ScalePointFromChipmonk[[x: 0, y: 0]],
      proto: ChipExpand.MakeProto[
        ob: uz.NEW[cell object ←
          [p: NIL,
          size: [ScaleToChipmonk[univ.x2-univ.x1],
            ScaleToChipmonk[univ.y2-univ.y1],
            ScaleToChipmonk[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: "Design"],
      caller: [NIL, 0],
      nets: cell[]
      ]];

    ColorOff[];
    [] ← ChipExpand.ProtoSeq[rootC];
    InsertCellInstPQ[p: cq, item: [reticleDesign.x1, [rootC, 0]]];
    InsertCellInstPQ[p: deadcq, item: [reticleDesign.x2, [rootC, 0]]];

    currentX ← FIRST[Coord];

    DO SELECT SelectNext[] FROM
      enterCellItem =>
        BEGIN -- enter a new item from a cell
        lps: ListPtrSeqPtr;
        globalR: CoordRect;
        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];
        IF notingMark THEN
          BEGIN
          globalR ← ItemInWorld[cir];
          ChipFeature.NoteMark[globalR,
            "New cell at lp↑ contains mark."];
          END;
        ChipExpand.MakeInstance[item: [c, idx],
          slice: NIL, futureFeatures: leftFq, presentFeatures: rightFq,
          cellQ: cq, deadCellQ: deadcq];
        END;

      enterFeature =>
        BEGIN
        f: FeaturePtr ← ExtractLeftFeaturePQ[leftFq];
        IF f.cover.x1>=currentX THEN currentX ← f.cover.x1
        ELSE DebugAtPoint[ScalePointToChipmonk[
          [x: f.cover.x1, y: f.cover.y1]],
          "Scan went backward"L];
        ChipFeature.BWCursor[world: [x: f.cover.x1, y: f.cover.y1]];
        IF notingMark THEN
          ChipFeature.NoteMark[f.cover,
            "New feature at f↑ contains mark."L];

        SELECT f.lev FROM
          unknown => -- codes text to appear on all reticles
            FOR mask: Masks IN Masks DO
              IF mask#unknown
                AND maskStates[mask].inReticleSet THEN
                [] ← NewReticleFeature[cover: f.cover,
                  mask: mask, lq: leftFq];
              ENDLOOP;
          pad =>
            BEGIN
            NoteFeature[state: @maskStates[(SELECT TRUE FROM
              maskStates[pad].inReticleSet => pad,
              maskStates[via].inReticleSet => via,
              ENDCASE => cut)], f: f];
            END;
          nWell =>
            BEGIN
            NoteFeature[state: @maskStates[nWell], f: f];
            CheckOverlapInDesign[p: maskStates[pWell].slice, f: f,
              problem: "Diffusion too close to well boundary"L];
            END;
          pWell =>
            BEGIN
            NoteFeature[state: @maskStates[pWell], f: f];
            CheckOverlapInDesign[p: maskStates[nWell].slice, f: f,
              problem: "Diffusion too close to well boundary"L];
            END;
          nImplant =>
            BEGIN
            NoteFeature[state: @maskStates[nImplant], f: f];
            CheckOverlapInDesign[p: maskStates[pImplant].slice, f: f,
              problem: "p/n diffusions too close"L];
            END;
          pImplant =>
            BEGIN
            NoteFeature[state: @maskStates[pImplant], f: f];
            CheckOverlapInDesign[p: maskStates[nImplant].slice, f: f,
              problem: "p/n diffusions too close"L];
            END;
          nPlus => NoteFeature[state: @maskStates[thinOx], f: f];
          pPlus => NoteFeature[state: @maskStates[thinOx], f: f];
          ENDCASE
 => NoteFeature[state: @maskStates[f.lev], f: f];

        RightFeaturePQ.InsertRightFeaturePQ[rightFq, f];
        END;

      exitFeature =>
        BEGIN
        f: FeaturePtr ← ExtractRightFeaturePQ[rightFq];
        IF f.cover.x2>=currentX THEN currentX ← f.cover.x2
        ELSE DebugAtPoint[ScalePointToChipmonk[
          [x: f.cover.x2, y: f.cover.y1]],
          "Scan went backward"L];
        IF notingMark THEN
          ChipFeature.NoteMark[f.cover,
            "Old feature at f↑ contains mark."L];
        SELECT f.lev FROM
          unknown => NULL;
          nPlus => ForgetFeature[state: @maskStates[thinOx], f: f];
          pPlus => ForgetFeature[state: @maskStates[thinOx], f: f];
          pad =>
            ForgetFeature[state: @maskStates[(SELECT TRUE FROM
              maskStates[pad].inReticleSet => pad,
              maskStates[via].inReticleSet => via,
              ENDCASE => cut)], f: f];
          ENDCASE => ForgetFeature[state: @maskStates[f.lev], f: f];
        f ← ChipFeature.DestroyFeature[f];
        END;

      exitCell =>
        BEGIN
        globalR: CoordRect;
        cqi: CellInstPt ← ExtractCellInstPQ[deadcq];
        [-- x: currentX, -- call: [head: c]] ← cqi;
        IF notingMark THEN
          BEGIN
          globalR ← IF c.caller.head#NIL
            THEN ItemInWorld[c.caller]
            ELSE [x1: rootC.min.x, y1: rootC.min.y,
              x2: rootC.min.x, y2: rootC.min.y];
          ChipFeature.NoteMark[globalR,
            "Leaving cell at c↑ containing mark."];
          END;
        ChipExpand.ExitInstance[c];
        END;

      ENDCASE => EXIT;
      ENDLOOP;

    cq ← DestroyCellInstPQ[cq];
    leftFq ← DestroyLeftFeaturePQ[leftFq];
    rightFq ← DestroyRightFeaturePQ[rightFq];

    IF (showMasks ←
      HeSetsParamsAndSaysYes["Shall I show masks on the screen?"L]) THEN
      BEGIN
      p1, p2: CoordPoint;
      Explain["Mark one corner of clip rectangle."L];
      p1 ← ScalePointFromChipmonk[markPnt];
      Explain["Now mark diagonally opposite corner."L];
      p2 ← ScalePointFromChipmonk[markPnt];
      screenClip ← [x1: MIN[p1.x, p2.x], y1: MIN[p1.y, p2.y],
        x2: MAX[p1.x, p2.x], y2: MAX[p1.y, p2.y]];
      END;

    FOR mask: Masks IN Masks DO
      state: ReticleStatePtr ← @maskStates[mask];
      IF state.inReticleSet AND state.rectCount>0 THEN
        FinishMask[state, mask, showMasks, screenClip];
      uz.FREE[@state.block];
      state.slice ← DestroyFeaturePST[state.slice];
      state.cover ← DestroyFeaturePST[state.cover];
      ENDLOOP;
    IF reticleName#NIL THEN
      {FreeString[reticleName]; reticleName ← NIL};

    ColorOn[];
    END; -- of ExtractReticles

  CheckOverlapInDesign: PROCEDURE[p: FeaturePSTHandle,
    f: FeaturePtr, problem: STRING] =
    BEGIN

    SayProblem: PROCEDURE[r: CoordRect] =
      {RemarkAtPoint[p: RefCoordPt[r], s: problem]};

    IF reticleDesign.x1<=f.cover.x1 AND
      f.cover.x2<=reticleDesign.x2 AND
      reticleDesign.y1<=f.cover.y1 AND
      f.cover.y2<=reticleDesign.y2 THEN
      ChipWire.OverlapIsViolation[p: p, f: f, problem: SayProblem];
    END; -- of CheckOverlapInDesign


  CoordBox: PUBLIC PROCEDURE[center, diameter: CoordPoint,
    offset: CoordPoint ← [0,0]] RETURNS[CoordRect] =
    BEGIN
    origin: CoordPoint ← [x: center.x+offset.x, y: center.y+offset.y];
    RETURN[[x1: (2*origin.x-diameter.x)/2,
      x2: (2*origin.x+diameter.x)/2,
      y1: (2*origin.y-diameter.y)/2,
      y2: (2*origin.y+diameter.y)/2]];
    END; -- of CoordBox


  NewReticleFeature: PUBLIC PROCEDURE[cover: CoordRect,
    mask: Masks, lq: LeftFeaturePQHandle ← NIL]
    RETURNS[FeaturePtr] =
    {RETURN[IF mask=unknown -- codes for all masks --
      OR maskStates[mask].inReticleSet THEN
      ChipFeature.NewFeature[cover: cover, lev: mask, lq: lq]
      ELSE NIL]};

  END. -- of ChipReticleImpl