-- ChipExpandAtomic.mesa

-- A package to expand atomic Chipmonk cell geometries,
-- such as transistors and contacts, for circuit extraction.

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

DIRECTORY
  ChipDRC,
  ChipExpand,
  ChipNetDefs,
  ppdefs;

ChipExpandAtomic: PROGRAM
  IMPORTS ChipDRC, ChipExpand, ChipNetDefs
  EXPORTS ChipExpand SHARES ChipExpand =
  BEGIN OPEN ppdefs, ChipNetDefs, ChipDRC, ChipExpand;


-- Procedures copied from Chipmonk and changed slightly
-- for design rule checking and circuit extraction. The main
-- difference here is that pol and dif are not allowed
-- to overlap at all.

  exXstr0: PUBLIC drProc =
    BEGIN
    p: LONG POINTER TO xstr object = LOOPHOLE[ob];
    IF p.l=pdif THEN
      pr.orArea[x-p.surround+p.wExt, y-p.surround,
        x+p.size[0]+p.surround-p.wExt, y+p.size[1]+p.surround,
        nwel, @pr.r];

      IF x > pr.r.x2 OR y > pr.r.y2 OR x + p.size[0] < pr.r.x1
      OR y + p.size[1] < pr.r.y1 THEN RETURN;
    -- IF p.lExt>0 THEN
      BEGIN -- make 0-length source/drain terminals anyway
      joinTo ← @xstrInst.map[drain];
      pr.orArea[x + p.wExt, y, x + p.width + p.wExt, y + p.lExt,
        p.l, @pr.r]; -- "drain" dif
      joinTo ← @xstrInst.map[source];
      pr.orArea[x + p.wExt, y + p.length + p.lExt,
        x + p.width + p.wExt, y + p.size[1],
        p.l, @pr.r]; -- "source" dif
      END;
    joinTo ← @xstrInst.map[gate];
    pr.orArea[x, y + p.lExt, x + p.size[0], y + p.length + p.lExt,
      pol, @pr.r]; -- gate
    IF doingDRC THEN
      BEGIN
      ExtractorFeature.p[x+p.wExt, y+p.lExt,
        x+p.width+p.wExt, y + p.length + p.lExt,
        (IF p.l=dif THEN nGate ELSE pGate)];
      IF p.wExt<polyGateOverlap THEN
        BEGIN
        ExtractorFeature.p[x-polyGateOverlap+p.wExt, y+p.lExt,
          x, y + p.length + p.lExt, polyRequired];
        ExtractorFeature.p[x+p.size[0], y+p.lExt,
          x+p.size[0]+polyGateOverlap-p.wExt, y + p.length + p.lExt,
          polyRequired];
        END;
      IF p.lExt<minTransistorDiffusionWidth THEN
        BEGIN
        ExtractorFeature.p[x+p.wExt,
          y-minTransistorDiffusionWidth+p.lExt,
          x+p.width+p.wExt, y,
          (IF p.l=dif THEN nPlusRequired ELSE pPlusRequired)];
        ExtractorFeature.p[x+p.wExt, y + p.size[1],
          x+p.width+p.wExt,
          y + p.length + p.lExt+minTransistorDiffusionWidth,
          (IF p.l=dif THEN nPlusRequired ELSE pPlusRequired)];
        END;
      ExtractorFeature[x+p.wExt-depletionOverlap,
        y+p.lExt-depletionOverlap,
        x+p.width+p.wExt+depletionOverlap,
        y + p.length + p.lExt+depletionOverlap,
        (IF p.impl THEN nDepletionRequired
          ELSE nDepletionForbidden)];
      END;
    IF p.impl THEN
      pr.orArea[x+p.wExt-depletionOverlap,
        y+p.lExt-depletionOverlap,
        x + p.size[0]-p.wExt+depletionOverlap,
        y + p.size[1]-p.lExt+depletionOverlap,
        imp, @pr.r];
    END;

  exAXstr0: PUBLIC drProc =
    BEGIN
    p: LONG POINTER TO xstr object = LOOPHOLE[ob];
    ele: locNum;
    hPoly, vPoly, nDrain, eDrain, wSource, sSource: Rect;
    IF x > pr.r.x2 OR y > pr.r.y2 OR x + p.size[0] < pr.r.x1
      OR y + p.size[1] < pr.r.y1 THEN RETURN;

    ele ← 2*p.lExt+p.length; -- length and two length extensions

    -- The transistor makes a 90-degree bend, going eastward and
    -- then southward.  The diffusion on the outer side of the angle,
    -- that is, on the northeast side, is arbitrarily called the drain.

    hPoly ← [x1: x, y1: y+p.lExt,
      x2: x+p.size[0]-p.lExt, y2: y+p.length+p.lExt];
    vPoly ← [x1: x+p.size[0]-p.length-p.lExt,
      y1: hPoly.y2, x2: hPoly.x2, y2: y+p.size[1]];
    nDrain ← [x1: x+p.wExt, y1: y, x2: x+p.size[0],
      y2: hPoly.y1];
    eDrain ← [x1: vPoly.x2, y1: nDrain.y2,
      x2: nDrain.x2, y2: y+p.size[1]-p.wExt];
    wSource ← [
      x1: x+p.size[0]-ele,
      y1: hPoly.y2,
      x2: vPoly.x1,
      y2: y+p.size[1]-p.wExt];
    sSource ← [x1: x+MIN[p.wExt, p.size[0]-ele],
      y1: hPoly.y2,
      x2: wSource.x1,
      y2: y+MIN[ele, p.size[1]-p.wExt]];

    -- We are willing to put out 0-width wires here
    -- so that other conductors can join onto them,
    -- and so that design rule checking can work.

    joinTo ← @xstrInst.map[drain];
    pr.orArea[nDrain.x1, nDrain.y1, nDrain.x2, nDrain.y2,
      dif, @pr.r]; -- north "drain" dif
    pr.orArea[eDrain.x1, eDrain.y1, eDrain.x2, eDrain.y2,
      dif, @pr.r]; -- east "drain" dif
    joinTo ← @xstrInst.map[source];
    pr.orArea[wSource.x1, wSource.y1, wSource.x2, wSource.y2,
      dif, @pr.r]; -- west "source" dif
    IF sSource.x1<sSource.x2 THEN
      pr.orArea[sSource.x1, sSource.y1, sSource.x2, sSource.y2,
        dif,@pr.r];  -- south "source" dif

    joinTo ← @xstrInst.map[gate];
    pr.orArea[hPoly.x1, hPoly.y1, hPoly.x2, hPoly.y2, pol, @pr.r];
      -- horizontal gate
    IF vPoly.y1<vPoly.y2 THEN
      pr.orArea[vPoly.x1, vPoly.y1, vPoly.x2, vPoly.y2, pol, @pr.r];
        -- vertical gate

    IF doingDRC THEN
      BEGIN
      reqLev: ExtractLevel ←
        IF p.l=dif THEN nPlusRequired ELSE pPlusRequired;

      ExtractorFeature.p[sSource.x1, hPoly.y1, hPoly.x2, hPoly.y2,
        (IF p.l=dif THEN nGate ELSE pGate)]; -- horizontal
      ExtractorFeature.p[vPoly.x1, vPoly.y1, vPoly.x2, wSource.y2,
        (IF p.l=dif THEN nGate ELSE pGate)]; -- vertical

      IF sSource.x1-hPoly.x1<polyGateOverlap THEN
        ExtractorFeature.p[
          sSource.x1-polyGateOverlap,
          hPoly.y1,
          hPoly.x1, hPoly.y2, polyRequired]; -- horizontal

      IF vPoly.y2-wSource.y2<polyGateOverlap THEN
        ExtractorFeature.p[vPoly.x1, vPoly.y2,
          vPoly.x2, wSource.y2+polyGateOverlap,
          polyRequired]; -- vertical

      IF p.lExt<minTransistorDiffusionWidth THEN
        BEGIN
        ExtractorFeature.p[
          nDrain.x1,
          nDrain.y2-minTransistorDiffusionWidth,
          eDrain.x1+minTransistorDiffusionWidth, nDrain.y1,
          reqLev]; -- north drain
        ExtractorFeature.p[
          eDrain.x2,
          eDrain.y1,
          eDrain.x1+minTransistorDiffusionWidth,
          eDrain.y2,
          reqLev]; -- east drain
        END;

      IF wSource.x2-wSource.x1<minTransistorDiffusionWidth THEN
        ExtractorFeature.p[
          wSource.x2-minTransistorDiffusionWidth,
          wSource.y1,
          wSource.x1,
          MAX[wSource.y2, wSource.y1+minTransistorDiffusionWidth],
          reqLev]; -- west source

      IF sSource.x1<sSource.x2 AND
        sSource.y2-sSource.y1<minTransistorDiffusionWidth THEN
        ExtractorFeature.p[
          sSource.x1,
          sSource.y2,
          sSource.x2,
          sSource.y1+minTransistorDiffusionWidth,
          reqLev]; -- south source
      END;

    IF p.impl THEN
      BEGIN
      pr.orArea[nDrain.x1-depletionOverlap,
        hPoly.y1-depletionOverlap,
        hPoly.x2+depletionOverlap,
        hPoly.y2+depletionOverlap,
        imp, @pr.r];
      pr.orArea[vPoly.x1-depletionOverlap,
        vPoly.y1-depletionOverlap,
        vPoly.x2+depletionOverlap,
        eDrain.y2+depletionOverlap,
        imp, @pr.r];
      END
    ELSE IF doingDRC THEN
      BEGIN
      ExtractorFeature.p[
        sSource.x1-depletionOverlap,
        hPoly.y1-depletionOverlap,
        hPoly.x2+depletionOverlap,
        hPoly.y2+depletionOverlap,
        nDepletionForbidden]; -- horizontal
      ExtractorFeature.p[
        vPoly.x1-depletionOverlap,
        vPoly.y1-depletionOverlap,
        vPoly.x2+depletionOverlap,
        wSource.y2+depletionOverlap,
        nDepletionForbidden]; -- vertical
      END;
    END; -- of exAXstr0

  exPu0: PUBLIC drProc =
    BEGIN
    p: LONG POINTER TO xstr object = LOOPHOLE[ob];
    xx, yy: INTEGER;
    id: NormalNetIdPtr;
    xstrInst.map[gate] ← xstrInst.map[source] ← NewNet[initRefs: 2];
    id ← GetNormalNetId[@xstrInst.map[gate]];
    id.source ← NearestCellInstance[xstrInst];
    id.couldBeLogo ← FALSE;
    IF x > pr.r.x2 OR y > pr.r.y2 OR x + p.size[0] < pr.r.x1
      OR y + p.size[1] < pr.r.y1 THEN RETURN;
    xx ← x + p.wExt;
    yy ← y + p.lExt;
    -- IF p.lExt>0 THEN
      BEGIN
      joinTo ← @xstrInst.map[drain];
      pr.orArea[xx, y, xx + p.width, y + p.lExt, dif, @pr.r];
        -- "drain" dif
      END;
    joinTo ← @xstrInst.map[gate];
    pr.orArea[x, yy, x + p.size[0], yy + p.length, pol, @pr.r];
    pr.orArea[x, y, x + p.size[0], yy + p.length + p.lExt,
      imp, @pr.r];
    xx ← x + p.size[0]/2 - butconSX/2;
    yy ← y + p.size[1];
    joinTo ← @xstrInst.map[source];
    pr.orArea[xx, y+p.lExt+p.length, xx + butconSX, yy,
      dif, @pr.r]; -- "source" dif
    joinTo ← @xstrInst.map[gate];
    pr.orArea[xx, yy - butconSY, xx + butconSX, yy, met, @pr.r];
    xx ← xx + butconSX/4;
    yy ← yy - butconSX/4;
    pr.saveArea[xx, yy - butconSX, xx + butconSX/2, yy,
      cut, @pr.r];
    END;

  exBC0: PUBLIC drProc =
    BEGIN
    p: LONG POINTER TO cont object = LOOPHOLE[ob];
    IF x > pr.r.x2 OR y > pr.r.y2 OR x + p.size[0] < pr.r.x1
      OR y + p.size[1] < pr.r.y1 THEN RETURN;
    pr.orArea[x, y, x + p.size[0], y + p.size[1], met, @pr.r];
    pr.orArea[x, y, x + p.size[0], y + p.size[1]/2, pol, @pr.r];
    pr.orArea[x, y + p.size[1]/2, x + p.size[0], y + p.size[1],
      dif, @pr.r];
    pr.saveArea[
      x + p.magicN, y + p.magicN, x - p.magicN + p.size[0],
      y + p.magicN + p.size[0], cut, @pr.r];
    END;

  exBuC0: PUBLIC drProc =
    BEGIN
    p: LONG POINTER TO cont object = LOOPHOLE[ob];
    IF x > pr.r.x2 OR y > pr.r.y2 OR x + p.size[0] < pr.r.x1
      OR y + p.size[1] < pr.r.y1 THEN RETURN;
    pr.orArea[x+p.wExt,y,x+p.size[0]-p.wExt+p.magicN,y+p.size[1], pol, @pr.r];
    pr.orArea[x,y+p.lExt,x+p.size[0],y+p.size[1]-p.lExt, dif, @pr.r];
    pr.saveArea[x,y,x+p.size[0],y+p.size[1],bur,@pr.r];
    END;

  END. -- of ChipExpandAtomic